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