From dae334b1d6ac0ceb7ecd610a21a8e633da5a702a Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sun, 5 Sep 2021 16:11:37 -0600 Subject: [PATCH] home: re-add sorting Re-add sorting to HomeFragment, except heavily improved. The major improvement here is the addition of song sorting, which was a heavily requested feature judging by #16. The setting does not save yet and is not present in the detail fragments, but it is still a major milestone for the new home ui. --- .../org/oxycblt/auxio/home/HomeAdapter.kt | 6 + .../org/oxycblt/auxio/home/HomeFragment.kt | 107 +++++++++---- .../oxycblt/auxio/home/HomeListFragment.kt | 35 ++--- .../org/oxycblt/auxio/home/HomeViewModel.kt | 85 ++++++++-- .../org/oxycblt/auxio/home/LibSortMode.kt | 148 ++++++++++++++++++ .../playback/system/PlaybackNotification.kt | 4 +- .../java/org/oxycblt/auxio/ui/SortMode.kt | 10 +- .../java/org/oxycblt/auxio/util/ViewUtil.kt | 24 +-- .../java/org/oxycblt/auxio/widgets/Forms.kt | 2 +- .../{ic_loop_inactive.xml => ic_loop_off.xml} | 0 ...huffle_inactive.xml => ic_shuffle_off.xml} | 0 ...c_shuffle_tinted.xml => ic_shuffle_on.xml} | 0 ...laying_state.xml => sel_playing_state.xml} | 0 .../res/layout/fragment_compact_playback.xml | 2 +- app/src/main/res/layout/widget_full.xml | 2 +- app/src/main/res/menu/menu_home.xml | 8 +- app/src/main/res/values-cs/strings.xml | 4 +- app/src/main/res/values-de/strings.xml | 4 +- app/src/main/res/values-es/strings.xml | 4 +- app/src/main/res/values-fr/strings.xml | 4 +- app/src/main/res/values-hu/strings.xml | 4 +- app/src/main/res/values-in/strings.xml | 4 +- app/src/main/res/values-it/strings.xml | 4 +- app/src/main/res/values-ko/strings.xml | 4 +- app/src/main/res/values-nl/strings.xml | 4 +- app/src/main/res/values-pl/strings.xml | 4 +- app/src/main/res/values-pt-rBR/strings.xml | 4 +- app/src/main/res/values-pt-rPT/strings.xml | 4 +- app/src/main/res/values-ro/strings.xml | 4 +- app/src/main/res/values-ru/strings.xml | 4 +- app/src/main/res/values-tr/strings.xml | 4 +- app/src/main/res/values-zh-rCN/strings.xml | 4 +- app/src/main/res/values-zh-rTW/strings.xml | 4 +- app/src/main/res/values/colors.xml | 1 - app/src/main/res/values/strings.xml | 4 +- app/src/main/res/values/styles_android.xml | 2 +- app/src/main/res/values/styles_component.xml | 2 +- app/src/main/res/values/styles_core.xml | 2 +- build.gradle | 2 +- 39 files changed, 371 insertions(+), 143 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/home/LibSortMode.kt rename app/src/main/res/drawable/{ic_loop_inactive.xml => ic_loop_off.xml} (100%) rename app/src/main/res/drawable/{ic_shuffle_inactive.xml => ic_shuffle_off.xml} (100%) rename app/src/main/res/drawable/{ic_shuffle_tinted.xml => ic_shuffle_on.xml} (100%) rename app/src/main/res/drawable/{ic_playing_state.xml => sel_playing_state.xml} (100%) diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeAdapter.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeAdapter.kt index 3dd747f79..3d1ddbb3d 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeAdapter.kt @@ -32,6 +32,9 @@ import org.oxycblt.auxio.ui.ArtistViewHolder import org.oxycblt.auxio.ui.GenreViewHolder import org.oxycblt.auxio.ui.SongViewHolder +/** + * A universal adapter for displaying data in [HomeFragment]. + */ class HomeAdapter( private val doOnClick: (data: BaseModel) -> Unit, private val doOnLongClick: (view: View, data: BaseModel) -> Unit @@ -89,6 +92,9 @@ class HomeAdapter( fun updateData(newData: List) { data = newData + // I would use ListAdapter instead of this inefficient invalidate call, but they still + // haven't fixed the issue where ListAdapter's calculations will cause wild scrolling + // for basically no reason. notifyDataSetChanged() } } diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 7649ae4bf..ed027fa1b 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -20,8 +20,10 @@ package org.oxycblt.auxio.home import android.os.Bundle import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.core.view.iterator import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -48,13 +50,9 @@ import org.oxycblt.auxio.util.makeScrollingViewFade /** * The main "Launching Point" fragment of Auxio, allowing navigation to the detail * views for each respective fragment. - * TODO: Re-add sorting (but new and improved) - * It will require a new SortMode to be made simply for compat. Migrate the old SortMode - * eventually. * @author OxygenCobalt */ class HomeFragment : Fragment() { - private val playbackModel: PlaybackViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels() private val homeModel: HomeViewModel by activityViewModels() @@ -64,6 +62,7 @@ class HomeFragment : Fragment() { savedInstanceState: Bundle? ): View { val binding = FragmentHomeBinding.inflate(inflater) + val sortItem: MenuItem // --- UI SETUP --- @@ -75,20 +74,35 @@ class HomeFragment : Fragment() { binding.homeAppbar.makeScrollingViewFade(binding.homeToolbar) - binding.homeToolbar.setOnMenuItemClickListener { item -> - when (item.itemId) { - R.id.action_settings -> { - parentFragment?.parentFragment?.findNavController()?.navigate( - MainFragmentDirections.actionShowSettings() - ) - } + binding.homeToolbar.apply { + setOnMenuItemClickListener { item -> + when (item.itemId) { + R.id.action_settings -> { + parentFragment?.parentFragment?.findNavController()?.navigate( + MainFragmentDirections.actionShowSettings() + ) + } + + R.id.action_search -> { + findNavController().navigate(HomeFragmentDirections.actionShowSearch()) + } - R.id.action_search -> { - findNavController().navigate(HomeFragmentDirections.actionShowSearch()) + R.id.submenu_sorting -> { } + + // Sorting option was selected, check then and update the mode + else -> { + item.isChecked = true + + homeModel.updateCurrentSort( + requireNotNull(LibSortMode.fromId(item.itemId)) + ) + } } + + true } - true + sortItem = menu.findItem(R.id.submenu_sorting) } binding.homePager.apply { @@ -121,24 +135,13 @@ class HomeFragment : Fragment() { // page transitions. offscreenPageLimit = homeModel.tabs.value!!.size - // ViewPager2 tends to garble any scrolling view events that occur within it's - // fragments, so we fix that by instructing our AppBarLayout to follow the specific - // view we have just selected. registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - binding.homeAppbar.liftOnScrollTargetViewId = - when (homeModel.tabs.value!![position]) { - DisplayMode.SHOW_SONGS -> R.id.home_song_list - DisplayMode.SHOW_ALBUMS -> R.id.home_album_list - DisplayMode.SHOW_ARTISTS -> R.id.home_artist_list - DisplayMode.SHOW_GENRES -> R.id.home_genre_list - } - } + override fun onPageSelected(position: Int) = homeModel.updateCurrentTab(position) }) } TabLayoutMediator(binding.homeTabs, binding.homePager) { tab, pos -> - val labelRes = when (requireNotNull(homeModel.tabs.value)[pos]) { + val labelRes = when (homeModel.tabs.value!![pos]) { DisplayMode.SHOW_SONGS -> R.string.lbl_songs DisplayMode.SHOW_ALBUMS -> R.string.lbl_albums DisplayMode.SHOW_ARTISTS -> R.string.lbl_artists @@ -150,6 +153,40 @@ class HomeFragment : Fragment() { // --- VIEWMODEL SETUP --- + homeModel.curTab.observe(viewLifecycleOwner) { tab -> + binding.homeAppbar.liftOnScrollTargetViewId = when (requireNotNull(tab)) { + DisplayMode.SHOW_SONGS -> { + updateSortMenu(sortItem, homeModel.songSortMode) + + R.id.home_song_list + } + + DisplayMode.SHOW_ALBUMS -> { + updateSortMenu(sortItem, homeModel.albumSortMode) { id -> + id != R.id.option_sort_album + } + + R.id.home_album_list + } + + DisplayMode.SHOW_ARTISTS -> { + updateSortMenu(sortItem, homeModel.artistSortMode) { id -> + id == R.id.option_sort_asc || id == R.id.option_sort_dsc + } + + R.id.home_artist_list + } + + DisplayMode.SHOW_GENRES -> { + updateSortMenu(sortItem, homeModel.genreSortMode) { id -> + id == R.id.option_sort_asc || id == R.id.option_sort_dsc + } + + R.id.home_genre_list + } + } + } + detailModel.navToItem.observe(viewLifecycleOwner) { item -> // The AppBarLayout gets confused and collapses when we navigate too fast, wait for it // to draw before we continue. @@ -182,10 +219,24 @@ class HomeFragment : Fragment() { return binding.root } + private fun updateSortMenu( + item: MenuItem, + toHighlight: LibSortMode, + isVisible: (Int) -> Boolean = { true } + ) { + for (option in item.subMenu) { + if (option.itemId == toHighlight.itemId) { + option.isChecked = true + } + + option.isVisible = isVisible(option.itemId) + } + } + private inner class HomePagerAdapter : FragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle) { - override fun getItemCount(): Int = requireNotNull(homeModel.tabs.value).size + override fun getItemCount(): Int = homeModel.tabs.value!!.size override fun createFragment(position: Int): Fragment = HomeListFragment.new(position) } } diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeListFragment.kt index 4218f499a..926a45842 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeListFragment.kt @@ -24,7 +24,7 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.IdRes import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels +import androidx.fragment.app.activityViewModels import androidx.lifecycle.LiveData import androidx.navigation.fragment.findNavController import org.oxycblt.auxio.BuildConfig @@ -38,7 +38,6 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.newMenu -import org.oxycblt.auxio.ui.sliceArticle import org.oxycblt.auxio.util.applySpans import org.oxycblt.auxio.util.logD @@ -47,8 +46,8 @@ import org.oxycblt.auxio.util.logD * should be created using the [new] method with it's position in the ViewPager. */ class HomeListFragment : Fragment() { - private val homeModel: HomeViewModel by viewModels() - private val playbackModel: PlaybackViewModel by viewModels() + private val homeModel: HomeViewModel by activityViewModels() + private val playbackModel: PlaybackViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, @@ -81,36 +80,36 @@ class HomeListFragment : Fragment() { ::newMenu ) - // --- ITEM SETUP --- - // Get some tab-specific values before we go ahead. More specifically, the data to use // and the unique ID that HomeFragment's AppBarLayout uses to determine lift state. val pos = requireNotNull(arguments).getInt(ARG_POS) @IdRes val customId: Int - val toObserve: LiveData> + val homeData: LiveData> - when (requireNotNull(homeModel.tabs.value)[pos]) { + when (homeModel.tabs.value!![pos]) { DisplayMode.SHOW_SONGS -> { customId = R.id.home_song_list - toObserve = homeModel.songs + homeData = homeModel.songs } DisplayMode.SHOW_ALBUMS -> { customId = R.id.home_album_list - toObserve = homeModel.albums + homeData = homeModel.albums } DisplayMode.SHOW_ARTISTS -> { customId = R.id.home_artist_list - toObserve = homeModel.artists + homeData = homeModel.artists } DisplayMode.SHOW_GENRES -> { customId = R.id.home_genre_list - toObserve = homeModel.genres + homeData = homeModel.genres } } // --- UI SETUP --- + binding.lifecycleOwner = viewLifecycleOwner + binding.homeRecycler.apply { id = customId adapter = homeAdapter @@ -121,16 +120,8 @@ class HomeListFragment : Fragment() { // --- VIEWMODEL SETUP --- // Make sure that this RecyclerView has data before startup - homeAdapter.updateData(toObserve.value!!) - - toObserve.observe(viewLifecycleOwner) { data -> - homeAdapter.updateData( - data.sortedWith( - compareBy(String.CASE_INSENSITIVE_ORDER) { - it.name.sliceArticle() - } - ) - ) + homeData.observe(viewLifecycleOwner) { data -> + homeAdapter.updateData(data) } logD("Fragment created") diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt index 70b64ba5d..c86779d3e 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -28,32 +28,85 @@ import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.ui.DisplayMode +/** + * The ViewModel for managing [HomeFragment]'s data and sorting modes. + */ class HomeViewModel : ViewModel() { - private val mGenres = MutableLiveData(listOf()) - val genres: LiveData> get() = mGenres - - private val mArtists = MutableLiveData(listOf()) - val artists: LiveData> get() = mArtists + private val mSongs = MutableLiveData(listOf()) + val songs: LiveData> get() = mSongs private val mAlbums = MutableLiveData(listOf()) val albums: LiveData> get() = mAlbums - private val mSongs = MutableLiveData(listOf()) - val songs: LiveData> get() = mSongs + private val mArtists = MutableLiveData(listOf()) + val artists: LiveData> get() = mArtists - private val mTabs = MutableLiveData(arrayOf()) + private val mGenres = MutableLiveData(listOf()) + val genres: LiveData> get() = mGenres + + private val mTabs = MutableLiveData( + arrayOf( + DisplayMode.SHOW_SONGS, DisplayMode.SHOW_ALBUMS, + DisplayMode.SHOW_ARTISTS, DisplayMode.SHOW_GENRES + ) + ) val tabs: LiveData> = mTabs + private val mCurTab = MutableLiveData(mTabs.value!![0]) + val curTab: LiveData = mCurTab + + var genreSortMode = LibSortMode.ASCENDING + private set + + var artistSortMode = LibSortMode.ASCENDING + private set + + var albumSortMode = LibSortMode.ASCENDING + private set + + var songSortMode = LibSortMode.ASCENDING + private set + private val musicStore = MusicStore.getInstance() init { - mGenres.value = musicStore.genres - mArtists.value = musicStore.artists - mAlbums.value = musicStore.albums - mSongs.value = musicStore.songs - mTabs.value = arrayOf( - DisplayMode.SHOW_SONGS, DisplayMode.SHOW_ALBUMS, - DisplayMode.SHOW_ARTISTS, DisplayMode.SHOW_GENRES - ) + mSongs.value = songSortMode.sortSongs(musicStore.songs) + mAlbums.value = albumSortMode.sortAlbums(musicStore.albums) + mArtists.value = artistSortMode.sortModels(musicStore.artists) + mGenres.value = genreSortMode.sortModels(musicStore.genres) + } + + /** + * Update the current tab based off of the new ViewPager position. + */ + fun updateCurrentTab(pos: Int) { + val mode = mTabs.value!![pos] + + mCurTab.value = mode + } + + /** + * Update the currently displayed item's [LibSortMode]. + */ + fun updateCurrentSort(sort: LibSortMode) { + when (mCurTab.value) { + DisplayMode.SHOW_SONGS -> { + songSortMode = sort + mSongs.value = sort.sortSongs(mSongs.value!!) + } + + DisplayMode.SHOW_ALBUMS -> { + albumSortMode = sort + mAlbums.value = sort.sortAlbums(mAlbums.value!!) + } + DisplayMode.SHOW_ARTISTS -> { + artistSortMode = sort + mArtists.value = sort.sortModels(mArtists.value!!) + } + DisplayMode.SHOW_GENRES -> { + genreSortMode = sort + mGenres.value = sort.sortModels(mGenres.value!!) + } + } } } diff --git a/app/src/main/java/org/oxycblt/auxio/home/LibSortMode.kt b/app/src/main/java/org/oxycblt/auxio/home/LibSortMode.kt new file mode 100644 index 000000000..071a76c5b --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/home/LibSortMode.kt @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021 Auxio Project + * LibSortMode.kt is part of Auxio. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.oxycblt.auxio.home + +import androidx.annotation.IdRes +import org.oxycblt.auxio.R +import org.oxycblt.auxio.music.Album +import org.oxycblt.auxio.music.BaseModel +import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.ui.sliceArticle + +/** + * The enum for the current sort state. + * This enum is semantic depending on the context it is used. Documentation describing each + * sorting functions behavior can be found in the function definition. + * @param itemId Menu ID associated with this enum + * @author OxygenCobalt + */ +enum class LibSortMode(@IdRes val itemId: Int) { + ASCENDING(R.id.option_sort_asc), + DESCENDING(R.id.option_sort_dsc), + ARTIST(R.id.option_sort_artist), + ALBUM(R.id.option_sort_album), + YEAR(R.id.option_sort_year); + + /** + * Sort a list of songs. + * + * **Behavior:** + * - [ASCENDING] & [DESCENDING]: See [sortModels] + * - [ARTIST]: Grouped by album and then sorted [ASCENDING] based off the artist name. + * - [ALBUM]: Grouped by album and sorted [ASCENDING] + * - [YEAR]: Grouped by album and sorted by year + * + * The grouping mode for songs in an album will be by track, [ASCENDING]. + * @see sortAlbums + */ + fun sortSongs(songs: Collection): List { + return when (this) { + ASCENDING, DESCENDING -> sortModels(songs) + + else -> sortAlbums(songs.groupBy { it.album }.keys).flatMap { album -> + ASCENDING.sortAlbum(album) + } + } + } + + /** + * Sort a list of albums. + * + * **Behavior:** + * - [ASCENDING] & [DESCENDING]: See [sortModels] + * - [ARTIST]: Grouped by artist and sorted [ASCENDING] + * - [ALBUM]: [ASCENDING] + * - [YEAR]: Sorted by year + * + * The grouping mode for albums in an artist will be [YEAR]. + */ + fun sortAlbums(albums: Collection): List { + return when (this) { + ASCENDING, DESCENDING -> sortModels(albums) + + ARTIST -> ASCENDING.sortModels(albums.groupBy { it.artist }.keys) + .flatMap { YEAR.sortAlbums(it.albums) } + + ALBUM -> ASCENDING.sortModels(albums) + + YEAR -> albums.sortedByDescending { it.year } + } + } + + /** + * Sort a list of generic [BaseModel] instances. + * + * **Behavior:** + * - [ASCENDING]: Sorted by name, ascending + * - [DESCENDING]: Sorted by name, descending + * - Same list is returned otherwise. + * + * Names will be treated as case-insensitive. Articles like "the" and "a" will be skipped + * to line up with MediaStore behavior. + */ + fun sortModels(models: Collection): List { + return when (this) { + ASCENDING -> models.sortedWith( + compareBy(String.CASE_INSENSITIVE_ORDER) { model -> + model.name.sliceArticle() + } + ) + + DESCENDING -> models.sortedWith( + compareByDescending(String.CASE_INSENSITIVE_ORDER) { model -> + model.name.sliceArticle() + } + ) + + else -> models.toList() + } + } + + /** + * Sort the songs in an album. + * + * **Behavior:** + * - [ASCENDING]: By track, ascending + * - [DESCENDING]: By track, descending + * - Same song list is returned otherwise. + */ + fun sortAlbum(album: Album): List { + return when (this) { + ASCENDING -> album.songs.sortedBy { it.track } + DESCENDING -> album.songs.sortedByDescending { it.track } + else -> album.songs + } + } + + companion object { + /** + * Convert a menu [id] to an instance of [LibSortMode]. + */ + fun fromId(@IdRes id: Int): LibSortMode? { + return when (id) { + ASCENDING.itemId -> ASCENDING + DESCENDING.itemId -> DESCENDING + ARTIST.itemId -> ARTIST + ALBUM.itemId -> ALBUM + YEAR.itemId -> YEAR + else -> null + } + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackNotification.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackNotification.kt index cb42354bc..b80cecf79 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackNotification.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackNotification.kt @@ -149,7 +149,7 @@ class PlaybackNotification private constructor( loopMode: LoopMode ): NotificationCompat.Action { val drawableRes = when (loopMode) { - LoopMode.NONE -> R.drawable.ic_loop_inactive + LoopMode.NONE -> R.drawable.ic_loop_off LoopMode.ALL -> R.drawable.ic_loop LoopMode.TRACK -> R.drawable.ic_loop_one } @@ -161,7 +161,7 @@ class PlaybackNotification private constructor( context: Context, isShuffled: Boolean ): NotificationCompat.Action { - val drawableRes = if (isShuffled) R.drawable.ic_shuffle else R.drawable.ic_shuffle_inactive + val drawableRes = if (isShuffled) R.drawable.ic_shuffle else R.drawable.ic_shuffle_off return buildAction(context, PlaybackService.ACTION_SHUFFLE, drawableRes) } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt b/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt index 5a8e12a32..aad4dabc9 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt @@ -29,8 +29,7 @@ import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song /** - * An enum for the current sorting mode. Contains helper functions to sort lists based - * off the given sorting mode. + * The legacy enum for sorting. This is set to be removed soon. * @property iconRes The icon for this [SortMode] * @author OxygenCobalt */ @@ -190,10 +189,9 @@ enum class SortMode(@DrawableRes val iconRes: Int) { @IdRes fun toMenuId(): Int { return when (this) { - ALPHA_UP -> R.id.option_sort_alpha_up - ALPHA_DOWN -> R.id.option_sort_alpha_down - - else -> R.id.option_sort_alpha_up + ALPHA_UP -> R.id.option_sort_asc + ALPHA_DOWN -> R.id.option_sort_dsc + else -> R.id.option_sort_dsc } } diff --git a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt index c890c547e..cbdbe4545 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt @@ -27,11 +27,9 @@ import android.util.TypedValue import android.view.View import android.view.WindowInsets import android.widget.ImageButton -import android.widget.TextView import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.annotation.ColorRes -import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -39,9 +37,6 @@ import androidx.viewbinding.ViewBinding import com.google.android.material.appbar.AppBarLayout import org.oxycblt.auxio.R -// TODO: Make a helper AppBarLayout of some kind that auto-updates the lifted state. I know -// what to do, it's just hard to make it work correctly. - /** * Apply the recommended spans for a [RecyclerView]. * @@ -72,6 +67,7 @@ fun RecyclerView.applySpans(shouldBeFullWidth: ((Int) -> Boolean)? = null) { /** * Disable an image button. + * TODO: Replace this fragile function with something else. */ fun ImageButton.disable() { if (isEnabled) { @@ -79,14 +75,6 @@ fun ImageButton.disable() { isEnabled = false } } - -/** - * Set a [TextView] text color, without having to resolve the resource. - */ -fun TextView.setTextColorResource(@ColorRes color: Int) { - setTextColor(color.resolveColor(context)) -} - /** * Returns whether a recyclerview can scroll. */ @@ -116,20 +104,14 @@ fun @receiver:ColorRes Int.resolveColor(context: Context): Int { * @see resolveColor */ fun @receiver:ColorRes Int.resolveStateList(context: Context) = - ColorStateList.valueOf(resolveColor(context)) - -/** - * Resolve a drawable resource into a [Drawable] - */ -fun @receiver:DrawableRes Int.resolveDrawable(context: Context) = - requireNotNull(ContextCompat.getDrawable(context, this)) + ContextCompat.getColorStateList(context, this) /** * Resolve this int into a color as if it was an attribute */ @ColorInt fun @receiver:AttrRes Int.resolveAttr(context: Context): Int { - // Convert the attribute into its color + // First resolve the attribute into its ID val resolvedAttr = TypedValue() context.theme.resolveAttribute(this, resolvedAttr, true) diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt index 5755d6da9..b2be578d4 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt @@ -123,7 +123,7 @@ fun createFullWidget(context: Context, state: WidgetState): RemoteViews { // And no, we can't control state drawables with RemoteViews. Because of course we can't. val shuffleRes = when { - state.isShuffled -> R.drawable.ic_shuffle_tinted + state.isShuffled -> R.drawable.ic_shuffle_on else -> R.drawable.ic_shuffle } diff --git a/app/src/main/res/drawable/ic_loop_inactive.xml b/app/src/main/res/drawable/ic_loop_off.xml similarity index 100% rename from app/src/main/res/drawable/ic_loop_inactive.xml rename to app/src/main/res/drawable/ic_loop_off.xml diff --git a/app/src/main/res/drawable/ic_shuffle_inactive.xml b/app/src/main/res/drawable/ic_shuffle_off.xml similarity index 100% rename from app/src/main/res/drawable/ic_shuffle_inactive.xml rename to app/src/main/res/drawable/ic_shuffle_off.xml diff --git a/app/src/main/res/drawable/ic_shuffle_tinted.xml b/app/src/main/res/drawable/ic_shuffle_on.xml similarity index 100% rename from app/src/main/res/drawable/ic_shuffle_tinted.xml rename to app/src/main/res/drawable/ic_shuffle_on.xml diff --git a/app/src/main/res/drawable/ic_playing_state.xml b/app/src/main/res/drawable/sel_playing_state.xml similarity index 100% rename from app/src/main/res/drawable/ic_playing_state.xml rename to app/src/main/res/drawable/sel_playing_state.xml diff --git a/app/src/main/res/layout/fragment_compact_playback.xml b/app/src/main/res/layout/fragment_compact_playback.xml index d98ab34b6..f989fb5fc 100644 --- a/app/src/main/res/layout/fragment_compact_playback.xml +++ b/app/src/main/res/layout/fragment_compact_playback.xml @@ -63,7 +63,7 @@ + android:src="@drawable/sel_playing_state" /> + android:id="@+id/option_sort_asc" + android:title="@string/lbl_sort_asc" /> + android:id="@+id/option_sort_dsc" + android:title="@string/lbl_sort_dsc" /> diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 2c94215a0..9f7437553 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -20,8 +20,8 @@ "Filtr" "Vše" "Řadit" - "Vzestupně" - "Sestupně" + "Vzestupně" + "Sestupně" "Umělec" "Album" "Rok" diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 68a6b7c3d..039d6dbc5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -19,8 +19,8 @@ Alles Sortierung - Aufsteigend - Absteigend + Aufsteigend + Absteigend Abspielen Zufällig diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 8d8c0603f..16ed3f926 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -20,8 +20,8 @@ Todo Ordenar - Ascendente - Descendente + Ascendente + Descendente Reproducir Aleatorio diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9f8031a15..63ea26311 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -16,8 +16,8 @@ Tout Tri - Ascendant - Descendant + Ascendant + Descendant Lecture Aléatoire diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 32d032edb..d51914bfd 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -16,8 +16,8 @@ Összes Összes - Növekvő - Csökkenő + Növekvő + Csökkenő Lejátszás Keverés diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index d830e414f..581bc1029 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -16,8 +16,8 @@ Semua Urutan - Naik - Turun + Naik + Turun Putar Acak diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index a52d78df8..0791941ed 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -16,8 +16,8 @@ Tutto Ordine - Ascendente - Discendente + Ascendente + Discendente Riproduci Casuale diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 68c3a6fc9..c57ef48eb 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -16,8 +16,8 @@ 전부 분류 - 오름차순 - 내림차순 + 오름차순 + 내림차순 재생 모든 곡 랜덤 재생 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 95132f646..e53b010cd 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -20,8 +20,8 @@ Alles Sorteren - Oplopend - Aflopend + Oplopend + Aflopend Afspelen Shuffle diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 27b4bf85b..f3c816bc0 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -16,8 +16,8 @@ Wszystkie Sortowanie - Rosnąco - Malejąco + Rosnąco + Malejąco Graj Losowo diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 62189a915..b36ef2b07 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -16,7 +16,7 @@ Tudo Classificação - Descendente + Descendente Reproduzir Embaralhar @@ -98,5 +98,5 @@ %d Álbum %d Álbuns - Ascendente + Ascendente \ No newline at end of file diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index a219220ff..e1ac55926 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -16,8 +16,8 @@ Tudo Classificação - Ascendente - Descendente + Ascendente + Descendente Reproduzir Embaralhar diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index a0ab9dbdc..d968f9c78 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -16,8 +16,8 @@ Tot Sortare - Crescător - Descrescător + Crescător + Descrescător Redă Amestecare diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 88f5de1fa..883520a90 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -16,8 +16,8 @@ Всё Сортировка - По возрастанию - По убыванию + По возрастанию + По убыванию Воспроизвести Перемешать diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index a7f69b30f..509c76d82 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -16,8 +16,8 @@ Tümü Sıralama - Artan - Azalan + Artan + Azalan Başlat Karıştır diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5f5eda679..a2c6521b5 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -16,8 +16,8 @@ 全部 排序方式 - 按首字符(正序) - 按首字符(倒序) + 按首字符(正序) + 按首字符(倒序) 播放 随机播放 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2ab47e42f..8def1b5cc 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -16,8 +16,8 @@ 全部 排序 - 升序排列 - 降序排列 + 升序排列 + 降序排列 播放 隨機播放 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 4fdf88ce6..3d3c5ff14 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,7 +1,6 @@ #fafafa - @android:color/black #202020 #01fafafa diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb6ca7756..13b5f5bd1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,8 +23,8 @@ All Sort - Ascending - Descending + Ascending + Descending Artist Album Year diff --git a/app/src/main/res/values/styles_android.xml b/app/src/main/res/values/styles_android.xml index 7918b7c39..4588bfbf6 100644 --- a/app/src/main/res/values/styles_android.xml +++ b/app/src/main/res/values/styles_android.xml @@ -36,7 +36,7 @@ diff --git a/app/src/main/res/values/styles_component.xml b/app/src/main/res/values/styles_component.xml index 96019796e..a1f6949db 100644 --- a/app/src/main/res/values/styles_component.xml +++ b/app/src/main/res/values/styles_component.xml @@ -9,7 +9,7 @@ @dimen/elevation_normal @string/desc_play_pause ?attr/colorSurface - @drawable/ic_playing_state + @drawable/sel_playing_state @dimen/spacing_large @dimen/spacing_medium @dimen/spacing_large diff --git a/app/src/main/res/values/styles_core.xml b/app/src/main/res/values/styles_core.xml index a033f4b0f..38c4a0d18 100644 --- a/app/src/main/res/values/styles_core.xml +++ b/app/src/main/res/values/styles_core.xml @@ -43,7 +43,7 @@ diff --git a/build.gradle b/build.gradle index 54cd59d55..3d062649e 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.0.1' + classpath 'com.android.tools.build:gradle:7.0.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version"