Highlight sort menu item when selected

Highlight the menu item for the currently shown order when its selected.
This commit is contained in:
OxygenCobalt 2020-09-28 18:11:56 -06:00
parent 37c52d9e5c
commit 08f8e50bbf
10 changed files with 94 additions and 40 deletions

View file

@ -32,7 +32,9 @@ class AlbumDetailFragment : Fragment() {
// If DetailViewModel isn't already storing the album, get it from MusicViewModel
// using the ID given by the navigation arguments.
if (detailModel.currentAlbum.value!!.id != args.albumId) {
if (detailModel.currentAlbum.value == null ||
detailModel.currentAlbum.value?.id != args.albumId
) {
val musicModel: MusicViewModel by activityViewModels()
detailModel.updateAlbum(

View file

@ -33,7 +33,9 @@ class ArtistDetailFragment : Fragment() {
// If DetailViewModel isn't already storing the artist, get it from MusicViewModel
// using the ID given by the navigation arguments
if (detailModel.currentArtist.value!!.id != args.artistId) {
if (detailModel.currentArtist.value == null ||
detailModel.currentArtist.value?.id != args.artistId
) {
val musicModel: MusicViewModel by activityViewModels()
detailModel.updateArtist(

View file

@ -21,20 +21,13 @@ class DetailViewModel : ViewModel() {
val albumSortMode: LiveData<SortMode> get() = mAlbumSortMode
// Current music models being shown
// These have placeholder values initially so that they don't have to be checked if they're null
private val mCurrentGenre = MutableLiveData(
Genre(id = Long.MIN_VALUE, name = "")
)
private val mCurrentGenre = MutableLiveData<Genre>()
val currentGenre: LiveData<Genre> get() = mCurrentGenre
private val mCurrentArtist = MutableLiveData(
Artist(id = Long.MIN_VALUE, name = "")
)
private val mCurrentArtist = MutableLiveData<Artist>()
val currentArtist: LiveData<Artist> get() = mCurrentArtist
private val mCurrentAlbum = MutableLiveData(
Album(id = Long.MIN_VALUE, name = "", artistName = "")
)
private val mCurrentAlbum = MutableLiveData<Album>()
val currentAlbum: LiveData<Album> get() = mCurrentAlbum
private val mNavToParent = MutableLiveData<Boolean>()

View file

@ -33,7 +33,9 @@ class GenreDetailFragment : Fragment() {
// If DetailViewModel isn't already storing the genre, get it from MusicViewModel
// using the ID given by the navigation arguments
if (detailModel.currentGenre.value!!.id != args.genreId) {
if (detailModel.currentGenre.value == null ||
detailModel.currentGenre.value?.id != args.genreId
) {
val musicModel: MusicViewModel by activityViewModels()
detailModel.updateGenre(

View file

@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.forEach
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
@ -19,7 +20,9 @@ import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.theme.applyColor
import org.oxycblt.auxio.theme.applyDivider
import org.oxycblt.auxio.theme.resolveAttr
class LibraryFragment : Fragment() {
@ -42,15 +45,28 @@ class LibraryFragment : Fragment() {
binding.libraryRecycler.setHasFixedSize(true)
libraryModel.sortMode.observe(viewLifecycleOwner) { mode ->
binding.libraryToolbar.overflowIcon = ContextCompat.getDrawable(
requireContext(), mode.iconRes
)
Log.d(this::class.simpleName, "Updating sort mode to $mode")
// Update the adapter with the new data
artistAdapter.updateData(
mode.getSortedArtistList(
musicModel.artists.value!!
)
)
// Then update the shown icon & the currently highlighted sort icon to reflect
// the new sorting mode.
binding.libraryToolbar.overflowIcon = ContextCompat.getDrawable(
requireContext(), mode.iconRes
)
binding.libraryToolbar.menu.forEach {
if (it.itemId == libraryModel.sortMode.value!!.toMenuId()) {
it.applyColor(resolveAttr(requireContext(), R.attr.colorPrimary))
} else {
it.applyColor(resolveAttr(requireContext(), android.R.attr.textColorPrimary))
}
}
}
binding.libraryToolbar.setOnMenuItemClickListener {

View file

@ -0,0 +1,27 @@
package org.oxycblt.auxio.recycler
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.music.BaseModel
// ViewHolder abstraction that automates some of the things that are common for all ViewHolders.
abstract class BaseViewHolder<T : BaseModel>(
private val baseBinding: ViewDataBinding,
protected val listener: ClickListener<T>
) : RecyclerView.ViewHolder(baseBinding.root) {
init {
baseBinding.root.layoutParams = RecyclerView.LayoutParams(
RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT
)
}
fun bind(model: T) {
baseBinding.root.setOnClickListener { listener.onClick(model) }
onBind(model)
baseBinding.executePendingBindings()
}
abstract fun onBind(model: T)
}

View file

@ -1,8 +1,6 @@
package org.oxycblt.auxio.recycler
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.music.BaseModel
// RecyclerView click listener
@ -18,25 +16,3 @@ class DiffCallback<T : BaseModel> : DiffUtil.ItemCallback<T>() {
return oldItem == newItem
}
}
// ViewHolder abstraction that automates some of the things that are common for all ViewHolders.
abstract class BaseViewHolder<T : BaseModel>(
private val baseBinding: ViewDataBinding,
protected val listener: ClickListener<T>
) : RecyclerView.ViewHolder(baseBinding.root) {
init {
baseBinding.root.layoutParams = RecyclerView.LayoutParams(
RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT
)
}
fun bind(model: T) {
baseBinding.root.setOnClickListener { listener.onClick(model) }
onBind(model)
baseBinding.executePendingBindings()
}
abstract fun onBind(model: T)
}

View file

@ -2,6 +2,11 @@ package org.oxycblt.auxio.theme
import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import android.util.TypedValue
import android.view.MenuItem
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
@ -60,6 +65,30 @@ fun Int.toColor(context: Context): Int {
}
}
@ColorInt
fun resolveAttr(context: Context, @AttrRes attr: Int): Int {
// Convert the attribute into its color
val resolvedAttr = TypedValue().apply {
context.theme.resolveAttribute(attr, this, true)
}
// Then convert it to a proper color
val color = if (resolvedAttr.resourceId != 0) {
resolvedAttr.resourceId
} else {
resolvedAttr.data
}
return color.toColor(context)
}
fun MenuItem.applyColor(color: Int) {
SpannableString(title).apply {
setSpan(ForegroundColorSpan(color), 0, length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
title = this
}
}
// Apply a custom vertical divider
fun RecyclerView.applyDivider() {
val div = DividerItemDecoration(

View file

@ -16,6 +16,7 @@
android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal"
app:popupTheme="@style/AppThemeOverlay.Popup"
app:titleTextAppearance="@style/TextAppearance.Toolbar.Bold"
app:title="@string/title_library_fragment" />

View file

@ -5,6 +5,7 @@
<item name="android:windowBackground">@color/background</item>
<item name="android:statusBarColor">@android:color/black</item>
<item name="android:fontFamily">@font/inter</item>
<item name="actionBarPopupTheme">@style/AppThemeOverlay.Popup</item>
</style>
<style name="TextAppearance.Toolbar.Bold" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
@ -18,4 +19,9 @@
<item name="android:fontFamily">@font/inter_black</item>
<item name="android:textSize">@dimen/detail_header_size_max</item>
</style>
<style name="AppThemeOverlay.Popup" parent="ThemeOverlay.AppCompat.DayNight">
<item name="android:colorBackground">@color/background</item>
<item name="colorControlHighlight">@color/selection_color</item>
</style>
</resources>