home: switch to sort dialogs

Switch the home view to sort dialogs, and simplify away any listeners
that expected popup menus.
This commit is contained in:
Alexander Capehart 2023-07-25 17:32:03 -06:00
parent 3340914c51
commit 04851893c5
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
26 changed files with 546 additions and 395 deletions

View file

@ -21,7 +21,6 @@ package org.oxycblt.auxio.detail
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
@ -111,7 +110,7 @@ class AlbumDetailFragment :
adapter = ConcatAdapter(albumHeaderAdapter, albumListAdapter) adapter = ConcatAdapter(albumHeaderAdapter, albumListAdapter)
(layoutManager as GridLayoutManager).setFullWidthLookup { (layoutManager as GridLayoutManager).setFullWidthLookup {
if (it != 0) { if (it != 0) {
val item = detailModel.albumList.value[it - 1] val item = detailModel.albumSongList.value[it - 1]
item is Divider || item is Header || item is Disc item is Divider || item is Header || item is Disc
} else { } else {
true true
@ -123,7 +122,7 @@ class AlbumDetailFragment :
// DetailViewModel handles most initialization from the navigation argument. // DetailViewModel handles most initialization from the navigation argument.
detailModel.setAlbum(args.albumUid) detailModel.setAlbum(args.albumUid)
collectImmediately(detailModel.currentAlbum, ::updateAlbum) collectImmediately(detailModel.currentAlbum, ::updateAlbum)
collectImmediately(detailModel.albumList, ::updateList) collectImmediately(detailModel.albumSongList, ::updateList)
collect(detailModel.toShow.flow, ::handleShow) collect(detailModel.toShow.flow, ::handleShow)
collect(listModel.menu.flow, ::handleMenu) collect(listModel.menu.flow, ::handleMenu)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
@ -139,7 +138,7 @@ class AlbumDetailFragment :
binding.detailRecycler.adapter = null binding.detailRecycler.adapter = null
// Avoid possible race conditions that could cause a bad replace instruction to be consumed // Avoid possible race conditions that could cause a bad replace instruction to be consumed
// during list initialization and crash the app. Could happen if the user is fast enough. // during list initialization and crash the app. Could happen if the user is fast enough.
detailModel.albumInstructions.consume() detailModel.albumSongInstructions.consume()
} }
override fun onMenuItemClick(item: MenuItem): Boolean { override fun onMenuItemClick(item: MenuItem): Boolean {
@ -182,7 +181,7 @@ class AlbumDetailFragment :
playbackModel.play(item, detailModel.playInAlbumWith) playbackModel.play(item, detailModel.playInAlbumWith)
} }
override fun onOpenMenu(item: Song, anchor: View) { override fun onOpenMenu(item: Song) {
listModel.openMenu(R.menu.item_album_song, item, detailModel.playInAlbumWith) listModel.openMenu(R.menu.item_album_song, item, detailModel.playInAlbumWith)
} }
@ -194,7 +193,7 @@ class AlbumDetailFragment :
playbackModel.shuffle(unlikelyToBeNull(detailModel.currentAlbum.value)) playbackModel.shuffle(unlikelyToBeNull(detailModel.currentAlbum.value))
} }
override fun onOpenSortMenu(anchor: View) { override fun onOpenSortMenu() {
findNavController().navigateSafe(AlbumDetailFragmentDirections.sort()) findNavController().navigateSafe(AlbumDetailFragmentDirections.sort())
} }
@ -213,7 +212,7 @@ class AlbumDetailFragment :
} }
private fun updateList(list: List<Item>) { private fun updateList(list: List<Item>) {
albumListAdapter.update(list, detailModel.albumInstructions.consume()) albumListAdapter.update(list, detailModel.albumSongInstructions.consume())
} }
private fun handleShow(show: Show?) { private fun handleShow(show: Show?) {
@ -339,7 +338,7 @@ class AlbumDetailFragment :
private fun scrollToAlbumSong(song: Song) { private fun scrollToAlbumSong(song: Song) {
// Calculate where the item for the currently played song is // Calculate where the item for the currently played song is
val pos = detailModel.albumList.value.indexOf(song) val pos = detailModel.albumSongList.value.indexOf(song)
if (pos != -1) { if (pos != -1) {
// Only scroll if the song is within this album. // Only scroll if the song is within this album.

View file

@ -21,7 +21,6 @@ package org.oxycblt.auxio.detail
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
@ -110,7 +109,7 @@ class ArtistDetailFragment :
(layoutManager as GridLayoutManager).setFullWidthLookup { (layoutManager as GridLayoutManager).setFullWidthLookup {
if (it != 0) { if (it != 0) {
val item = val item =
detailModel.artistList.value.getOrElse(it - 1) { detailModel.artistSongList.value.getOrElse(it - 1) {
return@setFullWidthLookup false return@setFullWidthLookup false
} }
item is Divider || item is Header item is Divider || item is Header
@ -124,7 +123,7 @@ class ArtistDetailFragment :
// DetailViewModel handles most initialization from the navigation argument. // DetailViewModel handles most initialization from the navigation argument.
detailModel.setArtist(args.artistUid) detailModel.setArtist(args.artistUid)
collectImmediately(detailModel.currentArtist, ::updateArtist) collectImmediately(detailModel.currentArtist, ::updateArtist)
collectImmediately(detailModel.artistList, ::updateList) collectImmediately(detailModel.artistSongList, ::updateList)
collect(detailModel.toShow.flow, ::handleShow) collect(detailModel.toShow.flow, ::handleShow)
collect(listModel.menu.flow, ::handleMenu) collect(listModel.menu.flow, ::handleMenu)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
@ -140,7 +139,7 @@ class ArtistDetailFragment :
binding.detailRecycler.adapter = null binding.detailRecycler.adapter = null
// Avoid possible race conditions that could cause a bad replace instruction to be consumed // Avoid possible race conditions that could cause a bad replace instruction to be consumed
// during list initialization and crash the app. Could happen if the user is fast enough. // during list initialization and crash the app. Could happen if the user is fast enough.
detailModel.artistInstructions.consume() detailModel.artistSongInstructions.consume()
} }
override fun onMenuItemClick(item: MenuItem): Boolean { override fun onMenuItemClick(item: MenuItem): Boolean {
@ -183,7 +182,7 @@ class ArtistDetailFragment :
} }
} }
override fun onOpenMenu(item: Music, anchor: View) { override fun onOpenMenu(item: Music) {
when (item) { when (item) {
is Song -> is Song ->
listModel.openMenu(R.menu.item_artist_song, item, detailModel.playInArtistWith) listModel.openMenu(R.menu.item_artist_song, item, detailModel.playInArtistWith)
@ -200,7 +199,7 @@ class ArtistDetailFragment :
playbackModel.shuffle(unlikelyToBeNull(detailModel.currentArtist.value)) playbackModel.shuffle(unlikelyToBeNull(detailModel.currentArtist.value))
} }
override fun onOpenSortMenu(anchor: View) { override fun onOpenSortMenu() {
findNavController().navigateSafe(ArtistDetailFragmentDirections.sort()) findNavController().navigateSafe(ArtistDetailFragmentDirections.sort())
} }
@ -227,7 +226,7 @@ class ArtistDetailFragment :
} }
private fun updateList(list: List<Item>) { private fun updateList(list: List<Item>) {
artistListAdapter.update(list, detailModel.artistInstructions.consume()) artistListAdapter.update(list, detailModel.artistSongInstructions.consume())
} }
private fun handleShow(show: Show?) { private fun handleShow(show: Show?) {

View file

@ -98,17 +98,17 @@ constructor(
val currentAlbum: StateFlow<Album?> val currentAlbum: StateFlow<Album?>
get() = _currentAlbum get() = _currentAlbum
private val _albumList = MutableStateFlow(listOf<Item>()) private val _albumSongList = MutableStateFlow(listOf<Item>())
/** The current list data derived from [currentAlbum]. */ /** The current list data derived from [currentAlbum]. */
val albumList: StateFlow<List<Item>> val albumSongList: StateFlow<List<Item>>
get() = _albumList get() = _albumSongList
private val _albumInstructions = MutableEvent<UpdateInstructions>() private val _albumSongInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for updating [albumList] in the UI. */ /** Instructions for updating [albumSongList] in the UI. */
val albumInstructions: Event<UpdateInstructions> val albumSongInstructions: Event<UpdateInstructions>
get() = _albumInstructions get() = _albumSongInstructions
/** The current [Sort] used for [Song]s in [albumList]. */ /** The current [Sort] used for [Song]s in [albumSongList]. */
val albumSongSort: Sort val albumSongSort: Sort
get() = musicSettings.albumSongSort get() = musicSettings.albumSongSort
@ -123,15 +123,16 @@ constructor(
val currentArtist: StateFlow<Artist?> val currentArtist: StateFlow<Artist?>
get() = _currentArtist get() = _currentArtist
private val _artistList = MutableStateFlow(listOf<Item>()) private val _artistSongList = MutableStateFlow(listOf<Item>())
/** The current list derived from [currentArtist]. */ /** The current list derived from [currentArtist]. */
val artistList: StateFlow<List<Item>> = _artistList val artistSongList: StateFlow<List<Item>> = _artistSongList
private val _artistInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for updating [artistList] in the UI. */
val artistInstructions: Event<UpdateInstructions>
get() = _artistInstructions
/** The current [Sort] used for [Song]s in [artistList]. */ private val _artistSongInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for updating [artistSongList] in the UI. */
val artistSongInstructions: Event<UpdateInstructions>
get() = _artistSongInstructions
/** The current [Sort] used for [Song]s in [artistSongList]. */
var artistSongSort: Sort var artistSongSort: Sort
get() = musicSettings.artistSongSort get() = musicSettings.artistSongSort
set(value) { set(value) {
@ -151,15 +152,16 @@ constructor(
val currentGenre: StateFlow<Genre?> val currentGenre: StateFlow<Genre?>
get() = _currentGenre get() = _currentGenre
private val _genreList = MutableStateFlow(listOf<Item>()) private val _genreSongList = MutableStateFlow(listOf<Item>())
/** The current list data derived from [currentGenre]. */ /** The current list data derived from [currentGenre]. */
val genreList: StateFlow<List<Item>> = _genreList val genreSongList: StateFlow<List<Item>> = _genreSongList
private val _genreInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for updating [artistList] in the UI. */
val genreInstructions: Event<UpdateInstructions>
get() = _genreInstructions
/** The current [Sort] used for [Song]s in [genreList]. */ private val _genreSongInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for updating [artistSongList] in the UI. */
val genreSongInstructions: Event<UpdateInstructions>
get() = _genreSongInstructions
/** The current [Sort] used for [Song]s in [genreSongList]. */
var genreSongSort: Sort var genreSongSort: Sort
get() = musicSettings.genreSongSort get() = musicSettings.genreSongSort
set(value) { set(value) {
@ -179,13 +181,14 @@ constructor(
val currentPlaylist: StateFlow<Playlist?> val currentPlaylist: StateFlow<Playlist?>
get() = _currentPlaylist get() = _currentPlaylist
private val _playlistList = MutableStateFlow(listOf<Item>()) private val _playlistSongList = MutableStateFlow(listOf<Item>())
/** The current list data derived from [currentPlaylist] */ /** The current list data derived from [currentPlaylist] */
val playlistList: StateFlow<List<Item>> = _playlistList val playlistSongList: StateFlow<List<Item>> = _playlistSongList
private val _playlistInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for updating [playlistList] in the UI. */ private val _playlistSongInstructions = MutableEvent<UpdateInstructions>()
val playlistInstructions: Event<UpdateInstructions> /** Instructions for updating [playlistSongList] in the UI. */
get() = _playlistInstructions val playlistSongInstructions: Event<UpdateInstructions>
get() = _playlistSongInstructions
private val _editedPlaylist = MutableStateFlow<List<Song>?>(null) private val _editedPlaylist = MutableStateFlow<List<Song>?>(null)
/** /**
@ -346,7 +349,7 @@ constructor(
} }
/** /**
* Set a new [currentAlbum] from it's [Music.UID]. [currentAlbum] and [albumList] will be * Set a new [currentAlbum] from it's [Music.UID]. [currentAlbum] and [albumSongList] will be
* updated to align with the new [Album]. * updated to align with the new [Album].
* *
* @param uid The [Music.UID] of the [Album] to update [currentAlbum] to. Must be valid. * @param uid The [Music.UID] of the [Album] to update [currentAlbum] to. Must be valid.
@ -360,13 +363,18 @@ constructor(
} }
} }
/**
* Apply a new [Sort] to [albumSongList].
*
* @param sort The [Sort] to apply.
*/
fun applyAlbumSongSort(sort: Sort) { fun applyAlbumSongSort(sort: Sort) {
musicSettings.albumSongSort = sort musicSettings.albumSongSort = sort
_currentAlbum.value?.let { refreshAlbumList(it, true) } _currentAlbum.value?.let { refreshAlbumList(it, true) }
} }
/** /**
* Set a new [currentArtist] from it's [Music.UID]. [currentArtist] and [artistList] will be * Set a new [currentArtist] from it's [Music.UID]. [currentArtist] and [artistSongList] will be
* updated to align with the new [Artist]. * updated to align with the new [Artist].
* *
* @param uid The [Music.UID] of the [Artist] to update [currentArtist] to. Must be valid. * @param uid The [Music.UID] of the [Artist] to update [currentArtist] to. Must be valid.
@ -380,13 +388,18 @@ constructor(
} }
} }
/**
* Apply a new [Sort] to [artistSongList].
*
* @param sort The [Sort] to apply.
*/
fun applyArtistSongSort(sort: Sort) { fun applyArtistSongSort(sort: Sort) {
musicSettings.artistSongSort = sort musicSettings.artistSongSort = sort
_currentArtist.value?.let { refreshArtistList(it, true) } _currentArtist.value?.let { refreshArtistList(it, true) }
} }
/** /**
* Set a new [currentGenre] from it's [Music.UID]. [currentGenre] and [genreList] will be * Set a new [currentGenre] from it's [Music.UID]. [currentGenre] and [genreSongList] will be
* updated to align with the new album. * updated to align with the new album.
* *
* @param uid The [Music.UID] of the [Genre] to update [currentGenre] to. Must be valid. * @param uid The [Music.UID] of the [Genre] to update [currentGenre] to. Must be valid.
@ -400,6 +413,11 @@ constructor(
} }
} }
/**
* Apply a new [Sort] to [genreSongList].
*
* @param sort The [Sort] to apply.
*/
fun applyGenreSongSort(sort: Sort) { fun applyGenreSongSort(sort: Sort) {
musicSettings.genreSongSort = sort musicSettings.genreSongSort = sort
_currentGenre.value?.let { refreshGenreList(it, true) } _currentGenre.value?.let { refreshGenreList(it, true) }
@ -554,8 +572,8 @@ constructor(
} }
logD("Update album list to ${list.size} items with $instructions") logD("Update album list to ${list.size} items with $instructions")
_albumInstructions.put(instructions) _albumSongInstructions.put(instructions)
_albumList.value = list _albumSongList.value = list
} }
private fun refreshArtistList(artist: Artist, replace: Boolean = false) { private fun refreshArtistList(artist: Artist, replace: Boolean = false) {
@ -617,8 +635,8 @@ constructor(
} }
logD("Updating artist list to ${list.size} items with $instructions") logD("Updating artist list to ${list.size} items with $instructions")
_artistInstructions.put(instructions) _artistSongInstructions.put(instructions)
_artistList.value = list.toList() _artistSongList.value = list.toList()
} }
private fun refreshGenreList(genre: Genre, replace: Boolean = false) { private fun refreshGenreList(genre: Genre, replace: Boolean = false) {
@ -643,8 +661,8 @@ constructor(
list.addAll(genreSongSort.songs(genre.songs)) list.addAll(genreSongSort.songs(genre.songs))
logD("Updating genre list to ${list.size} items with $instructions") logD("Updating genre list to ${list.size} items with $instructions")
_genreInstructions.put(instructions) _genreSongInstructions.put(instructions)
_genreList.value = list _genreSongList.value = list
} }
private fun refreshPlaylistList( private fun refreshPlaylistList(
@ -663,8 +681,8 @@ constructor(
} }
logD("Updating playlist list to ${list.size} items with $instructions") logD("Updating playlist list to ${list.size} items with $instructions")
_playlistInstructions.put(instructions) _playlistSongInstructions.put(instructions)
_playlistList.value = list _playlistSongList.value = list
} }
/** /**

View file

@ -21,7 +21,6 @@ package org.oxycblt.auxio.detail
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
@ -108,7 +107,7 @@ class GenreDetailFragment :
(layoutManager as GridLayoutManager).setFullWidthLookup { (layoutManager as GridLayoutManager).setFullWidthLookup {
if (it != 0) { if (it != 0) {
val item = val item =
detailModel.genreList.value.getOrElse(it - 1) { detailModel.genreSongList.value.getOrElse(it - 1) {
return@setFullWidthLookup false return@setFullWidthLookup false
} }
item is Divider || item is Header item is Divider || item is Header
@ -122,7 +121,7 @@ class GenreDetailFragment :
// DetailViewModel handles most initialization from the navigation argument. // DetailViewModel handles most initialization from the navigation argument.
detailModel.setGenre(args.genreUid) detailModel.setGenre(args.genreUid)
collectImmediately(detailModel.currentGenre, ::updatePlaylist) collectImmediately(detailModel.currentGenre, ::updatePlaylist)
collectImmediately(detailModel.genreList, ::updateList) collectImmediately(detailModel.genreSongList, ::updateList)
collect(detailModel.toShow.flow, ::handleShow) collect(detailModel.toShow.flow, ::handleShow)
collect(listModel.menu.flow, ::handleMenu) collect(listModel.menu.flow, ::handleMenu)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
@ -138,7 +137,7 @@ class GenreDetailFragment :
binding.detailRecycler.adapter = null binding.detailRecycler.adapter = null
// Avoid possible race conditions that could cause a bad replace instruction to be consumed // Avoid possible race conditions that could cause a bad replace instruction to be consumed
// during list initialization and crash the app. Could happen if the user is fast enough. // during list initialization and crash the app. Could happen if the user is fast enough.
detailModel.genreInstructions.consume() detailModel.genreSongInstructions.consume()
} }
override fun onMenuItemClick(item: MenuItem): Boolean { override fun onMenuItemClick(item: MenuItem): Boolean {
@ -181,7 +180,7 @@ class GenreDetailFragment :
} }
} }
override fun onOpenMenu(item: Music, anchor: View) { override fun onOpenMenu(item: Music) {
when (item) { when (item) {
is Artist -> listModel.openMenu(R.menu.item_parent, item) is Artist -> listModel.openMenu(R.menu.item_parent, item)
is Song -> listModel.openMenu(R.menu.item_song, item, detailModel.playInGenreWith) is Song -> listModel.openMenu(R.menu.item_song, item, detailModel.playInGenreWith)
@ -197,7 +196,7 @@ class GenreDetailFragment :
playbackModel.shuffle(unlikelyToBeNull(detailModel.currentGenre.value)) playbackModel.shuffle(unlikelyToBeNull(detailModel.currentGenre.value))
} }
override fun onOpenSortMenu(anchor: View) { override fun onOpenSortMenu() {
findNavController().navigateSafe(GenreDetailFragmentDirections.sort()) findNavController().navigateSafe(GenreDetailFragmentDirections.sort())
} }
@ -212,7 +211,7 @@ class GenreDetailFragment :
} }
private fun updateList(list: List<Item>) { private fun updateList(list: List<Item>) {
genreListAdapter.update(list, detailModel.genreInstructions.consume()) genreListAdapter.update(list, detailModel.genreSongInstructions.consume())
} }
private fun handleShow(show: Show?) { private fun handleShow(show: Show?) {

View file

@ -21,7 +21,6 @@ package org.oxycblt.auxio.detail
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination import androidx.navigation.NavDestination
@ -123,7 +122,7 @@ class PlaylistDetailFragment :
(layoutManager as GridLayoutManager).setFullWidthLookup { (layoutManager as GridLayoutManager).setFullWidthLookup {
if (it != 0) { if (it != 0) {
val item = val item =
detailModel.playlistList.value.getOrElse(it - 1) { detailModel.playlistSongList.value.getOrElse(it - 1) {
return@setFullWidthLookup false return@setFullWidthLookup false
} }
item is Divider || item is Header item is Divider || item is Header
@ -137,7 +136,7 @@ class PlaylistDetailFragment :
// DetailViewModel handles most initialization from the navigation argument. // DetailViewModel handles most initialization from the navigation argument.
detailModel.setPlaylist(args.playlistUid) detailModel.setPlaylist(args.playlistUid)
collectImmediately(detailModel.currentPlaylist, ::updatePlaylist) collectImmediately(detailModel.currentPlaylist, ::updatePlaylist)
collectImmediately(detailModel.playlistList, ::updateList) collectImmediately(detailModel.playlistSongList, ::updateList)
collectImmediately(detailModel.editedPlaylist, ::updateEditedList) collectImmediately(detailModel.editedPlaylist, ::updateEditedList)
collect(detailModel.toShow.flow, ::handleShow) collect(detailModel.toShow.flow, ::handleShow)
collect(listModel.menu.flow, ::handleMenu) collect(listModel.menu.flow, ::handleMenu)
@ -168,7 +167,7 @@ class PlaylistDetailFragment :
binding.detailRecycler.adapter = null binding.detailRecycler.adapter = null
// Avoid possible race conditions that could cause a bad replace instruction to be consumed // Avoid possible race conditions that could cause a bad replace instruction to be consumed
// during list initialization and crash the app. Could happen if the user is fast enough. // during list initialization and crash the app. Could happen if the user is fast enough.
detailModel.playlistInstructions.consume() detailModel.playlistSongInstructions.consume()
} }
override fun onDestinationChanged( override fun onDestinationChanged(
@ -236,7 +235,7 @@ class PlaylistDetailFragment :
requireNotNull(touchHelper) { "ItemTouchHelper was not available" }.startDrag(viewHolder) requireNotNull(touchHelper) { "ItemTouchHelper was not available" }.startDrag(viewHolder)
} }
override fun onOpenMenu(item: Song, anchor: View) { override fun onOpenMenu(item: Song) {
listModel.openMenu(R.menu.item_playlist_song, item, detailModel.playInPlaylistWith) listModel.openMenu(R.menu.item_playlist_song, item, detailModel.playInPlaylistWith)
} }
@ -252,7 +251,7 @@ class PlaylistDetailFragment :
detailModel.startPlaylistEdit() detailModel.startPlaylistEdit()
} }
override fun onOpenSortMenu(anchor: View) {} override fun onOpenSortMenu() {}
private fun updatePlaylist(playlist: Playlist?) { private fun updatePlaylist(playlist: Playlist?) {
if (playlist == null) { if (playlist == null) {
@ -278,7 +277,7 @@ class PlaylistDetailFragment :
} }
private fun updateList(list: List<Item>) { private fun updateList(list: List<Item>) {
playlistListAdapter.update(list, detailModel.playlistInstructions.consume()) playlistListAdapter.update(list, detailModel.playlistSongInstructions.consume())
} }
private fun updateEditedList(editedPlaylist: List<Song>?) { private fun updateEditedList(editedPlaylist: List<Song>?) {

View file

@ -82,7 +82,7 @@ abstract class DetailListAdapter(
* Called when the button in a [SortHeader] item is pressed, requesting that the sort menu * Called when the button in a [SortHeader] item is pressed, requesting that the sort menu
* should be opened. * should be opened.
*/ */
fun onOpenSortMenu(anchor: View) fun onOpenSortMenu()
} }
protected companion object { protected companion object {
@ -132,7 +132,7 @@ private class SortHeaderViewHolder(private val binding: ItemSortHeaderBinding) :
// Add a Tooltip based on the content description so that the purpose of this // Add a Tooltip based on the content description so that the purpose of this
// button can be clear. // button can be clear.
TooltipCompat.setTooltipText(this, contentDescription) TooltipCompat.setTooltipText(this, contentDescription)
setOnClickListener(listener::onOpenSortMenu) setOnClickListener { listener.onOpenSortMenu() }
} }
} }

View file

@ -30,6 +30,11 @@ import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
/**
* A [SortDialog] that controls the [Sort] of [DetailViewModel.albumSongSort].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint @AndroidEntryPoint
class AlbumSongSortDialog : SortDialog() { class AlbumSongSortDialog : SortDialog() {
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()

View file

@ -30,6 +30,11 @@ import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
/**
* A [SortDialog] that controls the [Sort] of [DetailViewModel.artistSongSort].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint @AndroidEntryPoint
class ArtistSongSortDialog : SortDialog() { class ArtistSongSortDialog : SortDialog() {
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()

View file

@ -30,6 +30,11 @@ import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
/**
* A [SortDialog] that controls the [Sort] of [DetailViewModel.genreSongSort].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint @AndroidEntryPoint
class GenreSongSortDialog : SortDialog() { class GenreSongSortDialog : SortDialog() {
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()

View file

@ -26,7 +26,6 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.MenuCompat import androidx.core.view.MenuCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.iterator
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
@ -57,7 +56,6 @@ import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.ListViewModel
import org.oxycblt.auxio.list.Menu import org.oxycblt.auxio.list.Menu
import org.oxycblt.auxio.list.SelectionFragment import org.oxycblt.auxio.list.SelectionFragment
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.IndexingProgress import org.oxycblt.auxio.music.IndexingProgress
import org.oxycblt.auxio.music.IndexingState import org.oxycblt.auxio.music.IndexingState
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
@ -76,7 +74,6 @@ import org.oxycblt.auxio.util.lazyReflectedField
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW import org.oxycblt.auxio.util.logW
import org.oxycblt.auxio.util.navigateSafe import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.unlikelyToBeNull
/** /**
* The starting [SelectionFragment] of Auxio. Shows the user's music library and enables navigation * The starting [SelectionFragment] of Auxio. Shows the user's music library and enables navigation
@ -172,7 +169,7 @@ class HomeFragment :
// --- VIEWMODEL SETUP --- // --- VIEWMODEL SETUP ---
collect(homeModel.recreateTabs.flow, ::handleRecreate) collect(homeModel.recreateTabs.flow, ::handleRecreate)
collectImmediately(homeModel.currentTabType, ::updateCurrentTab) collectImmediately(homeModel.currentTabType, ::updateCurrentTab)
collectImmediately(homeModel.songsList, homeModel.isFastScrolling, ::updateFab) collectImmediately(homeModel.songList, homeModel.isFastScrolling, ::updateFab)
collect(listModel.menu.flow, ::handleMenu) collect(listModel.menu.flow, ::handleMenu)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
collectImmediately(musicModel.indexingState, ::updateIndexerState) collectImmediately(musicModel.indexingState, ::updateIndexerState)
@ -232,41 +229,22 @@ class HomeFragment :
} }
// Handle sort menu // Handle sort menu
R.id.submenu_sorting -> { R.id.action_sort -> {
// Junk click event when opening the menu // Junk click event when opening the menu
true val directions =
} when (homeModel.currentTabType.value) {
R.id.option_sort_asc -> { MusicType.SONGS -> HomeFragmentDirections.sortSongs()
logD("Switching to ascending sorting") MusicType.ALBUMS -> HomeFragmentDirections.sortAlbums()
item.isChecked = true MusicType.ARTISTS -> HomeFragmentDirections.sortArtists()
homeModel.setSortForCurrentTab( MusicType.GENRES -> HomeFragmentDirections.sortGenres()
homeModel MusicType.PLAYLISTS -> HomeFragmentDirections.sortPlaylists()
.getSortForTab(homeModel.currentTabType.value) }
.withDirection(Sort.Direction.ASCENDING)) findNavController().navigateSafe(directions)
true
}
R.id.option_sort_dec -> {
logD("Switching to descending sorting")
item.isChecked = true
homeModel.setSortForCurrentTab(
homeModel
.getSortForTab(homeModel.currentTabType.value)
.withDirection(Sort.Direction.DESCENDING))
true true
} }
else -> { else -> {
val newMode = Sort.Mode.fromItemId(item.itemId) logW("Unexpected menu item selected")
if (newMode != null) { false
// Sorting option was selected, mark it as selected and update the mode
logD("Updating sort mode")
item.isChecked = true
homeModel.setSortForCurrentTab(
homeModel.getSortForTab(homeModel.currentTabType.value).withMode(newMode))
true
} else {
logW("Unexpected menu item selected")
false
}
} }
} }
} }
@ -300,61 +278,6 @@ class HomeFragment :
private fun updateCurrentTab(tabType: MusicType) { private fun updateCurrentTab(tabType: MusicType) {
val binding = requireBinding() val binding = requireBinding()
// Update the sort options to align with those allowed by the tab
val isVisible: (Int) -> Boolean =
when (tabType) {
// Disallow sorting by count for songs
MusicType.SONGS -> {
logD("Using song-specific menu options")
({ id -> id != R.id.option_sort_count })
}
// Disallow sorting by album for albums
MusicType.ALBUMS -> {
logD("Using album-specific menu options")
({ id -> id != R.id.option_sort_album })
}
// Only allow sorting by name, count, and duration for parents
else -> {
logD("Using parent-specific menu options")
({ id ->
id == R.id.option_sort_asc ||
id == R.id.option_sort_dec ||
id == R.id.option_sort_name ||
id == R.id.option_sort_count ||
id == R.id.option_sort_duration
})
}
}
val sortMenu =
unlikelyToBeNull(binding.homeNormalToolbar.menu.findItem(R.id.submenu_sorting).subMenu)
val toHighlight = homeModel.getSortForTab(tabType)
for (option in sortMenu) {
val isCurrentMode = option.itemId == toHighlight.mode.itemId
val isCurrentlyAscending =
option.itemId == R.id.option_sort_asc &&
toHighlight.direction == Sort.Direction.ASCENDING
val isCurrentlyDescending =
option.itemId == R.id.option_sort_dec &&
toHighlight.direction == Sort.Direction.DESCENDING
// Check the corresponding direction and mode sort options to align with
// the current sort of the tab.
if (isCurrentMode || isCurrentlyAscending || isCurrentlyDescending) {
logD(
"Checking $option option [mode: $isCurrentMode asc: $isCurrentlyAscending dec: $isCurrentlyDescending]")
// Note: We cannot inline this boolean assignment since it unchecks all other radio
// buttons (even when setting it to false), which would result in nothing being
// selected.
option.isChecked = true
}
// Disable options that are not allowed by the isVisible lambda
option.isVisible = isVisible(option.itemId)
if (!option.isVisible) {
logD("Hiding $option option")
}
}
// Update the scrolling view in AppBarLayout to align with the current tab's // Update the scrolling view in AppBarLayout to align with the current tab's
// scrolling state. This prevents the lift state from being confused as one // scrolling state. This prevents the lift state from being confused as one

View file

@ -55,63 +55,83 @@ constructor(
private val musicSettings: MusicSettings private val musicSettings: MusicSettings
) : ViewModel(), MusicRepository.UpdateListener, HomeSettings.Listener { ) : ViewModel(), MusicRepository.UpdateListener, HomeSettings.Listener {
private val _songsList = MutableStateFlow(listOf<Song>()) private val _songList = MutableStateFlow(listOf<Song>())
/** A list of [Song]s, sorted by the preferred [Sort], to be shown in the home view. */ /** A list of [Song]s, sorted by the preferred [Sort], to be shown in the home view. */
val songsList: StateFlow<List<Song>> val songList: StateFlow<List<Song>>
get() = _songsList get() = _songList
private val _songsInstructions = MutableEvent<UpdateInstructions>() private val _songInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [songsList] in the UI. */ /** Instructions for how to update [songList] in the UI. */
val songsInstructions: Event<UpdateInstructions> val songInstructions: Event<UpdateInstructions>
get() = _songsInstructions get() = _songInstructions
private val _albumsLists = MutableStateFlow(listOf<Album>()) /** The current [Sort] used for [songList]. */
/** A list of [Album]s, sorted by the preferred [Sort], to be shown in the home view. */ val songSort: Sort
val albumsList: StateFlow<List<Album>> get() = musicSettings.songSort
get() = _albumsLists
private val _albumsInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [albumsList] in the UI. */
val albumsInstructions: Event<UpdateInstructions>
get() = _albumsInstructions
private val _artistsList = MutableStateFlow(listOf<Artist>())
/**
* A list of [Artist]s, sorted by the preferred [Sort], to be shown in the home view. Note that
* if "Hide collaborators" is on, this list will not include collaborator [Artist]s.
*/
val artistsList: MutableStateFlow<List<Artist>>
get() = _artistsList
private val _artistsInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [artistsList] in the UI. */
val artistsInstructions: Event<UpdateInstructions>
get() = _artistsInstructions
private val _genresList = MutableStateFlow(listOf<Genre>())
/** A list of [Genre]s, sorted by the preferred [Sort], to be shown in the home view. */
val genresList: StateFlow<List<Genre>>
get() = _genresList
private val _genresInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [genresList] in the UI. */
val genresInstructions: Event<UpdateInstructions>
get() = _genresInstructions
private val _playlistsList = MutableStateFlow(listOf<Playlist>())
/** A list of [Playlist]s, sorted by the preferred [Sort], to be shown in the home view. */
val playlistsList: StateFlow<List<Playlist>>
get() = _playlistsList
private val _playlistsInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [genresList] in the UI. */
val playlistsInstructions: Event<UpdateInstructions>
get() = _playlistsInstructions
/** The [PlaySong] instructions to use when playing a [Song]. */ /** The [PlaySong] instructions to use when playing a [Song]. */
val playWith val playWith
get() = playbackSettings.playInListWith get() = playbackSettings.playInListWith
private val _albumList = MutableStateFlow(listOf<Album>())
/** A list of [Album]s, sorted by the preferred [Sort], to be shown in the home view. */
val albumList: StateFlow<List<Album>>
get() = _albumList
private val _albumInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [albumList] in the UI. */
val albumInstructions: Event<UpdateInstructions>
get() = _albumInstructions
/** The current [Sort] used for [albumList]. */
val albumSort: Sort
get() = musicSettings.albumSort
private val _artistList = MutableStateFlow(listOf<Artist>())
/**
* A list of [Artist]s, sorted by the preferred [Sort], to be shown in the home view. Note that
* if "Hide collaborators" is on, this list will not include collaborator [Artist]s.
*/
val artistList: MutableStateFlow<List<Artist>>
get() = _artistList
private val _artistInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [artistList] in the UI. */
val artistInstructions: Event<UpdateInstructions>
get() = _artistInstructions
/** The current [Sort] used for [artistList]. */
val artistSort: Sort
get() = musicSettings.artistSort
private val _genreList = MutableStateFlow(listOf<Genre>())
/** A list of [Genre]s, sorted by the preferred [Sort], to be shown in the home view. */
val genreList: StateFlow<List<Genre>>
get() = _genreList
private val _genreInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [genreList] in the UI. */
val genreInstructions: Event<UpdateInstructions>
get() = _genreInstructions
/** The current [Sort] used for [genreList]. */
val genreSort: Sort
get() = musicSettings.genreSort
private val _playlistList = MutableStateFlow(listOf<Playlist>())
/** A list of [Playlist]s, sorted by the preferred [Sort], to be shown in the home view. */
val playlistList: StateFlow<List<Playlist>>
get() = _playlistList
private val _playlistInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [genreList] in the UI. */
val playlistInstructions: Event<UpdateInstructions>
get() = _playlistInstructions
/** The current [Sort] used for [genreList]. */
val playlistSort: Sort
get() = musicSettings.playlistSort
/** /**
* A list of [MusicType] corresponding to the current [Tab] configuration, excluding invisible * A list of [MusicType] corresponding to the current [Tab] configuration, excluding invisible
* [Tab]s. * [Tab]s.
@ -157,12 +177,12 @@ constructor(
logD("Refreshing library") logD("Refreshing library")
// Get the each list of items in the library to use as our list data. // Get the each list of items in the library to use as our list data.
// Applying the preferred sorting to them. // Applying the preferred sorting to them.
_songsInstructions.put(UpdateInstructions.Diff) _songInstructions.put(UpdateInstructions.Diff)
_songsList.value = musicSettings.songSort.songs(deviceLibrary.songs) _songList.value = musicSettings.songSort.songs(deviceLibrary.songs)
_albumsInstructions.put(UpdateInstructions.Diff) _albumInstructions.put(UpdateInstructions.Diff)
_albumsLists.value = musicSettings.albumSort.albums(deviceLibrary.albums) _albumList.value = musicSettings.albumSort.albums(deviceLibrary.albums)
_artistsInstructions.put(UpdateInstructions.Diff) _artistInstructions.put(UpdateInstructions.Diff)
_artistsList.value = _artistList.value =
musicSettings.artistSort.artists( musicSettings.artistSort.artists(
if (homeSettings.shouldHideCollaborators) { if (homeSettings.shouldHideCollaborators) {
logD("Filtering collaborator artists") logD("Filtering collaborator artists")
@ -172,15 +192,15 @@ constructor(
logD("Using all artists") logD("Using all artists")
deviceLibrary.artists deviceLibrary.artists
}) })
_genresInstructions.put(UpdateInstructions.Diff) _genreInstructions.put(UpdateInstructions.Diff)
_genresList.value = musicSettings.genreSort.genres(deviceLibrary.genres) _genreList.value = musicSettings.genreSort.genres(deviceLibrary.genres)
} }
val userLibrary = musicRepository.userLibrary val userLibrary = musicRepository.userLibrary
if (changes.userLibrary && userLibrary != null) { if (changes.userLibrary && userLibrary != null) {
logD("Refreshing playlists") logD("Refreshing playlists")
_playlistsInstructions.put(UpdateInstructions.Diff) _playlistInstructions.put(UpdateInstructions.Diff)
_playlistsList.value = musicSettings.playlistSort.playlists(userLibrary.playlists) _playlistList.value = musicSettings.playlistSort.playlists(userLibrary.playlists)
} }
} }
@ -199,59 +219,58 @@ constructor(
} }
/** /**
* Get the preferred [Sort] for a given [Tab]. * Apply a new [Sort] to [songList].
* *
* @param tabType The [MusicType] of the [Tab] desired. * @param sort The [Sort] to apply.
* @return The [Sort] preferred for that [Tab]
*/ */
fun getSortForTab(tabType: MusicType) = fun applySongSort(sort: Sort) {
when (tabType) { musicSettings.songSort = sort
MusicType.SONGS -> musicSettings.songSort _songInstructions.put(UpdateInstructions.Replace(0))
MusicType.ALBUMS -> musicSettings.albumSort _songList.value = musicSettings.songSort.songs(_songList.value)
MusicType.ARTISTS -> musicSettings.artistSort }
MusicType.GENRES -> musicSettings.genreSort
MusicType.PLAYLISTS -> musicSettings.playlistSort
}
/** /**
* Update the preferred [Sort] for the current [Tab]. Will update corresponding list. * Apply a new [Sort] to [albumList].
* *
* @param sort The new [Sort] to apply. Assumed to be an allowed sort for the current [Tab]. * @param sort The [Sort] to apply.
*/ */
fun setSortForCurrentTab(sort: Sort) { fun applyAlbumSort(sort: Sort) {
// Can simply re-sort the current list of items without having to access the library. musicSettings.albumSort = sort
when (val type = _currentTabType.value) { _albumInstructions.put(UpdateInstructions.Replace(0))
MusicType.SONGS -> { _albumList.value = musicSettings.albumSort.albums(_albumList.value)
logD("Updating song [$type] sort mode to $sort") }
musicSettings.songSort = sort
_songsInstructions.put(UpdateInstructions.Replace(0)) /**
_songsList.value = sort.songs(_songsList.value) * Apply a new [Sort] to [artistList].
} *
MusicType.ALBUMS -> { * @param sort The [Sort] to apply.
logD("Updating album [$type] sort mode to $sort") */
musicSettings.albumSort = sort fun applyArtistSort(sort: Sort) {
_albumsInstructions.put(UpdateInstructions.Replace(0)) musicSettings.artistSort = sort
_albumsLists.value = sort.albums(_albumsLists.value) _artistInstructions.put(UpdateInstructions.Replace(0))
} _artistList.value = musicSettings.artistSort.artists(_artistList.value)
MusicType.ARTISTS -> { }
logD("Updating artist [$type] sort mode to $sort")
musicSettings.artistSort = sort /**
_artistsInstructions.put(UpdateInstructions.Replace(0)) * Apply a new [Sort] to [genreList].
_artistsList.value = sort.artists(_artistsList.value) *
} * @param sort The [Sort] to apply.
MusicType.GENRES -> { */
logD("Updating genre [$type] sort mode to $sort") fun applyGenreSort(sort: Sort) {
musicSettings.genreSort = sort musicSettings.genreSort = sort
_genresInstructions.put(UpdateInstructions.Replace(0)) _genreInstructions.put(UpdateInstructions.Replace(0))
_genresList.value = sort.genres(_genresList.value) _genreList.value = musicSettings.genreSort.genres(_genreList.value)
} }
MusicType.PLAYLISTS -> {
logD("Updating playlist [$type] sort mode to $sort") /**
musicSettings.playlistSort = sort * Apply a new [Sort] to [playlistList].
_playlistsInstructions.put(UpdateInstructions.Replace(0)) *
_playlistsList.value = sort.playlists(_playlistsList.value) * @param sort The [Sort] to apply.
} */
} fun applyPlaylistSort(sort: Sort) {
musicSettings.playlistSort = sort
_playlistInstructions.put(UpdateInstructions.Replace(0))
_playlistList.value = musicSettings.playlistSort.playlists(_playlistList.value)
} }
/** /**

View file

@ -21,7 +21,6 @@ package org.oxycblt.auxio.home.list
import android.os.Bundle import android.os.Bundle
import android.text.format.DateUtils import android.text.format.DateUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -40,13 +39,13 @@ import org.oxycblt.auxio.list.recycler.AlbumViewHolder
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.secsToMs import org.oxycblt.auxio.playback.secsToMs
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
/** /**
* A [ListFragment] that shows a list of [Album]s. * A [ListFragment] that shows a list of [Album]s.
@ -81,7 +80,7 @@ class AlbumListFragment :
listener = this@AlbumListFragment listener = this@AlbumListFragment
} }
collectImmediately(homeModel.albumsList, ::updateAlbums) collectImmediately(homeModel.albumList, ::updateAlbums)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
collectImmediately( collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback) playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -97,9 +96,9 @@ class AlbumListFragment :
} }
override fun getPopup(pos: Int): String? { override fun getPopup(pos: Int): String? {
val album = homeModel.albumsList.value[pos] val album = homeModel.albumList.value[pos]
// Change how we display the popup depending on the current sort mode. // Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicType.ALBUMS).mode) { return when (homeModel.albumSort.mode) {
// By Name -> Use Name // By Name -> Use Name
is Sort.Mode.ByName -> album.name.thumb is Sort.Mode.ByName -> album.name.thumb
@ -141,12 +140,13 @@ class AlbumListFragment :
detailModel.showAlbum(item) detailModel.showAlbum(item)
} }
override fun onOpenMenu(item: Album, anchor: View) { override fun onOpenMenu(item: Album) {
listModel.openMenu(R.menu.item_album, item) listModel.openMenu(R.menu.item_album, item)
} }
private fun updateAlbums(albums: List<Album>) { private fun updateAlbums(albums: List<Album>) {
albumAdapter.update(albums, homeModel.albumsInstructions.consume()) logD("Absolute fucking retard")
albumAdapter.update(albums, homeModel.albumInstructions.consume())
} }
private fun updateSelection(selection: List<Music>) { private fun updateSelection(selection: List<Music>) {

View file

@ -20,7 +20,6 @@ package org.oxycblt.auxio.home.list
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -38,7 +37,6 @@ import org.oxycblt.auxio.list.recycler.ArtistViewHolder
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
@ -76,7 +74,7 @@ class ArtistListFragment :
listener = this@ArtistListFragment listener = this@ArtistListFragment
} }
collectImmediately(homeModel.artistsList, ::updateArtists) collectImmediately(homeModel.artistList, ::updateArtists)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
collectImmediately( collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback) playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -92,9 +90,9 @@ class ArtistListFragment :
} }
override fun getPopup(pos: Int): String? { override fun getPopup(pos: Int): String? {
val artist = homeModel.artistsList.value[pos] val artist = homeModel.artistList.value[pos]
// Change how we display the popup depending on the current sort mode. // Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicType.ARTISTS).mode) { return when (homeModel.artistSort.mode) {
// By Name -> Use Name // By Name -> Use Name
is Sort.Mode.ByName -> artist.name.thumb is Sort.Mode.ByName -> artist.name.thumb
@ -117,12 +115,12 @@ class ArtistListFragment :
detailModel.showArtist(item) detailModel.showArtist(item)
} }
override fun onOpenMenu(item: Artist, anchor: View) { override fun onOpenMenu(item: Artist) {
listModel.openMenu(R.menu.item_parent, item) listModel.openMenu(R.menu.item_parent, item)
} }
private fun updateArtists(artists: List<Artist>) { private fun updateArtists(artists: List<Artist>) {
artistAdapter.update(artists, homeModel.artistsInstructions.consume()) artistAdapter.update(artists, homeModel.artistInstructions.consume())
} }
private fun updateSelection(selection: List<Music>) { private fun updateSelection(selection: List<Music>) {

View file

@ -20,7 +20,6 @@ package org.oxycblt.auxio.home.list
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -38,7 +37,6 @@ import org.oxycblt.auxio.list.recycler.GenreViewHolder
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
@ -75,7 +73,7 @@ class GenreListFragment :
listener = this@GenreListFragment listener = this@GenreListFragment
} }
collectImmediately(homeModel.genresList, ::updateGenres) collectImmediately(homeModel.genreList, ::updateGenres)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
collectImmediately( collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback) playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -91,9 +89,9 @@ class GenreListFragment :
} }
override fun getPopup(pos: Int): String? { override fun getPopup(pos: Int): String? {
val genre = homeModel.genresList.value[pos] val genre = homeModel.genreList.value[pos]
// Change how we display the popup depending on the current sort mode. // Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicType.GENRES).mode) { return when (homeModel.genreSort.mode) {
// By Name -> Use Name // By Name -> Use Name
is Sort.Mode.ByName -> genre.name.thumb is Sort.Mode.ByName -> genre.name.thumb
@ -116,12 +114,12 @@ class GenreListFragment :
detailModel.showGenre(item) detailModel.showGenre(item)
} }
override fun onOpenMenu(item: Genre, anchor: View) { override fun onOpenMenu(item: Genre) {
listModel.openMenu(R.menu.item_parent, item) listModel.openMenu(R.menu.item_parent, item)
} }
private fun updateGenres(genres: List<Genre>) { private fun updateGenres(genres: List<Genre>) {
genreAdapter.update(genres, homeModel.genresInstructions.consume()) genreAdapter.update(genres, homeModel.genreInstructions.consume())
} }
private fun updateSelection(selection: List<Music>) { private fun updateSelection(selection: List<Music>) {

View file

@ -20,7 +20,6 @@ package org.oxycblt.auxio.home.list
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
@ -36,7 +35,6 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.PlaylistViewHolder import org.oxycblt.auxio.list.recycler.PlaylistViewHolder
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
@ -73,7 +71,7 @@ class PlaylistListFragment :
listener = this@PlaylistListFragment listener = this@PlaylistListFragment
} }
collectImmediately(homeModel.playlistsList, ::updatePlaylists) collectImmediately(homeModel.playlistList, ::updatePlaylists)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
collectImmediately( collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback) playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -89,9 +87,9 @@ class PlaylistListFragment :
} }
override fun getPopup(pos: Int): String? { override fun getPopup(pos: Int): String? {
val playlist = homeModel.playlistsList.value[pos] val playlist = homeModel.playlistList.value[pos]
// Change how we display the popup depending on the current sort mode. // Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicType.GENRES).mode) { return when (homeModel.playlistSort.mode) {
// By Name -> Use Name // By Name -> Use Name
is Sort.Mode.ByName -> playlist.name.thumb is Sort.Mode.ByName -> playlist.name.thumb
@ -114,12 +112,12 @@ class PlaylistListFragment :
detailModel.showPlaylist(item) detailModel.showPlaylist(item)
} }
override fun onOpenMenu(item: Playlist, anchor: View) { override fun onOpenMenu(item: Playlist) {
listModel.openMenu(R.menu.item_playlist, item) listModel.openMenu(R.menu.item_playlist, item)
} }
private fun updatePlaylists(playlists: List<Playlist>) { private fun updatePlaylists(playlists: List<Playlist>) {
playlistAdapter.update(playlists, homeModel.playlistsInstructions.consume()) playlistAdapter.update(playlists, homeModel.playlistInstructions.consume())
} }
private fun updateSelection(selection: List<Music>) { private fun updateSelection(selection: List<Music>) {

View file

@ -21,7 +21,6 @@ package org.oxycblt.auxio.home.list
import android.os.Bundle import android.os.Bundle
import android.text.format.DateUtils import android.text.format.DateUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -38,7 +37,6 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.SongViewHolder import org.oxycblt.auxio.list.recycler.SongViewHolder
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
@ -78,7 +76,7 @@ class SongListFragment :
listener = this@SongListFragment listener = this@SongListFragment
} }
collectImmediately(homeModel.songsList, ::updateSongs) collectImmediately(homeModel.songList, ::updateSongs)
collectImmediately(listModel.selected, ::updateSelection) collectImmediately(listModel.selected, ::updateSelection)
collectImmediately( collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback) playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -94,11 +92,11 @@ class SongListFragment :
} }
override fun getPopup(pos: Int): String? { override fun getPopup(pos: Int): String? {
val song = homeModel.songsList.value[pos] val song = homeModel.songList.value[pos]
// Change how we display the popup depending on the current sort mode. // Change how we display the popup depending on the current sort mode.
// Note: We don't use the more correct individual artist name here, as sorts are largely // Note: We don't use the more correct individual artist name here, as sorts are largely
// based off the names of the parent objects and not the child objects. // based off the names of the parent objects and not the child objects.
return when (homeModel.getSortForTab(MusicType.SONGS).mode) { return when (homeModel.songSort.mode) {
// Name -> Use name // Name -> Use name
is Sort.Mode.ByName -> song.name.thumb is Sort.Mode.ByName -> song.name.thumb
@ -140,12 +138,12 @@ class SongListFragment :
playbackModel.play(item, homeModel.playWith) playbackModel.play(item, homeModel.playWith)
} }
override fun onOpenMenu(item: Song, anchor: View) { override fun onOpenMenu(item: Song) {
listModel.openMenu(R.menu.item_song, item, homeModel.playWith) listModel.openMenu(R.menu.item_song, item, homeModel.playWith)
} }
private fun updateSongs(songs: List<Song>) { private fun updateSongs(songs: List<Song>) {
songAdapter.update(songs, homeModel.songsInstructions.consume()) songAdapter.update(songs, homeModel.songInstructions.consume())
} }
private fun updateSelection(selection: List<Music>) { private fun updateSelection(selection: List<Music>) {

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023 Auxio Project
* AlbumSortDialog.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 <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.sort
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.sort.SortDialog
/**
* A [SortDialog] that controls the [Sort] of [HomeViewModel.albumList].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint
class AlbumSortDialog : SortDialog() {
private val homeModel: HomeViewModel by activityViewModels()
override fun getInitialSort() = homeModel.albumSort
override fun applyChosenSort(sort: Sort) {
homeModel.applyAlbumSort(sort)
}
override fun getModeChoices() =
listOf(
Sort.Mode.ByName,
Sort.Mode.ByArtist,
Sort.Mode.ByDate,
Sort.Mode.ByDuration,
Sort.Mode.ByCount,
Sort.Mode.ByDateAdded)
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 Auxio Project
* ArtistSortDialog.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 <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.sort
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.sort.SortDialog
/**
* A [SortDialog] that controls the [Sort] of [HomeViewModel.artistList].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint
class ArtistSortDialog : SortDialog() {
private val homeModel: HomeViewModel by activityViewModels()
override fun getInitialSort() = homeModel.artistSort
override fun applyChosenSort(sort: Sort) {
homeModel.applyArtistSort(sort)
}
override fun getModeChoices() =
listOf(Sort.Mode.ByName, Sort.Mode.ByDuration, Sort.Mode.ByCount)
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 Auxio Project
* GenreSortDialog.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 <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.sort
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.sort.SortDialog
/**
* A [SortDialog] that controls the [Sort] of [HomeViewModel.genreList].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint
class GenreSortDialog : SortDialog() {
private val homeModel: HomeViewModel by activityViewModels()
override fun getInitialSort() = homeModel.genreSort
override fun applyChosenSort(sort: Sort) {
homeModel.applyGenreSort(sort)
}
override fun getModeChoices() =
listOf(Sort.Mode.ByName, Sort.Mode.ByDuration, Sort.Mode.ByCount)
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 Auxio Project
* PlaylistSortDialog.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 <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.sort
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.sort.SortDialog
/**
* A [SortDialog] that controls the [Sort] of [HomeViewModel.playlistList].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint
class PlaylistSortDialog : SortDialog() {
private val homeModel: HomeViewModel by activityViewModels()
override fun getInitialSort() = homeModel.playlistSort
override fun applyChosenSort(sort: Sort) {
homeModel.applyPlaylistSort(sort)
}
override fun getModeChoices() =
listOf(Sort.Mode.ByName, Sort.Mode.ByDuration, Sort.Mode.ByCount)
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023 Auxio Project
* SongSortDialog.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 <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home.sort
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.sort.SortDialog
/**
* A [SortDialog] that controls the [Sort] of [HomeViewModel.songList].
*
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint
class SongSortDialog : SortDialog() {
private val homeModel: HomeViewModel by activityViewModels()
override fun getInitialSort() = homeModel.songSort
override fun applyChosenSort(sort: Sort) {
homeModel.applySongSort(sort)
}
override fun getModeChoices() =
listOf(
Sort.Mode.ByName,
Sort.Mode.ByArtist,
Sort.Mode.ByAlbum,
Sort.Mode.ByDate,
Sort.Mode.ByDuration,
Sort.Mode.ByDateAdded)
}

View file

@ -115,9 +115,8 @@ interface SelectableListListener<in T> : ClickableListListener<T> {
* Called when an item in the list requests that a menu related to it should be opened. * Called when an item in the list requests that a menu related to it should be opened.
* *
* @param item The [T] item to open a menu for. * @param item The [T] item to open a menu for.
* @param anchor The [View] to anchor the menu to.
*/ */
fun onOpenMenu(item: T, anchor: View) fun onOpenMenu(item: T)
/** /**
* Called when an item in the list requests that it be selected. * Called when an item in the list requests that it be selected.
@ -148,6 +147,6 @@ interface SelectableListListener<in T> : ClickableListListener<T> {
true true
} }
// Map the menu button to the menu opening listener. // Map the menu button to the menu opening listener.
menuButton.setOnClickListener { onOpenMenu(item, it) } menuButton.setOnClickListener { onOpenMenu(item) }
} }
} }

View file

@ -18,8 +18,6 @@
package org.oxycblt.auxio.list package org.oxycblt.auxio.list
import androidx.annotation.IdRes
import java.lang.IllegalStateException
import kotlin.math.max import kotlin.math.max
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
@ -164,8 +162,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
sealed interface Mode { sealed interface Mode {
/** The integer representation of this sort mode. */ /** The integer representation of this sort mode. */
val intCode: Int val intCode: Int
/** The item ID of this sort mode in menu resources. */
val itemId: Int
/** The string resource of the human-readable name of this sort mode. */ /** The string resource of the human-readable name of this sort mode. */
val stringRes: Int val stringRes: Int
@ -223,9 +219,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_NAME get() = IntegerTable.SORT_BY_NAME
override val itemId: Int
get() = R.id.option_sort_name
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_name get() = R.string.lbl_name
@ -254,9 +247,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_ALBUM get() = IntegerTable.SORT_BY_ALBUM
override val itemId: Int
get() = R.id.option_sort_album
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_album get() = R.string.lbl_album
@ -277,9 +267,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_ARTIST get() = IntegerTable.SORT_BY_ARTIST
override val itemId: Int
get() = R.id.option_sort_artist
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_artist get() = R.string.lbl_artist
@ -309,9 +296,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_YEAR get() = IntegerTable.SORT_BY_YEAR
override val itemId: Int
get() = R.id.option_sort_year
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_date get() = R.string.lbl_date
@ -334,9 +318,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_DURATION get() = IntegerTable.SORT_BY_DURATION
override val itemId: Int
get() = R.id.option_sort_duration
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_duration get() = R.string.lbl_duration
@ -372,9 +353,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_COUNT get() = IntegerTable.SORT_BY_COUNT
override val itemId: Int
get() = R.id.option_sort_count
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_song_count get() = R.string.lbl_song_count
@ -406,9 +384,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_DISC get() = IntegerTable.SORT_BY_DISC
override val itemId: Int
get() = throw IllegalStateException()
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_disc get() = R.string.lbl_disc
@ -428,9 +403,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_TRACK get() = IntegerTable.SORT_BY_TRACK
override val itemId: Int
get() = throw IllegalStateException()
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_track get() = R.string.lbl_track
@ -451,9 +423,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
override val intCode: Int override val intCode: Int
get() = IntegerTable.SORT_BY_DATE_ADDED get() = IntegerTable.SORT_BY_DATE_ADDED
override val itemId: Int
get() = R.id.option_sort_date_added
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_date_added get() = R.string.lbl_date_added
@ -488,27 +457,6 @@ data class Sort(val mode: Mode, val direction: Direction) {
ByDateAdded.intCode -> ByDateAdded ByDateAdded.intCode -> ByDateAdded
else -> null else -> null
} }
/**
* Convert a menu item ID into a [Mode].
*
* @param itemId The menu resource ID to convert
* @return A [Mode] corresponding to the given ID, or null if the ID is invalid.
* @see itemId
*/
fun fromItemId(@IdRes itemId: Int) =
when (itemId) {
ByName.itemId -> ByName
ByAlbum.itemId -> ByAlbum
ByArtist.itemId -> ByArtist
ByDate.itemId -> ByDate
ByDuration.itemId -> ByDuration
ByCount.itemId -> ByCount
ByDisc.itemId -> ByDisc
ByTrack.itemId -> ByTrack
ByDateAdded.itemId -> ByDateAdded
else -> null
}
} }
} }

View file

@ -182,7 +182,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
} }
} }
override fun onOpenMenu(item: Music, anchor: View) { override fun onOpenMenu(item: Music) {
when (item) { when (item) {
is Song -> listModel.openMenu(R.menu.item_song, item, searchModel.playWith) is Song -> listModel.openMenu(R.menu.item_song, item, searchModel.playWith)
is Album -> listModel.openMenu(R.menu.item_album, item) is Album -> listModel.openMenu(R.menu.item_album, item)

View file

@ -9,46 +9,10 @@
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/submenu_sorting" android:id="@+id/action_sort"
android:icon="@drawable/ic_sort_24" android:icon="@drawable/ic_sort_24"
android:title="@string/lbl_sort" android:title="@string/lbl_sort"
app:showAsAction="ifRoom"> app:showAsAction="ifRoom" />
<menu>
<group android:checkableBehavior="single"
android:id="@+id/sort_modes">
<item
android:id="@+id/option_sort_name"
android:title="@string/lbl_name" />
<item
android:id="@+id/option_sort_artist"
android:title="@string/lbl_artist" />
<item
android:id="@+id/option_sort_album"
android:title="@string/lbl_album" />
<item
android:id="@+id/option_sort_year"
android:title="@string/lbl_date" />
<item
android:id="@+id/option_sort_duration"
android:title="@string/lbl_duration" />
<item
android:id="@+id/option_sort_count"
android:title="@string/lbl_song_count" />
<item
android:id="@+id/option_sort_date_added"
android:title="@string/lbl_date_added" />
</group>
<group android:checkableBehavior="single"
android:id="@+id/sort_direction">
<item
android:id="@+id/option_sort_asc"
android:title="@string/lbl_sort_asc" />
<item
android:id="@+id/option_sort_dec"
android:title="@string/lbl_sort_dsc" />
</group>
</menu>
</item>
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"

View file

@ -12,6 +12,21 @@
<action <action
android:id="@+id/search" android:id="@+id/search"
app:destination="@id/search_fragment" /> app:destination="@id/search_fragment" />
<action
android:id="@+id/sort_songs"
app:destination="@+id/song_sort_dialog" />
<action
android:id="@+id/sort_albums"
app:destination="@+id/album_sort_dialog" />
<action
android:id="@+id/sort_artists"
app:destination="@+id/artist_sort_dialog" />
<action
android:id="@+id/sort_genres"
app:destination="@+id/genre_sort_dialog" />
<action
android:id="@+id/sort_playlists"
app:destination="@+id/playlist_sort_dialog" />
<action <action
android:id="@+id/show_song" android:id="@+id/show_song"
app:destination="@id/song_detail_dialog" /> app:destination="@id/song_detail_dialog" />
@ -65,6 +80,36 @@
app:destination="@id/play_from_genre_dialog" /> app:destination="@id/play_from_genre_dialog" />
</fragment> </fragment>
<dialog
android:id="@+id/song_sort_dialog"
android:name="org.oxycblt.auxio.home.sort.SongSortDialog"
android:label="song_sort_dialog"
tools:layout="@layout/dialog_sort" />
<dialog
android:id="@+id/album_sort_dialog"
android:name="org.oxycblt.auxio.home.sort.AlbumSortDialog"
android:label="song_sort_dialog"
tools:layout="@layout/dialog_sort" />
<dialog
android:id="@+id/artist_sort_dialog"
android:name="org.oxycblt.auxio.home.sort.ArtistSortDialog"
android:label="song_sort_dialog"
tools:layout="@layout/dialog_sort" />
<dialog
android:id="@+id/genre_sort_dialog"
android:name="org.oxycblt.auxio.home.sort.GenreSortDialog"
android:label="song_sort_dialog"
tools:layout="@layout/dialog_sort" />
<dialog
android:id="@+id/playlist_sort_dialog"
android:name="org.oxycblt.auxio.home.sort.PlaylistSortDialog"
android:label="song_sort_dialog"
tools:layout="@layout/dialog_sort" />
<dialog <dialog
android:id="@+id/song_detail_dialog" android:id="@+id/song_detail_dialog"
android:name="org.oxycblt.auxio.detail.SongDetailDialog" android:name="org.oxycblt.auxio.detail.SongDetailDialog"