Add playing indicators to GenreDetailFragment

Add an indicator that a song is playing from a specific genre in GenreDetailFragment.
This commit is contained in:
OxygenCobalt 2020-12-31 09:37:37 -07:00
parent 33abb1419a
commit dfaffecbd3
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 77 additions and 13 deletions

View file

@ -106,8 +106,6 @@ class ArtistDetailFragment : DetailFragment() {
}
}
// --- PLAYBACKVIEWMODEL SETUP ---
playbackModel.parent.observe(viewLifecycleOwner) { parent ->
if (playbackModel.mode.value == PlaybackMode.IN_ALBUM && parent is Album?) {
detailAdapter.setCurrentAlbum(parent, binding.detailRecycler)

View file

@ -13,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.FragmentDetailBinding
import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.Highlightable
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.memberBinding

View file

@ -74,7 +74,7 @@ class GenreDetailFragment : DetailFragment() {
setupRecycler(detailAdapter)
// --- VIEWMODEL SETUP ---
// --- DETAILVIEWMODEL SETUP ---
detailModel.genreSortMode.observe(viewLifecycleOwner) { mode ->
logD("Updating sort mode to $mode")
@ -102,6 +102,25 @@ class GenreDetailFragment : DetailFragment() {
}
}
// --- PLAYBACKVIEWMODEL SETUP ---
playbackModel.song.observe(viewLifecycleOwner) { song ->
if (playbackModel.mode.value == PlaybackMode.IN_GENRE &&
playbackModel.parent.value?.id == detailModel.currentGenre.value!!.id
) {
detailAdapter.highlightSong(song, binding.detailRecycler)
} else {
// Clear the viewholders if the mode isn't ALL_SONGS
detailAdapter.highlightSong(null, binding.detailRecycler)
}
}
playbackModel.isInUserQueue.observe(viewLifecycleOwner) {
if (it) {
detailAdapter.highlightSong(null, binding.detailRecycler)
}
}
logD("Fragment created.")
return binding.root

View file

@ -13,8 +13,11 @@ import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.Highlightable
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setTextColorResource
/**
* An adapter for displaying the [Song]s of a genre.
@ -26,6 +29,9 @@ class GenreDetailAdapter(
private val doOnLongClick: (data: Song, view: View) -> Unit
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback()) {
private var currentSong: Song? = null
private var lastHolder: Highlightable? = null
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is Genre -> GENRE_HEADER_ITEM_TYPE
@ -54,6 +60,47 @@ class GenreDetailAdapter(
is Genre -> (holder as GenreHeaderViewHolder).bind(item)
is Song -> (holder as GenreSongViewHolder).bind(item)
}
if (currentSong != null && position > 0) {
if (getItem(position).id == currentSong?.id) {
// Reset the last ViewHolder before assigning the new, correct one to be highlighted
lastHolder?.setHighlighted(false)
lastHolder = (holder as Highlightable)
holder.setHighlighted(true)
} else {
(holder as Highlightable).setHighlighted(false)
}
}
}
/**
* Update the current song that this adapter should be watching for to highlight.
* @param song The [Song] to highlight if found, null to clear any highlighted ViewHolders
*/
fun highlightSong(song: Song?, recycler: RecyclerView) {
// Clear out the last ViewHolder as a song update usually signifies that this current
// ViewHolder is likely invalid.
lastHolder?.setHighlighted(false)
lastHolder = null
currentSong = song
if (song != null) {
// Use existing data instead of having to re-sort it.
val pos = currentList.indexOfFirst {
it.name == song.name && it is Song
}
// Check if the ViewHolder for this song is visible, if it is then highlight it.
// If the ViewHolder is not visible, then the adapter should take care of it if
// it does become visible.
recycler.layoutManager?.findViewByPosition(pos)?.let { child ->
recycler.getChildViewHolder(child)?.let {
lastHolder = it as Highlightable
lastHolder?.setHighlighted(true)
}
}
}
}
inner class GenreHeaderViewHolder(
@ -72,7 +119,8 @@ class GenreDetailAdapter(
inner class GenreSongViewHolder(
private val binding: ItemGenreSongBinding,
) : BaseViewHolder<Song>(binding, doOnClick, doOnLongClick) {
) : BaseViewHolder<Song>(binding, doOnClick, doOnLongClick), Highlightable {
private val normalTextColor = binding.songName.currentTextColor
override fun onBind(data: Song) {
binding.song = data
@ -80,6 +128,14 @@ class GenreDetailAdapter(
binding.songName.requestLayout()
binding.songInfo.requestLayout()
}
override fun setHighlighted(isHighlighted: Boolean) {
if (isHighlighted) {
binding.songName.setTextColorResource(accent.first)
} else {
binding.songName.setTextColor(normalTextColor)
}
}
}
companion object {

View file

@ -11,7 +11,6 @@ import android.view.MenuItem
import android.widget.ImageButton
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.MenuRes
@ -91,13 +90,6 @@ fun TextView.setTextColorResource(@ColorRes color: Int) {
setTextColor(color.toColor(context))
}
/**
* Set a [TextView] text color, using an attr resource
*/
fun TextView.setTextColorAttr(@AttrRes attr: Int) {
setTextColor(resolveAttr(context, attr))
}
/**
* Show actions for a song item, such as the ones found in [org.oxycblt.auxio.songs.SongsFragment]
* @param context [Context] required