From 3340914c5167f3ca841a1a542d78f95ae0e695e6 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Tue, 25 Jul 2023 16:47:25 -0600 Subject: [PATCH] detail: switch to sort dialogs Use the new sort dialogs on in detail views. --- .../auxio/detail/AlbumDetailFragment.kt | 26 +------- .../auxio/detail/ArtistDetailFragment.kt | 28 +------- .../oxycblt/auxio/detail/DetailViewModel.kt | 22 +++++-- .../auxio/detail/GenreDetailFragment.kt | 26 +------- .../auxio/detail/sort/AlbumSongSortDialog.kt | 58 +++++++++++++++++ .../auxio/detail/sort/ArtistSongSortDialog.kt | 59 +++++++++++++++++ .../auxio/detail/sort/GenreSongSortDialog.kt | 64 +++++++++++++++++++ .../org/oxycblt/auxio/list/ListFragment.kt | 39 ----------- .../main/java/org/oxycblt/auxio/list/Sort.kt | 5 +- app/src/main/res/menu/sort_album.xml | 21 ------ app/src/main/res/menu/sort_artist.xml | 27 -------- app/src/main/res/menu/sort_genre.xml | 30 --------- app/src/main/res/navigation/inner.xml | 36 ++++++++--- 13 files changed, 230 insertions(+), 211 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/detail/sort/AlbumSongSortDialog.kt create mode 100644 app/src/main/java/org/oxycblt/auxio/detail/sort/ArtistSongSortDialog.kt create mode 100644 app/src/main/java/org/oxycblt/auxio/detail/sort/GenreSongSortDialog.kt delete mode 100644 app/src/main/res/menu/sort_album.xml delete mode 100644 app/src/main/res/menu/sort_artist.xml delete mode 100644 app/src/main/res/menu/sort_genre.xml 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 8dc4bb400..40f5d5796 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -41,7 +41,6 @@ import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.Menu -import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent @@ -196,30 +195,7 @@ class AlbumDetailFragment : } override fun onOpenSortMenu(anchor: View) { - openMenu(anchor, R.menu.sort_album) { - // Select the corresponding sort mode option - val sort = detailModel.albumSongSort - unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true - // Select the corresponding sort direction option - val directionItemId = - when (sort.direction) { - Sort.Direction.ASCENDING -> R.id.option_sort_asc - Sort.Direction.DESCENDING -> R.id.option_sort_dec - } - unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true - setOnMenuItemClickListener { item -> - item.isChecked = !item.isChecked - detailModel.albumSongSort = - when (item.itemId) { - // Sort direction options - R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING) - R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING) - // Any other option is a sort mode - else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId))) - } - true - } - } + findNavController().navigateSafe(AlbumDetailFragmentDirections.sort()) } override fun onNavigateToParentArtist() { 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 9997496b6..04b3b8c2a 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -41,7 +41,6 @@ import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.Menu -import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Music @@ -202,32 +201,7 @@ class ArtistDetailFragment : } override fun onOpenSortMenu(anchor: View) { - openMenu(anchor, R.menu.sort_artist) { - // Select the corresponding sort mode option - val sort = detailModel.artistSongSort - unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true - // Select the corresponding sort direction option - val directionItemId = - when (sort.direction) { - Sort.Direction.ASCENDING -> R.id.option_sort_asc - Sort.Direction.DESCENDING -> R.id.option_sort_dec - } - unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true - setOnMenuItemClickListener { item -> - item.isChecked = !item.isChecked - - detailModel.artistSongSort = - when (item.itemId) { - // Sort direction options - R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING) - R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING) - // Any other option is a sort mode - else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId))) - } - - true - } - } + findNavController().navigateSafe(ArtistDetailFragmentDirections.sort()) } private fun updateArtist(artist: Artist?) { 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 ea618078c..735c15019 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -109,13 +109,8 @@ constructor( get() = _albumInstructions /** The current [Sort] used for [Song]s in [albumList]. */ - var albumSongSort: Sort + val albumSongSort: Sort get() = musicSettings.albumSongSort - set(value) { - musicSettings.albumSongSort = value - // Refresh the album list to reflect the new sort. - currentAlbum.value?.let { refreshAlbumList(it, true) } - } /** The [PlaySong] instructions to use when playing a [Song] from [Album] details. */ val playInAlbumWith @@ -365,6 +360,11 @@ constructor( } } + fun applyAlbumSongSort(sort: Sort) { + musicSettings.albumSongSort = sort + _currentAlbum.value?.let { refreshAlbumList(it, true) } + } + /** * Set a new [currentArtist] from it's [Music.UID]. [currentArtist] and [artistList] will be * updated to align with the new [Artist]. @@ -380,6 +380,11 @@ constructor( } } + fun applyArtistSongSort(sort: Sort) { + musicSettings.artistSongSort = sort + _currentArtist.value?.let { refreshArtistList(it, true) } + } + /** * Set a new [currentGenre] from it's [Music.UID]. [currentGenre] and [genreList] will be * updated to align with the new album. @@ -395,6 +400,11 @@ constructor( } } + fun applyGenreSongSort(sort: Sort) { + musicSettings.genreSongSort = sort + _currentGenre.value?.let { refreshGenreList(it, true) } + } + /** * Set a new [currentPlaylist] from it's [Music.UID]. If the [Music.UID] differs, * [currentPlaylist] and [currentPlaylist] will be updated to align with the new album. 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 dfb9adc29..49b6f451e 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -41,7 +41,6 @@ import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.Menu -import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Music @@ -199,30 +198,7 @@ class GenreDetailFragment : } override fun onOpenSortMenu(anchor: View) { - openMenu(anchor, R.menu.sort_genre) { - // Select the corresponding sort mode option - val sort = detailModel.genreSongSort - unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true - // Select the corresponding sort direction option - val directionItemId = - when (sort.direction) { - Sort.Direction.ASCENDING -> R.id.option_sort_asc - Sort.Direction.DESCENDING -> R.id.option_sort_dec - } - unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true - setOnMenuItemClickListener { item -> - item.isChecked = !item.isChecked - detailModel.genreSongSort = - when (item.itemId) { - // Sort direction options - R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING) - R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING) - // Any other option is a sort mode - else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId))) - } - true - } - } + findNavController().navigateSafe(GenreDetailFragmentDirections.sort()) } private fun updatePlaylist(genre: Genre?) { diff --git a/app/src/main/java/org/oxycblt/auxio/detail/sort/AlbumSongSortDialog.kt b/app/src/main/java/org/oxycblt/auxio/detail/sort/AlbumSongSortDialog.kt new file mode 100644 index 000000000..8c7290e98 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/detail/sort/AlbumSongSortDialog.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Auxio Project + * AlbumSongSortDialog.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.detail.sort + +import android.os.Bundle +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import dagger.hilt.android.AndroidEntryPoint +import org.oxycblt.auxio.databinding.DialogSortBinding +import org.oxycblt.auxio.detail.DetailViewModel +import org.oxycblt.auxio.list.Sort +import org.oxycblt.auxio.list.sort.SortDialog +import org.oxycblt.auxio.music.Album +import org.oxycblt.auxio.util.collectImmediately +import org.oxycblt.auxio.util.logD + +@AndroidEntryPoint +class AlbumSongSortDialog : SortDialog() { + private val detailModel: DetailViewModel by activityViewModels() + + override fun onBindingCreated(binding: DialogSortBinding, savedInstanceState: Bundle?) { + super.onBindingCreated(binding, savedInstanceState) + + // --- VIEWMODEL SETUP --- + collectImmediately(detailModel.currentAlbum, ::updateAlbum) + } + + override fun getInitialSort() = detailModel.albumSongSort + + override fun applyChosenSort(sort: Sort) { + detailModel.applyAlbumSongSort(sort) + } + + override fun getModeChoices() = listOf(Sort.Mode.ByDisc, Sort.Mode.ByTrack) + + private fun updateAlbum(album: Album?) { + if (album == null) { + logD("No album to sort, navigating away") + findNavController().navigateUp() + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/detail/sort/ArtistSongSortDialog.kt b/app/src/main/java/org/oxycblt/auxio/detail/sort/ArtistSongSortDialog.kt new file mode 100644 index 000000000..a745bd11a --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/detail/sort/ArtistSongSortDialog.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Auxio Project + * ArtistSongSortDialog.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.detail.sort + +import android.os.Bundle +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import dagger.hilt.android.AndroidEntryPoint +import org.oxycblt.auxio.databinding.DialogSortBinding +import org.oxycblt.auxio.detail.DetailViewModel +import org.oxycblt.auxio.list.Sort +import org.oxycblt.auxio.list.sort.SortDialog +import org.oxycblt.auxio.music.Artist +import org.oxycblt.auxio.util.collectImmediately +import org.oxycblt.auxio.util.logD + +@AndroidEntryPoint +class ArtistSongSortDialog : SortDialog() { + private val detailModel: DetailViewModel by activityViewModels() + + override fun onBindingCreated(binding: DialogSortBinding, savedInstanceState: Bundle?) { + super.onBindingCreated(binding, savedInstanceState) + + // --- VIEWMODEL SETUP --- + collectImmediately(detailModel.currentArtist, ::updateArtist) + } + + override fun getInitialSort() = detailModel.artistSongSort + + override fun applyChosenSort(sort: Sort) { + detailModel.applyArtistSongSort(sort) + } + + override fun getModeChoices() = + listOf(Sort.Mode.ByName, Sort.Mode.ByAlbum, Sort.Mode.ByDate, Sort.Mode.ByDuration) + + private fun updateArtist(artist: Artist?) { + if (artist == null) { + logD("No artist to sort, navigating away") + findNavController().navigateUp() + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/detail/sort/GenreSongSortDialog.kt b/app/src/main/java/org/oxycblt/auxio/detail/sort/GenreSongSortDialog.kt new file mode 100644 index 000000000..d491310c8 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/detail/sort/GenreSongSortDialog.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Auxio Project + * GenreSongSortDialog.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.detail.sort + +import android.os.Bundle +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import dagger.hilt.android.AndroidEntryPoint +import org.oxycblt.auxio.databinding.DialogSortBinding +import org.oxycblt.auxio.detail.DetailViewModel +import org.oxycblt.auxio.list.Sort +import org.oxycblt.auxio.list.sort.SortDialog +import org.oxycblt.auxio.music.Genre +import org.oxycblt.auxio.util.collectImmediately +import org.oxycblt.auxio.util.logD + +@AndroidEntryPoint +class GenreSongSortDialog : SortDialog() { + private val detailModel: DetailViewModel by activityViewModels() + + override fun onBindingCreated(binding: DialogSortBinding, savedInstanceState: Bundle?) { + super.onBindingCreated(binding, savedInstanceState) + + // --- VIEWMODEL SETUP --- + collectImmediately(detailModel.currentGenre, ::updateGenre) + } + + override fun getInitialSort() = detailModel.genreSongSort + + override fun applyChosenSort(sort: Sort) { + detailModel.applyGenreSongSort(sort) + } + + override fun getModeChoices() = + listOf( + Sort.Mode.ByName, + Sort.Mode.ByArtist, + Sort.Mode.ByAlbum, + Sort.Mode.ByDate, + Sort.Mode.ByDuration) + + private fun updateGenre(genre: Genre?) { + if (genre == null) { + logD("No genre to sort, navigating away") + findNavController().navigateUp() + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt index 4d2d45c14..546b03a49 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt @@ -18,14 +18,9 @@ package org.oxycblt.auxio.list -import android.view.View -import androidx.annotation.MenuRes -import androidx.appcompat.widget.PopupMenu -import androidx.core.view.MenuCompat import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding import org.oxycblt.auxio.music.Music -import org.oxycblt.auxio.util.logD /** * A Fragment containing a selectable list. @@ -34,14 +29,6 @@ import org.oxycblt.auxio.util.logD */ abstract class ListFragment : SelectionFragment(), SelectableListListener { - private var currentMenu: PopupMenu? = null - - override fun onDestroyBinding(binding: VB) { - super.onDestroyBinding(binding) - currentMenu?.dismiss() - currentMenu = null - } - /** * Called when [onClick] is called, but does not result in the item being selected. This more or * less corresponds to an [onClick] implementation in a non-[ListFragment]. @@ -63,30 +50,4 @@ abstract class ListFragment : final override fun onSelect(item: T) { listModel.select(item) } - - /** - * Open a menu. This menu will be managed by the Fragment and closed when the view is destroyed. - * If a menu is already opened, this call is ignored. - * - * @param anchor The [View] to anchor the menu to. - * @param menuRes The resource of the menu to load. - * @param block A block that is ran within [PopupMenu] that allows further configuration. - */ - protected fun openMenu(anchor: View, @MenuRes menuRes: Int, block: PopupMenu.() -> Unit) { - if (currentMenu != null) { - logD("Menu already present, not launching") - return - } - - logD("Opening popup menu menu") - - currentMenu = - PopupMenu(requireContext(), anchor).apply { - inflate(menuRes) - MenuCompat.setGroupDividerEnabled(menu, true) - block() - setOnDismissListener { currentMenu = null } - show() - } - } } diff --git a/app/src/main/java/org/oxycblt/auxio/list/Sort.kt b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt index 013c498d2..9b453e774 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/Sort.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt @@ -19,6 +19,7 @@ package org.oxycblt.auxio.list import androidx.annotation.IdRes +import java.lang.IllegalStateException import kotlin.math.max import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R @@ -406,7 +407,7 @@ data class Sort(val mode: Mode, val direction: Direction) { get() = IntegerTable.SORT_BY_DISC override val itemId: Int - get() = R.id.option_sort_disc + get() = throw IllegalStateException() override val stringRes: Int get() = R.string.lbl_disc @@ -428,7 +429,7 @@ data class Sort(val mode: Mode, val direction: Direction) { get() = IntegerTable.SORT_BY_TRACK override val itemId: Int - get() = R.id.option_sort_track + get() = throw IllegalStateException() override val stringRes: Int get() = R.string.lbl_track diff --git a/app/src/main/res/menu/sort_album.xml b/app/src/main/res/menu/sort_album.xml deleted file mode 100644 index 2e172f698..000000000 --- a/app/src/main/res/menu/sort_album.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/sort_artist.xml b/app/src/main/res/menu/sort_artist.xml deleted file mode 100644 index 796be63b3..000000000 --- a/app/src/main/res/menu/sort_artist.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/sort_genre.xml b/app/src/main/res/menu/sort_genre.xml deleted file mode 100644 index 0c525bbc9..000000000 --- a/app/src/main/res/menu/sort_genre.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/inner.xml b/app/src/main/res/navigation/inner.xml index f782d8456..8956f71fa 100644 --- a/app/src/main/res/navigation/inner.xml +++ b/app/src/main/res/navigation/inner.xml @@ -138,6 +138,9 @@ + @@ -162,11 +165,14 @@ - + + + @@ -198,6 +207,12 @@ app:destination="@id/play_from_genre_dialog" /> + + + @@ -232,6 +250,12 @@ app:destination="@id/play_from_artist_dialog" /> + + - - \ No newline at end of file