ui: add image playing indicator

Add a playing indicator to cover art.

This is simply to improve the general aestethics of this view. Of
course, the current way I implement this is incredibly stupid and I
plan to replace it.
This commit is contained in:
OxygenCobalt 2022-06-10 09:47:37 -06:00
parent 1d66907862
commit ffe7298665
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 51 additions and 16 deletions

View file

@ -10,6 +10,8 @@
- The toolbar in the home UI now collapses when scrolling - The toolbar in the home UI now collapses when scrolling
- The toolbar layout is now consistent with Material Design 3 - The toolbar layout is now consistent with Material Design 3
- Genre parsing now handles multiple integer values and cover/remix indicators (May wipe playback state) - Genre parsing now handles multiple integer values and cover/remix indicators (May wipe playback state)
#### What's Fixed
- Playback bar now picks the larger inset in case that gesture inset is missing [#149] - Playback bar now picks the larger inset in case that gesture inset is missing [#149]
#### Dev/Meta #### Dev/Meta

View file

@ -74,8 +74,7 @@ abstract class BaseFetcher : Fetcher {
fetchMediaStoreCovers(context, album) fetchMediaStoreCovers(context, album)
} }
} catch (e: Exception) { } catch (e: Exception) {
logW("Unable to extract album art due to an error") logW("Unable to extract album art due to an error: $e")
logW(e.stackTraceToString())
null null
} }
} }

View file

@ -54,7 +54,7 @@ constructor(
FrameLayout(context, attrs, defStyleAttr), FrameLayout(context, attrs, defStyleAttr),
Slider.OnSliderTouchListener, Slider.OnSliderTouchListener,
Slider.OnChangeListener { Slider.OnChangeListener {
private val binding = ViewSeekBarBinding.inflate(context.inflater, this, true) private val binding = ViewSeekBarBinding.inflate(context.inflater, this)
init { init {
binding.seekBarSlider.addOnSliderTouchListener(this) binding.seekBarSlider.addOnSliderTouchListener(this)

View file

@ -29,6 +29,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
import coil.dispose import coil.dispose
import coil.drawable.CrossfadeDrawable
import coil.load import coil.load
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
@ -50,19 +51,18 @@ import org.oxycblt.auxio.util.getDrawableSafe
* of the view size, and corner radius application depending on user preference. * of the view size, and corner radius application depending on user preference.
* @author OxygenCobalt * @author OxygenCobalt
* *
* TODO: Rework this layout into a total ViewGroup that enables more customization + an indicator * TODO: I'll need to make it a whole ViewGroup eventually
*/ */
class StyledImageView class StyledImageView
@JvmOverloads @JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) : constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
AppCompatImageView(context, attrs, defStyleAttr) { AppCompatImageView(context, attrs, defStyleAttr) {
private var cornerRadius = 0f private var cornerRadius = 0f
private var indicator = StyledDrawable(context, R.drawable.ic_equalizer)
init { init {
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageView) val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageView)
cornerRadius = styledAttrs.getDimension(R.styleable.StyledImageView_cornerRadius, 0f) cornerRadius = styledAttrs.getDimension(R.styleable.StyledImageView_cornerRadius, 0f)
styledAttrs.recycle() styledAttrs.recycle()
// Use clipToOutline and a background drawable to crop images. While Coil's transformation // Use clipToOutline and a background drawable to crop images. While Coil's transformation
@ -95,19 +95,35 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
} }
} }
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (isActivated) {
// We can't modify the view alpha since that would change the background opacity,
// but we also can't modify the image alpha since that breaks CrossfadeDrawable.
// Instead, we just draw the background again when activated in order to obscure
// the actual image, and then draw the indicator. The only other option is to make
// a proper ViewGroup, and I really don't want that.
val src = drawable?.let { if (it is CrossfadeDrawable) it.end else it }
background.alpha = if (src is StyledDrawable) 255 else 128
background.draw(canvas)
background.alpha = 255
indicator.draw(canvas)
}
}
/** Bind the album cover for a [song]. */ /** Bind the album cover for a [song]. */
fun bind(song: Song) = load(song, R.drawable.ic_song, R.string.desc_album_cover) fun bind(song: Song) = loadImpl(song, R.drawable.ic_song, R.string.desc_album_cover)
/** Bind the album cover for an [album]. */ /** Bind the album cover for an [album]. */
fun bind(album: Album) = load(album, R.drawable.ic_album, R.string.desc_album_cover) fun bind(album: Album) = loadImpl(album, R.drawable.ic_album, R.string.desc_album_cover)
/** Bind the image for an [artist] */ /** Bind the image for an [artist] */
fun bind(artist: Artist) = load(artist, R.drawable.ic_artist, R.string.desc_artist_image) fun bind(artist: Artist) = loadImpl(artist, R.drawable.ic_artist, R.string.desc_artist_image)
/** Bind the image for a [genre] */ /** Bind the image for a [genre] */
fun bind(genre: Genre) = load(genre, R.drawable.ic_genre, R.string.desc_genre_image) fun bind(genre: Genre) = loadImpl(genre, R.drawable.ic_genre, R.string.desc_genre_image)
private fun <T : Music> load(music: T, @DrawableRes error: Int, @StringRes desc: Int) { private fun <T : Music> loadImpl(music: T, @DrawableRes error: Int, @StringRes desc: Int) {
dispose() dispose()
load(music) { load(music) {
error(StyledDrawable(context, error)) error(StyledDrawable(context, error))

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/transparent" android:state_activated="true" />
<item android:color="?attr/colorSurfaceInverse" />
</selector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M10,20h4L14,4h-4v16zM4,20h4v-8L4,12v8zM16,9v11h4L20,9h-4z"/>
</vector>

View file

@ -8,7 +8,8 @@
<!-- <!--
We don't want to show an album cover, but we still want the spacing of this song We don't want to show an album cover, but we still want the spacing of this song
to be alike to other songs. So, add a pastel-ish background to each track number to be alike to other songs. So, add a pastel-ish background to each track number
view. The way we do this is odd, but it's designed this way--> view. The way we do this is odd, but it's designed this way.
-->
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.ui.StyledImageView
android:id="@+id/song_track_bg" android:id="@+id/song_track_bg"
@ -27,7 +28,7 @@
android:maxLines="1" android:maxLines="1"
android:textAlignment="center" android:textAlignment="center"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge" android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
android:textColor="@color/sel_on_cover_bg" android:textColor="@color/sel_track_cover"
app:autoSizeMaxTextSize="@dimen/text_size_track_number_max" app:autoSizeMaxTextSize="@dimen/text_size_track_number_max"
app:autoSizeMinTextSize="@dimen/text_size_track_number_min" app:autoSizeMinTextSize="@dimen/text_size_track_number_min"
app:autoSizeStepGranularity="@dimen/text_size_track_number_step" app:autoSizeStepGranularity="@dimen/text_size_track_number_step"

View file

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
tools:parentTag="android.widget.FrameLayout">
<com.google.android.material.slider.Slider <com.google.android.material.slider.Slider
android:id="@+id/seek_bar_slider" android:id="@+id/seek_bar_slider"
@ -41,4 +42,4 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" /> tools:text="16:16" />
</FrameLayout> </merge>