Add playing indicators to GenreDetailFragment
Add an indicator that a song is playing from a specific genre in GenreDetailFragment.
This commit is contained in:
parent
33abb1419a
commit
dfaffecbd3
5 changed files with 77 additions and 13 deletions
|
@ -106,8 +106,6 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- PLAYBACKVIEWMODEL SETUP ---
|
|
||||||
|
|
||||||
playbackModel.parent.observe(viewLifecycleOwner) { parent ->
|
playbackModel.parent.observe(viewLifecycleOwner) { parent ->
|
||||||
if (playbackModel.mode.value == PlaybackMode.IN_ALBUM && parent is Album?) {
|
if (playbackModel.mode.value == PlaybackMode.IN_ALBUM && parent is Album?) {
|
||||||
detailAdapter.setCurrentAlbum(parent, binding.detailRecycler)
|
detailAdapter.setCurrentAlbum(parent, binding.detailRecycler)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
||||||
import org.oxycblt.auxio.music.BaseModel
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.recycler.Highlightable
|
|
||||||
import org.oxycblt.auxio.ui.isLandscape
|
import org.oxycblt.auxio.ui.isLandscape
|
||||||
import org.oxycblt.auxio.ui.memberBinding
|
import org.oxycblt.auxio.ui.memberBinding
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ class GenreDetailFragment : DetailFragment() {
|
||||||
|
|
||||||
setupRecycler(detailAdapter)
|
setupRecycler(detailAdapter)
|
||||||
|
|
||||||
// --- VIEWMODEL SETUP ---
|
// --- DETAILVIEWMODEL SETUP ---
|
||||||
|
|
||||||
detailModel.genreSortMode.observe(viewLifecycleOwner) { mode ->
|
detailModel.genreSortMode.observe(viewLifecycleOwner) { mode ->
|
||||||
logD("Updating sort mode to $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.")
|
logD("Fragment created.")
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
|
|
|
@ -13,8 +13,11 @@ import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
|
import org.oxycblt.auxio.recycler.Highlightable
|
||||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||||
|
import org.oxycblt.auxio.ui.accent
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
|
import org.oxycblt.auxio.ui.setTextColorResource
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An adapter for displaying the [Song]s of a genre.
|
* An adapter for displaying the [Song]s of a genre.
|
||||||
|
@ -26,6 +29,9 @@ class GenreDetailAdapter(
|
||||||
private val doOnLongClick: (data: Song, view: View) -> Unit
|
private val doOnLongClick: (data: Song, view: View) -> Unit
|
||||||
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback()) {
|
) : ListAdapter<BaseModel, RecyclerView.ViewHolder>(DiffCallback()) {
|
||||||
|
|
||||||
|
private var currentSong: Song? = null
|
||||||
|
private var lastHolder: Highlightable? = null
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (getItem(position)) {
|
return when (getItem(position)) {
|
||||||
is Genre -> GENRE_HEADER_ITEM_TYPE
|
is Genre -> GENRE_HEADER_ITEM_TYPE
|
||||||
|
@ -54,6 +60,47 @@ class GenreDetailAdapter(
|
||||||
is Genre -> (holder as GenreHeaderViewHolder).bind(item)
|
is Genre -> (holder as GenreHeaderViewHolder).bind(item)
|
||||||
is Song -> (holder as GenreSongViewHolder).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(
|
inner class GenreHeaderViewHolder(
|
||||||
|
@ -72,7 +119,8 @@ class GenreDetailAdapter(
|
||||||
|
|
||||||
inner class GenreSongViewHolder(
|
inner class GenreSongViewHolder(
|
||||||
private val binding: ItemGenreSongBinding,
|
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) {
|
override fun onBind(data: Song) {
|
||||||
binding.song = data
|
binding.song = data
|
||||||
|
@ -80,6 +128,14 @@ class GenreDetailAdapter(
|
||||||
binding.songName.requestLayout()
|
binding.songName.requestLayout()
|
||||||
binding.songInfo.requestLayout()
|
binding.songInfo.requestLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setHighlighted(isHighlighted: Boolean) {
|
||||||
|
if (isHighlighted) {
|
||||||
|
binding.songName.setTextColorResource(accent.first)
|
||||||
|
} else {
|
||||||
|
binding.songName.setTextColor(normalTextColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import android.view.MenuItem
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.AttrRes
|
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import androidx.annotation.MenuRes
|
import androidx.annotation.MenuRes
|
||||||
|
@ -91,13 +90,6 @@ fun TextView.setTextColorResource(@ColorRes color: Int) {
|
||||||
setTextColor(color.toColor(context))
|
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]
|
* Show actions for a song item, such as the ones found in [org.oxycblt.auxio.songs.SongsFragment]
|
||||||
* @param context [Context] required
|
* @param context [Context] required
|
||||||
|
|
Loading…
Reference in a new issue