From 08f8e50bbffc4538ef86e8e21da1435f6d9b886d Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Mon, 28 Sep 2020 18:11:56 -0600 Subject: [PATCH] Highlight sort menu item when selected Highlight the menu item for the currently shown order when its selected. --- .../auxio/detail/AlbumDetailFragment.kt | 4 ++- .../auxio/detail/ArtistDetailFragment.kt | 4 ++- .../oxycblt/auxio/detail/DetailViewModel.kt | 13 ++------- .../auxio/detail/GenreDetailFragment.kt | 4 ++- .../oxycblt/auxio/library/LibraryFragment.kt | 22 ++++++++++++-- .../oxycblt/auxio/recycler/BaseViewHolder.kt | 27 +++++++++++++++++ .../oxycblt/auxio/recycler/RecyclerUtils.kt | 24 --------------- .../org/oxycblt/auxio/theme/ThemeUtils.kt | 29 +++++++++++++++++++ app/src/main/res/layout/fragment_library.xml | 1 + app/src/main/res/values/styles.xml | 6 ++++ 10 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/recycler/BaseViewHolder.kt diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index bcd4c649c..581d4820f 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -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( diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index a6efc4377..d80070134 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -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( diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt index 7f95dcd17..2ee161426 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -21,20 +21,13 @@ class DetailViewModel : ViewModel() { val albumSortMode: LiveData 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() val currentGenre: LiveData get() = mCurrentGenre - private val mCurrentArtist = MutableLiveData( - Artist(id = Long.MIN_VALUE, name = "") - ) + private val mCurrentArtist = MutableLiveData() val currentArtist: LiveData get() = mCurrentArtist - private val mCurrentAlbum = MutableLiveData( - Album(id = Long.MIN_VALUE, name = "", artistName = "") - ) + private val mCurrentAlbum = MutableLiveData() val currentAlbum: LiveData get() = mCurrentAlbum private val mNavToParent = MutableLiveData() diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index 2558c9f1e..63737ebb5 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -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( diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt index 21ed41fd0..9bdae8f4b 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -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 { diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/BaseViewHolder.kt b/app/src/main/java/org/oxycblt/auxio/recycler/BaseViewHolder.kt new file mode 100644 index 000000000..7b9bbeb6a --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/recycler/BaseViewHolder.kt @@ -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( + private val baseBinding: ViewDataBinding, + protected val listener: ClickListener +) : 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) +} diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt b/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt index f9fc0e8da..45c7d362b 100644 --- a/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/recycler/RecyclerUtils.kt @@ -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 : DiffUtil.ItemCallback() { return oldItem == newItem } } - -// ViewHolder abstraction that automates some of the things that are common for all ViewHolders. -abstract class BaseViewHolder( - private val baseBinding: ViewDataBinding, - protected val listener: ClickListener -) : 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) -} diff --git a/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt b/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt index 674522478..5cdccf767 100644 --- a/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt @@ -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( diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index 661ec482c..f06c3d0f7 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -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" /> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9de8a7b57..850bb1c3c 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -5,6 +5,7 @@ @color/background @android:color/black @font/inter + @style/AppThemeOverlay.Popup + + \ No newline at end of file