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 e5e12ce83..f4dc3dc67 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -23,7 +23,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import org.oxycblt.auxio.R -import org.oxycblt.auxio.home.LibSortMode import org.oxycblt.auxio.music.ActionHeader import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist @@ -88,7 +87,7 @@ class DetailViewModel : ViewModel() { ) ) - data.addAll(LibSortMode.ASCENDING.sortGenre(curGenre.value!!)) + data.addAll(SortMode.ASCENDING.sortGenre(curGenre.value!!)) mGenreData.value = data } @@ -108,7 +107,7 @@ class DetailViewModel : ViewModel() { ) ) - data.addAll(LibSortMode.YEAR.sortAlbums(artist.albums)) + data.addAll(SortMode.YEAR.sortAlbums(artist.albums)) data.add( ActionHeader( @@ -121,7 +120,7 @@ class DetailViewModel : ViewModel() { ) ) - data.addAll(LibSortMode.YEAR.sortArtist(artist)) + data.addAll(SortMode.YEAR.sortArtist(artist)) mArtistData.value = data.toList() } @@ -144,7 +143,7 @@ class DetailViewModel : ViewModel() { ) ) - data.addAll(LibSortMode.ASCENDING.sortAlbum(curAlbum.value!!)) + data.addAll(SortMode.ASCENDING.sortAlbum(curAlbum.value!!)) mAlbumData.value = data } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt index fee2bd3d5..b4eb195bf 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt @@ -53,7 +53,7 @@ class AlbumDetailAdapter( override fun getItemViewType(position: Int): Int { return when (getItem(position)) { - is Album -> ALBUM_HEADER_ITEM_TYPE + is Album -> ALBUM_DETAIL_ITEM_TYPE is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE is Song -> ALBUM_SONG_ITEM_TYPE @@ -63,7 +63,7 @@ class AlbumDetailAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { - ALBUM_HEADER_ITEM_TYPE -> AlbumHeaderViewHolder( + ALBUM_DETAIL_ITEM_TYPE -> AlbumDetailViewHolder( ItemDetailBinding.inflate(parent.context.inflater) ) @@ -81,7 +81,7 @@ class AlbumDetailAdapter( val item = getItem(position) when (item) { - is Album -> (holder as AlbumHeaderViewHolder).bind(item) + is Album -> (holder as AlbumDetailViewHolder).bind(item) is Song -> (holder as AlbumSongViewHolder).bind(item) is ActionHeader -> (holder as ActionHeaderViewHolder).bind(item) @@ -132,7 +132,7 @@ class AlbumDetailAdapter( } } - inner class AlbumHeaderViewHolder( + inner class AlbumDetailViewHolder( private val binding: ItemDetailBinding ) : BaseViewHolder(binding) { @@ -188,7 +188,7 @@ class AlbumDetailAdapter( } companion object { - const val ALBUM_HEADER_ITEM_TYPE = 0xA007 - const val ALBUM_SONG_ITEM_TYPE = 0xA008 + const val ALBUM_DETAIL_ITEM_TYPE = 0xA006 + const val ALBUM_SONG_ITEM_TYPE = 0xA007 } } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt index 8cf39e0b3..3ff57a6e2 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt @@ -59,7 +59,7 @@ class ArtistDetailAdapter( override fun getItemViewType(position: Int): Int { return when (getItem(position)) { - is Artist -> ARTIST_HEADER_ITEM_TYPE + is Artist -> ARTIST_DETAIL_ITEM_TYPE is Album -> ARTIST_ALBUM_ITEM_TYPE is Song -> ARTIST_SONG_ITEM_TYPE is Header -> HeaderViewHolder.ITEM_TYPE @@ -71,7 +71,7 @@ class ArtistDetailAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { - ARTIST_HEADER_ITEM_TYPE -> ArtistHeaderViewHolder( + ARTIST_DETAIL_ITEM_TYPE -> ArtistDetailViewHolder( ItemDetailBinding.inflate(parent.context.inflater) ) @@ -95,7 +95,7 @@ class ArtistDetailAdapter( val item = getItem(position) when (item) { - is Artist -> (holder as ArtistHeaderViewHolder).bind(item) + is Artist -> (holder as ArtistDetailViewHolder).bind(item) is Album -> (holder as ArtistAlbumViewHolder).bind(item) is Song -> (holder as ArtistSongViewHolder).bind(item) is Header -> (holder as HeaderViewHolder).bind(item) @@ -181,7 +181,7 @@ class ArtistDetailAdapter( } } - inner class ArtistHeaderViewHolder( + inner class ArtistDetailViewHolder( private val binding: ItemDetailBinding ) : BaseViewHolder(binding) { @@ -241,8 +241,8 @@ class ArtistDetailAdapter( } companion object { - const val ARTIST_HEADER_ITEM_TYPE = 0xA009 - const val ARTIST_ALBUM_ITEM_TYPE = 0xA00A - const val ARTIST_SONG_ITEM_TYPE = 0xA00C + const val ARTIST_DETAIL_ITEM_TYPE = 0xA008 + const val ARTIST_ALBUM_ITEM_TYPE = 0xA009 + const val ARTIST_SONG_ITEM_TYPE = 0xA00A } } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt index 7f3bda6e5..7b642f93b 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt @@ -51,7 +51,7 @@ class GenreDetailAdapter( override fun getItemViewType(position: Int): Int { return when (getItem(position)) { - is Genre -> GENRE_HEADER_ITEM_TYPE + is Genre -> GENRE_DETAIL_ITEM_TYPE is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE is Song -> GENRE_SONG_ITEM_TYPE @@ -61,7 +61,7 @@ class GenreDetailAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { - GENRE_HEADER_ITEM_TYPE -> GenreHeaderViewHolder( + GENRE_DETAIL_ITEM_TYPE -> GenreDetailViewHolder( ItemDetailBinding.inflate(parent.context.inflater) ) @@ -79,7 +79,7 @@ class GenreDetailAdapter( val item = getItem(position) when (item) { - is Genre -> (holder as GenreHeaderViewHolder).bind(item) + is Genre -> (holder as GenreDetailViewHolder).bind(item) is ActionHeader -> (holder as ActionHeaderViewHolder).bind(item) is Song -> (holder as GenreSongViewHolder).bind(item) else -> {} @@ -128,7 +128,7 @@ class GenreDetailAdapter( } } - inner class GenreHeaderViewHolder( + inner class GenreDetailViewHolder( private val binding: ItemDetailBinding ) : BaseViewHolder(binding) { override fun onBind(data: Genre) { @@ -173,7 +173,7 @@ class GenreDetailAdapter( } companion object { - const val GENRE_HEADER_ITEM_TYPE = 0xA00D - const val GENRE_SONG_ITEM_TYPE = 0xA00E + const val GENRE_DETAIL_ITEM_TYPE = 0xA00B + const val GENRE_SONG_ITEM_TYPE = 0xA00C } } 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 54b7261a4..21e139019 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -41,6 +41,7 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.ui.DisplayMode +import org.oxycblt.auxio.ui.SortMode import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logE @@ -93,7 +94,7 @@ class HomeFragment : Fragment() { item.isChecked = true homeModel.updateCurrentSort( - requireNotNull(LibSortMode.fromId(item.itemId)) + requireNotNull(SortMode.fromId(item.itemId)) ) } } @@ -220,7 +221,7 @@ class HomeFragment : Fragment() { private fun updateSortMenu( item: MenuItem, - toHighlight: LibSortMode, + toHighlight: SortMode, isVisible: (Int) -> Boolean = { true } ) { for (option in item.subMenu) { 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 c86779d3e..a2a3ab54a 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.ui.DisplayMode +import org.oxycblt.auxio.ui.SortMode /** * The ViewModel for managing [HomeFragment]'s data and sorting modes. @@ -55,16 +56,16 @@ class HomeViewModel : ViewModel() { private val mCurTab = MutableLiveData(mTabs.value!![0]) val curTab: LiveData = mCurTab - var genreSortMode = LibSortMode.ASCENDING + var genreSortMode = SortMode.ASCENDING private set - var artistSortMode = LibSortMode.ASCENDING + var artistSortMode = SortMode.ASCENDING private set - var albumSortMode = LibSortMode.ASCENDING + var albumSortMode = SortMode.ASCENDING private set - var songSortMode = LibSortMode.ASCENDING + var songSortMode = SortMode.ASCENDING private set private val musicStore = MusicStore.getInstance() @@ -86,9 +87,9 @@ class HomeViewModel : ViewModel() { } /** - * Update the currently displayed item's [LibSortMode]. + * Update the currently displayed item's [SortMode]. */ - fun updateCurrentSort(sort: LibSortMode) { + fun updateCurrentSort(sort: SortMode) { when (mCurTab.value) { DisplayMode.SHOW_SONGS -> { songSortMode = sort diff --git a/app/src/main/java/org/oxycblt/auxio/home/LibSortMode.kt b/app/src/main/java/org/oxycblt/auxio/home/LibSortMode.kt deleted file mode 100644 index 67ae8bfb9..000000000 --- a/app/src/main/java/org/oxycblt/auxio/home/LibSortMode.kt +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2021 Auxio Project - * LibSortMode.kt is part of Auxio. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.oxycblt.auxio.home - -import androidx.annotation.IdRes -import org.oxycblt.auxio.R -import org.oxycblt.auxio.music.Album -import org.oxycblt.auxio.music.Artist -import org.oxycblt.auxio.music.BaseModel -import org.oxycblt.auxio.music.Genre -import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.ui.sliceArticle - -/** - * The enum for the current sort state. - * This enum is semantic depending on the context it is used. Documentation describing each - * sorting functions behavior can be found in the function definition. - * @param itemId Menu ID associated with this enum - * @author OxygenCobalt - */ -enum class LibSortMode(@IdRes val itemId: Int) { - ASCENDING(R.id.option_sort_asc), - DESCENDING(R.id.option_sort_dsc), - ARTIST(R.id.option_sort_artist), - ALBUM(R.id.option_sort_album), - YEAR(R.id.option_sort_year); - - /** - * Sort a list of songs. - * - * **Behavior:** - * - [ASCENDING] & [DESCENDING]: See [sortModels] - * - [ARTIST]: Grouped by album and then sorted [ASCENDING] based off the artist name. - * - [ALBUM]: Grouped by album and sorted [ASCENDING] - * - [YEAR]: Grouped by album and sorted by year - * - * The grouping mode for songs in an album will be by track, [ASCENDING]. - * @see sortAlbums - */ - fun sortSongs(songs: Collection): List { - return when (this) { - ASCENDING, DESCENDING -> sortModels(songs) - - else -> sortAlbums(songs.groupBy { it.album }.keys).flatMap { album -> - ASCENDING.sortAlbum(album) - } - } - } - - /** - * Sort a list of albums. - * - * **Behavior:** - * - [ASCENDING] & [DESCENDING]: See [sortModels] - * - [ARTIST]: Grouped by artist and sorted [ASCENDING] - * - [ALBUM]: [ASCENDING] - * - [YEAR]: Sorted by year - * - * The grouping mode for albums in an artist will be [YEAR]. - */ - fun sortAlbums(albums: Collection): List { - return when (this) { - ASCENDING, DESCENDING -> sortModels(albums) - - ARTIST -> ASCENDING.sortModels(albums.groupBy { it.artist }.keys) - .flatMap { YEAR.sortAlbums(it.albums) } - - ALBUM -> ASCENDING.sortModels(albums) - - YEAR -> albums.sortedByDescending { it.year } - } - } - - /** - * Sort a list of generic [BaseModel] instances. - * - * **Behavior:** - * - [ASCENDING]: Sorted by name, ascending - * - [DESCENDING]: Sorted by name, descending - * - Same list is returned otherwise. - * - * Names will be treated as case-insensitive. Articles like "the" and "a" will be skipped - * to line up with MediaStore behavior. - */ - fun sortModels(models: Collection): List { - return when (this) { - ASCENDING -> models.sortedWith( - compareBy(String.CASE_INSENSITIVE_ORDER) { model -> - model.name.sliceArticle() - } - ) - - DESCENDING -> models.sortedWith( - compareByDescending(String.CASE_INSENSITIVE_ORDER) { model -> - model.name.sliceArticle() - } - ) - - else -> models.toList() - } - } - - /** - * Sort the songs in an album. - * - * **Behavior:** - * - [ASCENDING]: By track, ascending - * - [DESCENDING]: By track, descending - * - Same song list is returned otherwise. - */ - fun sortAlbum(album: Album): List { - return when (this) { - ASCENDING -> album.songs.sortedBy { it.track } - DESCENDING -> album.songs.sortedByDescending { it.track } - else -> album.songs - } - } - - /** - * Sort the songs in an artist. - * @see sortSongs - */ - fun sortArtist(artist: Artist): List { - return sortSongs(artist.songs) - } - - /** - * Sort the songs in a genre. - * @see sortSongs - */ - fun sortGenre(genre: Genre): List { - return sortSongs(genre.songs) - } - - companion object { - /** - * Convert a menu [id] to an instance of [LibSortMode]. - */ - fun fromId(@IdRes id: Int): LibSortMode? { - return when (id) { - ASCENDING.itemId -> ASCENDING - DESCENDING.itemId -> DESCENDING - ARTIST.itemId -> ARTIST - ALBUM.itemId -> ALBUM - YEAR.itemId -> YEAR - else -> null - } - } - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index fec401370..8484e596f 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -331,9 +331,8 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { * Add an [Album] to the user queue */ fun addToUserQueue(album: Album) { - val songs = SortMode.NUMERIC_DOWN.getSortedSongList(album.songs) - - playbackManager.addToUserQueue(songs) + // TODO: Make this reflect the sort mode + playbackManager.addToUserQueue(SortMode.ASCENDING.sortAlbum(album)) } /** diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt index ff2b951bb..739426975 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt @@ -169,7 +169,6 @@ class QueueAdapter( } companion object { - const val QUEUE_SONG_ITEM_TYPE = 0xA005 - const val USER_QUEUE_HEADER_ITEM_TYPE = 0xA006 + const val QUEUE_SONG_ITEM_TYPE = 0xA00D } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index 1eabc616e..2126933c7 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.Parent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.settings.SettingsManager +import org.oxycblt.auxio.ui.SortMode import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logE @@ -731,21 +732,21 @@ class PlaybackStateManager private constructor() { * Create an ordered queue based on an [Album]. */ private fun orderSongsInAlbum(album: Album): MutableList { - return settingsManager.albumSortMode.getSortedSongList(album.songs).toMutableList() + return SortMode.ASCENDING.sortAlbum(album).toMutableList() } /** * Create an ordered queue based on an [Artist]. */ private fun orderSongsInArtist(artist: Artist): MutableList { - return settingsManager.artistSortMode.getSortedArtistSongList(artist.songs).toMutableList() + return SortMode.YEAR.sortArtist(artist).toMutableList() } /** * Create an ordered queue based on a [Genre]. */ private fun orderSongsInGenre(genre: Genre): MutableList { - return settingsManager.genreSortMode.getSortedSongList(genre.songs).toMutableList() + return SortMode.ASCENDING.sortGenre(genre).toMutableList() } /** diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt index e9772b296..c99254e71 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt @@ -26,7 +26,6 @@ import org.oxycblt.auxio.accent.ACCENTS import org.oxycblt.auxio.accent.Accent import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.SortMode /** * Wrapper around the [SharedPreferences] class that writes & reads values without a context. @@ -114,33 +113,6 @@ class SettingsManager private constructor(context: Context) : val pauseOnLoop: Boolean get() = sharedPrefs.getBoolean(KEY_LOOP_PAUSE, false) - var albumSortMode: SortMode - get() = sharedPrefs.getData(KEY_ALBUM_SORT_MODE, SortMode::fromInt) ?: SortMode.NUMERIC_DOWN - set(value) { - sharedPrefs.edit { - putInt(KEY_ALBUM_SORT_MODE, value.toInt()) - apply() - } - } - - var artistSortMode: SortMode - get() = sharedPrefs.getData(KEY_ARTIST_SORT_MODE, SortMode::fromInt) ?: SortMode.NUMERIC_DOWN - set(value) { - sharedPrefs.edit { - putInt(KEY_ARTIST_SORT_MODE, value.toInt()) - apply() - } - } - - var genreSortMode: SortMode - get() = sharedPrefs.getData(KEY_GENRE_SORT_MODE, SortMode::fromInt) ?: SortMode.ALPHA_DOWN - set(value) { - sharedPrefs.edit { - putInt(KEY_GENRE_SORT_MODE, value.toInt()) - apply() - } - } - /** The current filter mode of the search tab */ var searchFilterMode: DisplayMode? get() = sharedPrefs.getData(KEY_SEARCH_FILTER_MODE, DisplayMode::fromSearchInt) diff --git a/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt b/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt index 5bdcc93b1..115056fbf 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt @@ -29,7 +29,7 @@ enum class DisplayMode { SHOW_SONGS; companion object { - private const val CONST_SHOW_ALL = 0xA107 + private const val CONST_NULL = 0xA107 private const val CONST_SHOW_GENRES = 0xA108 private const val CONST_SHOW_ARTISTS = 0xA109 private const val CONST_SHOW_ALBUMS = 0xA10A @@ -41,7 +41,7 @@ enum class DisplayMode { SHOW_ALBUMS -> CONST_SHOW_ALBUMS SHOW_ARTISTS -> CONST_SHOW_ARTISTS SHOW_GENRES -> CONST_SHOW_GENRES - null -> CONST_SHOW_ALL + null -> CONST_NULL } } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt b/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt index 1fe65e9da..45629eb88 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/SortMode.kt @@ -18,125 +18,146 @@ package org.oxycblt.auxio.ui -import androidx.annotation.DrawableRes +import androidx.annotation.IdRes import org.oxycblt.auxio.R +import org.oxycblt.auxio.music.Album +import org.oxycblt.auxio.music.Artist +import org.oxycblt.auxio.music.BaseModel +import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song /** - * The legacy enum for sorting. This is set to be removed soon. - * @property iconRes The icon for this [SortMode] + * The enum for the current sort state. + * This enum is semantic depending on the context it is used. Documentation describing each + * sorting functions behavior can be found in the function definition. + * @param itemId Menu ID associated with this enum * @author OxygenCobalt */ -enum class SortMode(@DrawableRes val iconRes: Int) { - // Icons for each mode are assigned to the enums themselves - NONE(R.drawable.ic_sort), - ALPHA_UP(R.drawable.ic_sort), - ALPHA_DOWN(R.drawable.ic_sort), - NUMERIC_UP(R.drawable.ic_sort), - NUMERIC_DOWN(R.drawable.ic_sort); +enum class SortMode(@IdRes val itemId: Int) { + ASCENDING(R.id.option_sort_asc), + DESCENDING(R.id.option_sort_dsc), + ARTIST(R.id.option_sort_artist), + ALBUM(R.id.option_sort_album), + YEAR(R.id.option_sort_year); /** - * Get a sorted list of songs for a SortMode. Supports alpha + numeric sorting. - * @param songs An unsorted list of songs. - * @return The sorted list of songs. + * Sort a list of songs. + * + * **Behavior:** + * - [ASCENDING] & [DESCENDING]: See [sortModels] + * - [ARTIST]: Grouped by album and then sorted [ASCENDING] based off the artist name. + * - [ALBUM]: Grouped by album and sorted [ASCENDING] + * - [YEAR]: Grouped by album and sorted by year + * + * The grouping mode for songs in an album will be by track, [ASCENDING]. + * @see sortAlbums */ - fun getSortedSongList(songs: List): List { + fun sortSongs(songs: Collection): List { return when (this) { - ALPHA_UP -> songs.sortedWith( - compareByDescending(String.CASE_INSENSITIVE_ORDER) { - it.name.sliceArticle() - } - ) + ASCENDING, DESCENDING -> sortModels(songs) - ALPHA_DOWN -> songs.sortedWith( - compareBy(String.CASE_INSENSITIVE_ORDER) { - it.name.sliceArticle() - } - ) - - NUMERIC_UP -> songs.sortedWith(compareByDescending { it.track }) - NUMERIC_DOWN -> songs.sortedWith(compareBy { it.track }) - - else -> songs + else -> sortAlbums(songs.groupBy { it.album }.keys).flatMap { album -> + ASCENDING.sortAlbum(album) + } } } /** - * Get a sorted list of songs with regards to an artist. - * @param songs An unsorted list of songs - * @return The sorted list of songs + * Sort a list of albums. + * + * **Behavior:** + * - [ASCENDING] & [DESCENDING]: See [sortModels] + * - [ARTIST]: Grouped by artist and sorted [ASCENDING] + * - [ALBUM]: [ASCENDING] + * - [YEAR]: Sorted by year + * + * The grouping mode for albums in an artist will be [YEAR]. */ - fun getSortedArtistSongList(songs: List): List { + fun sortAlbums(albums: Collection): List { return when (this) { - ALPHA_UP -> songs.sortedWith( - compareByDescending(String.CASE_INSENSITIVE_ORDER) { - it.name.sliceArticle() - } - ) + ASCENDING, DESCENDING -> sortModels(albums) - ALPHA_DOWN -> songs.sortedWith( - compareBy(String.CASE_INSENSITIVE_ORDER) { - it.name.sliceArticle() - } - ) + ARTIST -> ASCENDING.sortModels(albums.groupBy { it.artist }.keys) + .flatMap { YEAR.sortAlbums(it.albums) } - NUMERIC_UP -> { - val list = mutableListOf() + ALBUM -> ASCENDING.sortModels(albums) - songs.groupBy { it.album }.entries.sortedBy { it.key.year }.forEach { entry -> - list.addAll(entry.value.sortedWith(compareBy { it.track })) - } - - list - } - - NUMERIC_DOWN -> { - val list = mutableListOf() - - songs.groupBy { it.album }.entries.sortedWith(compareByDescending { it.key.year }).forEach { entry -> - list.addAll(entry.value.sortedWith(compareBy { it.track })) - } - - list - } - - else -> songs + YEAR -> albums.sortedByDescending { it.year } } } /** - * Get the constant for this mode. Used to write a compressed variant to SettingsManager - * @return The int constant for this mode. + * Sort a list of generic [BaseModel] instances. + * + * **Behavior:** + * - [ASCENDING]: Sorted by name, ascending + * - [DESCENDING]: Sorted by name, descending + * - Same list is returned otherwise. + * + * Names will be treated as case-insensitive. Articles like "the" and "a" will be skipped + * to line up with MediaStore behavior. */ - fun toInt(): Int { + fun sortModels(models: Collection): List { return when (this) { - NONE -> CONST_NONE - ALPHA_UP -> CONST_ALPHA_UP - ALPHA_DOWN -> CONST_ALPHA_DOWN - NUMERIC_UP -> CONST_NUMERIC_UP - NUMERIC_DOWN -> CONST_NUMERIC_DOWN + ASCENDING -> models.sortedWith( + compareBy(String.CASE_INSENSITIVE_ORDER) { model -> + model.name.sliceArticle() + } + ) + + DESCENDING -> models.sortedWith( + compareByDescending(String.CASE_INSENSITIVE_ORDER) { model -> + model.name.sliceArticle() + } + ) + + else -> models.toList() } } + /** + * Sort the songs in an album. + * + * **Behavior:** + * - [ASCENDING]: By track, ascending + * - [DESCENDING]: By track, descending + * - Same song list is returned otherwise. + */ + fun sortAlbum(album: Album): List { + return when (this) { + ASCENDING -> album.songs.sortedBy { it.track } + DESCENDING -> album.songs.sortedByDescending { it.track } + else -> album.songs + } + } + + /** + * Sort the songs in an artist. + * @see sortSongs + */ + fun sortArtist(artist: Artist): List { + return sortSongs(artist.songs) + } + + /** + * Sort the songs in a genre. + * @see sortSongs + */ + fun sortGenre(genre: Genre): List { + return sortSongs(genre.songs) + } + companion object { - const val CONST_NONE = 0xA10C - const val CONST_ALPHA_UP = 0xA10D - const val CONST_ALPHA_DOWN = 0xA10E - const val CONST_NUMERIC_UP = 0xA10F - const val CONST_NUMERIC_DOWN = 0xA110 - /** - * Get an enum for an int constant - * @return The [SortMode] if the constant is valid, null otherwise. + * Convert a menu [id] to an instance of [SortMode]. */ - fun fromInt(value: Int): SortMode? { - return when (value) { - CONST_NONE -> NONE - CONST_ALPHA_UP -> ALPHA_UP - CONST_ALPHA_DOWN -> ALPHA_DOWN - CONST_NUMERIC_UP -> NUMERIC_UP - CONST_NUMERIC_DOWN -> NUMERIC_DOWN - + fun fromId(@IdRes id: Int): SortMode? { + return when (id) { + ASCENDING.itemId -> ASCENDING + DESCENDING.itemId -> DESCENDING + ARTIST.itemId -> ARTIST + ALBUM.itemId -> ALBUM + YEAR.itemId -> YEAR else -> null } } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt b/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt index dad508ef0..9d40c2f00 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt @@ -266,7 +266,7 @@ class ActionHeaderViewHolder private constructor( } companion object { - const val ITEM_TYPE = 0xA999 // TODO: Give this an ID + const val ITEM_TYPE = 0xA005 /** * Create an instance of [ActionHeaderViewHolder] diff --git a/app/src/main/res/values/styleable.xml b/app/src/main/res/values/attrs.xml similarity index 100% rename from app/src/main/res/values/styleable.xml rename to app/src/main/res/values/attrs.xml diff --git a/info/ARCHITECTURE.md b/info/ARCHITECTURE.md index bded68d0f..8dd7b281e 100644 --- a/info/ARCHITECTURE.md +++ b/info/ARCHITECTURE.md @@ -45,18 +45,17 @@ To prevent any strange bugs, all integer representations must be unique. A table 0xA002 | ArtistViewHolder 0xA003 | GenreViewHolder 0xA004 | HeaderViewHolder +0xA005 | ActionHeaderViewHolder -0xA005 | QueueSongViewHolder -0xA006 | UserQueueHeaderViewHolder +0xA005 | AlbumDetailViewHolder +0xA006 | AlbumSongViewHolder +0xA007 | ArtistDetailViewHolder +0xA008 | ArtistAlbumViewHolder +0xA009 | ArtistSongViewHolder +0xA010 | GenreDetailViewHolder +0xA011 | GenreSongViewHolder -0xA007 | AlbumHeaderViewHolder -0xA008 | AlbumSongViewHolder -0xA009 | ArtistHeaderViewHolder -0xA00A | ArtistAlbumViewHolder -0xA00B | ArtistSongHeaderViewHolder -0xA00C | ArtistSongViewHolder -0xA00D | GenreHeaderViewHolder -0xA00E | GenreSongViewHolder +0xA00A | QueueSongViewHolder 0xA0A0 | Auxio notification code 0xA0C0 | Auxio request code @@ -77,12 +76,6 @@ To prevent any strange bugs, all integer representations must be unique. A table 0xA109 | DisplayMode.SHOW_ARTISTS 0xA10A | DisplayMode.SHOW_ALBUMS 0xA10B | DisplayMode.SHOW_SONGS - -0xA10C | SortMode.NONE -0xA10D | SortMode.ALPHA_UP -0xA10E | SortMode.ALPHA_DOWN -0xA10F | SortMode.NUMERIC_UP -0xA110 | SortMode.NUMERIC_DOWN ``` #### Package structure overview