Highlight sort menu item when selected
Highlight the menu item for the currently shown order when its selected.
This commit is contained in:
parent
37c52d9e5c
commit
08f8e50bbf
10 changed files with 94 additions and 40 deletions
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>()
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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" />
|
||||
|
||||
|
|
|
@ -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>
|
Loading…
Reference in a new issue