coil: make rounded images more nuanced

Create a custom view for rounded images, making them more nuanced in
the process.

The previous method for applying rounded images in-app was generally
clunky and fragile. Introduce a new custom view that actually takes a
cornerRadius attribute from the ImageView itself that then applies it
whenever the user enables the setting. This also allows rounded images
to be more nuanced, as typical 8dp elevation can be used for small
views and a more fitting 16dp radius can be used for large views.
This commit is contained in:
OxygenCobalt 2022-02-23 17:36:17 -07:00
parent 280b582efa
commit 61dbfe3185
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
31 changed files with 83 additions and 53 deletions

View file

@ -3,6 +3,7 @@
## dev [v2.2.2 or 2.3.0]
#### What's Improved
- Rounded images are more nuanced
- Shuffle and Repeat mode buttons now have more contrast when they are turned on
#### What's Changed

View file

@ -79,10 +79,6 @@ class MainFragment : Fragment() {
// but for some insane reason google decided to cripple the window APIs one could use
// to limit it's size. So, we just have our own special layout that is shown whenever
// the screen is too small because of course we have to.
// Another fun fact: smallestScreenWidthDp is completely bugged and uses the total
// screen size, even when the window is smaller. This basically borks split screen
// even more than it already does. Fun!
if (requireActivity().isInMultiWindowMode) {
val config = resources.configuration

View file

@ -35,7 +35,6 @@ import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.settings.SettingsManager
// --- BINDING ADAPTERS ---
@ -66,21 +65,6 @@ fun ImageView.bindGenreImage(genre: Genre?) = load(genre, R.drawable.ic_genre)
fun <T : Music> ImageView.load(music: T?, @DrawableRes error: Int) {
dispose()
// We don't round album covers by default as it desecrates album artwork, but we do provide
// an option if one wants it.
// As for why we use clipToOutline instead of coils RoundedCornersTransformation, the radii
// of an image's corners is dependent on the actual dimensions of the image, which would force
// us to resize all images to a fixed size. clipToOutline is pretty much always cheaper as long
// as we have a perfectly-square image.
val settingsManager = SettingsManager.getInstance()
if (settingsManager.roundCovers && background == null) {
setBackgroundResource(R.drawable.ui_rounded_cutout)
clipToOutline = true
} else if (!settingsManager.roundCovers && background != null) {
background = null
clipToOutline = false
}
load(music) {
error(error)
transformations(SquareFrameTransform())

View file

@ -0,0 +1,41 @@
package org.oxycblt.auxio.coil
import android.content.Context
import android.util.AttributeSet
import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatImageView
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.util.getColorSafe
import org.oxycblt.auxio.util.stateList
class RoundableImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
init {
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.RoundableImageView)
val cornerRadius = styledAttrs.getDimension(R.styleable.RoundableImageView_cornerRadius, 0.0f)
styledAttrs.recycle()
background = MaterialShapeDrawable().apply {
setCornerSize(cornerRadius)
fillColor = context.getColorSafe(android.R.color.transparent).stateList
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// We don't round album covers by default as it desecrates album artwork, but we do
// provide an option if one wants it.
// As for why we use clipToOutline instead of coils RoundedCornersTransformation, the radii
// of an image's corners is dependent on the actual dimensions of the image, which would
// force us to resize all images to a fixed size. clipToOutline is pretty much always
// cheaper as long as we have a perfectly-square image.
val settingsManager = SettingsManager.getInstance()
clipToOutline = settingsManager.roundCovers
}
}

View file

@ -159,7 +159,9 @@ class HomeFragment : Fragment() {
).attach()
}
binding.homeShuffleFab.setup(playbackModel)
binding.homeFab.setOnClickListener {
playbackModel.shuffleAll()
}
// --- VIEWMODEL SETUP ---
@ -169,12 +171,12 @@ class HomeFragment : Fragment() {
musicModel.loaderResponse.observe(viewLifecycleOwner) { response ->
// Handle the loader response.
when (response) {
is MusicStore.Response.Ok -> binding.homeShuffleFab.show()
is MusicStore.Response.Ok -> binding.homeFab.show()
// While loading or during an error, make sure we keep the shuffle fab hidden so
// that any kind of playback is impossible. PlaybackStateManager also relies on this
// invariant, so please don't change it.
else -> binding.homeShuffleFab.hide()
else -> binding.homeFab.hide()
}
}
@ -186,9 +188,9 @@ class HomeFragment : Fragment() {
}
if (scrolling) {
binding.homeShuffleFab.hide()
binding.homeFab.hide()
} else {
binding.homeShuffleFab.show()
binding.homeFab.show()
}
}

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/spacing_small" />
</shape>

View file

@ -10,7 +10,7 @@
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.Huge"
app:layout_constraintEnd_toEndOf="parent"

View file

@ -35,7 +35,7 @@
tools:subtitle="@string/lbl_all_songs"
app:title="@string/lbl_playback" />
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_marginStart="@dimen/spacing_mid_large"

View file

@ -10,7 +10,7 @@
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.Large"
app:layout_constraintStart_toStartOf="parent"

View file

@ -35,7 +35,7 @@
app:layout_constraintTop_toTopOf="parent"
app:menu="@menu/menu_playback" />
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"

View file

@ -35,7 +35,7 @@
tools:subtitle="@string/lbl_all_songs"
app:menu="@menu/menu_playback" />
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_large"

View file

@ -10,7 +10,7 @@
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.MidHuge"
app:layout_constraintDimensionRatio="1"

View file

@ -17,7 +17,7 @@
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Medium"
android:layout_margin="@dimen/spacing_small"

View file

@ -8,7 +8,7 @@
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.Huge"
app:layout_constraintStart_toStartOf="parent"

View file

@ -35,7 +35,7 @@
tools:subtitle="@string/lbl_all_songs"
app:menu="@menu/menu_playback" />
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"

View file

@ -17,7 +17,7 @@
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_small"

View file

@ -34,7 +34,7 @@
tools:subtitle="@string/lbl_all_songs"
app:menu="@menu/menu_playback" />
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_album_cover(album.name)}"

View file

@ -13,7 +13,6 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
android:id="@+id/song_track_placeholder"
android:layout_width="wrap_content"

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/artist_image"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_artist_image(artist.resolvedName)}"

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_album_cover(album.name)}"

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Small"
android:contentDescription="@{@string/desc_album_cover(song.name)}"

