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 d1b7199f8..29afcc68f 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -39,7 +39,7 @@ import org.oxycblt.auxio.list.Header 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.menu.Menu import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent 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 c50fb16b4..8ae1c66da 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -39,7 +39,7 @@ import org.oxycblt.auxio.list.Header 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.menu.Menu import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Music 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 665b56835..648424458 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -36,6 +36,7 @@ import org.oxycblt.auxio.detail.list.SortHeader import org.oxycblt.auxio.list.BasicHeader import org.oxycblt.auxio.list.Divider import org.oxycblt.auxio.list.Item +import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.list.sort.Sort import org.oxycblt.auxio.music.Album @@ -43,7 +44,6 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicRepository -import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.info.ReleaseType @@ -66,9 +66,9 @@ import org.oxycblt.auxio.util.unlikelyToBeNull class DetailViewModel @Inject constructor( + private val listSettings: ListSettings, private val musicRepository: MusicRepository, private val audioPropertiesFactory: AudioProperties.Factory, - private val musicSettings: MusicSettings, private val playbackSettings: PlaybackSettings ) : ViewModel(), MusicRepository.UpdateListener { private val _toShow = MutableEvent() @@ -110,7 +110,7 @@ constructor( /** The current [Sort] used for [Song]s in [albumSongList]. */ val albumSongSort: Sort - get() = musicSettings.albumSongSort + get() = listSettings.albumSongSort /** The [PlaySong] instructions to use when playing a [Song] from [Album] details. */ val playInAlbumWith @@ -134,9 +134,9 @@ constructor( /** The current [Sort] used for [Song]s in [artistSongList]. */ var artistSongSort: Sort - get() = musicSettings.artistSongSort + get() = listSettings.artistSongSort set(value) { - musicSettings.artistSongSort = value + listSettings.artistSongSort = value // Refresh the artist list to reflect the new sort. currentArtist.value?.let { refreshArtistList(it, true) } } @@ -163,9 +163,9 @@ constructor( /** The current [Sort] used for [Song]s in [genreSongList]. */ var genreSongSort: Sort - get() = musicSettings.genreSongSort + get() = listSettings.genreSongSort set(value) { - musicSettings.genreSongSort = value + listSettings.genreSongSort = value // Refresh the genre list to reflect the new sort. currentGenre.value?.let { refreshGenreList(it, true) } } @@ -369,7 +369,7 @@ constructor( * @param sort The [Sort] to apply. */ fun applyAlbumSongSort(sort: Sort) { - musicSettings.albumSongSort = sort + listSettings.albumSongSort = sort _currentAlbum.value?.let { refreshAlbumList(it, true) } } @@ -394,7 +394,7 @@ constructor( * @param sort The [Sort] to apply. */ fun applyArtistSongSort(sort: Sort) { - musicSettings.artistSongSort = sort + listSettings.artistSongSort = sort _currentArtist.value?.let { refreshArtistList(it, true) } } @@ -419,7 +419,7 @@ constructor( * @param sort The [Sort] to apply. */ fun applyGenreSongSort(sort: Sort) { - musicSettings.genreSongSort = sort + listSettings.genreSongSort = sort _currentGenre.value?.let { refreshGenreList(it, true) } } 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 190ae4c81..cdcd59e37 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -39,7 +39,7 @@ import org.oxycblt.auxio.list.Header 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.menu.Menu import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Music diff --git a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt index b9c8e4815..b97135cb5 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt @@ -43,7 +43,7 @@ import org.oxycblt.auxio.list.Header 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.menu.Menu import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicViewModel diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 51e25378a..66de36045 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -54,8 +54,8 @@ import org.oxycblt.auxio.home.list.SongListFragment import org.oxycblt.auxio.home.tabs.AdaptiveTabStrategy import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.list.ListViewModel -import org.oxycblt.auxio.list.Menu import org.oxycblt.auxio.list.SelectionFragment +import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.music.IndexingProgress import org.oxycblt.auxio.music.IndexingState import org.oxycblt.auxio.music.Music diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt index 1e81c18e4..bb9311c84 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -24,13 +24,13 @@ import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.oxycblt.auxio.home.tabs.Tab +import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.list.sort.Sort import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicRepository -import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.MusicType import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Song @@ -50,9 +50,9 @@ class HomeViewModel @Inject constructor( private val homeSettings: HomeSettings, + private val listSettings: ListSettings, private val playbackSettings: PlaybackSettings, private val musicRepository: MusicRepository, - private val musicSettings: MusicSettings ) : ViewModel(), MusicRepository.UpdateListener, HomeSettings.Listener { private val _songList = MutableStateFlow(listOf()) @@ -67,7 +67,7 @@ constructor( /** The current [Sort] used for [songList]. */ val songSort: Sort - get() = musicSettings.songSort + get() = listSettings.songSort /** The [PlaySong] instructions to use when playing a [Song]. */ val playWith @@ -85,7 +85,7 @@ constructor( /** The current [Sort] used for [albumList]. */ val albumSort: Sort - get() = musicSettings.albumSort + get() = listSettings.albumSort private val _artistList = MutableStateFlow(listOf()) /** @@ -102,7 +102,7 @@ constructor( /** The current [Sort] used for [artistList]. */ val artistSort: Sort - get() = musicSettings.artistSort + get() = listSettings.artistSort private val _genreList = MutableStateFlow(listOf()) /** A list of [Genre]s, sorted by the preferred [Sort], to be shown in the home view. */ @@ -116,7 +116,7 @@ constructor( /** The current [Sort] used for [genreList]. */ val genreSort: Sort - get() = musicSettings.genreSort + get() = listSettings.genreSort private val _playlistList = MutableStateFlow(listOf()) /** A list of [Playlist]s, sorted by the preferred [Sort], to be shown in the home view. */ @@ -130,7 +130,7 @@ constructor( /** The current [Sort] used for [genreList]. */ val playlistSort: Sort - get() = musicSettings.playlistSort + get() = listSettings.playlistSort /** * A list of [MusicType] corresponding to the current [Tab] configuration, excluding invisible @@ -178,12 +178,12 @@ constructor( // Get the each list of items in the library to use as our list data. // Applying the preferred sorting to them. _songInstructions.put(UpdateInstructions.Diff) - _songList.value = musicSettings.songSort.songs(deviceLibrary.songs) + _songList.value = listSettings.songSort.songs(deviceLibrary.songs) _albumInstructions.put(UpdateInstructions.Diff) - _albumList.value = musicSettings.albumSort.albums(deviceLibrary.albums) + _albumList.value = listSettings.albumSort.albums(deviceLibrary.albums) _artistInstructions.put(UpdateInstructions.Diff) _artistList.value = - musicSettings.artistSort.artists( + listSettings.artistSort.artists( if (homeSettings.shouldHideCollaborators) { logD("Filtering collaborator artists") // Hide Collaborators is enabled, filter out collaborators. @@ -193,14 +193,14 @@ constructor( deviceLibrary.artists }) _genreInstructions.put(UpdateInstructions.Diff) - _genreList.value = musicSettings.genreSort.genres(deviceLibrary.genres) + _genreList.value = listSettings.genreSort.genres(deviceLibrary.genres) } val userLibrary = musicRepository.userLibrary if (changes.userLibrary && userLibrary != null) { logD("Refreshing playlists") _playlistInstructions.put(UpdateInstructions.Diff) - _playlistList.value = musicSettings.playlistSort.playlists(userLibrary.playlists) + _playlistList.value = listSettings.playlistSort.playlists(userLibrary.playlists) } } @@ -224,9 +224,9 @@ constructor( * @param sort The [Sort] to apply. */ fun applySongSort(sort: Sort) { - musicSettings.songSort = sort + listSettings.songSort = sort _songInstructions.put(UpdateInstructions.Replace(0)) - _songList.value = musicSettings.songSort.songs(_songList.value) + _songList.value = listSettings.songSort.songs(_songList.value) } /** @@ -235,9 +235,9 @@ constructor( * @param sort The [Sort] to apply. */ fun applyAlbumSort(sort: Sort) { - musicSettings.albumSort = sort + listSettings.albumSort = sort _albumInstructions.put(UpdateInstructions.Replace(0)) - _albumList.value = musicSettings.albumSort.albums(_albumList.value) + _albumList.value = listSettings.albumSort.albums(_albumList.value) } /** @@ -246,9 +246,9 @@ constructor( * @param sort The [Sort] to apply. */ fun applyArtistSort(sort: Sort) { - musicSettings.artistSort = sort + listSettings.artistSort = sort _artistInstructions.put(UpdateInstructions.Replace(0)) - _artistList.value = musicSettings.artistSort.artists(_artistList.value) + _artistList.value = listSettings.artistSort.artists(_artistList.value) } /** @@ -257,9 +257,9 @@ constructor( * @param sort The [Sort] to apply. */ fun applyGenreSort(sort: Sort) { - musicSettings.genreSort = sort + listSettings.genreSort = sort _genreInstructions.put(UpdateInstructions.Replace(0)) - _genreList.value = musicSettings.genreSort.genres(_genreList.value) + _genreList.value = listSettings.genreSort.genres(_genreList.value) } /** @@ -268,9 +268,9 @@ constructor( * @param sort The [Sort] to apply. */ fun applyPlaylistSort(sort: Sort) { - musicSettings.playlistSort = sort + listSettings.playlistSort = sort _playlistInstructions.put(UpdateInstructions.Replace(0)) - _playlistList.value = musicSettings.playlistSort.playlists(_playlistList.value) + _playlistList.value = listSettings.playlistSort.playlists(_playlistList.value) } /** diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListModule.kt b/app/src/main/java/org/oxycblt/auxio/list/ListModule.kt new file mode 100644 index 000000000..521bc4283 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/list/ListModule.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Auxio Project + * ListModule.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.list + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +interface ListModule { + @Binds fun settings(settings: ListSettingsImpl): ListSettings +} diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListSettings.kt b/app/src/main/java/org/oxycblt/auxio/list/ListSettings.kt new file mode 100644 index 000000000..3f3388b73 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/list/ListSettings.kt @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023 Auxio Project + * ListSettings.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.list + +import android.content.Context +import androidx.core.content.edit +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import org.oxycblt.auxio.R +import org.oxycblt.auxio.list.sort.Sort +import org.oxycblt.auxio.settings.Settings + +interface ListSettings : Settings { + /** The [Sort] mode used in Song lists. */ + var songSort: Sort + /** The [Sort] mode used in Album lists. */ + var albumSort: Sort + /** The [Sort] mode used in Artist lists. */ + var artistSort: Sort + /** The [Sort] mode used in Genre lists. */ + var genreSort: Sort + /** The [Sort] mode used in Playlist lists. */ + var playlistSort: Sort + /** The [Sort] mode used in an Album's Song list. */ + var albumSongSort: Sort + /** The [Sort] mode used in an Artist's Song list. */ + var artistSongSort: Sort + /** The [Sort] mode used in a Genre's Song list. */ + var genreSongSort: Sort +} + +class ListSettingsImpl @Inject constructor(@ApplicationContext val context: Context) : + Settings.Impl(context), ListSettings { + override var songSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_songs_sort), value.intCode) + apply() + } + } + + override var albumSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_albums_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_albums_sort), value.intCode) + apply() + } + } + + override var artistSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_artists_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_artists_sort), value.intCode) + apply() + } + } + + override var genreSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_genres_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_genres_sort), value.intCode) + apply() + } + } + + override var playlistSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_playlists_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_playlists_sort), value.intCode) + apply() + } + } + + override var albumSongSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt( + getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByDisc, Sort.Direction.ASCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_album_songs_sort), value.intCode) + apply() + } + } + + override var artistSongSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt( + getString(R.string.set_key_artist_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_artist_songs_sort), value.intCode) + apply() + } + } + + override var genreSongSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt( + getString(R.string.set_key_genre_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_genre_songs_sort), value.intCode) + apply() + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListViewModel.kt b/app/src/main/java/org/oxycblt/auxio/list/ListViewModel.kt index 115a118a0..ed6536fe2 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/ListViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/ListViewModel.kt @@ -18,21 +18,19 @@ package org.oxycblt.auxio.list -import android.os.Parcelable import androidx.annotation.MenuRes import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.parcelize.Parcelize +import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicRepository -import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaySong @@ -49,10 +47,8 @@ import org.oxycblt.auxio.util.logW @HiltViewModel class ListViewModel @Inject -constructor( - private val musicRepository: MusicRepository, - private val musicSettings: MusicSettings -) : ViewModel(), MusicRepository.UpdateListener { +constructor(private val listSettings: ListSettings, private val musicRepository: MusicRepository) : + ViewModel(), MusicRepository.UpdateListener { private val _selected = MutableStateFlow(listOf()) /** The currently selected items. These are ordered in earliest selected and latest selected. */ val selected: StateFlow> @@ -124,9 +120,9 @@ constructor( .flatMap { when (it) { is Song -> listOf(it) - is Album -> musicSettings.albumSongSort.songs(it.songs) - is Artist -> musicSettings.artistSongSort.songs(it.songs) - is Genre -> musicSettings.genreSongSort.songs(it.songs) + is Album -> listSettings.albumSongSort.songs(it.songs) + is Artist -> listSettings.artistSongSort.songs(it.songs) + is Genre -> listSettings.genreSongSort.songs(it.songs) is Playlist -> it.songs } } @@ -214,75 +210,3 @@ constructor( _menu.put(menu) } } - -/** - * Command to navigate to a specific menu dialog configuration. - * - * @author Alexander Capehart (OxygenCobalt) - */ -sealed interface Menu { - /** The menu resource to inflate in the menu dialog. */ - @get:MenuRes val res: Int - /** A [Parcel] version of this instance that can be used as a navigation argument. */ - val parcel: Parcel - - sealed interface Parcel : Parcelable - - /** Navigate to a [Song] menu dialog. */ - class ForSong(@MenuRes override val res: Int, val song: Song, val playWith: PlaySong) : Menu { - override val parcel: Parcel - get() { - val playWithUid = - when (playWith) { - is PlaySong.FromArtist -> playWith.which?.uid - is PlaySong.FromGenre -> playWith.which?.uid - is PlaySong.FromPlaylist -> playWith.which.uid - is PlaySong.FromAll, - is PlaySong.FromAlbum, - is PlaySong.ByItself -> null - } - - return Parcel(res, song.uid, playWith.intCode, playWithUid) - } - - @Parcelize - data class Parcel( - val res: Int, - val songUid: Music.UID, - val playWithCode: Int, - val playWithUid: Music.UID? - ) : Menu.Parcel - } - - /** Navigate to a [Album] menu dialog. */ - class ForAlbum(@MenuRes override val res: Int, val album: Album) : Menu { - override val parcel - get() = Parcel(res, album.uid) - - @Parcelize data class Parcel(val res: Int, val albumUid: Music.UID) : Menu.Parcel - } - - /** Navigate to a [Artist] menu dialog. */ - class ForArtist(@MenuRes override val res: Int, val artist: Artist) : Menu { - override val parcel - get() = Parcel(res, artist.uid) - - @Parcelize data class Parcel(val res: Int, val artistUid: Music.UID) : Menu.Parcel - } - - /** Navigate to a [Genre] menu dialog. */ - class ForGenre(@MenuRes override val res: Int, val genre: Genre) : Menu { - override val parcel - get() = Parcel(res, genre.uid) - - @Parcelize data class Parcel(val res: Int, val genreUid: Music.UID) : Menu.Parcel - } - - /** Navigate to a [Playlist] menu dialog. */ - class ForPlaylist(@MenuRes override val res: Int, val playlist: Playlist) : Menu { - override val parcel - get() = Parcel(res, playlist.uid) - - @Parcelize data class Parcel(val res: Int, val playlistUid: Music.UID) : Menu.Parcel - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/list/menu/Menu.kt b/app/src/main/java/org/oxycblt/auxio/list/menu/Menu.kt new file mode 100644 index 000000000..fc388cd36 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/list/menu/Menu.kt @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Auxio Project + * Menu.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.list.menu + +import android.os.Parcelable +import androidx.annotation.MenuRes +import kotlinx.parcelize.Parcelize +import org.oxycblt.auxio.music.Album +import org.oxycblt.auxio.music.Artist +import org.oxycblt.auxio.music.Genre +import org.oxycblt.auxio.music.Music +import org.oxycblt.auxio.music.Playlist +import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.playback.PlaySong + +/** + * Command to navigate to a specific menu dialog configuration. + * + * @author Alexander Capehart (OxygenCobalt) + */ +sealed interface Menu { + /** The menu resource to inflate in the menu dialog. */ + @get:MenuRes val res: Int + /** A [Parcel] version of this instance that can be used as a navigation argument. */ + val parcel: Parcel + + sealed interface Parcel : Parcelable + + /** Navigate to a [Song] menu dialog. */ + class ForSong(@MenuRes override val res: Int, val song: Song, val playWith: PlaySong) : Menu { + override val parcel: Parcel + get() { + val playWithUid = + when (playWith) { + is PlaySong.FromArtist -> playWith.which?.uid + is PlaySong.FromGenre -> playWith.which?.uid + is PlaySong.FromPlaylist -> playWith.which.uid + is PlaySong.FromAll, + is PlaySong.FromAlbum, + is PlaySong.ByItself -> null + } + + return Parcel(res, song.uid, playWith.intCode, playWithUid) + } + + @Parcelize + data class Parcel( + val res: Int, + val songUid: Music.UID, + val playWithCode: Int, + val playWithUid: Music.UID? + ) : Menu.Parcel + } + + /** Navigate to a [Album] menu dialog. */ + class ForAlbum(@MenuRes override val res: Int, val album: Album) : Menu { + override val parcel + get() = Parcel(res, album.uid) + + @Parcelize data class Parcel(val res: Int, val albumUid: Music.UID) : Menu.Parcel + } + + /** Navigate to a [Artist] menu dialog. */ + class ForArtist(@MenuRes override val res: Int, val artist: Artist) : Menu { + override val parcel + get() = Parcel(res, artist.uid) + + @Parcelize data class Parcel(val res: Int, val artistUid: Music.UID) : Menu.Parcel + } + + /** Navigate to a [Genre] menu dialog. */ + class ForGenre(@MenuRes override val res: Int, val genre: Genre) : Menu { + override val parcel + get() = Parcel(res, genre.uid) + + @Parcelize data class Parcel(val res: Int, val genreUid: Music.UID) : Menu.Parcel + } + + /** Navigate to a [Playlist] menu dialog. */ + class ForPlaylist(@MenuRes override val res: Int, val playlist: Playlist) : Menu { + override val parcel + get() = Parcel(res, playlist.uid) + + @Parcelize data class Parcel(val res: Int, val playlistUid: Music.UID) : Menu.Parcel + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt index a65f993bc..907cef049 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt @@ -30,7 +30,6 @@ import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.databinding.DialogMenuBinding import org.oxycblt.auxio.list.ClickableListListener import org.oxycblt.auxio.list.ListViewModel -import org.oxycblt.auxio.list.Menu import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.ui.ViewBindingBottomSheetDialogFragment import org.oxycblt.auxio.util.collectImmediately diff --git a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt index d135117bd..9abf34133 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt @@ -27,7 +27,6 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogMenuBinding import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.list.ListViewModel -import org.oxycblt.auxio.list.Menu import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicViewModel diff --git a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt index 577fe0e48..0d5388854 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt @@ -23,7 +23,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import org.oxycblt.auxio.list.Menu import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicRepository import org.oxycblt.auxio.playback.PlaySong diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt index 89d4476ad..f2930d3ec 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt @@ -24,7 +24,6 @@ import androidx.core.content.edit import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import org.oxycblt.auxio.R -import org.oxycblt.auxio.list.sort.Sort import org.oxycblt.auxio.music.fs.Directory import org.oxycblt.auxio.music.fs.MusicDirectories import org.oxycblt.auxio.settings.Settings @@ -47,23 +46,6 @@ interface MusicSettings : Settings { var multiValueSeparators: String /** Whether to enable more advanced sorting by articles and numbers. */ val intelligentSorting: Boolean - // TODO: Move sort settings to list module - /** The [Sort] mode used in [Song] lists. */ - var songSort: Sort - /** The [Sort] mode used in [Album] lists. */ - var albumSort: Sort - /** The [Sort] mode used in [Artist] lists. */ - var artistSort: Sort - /** The [Sort] mode used in [Genre] lists. */ - var genreSort: Sort - /** The [Sort] mode used in [Playlist] lists. */ - var playlistSort: Sort - /** The [Sort] mode used in an [Album]'s [Song] list. */ - var albumSongSort: Sort - /** The [Sort] mode used in an [Artist]'s [Song] list. */ - var artistSongSort: Sort - /** The [Sort] mode used in a [Genre]'s [Song] list. */ - var genreSongSort: Sort interface Listener { /** Called when a setting controlling how music is loaded has changed. */ @@ -117,105 +99,6 @@ class MusicSettingsImpl @Inject constructor(@ApplicationContext context: Context override val intelligentSorting: Boolean get() = sharedPreferences.getBoolean(getString(R.string.set_key_auto_sort_names), true) - override var songSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_songs_sort), value.intCode) - apply() - } - } - - override var albumSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt(getString(R.string.set_key_albums_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_albums_sort), value.intCode) - apply() - } - } - - override var artistSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt(getString(R.string.set_key_artists_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_artists_sort), value.intCode) - apply() - } - } - - override var genreSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt(getString(R.string.set_key_genres_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_genres_sort), value.intCode) - apply() - } - } - - override var playlistSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt(getString(R.string.set_key_playlists_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_playlists_sort), value.intCode) - apply() - } - } - - override var albumSongSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByDisc, Sort.Direction.ASCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_album_songs_sort), value.intCode) - apply() - } - } - - override var artistSongSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_artist_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_artist_songs_sort), value.intCode) - apply() - } - } - - override var genreSongSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_genre_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_genre_songs_sort), value.intCode) - apply() - } - } - override fun onSettingChanged(key: String, listener: MusicSettings.Listener) { // TODO: Differentiate "hard reloads" (Need the cache) and "Soft reloads" // (just need to manipulate data) diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt index 6e314a4f1..314b38785 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.util.Event import org.oxycblt.auxio.util.MutableEvent import org.oxycblt.auxio.util.logD @@ -39,8 +40,8 @@ import org.oxycblt.auxio.util.logD class MusicViewModel @Inject constructor( + private val listSettings: ListSettings, private val musicRepository: MusicRepository, - private val musicSettings: MusicSettings ) : ViewModel(), MusicRepository.UpdateListener, MusicRepository.IndexingListener { private val _indexingState = MutableStateFlow(null) @@ -167,7 +168,7 @@ constructor( */ fun addToPlaylist(album: Album, playlist: Playlist? = null) { logD("Adding $album to playlist") - addToPlaylist(musicSettings.albumSongSort.songs(album.songs), playlist) + addToPlaylist(listSettings.albumSongSort.songs(album.songs), playlist) } /** @@ -178,7 +179,7 @@ constructor( */ fun addToPlaylist(artist: Artist, playlist: Playlist? = null) { logD("Adding $artist to playlist") - addToPlaylist(musicSettings.artistSongSort.songs(artist.songs), playlist) + addToPlaylist(listSettings.artistSongSort.songs(artist.songs), playlist) } /** @@ -189,7 +190,7 @@ constructor( */ fun addToPlaylist(genre: Genre, playlist: Playlist? = null) { logD("Adding $genre to playlist") - addToPlaylist(musicSettings.genreSongSort.songs(genre.songs), playlist) + addToPlaylist(listSettings.genreSongSort.songs(genre.songs), playlist) } /** diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index 9b7ad397b..e497c96ad 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -27,12 +27,12 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicRepository -import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.persist.PersistenceRepository @@ -58,8 +58,8 @@ constructor( private val playbackManager: PlaybackStateManager, private val playbackSettings: PlaybackSettings, private val persistenceRepository: PersistenceRepository, + private val listSettings: ListSettings, private val musicRepository: MusicRepository, - private val musicSettings: MusicSettings ) : ViewModel(), PlaybackStateManager.Listener, PlaybackSettings.Listener { private var lastPositionJob: Job? = null @@ -401,11 +401,11 @@ constructor( val deviceLibrary = musicRepository.deviceLibrary ?: return val queue = when (parent) { - is Genre -> musicSettings.genreSongSort.songs(parent.songs) - is Artist -> musicSettings.artistSongSort.songs(parent.songs) - is Album -> musicSettings.albumSongSort.songs(parent.songs) + is Genre -> listSettings.genreSongSort.songs(parent.songs) + is Artist -> listSettings.artistSongSort.songs(parent.songs) + is Album -> listSettings.albumSongSort.songs(parent.songs) is Playlist -> parent.songs - null -> musicSettings.songSort.songs(deviceLibrary.songs) + null -> listSettings.songSort.songs(deviceLibrary.songs) } playbackManager.play(song, parent, queue, shuffled) } @@ -464,7 +464,7 @@ constructor( */ fun playNext(album: Album) { logD("Playing $album next") - playbackManager.playNext(musicSettings.albumSongSort.songs(album.songs)) + playbackManager.playNext(listSettings.albumSongSort.songs(album.songs)) } /** @@ -474,7 +474,7 @@ constructor( */ fun playNext(artist: Artist) { logD("Playing $artist next") - playbackManager.playNext(musicSettings.artistSongSort.songs(artist.songs)) + playbackManager.playNext(listSettings.artistSongSort.songs(artist.songs)) } /** @@ -484,7 +484,7 @@ constructor( */ fun playNext(genre: Genre) { logD("Playing $genre next") - playbackManager.playNext(musicSettings.genreSongSort.songs(genre.songs)) + playbackManager.playNext(listSettings.genreSongSort.songs(genre.songs)) } /** @@ -524,7 +524,7 @@ constructor( */ fun addToQueue(album: Album) { logD("Adding $album to queue") - playbackManager.addToQueue(musicSettings.albumSongSort.songs(album.songs)) + playbackManager.addToQueue(listSettings.albumSongSort.songs(album.songs)) } /** @@ -534,7 +534,7 @@ constructor( */ fun addToQueue(artist: Artist) { logD("Adding $artist to queue") - playbackManager.addToQueue(musicSettings.artistSongSort.songs(artist.songs)) + playbackManager.addToQueue(listSettings.artistSongSort.songs(artist.songs)) } /** @@ -544,7 +544,7 @@ constructor( */ fun addToQueue(genre: Genre) { logD("Adding $genre to queue") - playbackManager.addToQueue(musicSettings.genreSongSort.songs(genre.songs)) + playbackManager.addToQueue(listSettings.genreSongSort.songs(genre.songs)) } /** diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt index 96aa107c6..c131238e0 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt @@ -47,8 +47,8 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.oxycblt.auxio.BuildConfig +import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.music.MusicRepository -import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.persist.PersistenceRepository @@ -99,8 +99,8 @@ class PlaybackService : @Inject lateinit var playbackManager: PlaybackStateManager @Inject lateinit var playbackSettings: PlaybackSettings @Inject lateinit var persistenceRepository: PersistenceRepository + @Inject lateinit var listSettings: ListSettings @Inject lateinit var musicRepository: MusicRepository - @Inject lateinit var musicSettings: MusicSettings // State private lateinit var foregroundManager: ForegroundManager @@ -369,7 +369,7 @@ class PlaybackService : is InternalPlayer.Action.ShuffleAll -> { logD("Shuffling all tracks") playbackManager.play( - null, null, musicSettings.songSort.songs(deviceLibrary.songs), true) + null, null, listSettings.songSort.songs(deviceLibrary.songs), true) } // Open -> Try to find the Song for the given file and then play it from all songs is InternalPlayer.Action.Open -> { @@ -378,7 +378,7 @@ class PlaybackService : playbackManager.play( song, null, - musicSettings.songSort.songs(deviceLibrary.songs), + listSettings.songSort.songs(deviceLibrary.songs), playbackManager.queue.isShuffled && playbackSettings.keepShuffle) } } diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt index 1a3a29d5f..128a3c394 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt @@ -41,7 +41,7 @@ import org.oxycblt.auxio.list.Header 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.menu.Menu import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre diff --git a/app/src/main/res/navigation/inner.xml b/app/src/main/res/navigation/inner.xml index df95f29ad..f6d03a0ba 100644 --- a/app/src/main/res/navigation/inner.xml +++ b/app/src/main/res/navigation/inner.xml @@ -427,7 +427,7 @@ tools:layout="@layout/dialog_menu"> + app:argType="org.oxycblt.auxio.list.menu.Menu$ForSong$Parcel" /> + app:argType="org.oxycblt.auxio.list.menu.Menu$ForAlbum$Parcel" /> + app:argType="org.oxycblt.auxio.list.menu.Menu$ForArtist$Parcel" /> + app:argType="org.oxycblt.auxio.list.menu.Menu$ForGenre$Parcel" /> + app:argType="org.oxycblt.auxio.list.menu.Menu$ForPlaylist$Parcel" /> \ No newline at end of file