View file

@ -10,7 +10,7 @@
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.MidHuge"
app:layout_constraintEnd_toEndOf="parent"

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/genre_image"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_genre_image(genre.resolvedName)}"

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Small"
android:contentDescription="@{@string/desc_album_cover(song.name)}"

View file

@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:background="?attr/colorSurface">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_medium"

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Small"
android:contentDescription="@{@string/desc_album_cover(song.name)}"

View file

@ -17,7 +17,7 @@
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<ImageView
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_small"

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RoundableImageView">
<attr name="cornerRadius" format="dimension" />
</declare-styleable>
<declare-styleable name="PlaybackButton">
<attr name="hasIndicator" format="boolean" />
</declare-styleable>

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Spacing Namespace | Dimens for padding/margin attributes -->
<dimen name="spacing_tiny">4dp</dimen>
<dimen name="spacing_small">8dp</dimen>
<dimen name="spacing_medium">16dp</dimen>
<dimen name="spacing_mid_large">24dp</dimen>
@ -17,6 +16,9 @@
<dimen name="size_cover_mid_huge">192dp</dimen>
<dimen name="size_cover_huge">256dp</dimen>
<dimen name="size_corners_small">8dp</dimen>
<dimen name="size_corners_large">16dp</dimen>
<dimen name="size_track_number">32dp</dimen>
<dimen name="size_playback_icon">32dp</dimen>

View file

@ -26,32 +26,38 @@
<style name="Widget.Auxio.Image.Small" parent="">
<item name="android:layout_width">@dimen/size_cover_compact</item>
<item name="android:layout_height">@dimen/size_cover_compact</item>
<item name="cornerRadius">@dimen/size_corners_small</item>
</style>
<style name="Widget.Auxio.Image.Medium" parent="">
<item name="android:layout_width">@dimen/size_cover_normal</item>
<item name="android:layout_height">@dimen/size_cover_normal</item>
<item name="cornerRadius">@dimen/size_corners_small</item>
</style>
<style name="Widget.Auxio.Image.Large" parent="">
<item name="android:layout_width">@dimen/size_cover_large</item>
<item name="android:layout_height">@dimen/size_cover_large</item>
<item name="cornerRadius">@dimen/size_corners_large</item>
</style>
<style name="Widget.Auxio.Image.MidHuge" parent="">
<item name="android:layout_width">@dimen/size_cover_mid_huge</item>
<item name="android:layout_height">@dimen/size_cover_mid_huge</item>
<item name="cornerRadius">@dimen/size_corners_large</item>
</style>
<style name="Widget.Auxio.Image.Huge" parent="">
<item name="android:layout_width">@dimen/size_cover_huge</item>
<item name="android:layout_height">@dimen/size_cover_huge</item>
<item name="cornerRadius">@dimen/size_corners_large</item>
</style>
<style name="Widget.Auxio.Image.Full" parent="">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">0dp</item>
<item name="layout_constraintDimensionRatio">1</item>
<item name="cornerRadius">@dimen/size_corners_large</item>
</style>
<style name="Widget.Auxio.ItemLayout" parent="">