ui: clean up dead code

Clean up the last remaining legacy SortMode remnants. Also reformat all
ViewHolder IDs to be properly unique and sequential.
This commit is contained in:
OxygenCobalt 2021-09-12 17:01:52 -06:00
parent c9dd3b97a2
commit 08169b6167
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
16 changed files with 160 additions and 340 deletions

View file

@ -23,7 +23,6 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.LibSortMode
import org.oxycblt.auxio.music.ActionHeader import org.oxycblt.auxio.music.ActionHeader
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist 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 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( data.add(
ActionHeader( ActionHeader(
@ -121,7 +120,7 @@ class DetailViewModel : ViewModel() {
) )
) )
data.addAll(LibSortMode.YEAR.sortArtist(artist)) data.addAll(SortMode.YEAR.sortArtist(artist))
mArtistData.value = data.toList() 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 mAlbumData.value = data
} }

View file

@ -53,7 +53,7 @@ class AlbumDetailAdapter(
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return when (getItem(position)) { return when (getItem(position)) {
is Album -> ALBUM_HEADER_ITEM_TYPE is Album -> ALBUM_DETAIL_ITEM_TYPE
is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE
is Song -> ALBUM_SONG_ITEM_TYPE is Song -> ALBUM_SONG_ITEM_TYPE
@ -63,7 +63,7 @@ class AlbumDetailAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) { return when (viewType) {
ALBUM_HEADER_ITEM_TYPE -> AlbumHeaderViewHolder( ALBUM_DETAIL_ITEM_TYPE -> AlbumDetailViewHolder(
ItemDetailBinding.inflate(parent.context.inflater) ItemDetailBinding.inflate(parent.context.inflater)
) )
@ -81,7 +81,7 @@ class AlbumDetailAdapter(
val item = getItem(position) val item = getItem(position)
when (item) { when (item) {
is Album -> (holder as AlbumHeaderViewHolder).bind(item) is Album -> (holder as AlbumDetailViewHolder).bind(item)
is Song -> (holder as AlbumSongViewHolder).bind(item) is Song -> (holder as AlbumSongViewHolder).bind(item)
is ActionHeader -> (holder as ActionHeaderViewHolder).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 private val binding: ItemDetailBinding
) : BaseViewHolder<Album>(binding) { ) : BaseViewHolder<Album>(binding) {
@ -188,7 +188,7 @@ class AlbumDetailAdapter(
} }
companion object { companion object {
const val ALBUM_HEADER_ITEM_TYPE = 0xA007 const val ALBUM_DETAIL_ITEM_TYPE = 0xA006
const val ALBUM_SONG_ITEM_TYPE = 0xA008 const val ALBUM_SONG_ITEM_TYPE = 0xA007
} }
} }

View file

@ -59,7 +59,7 @@ class ArtistDetailAdapter(
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return when (getItem(position)) { return when (getItem(position)) {
is Artist -> ARTIST_HEADER_ITEM_TYPE is Artist -> ARTIST_DETAIL_ITEM_TYPE
is Album -> ARTIST_ALBUM_ITEM_TYPE is Album -> ARTIST_ALBUM_ITEM_TYPE
is Song -> ARTIST_SONG_ITEM_TYPE is Song -> ARTIST_SONG_ITEM_TYPE
is Header -> HeaderViewHolder.ITEM_TYPE is Header -> HeaderViewHolder.ITEM_TYPE
@ -71,7 +71,7 @@ class ArtistDetailAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) { return when (viewType) {
ARTIST_HEADER_ITEM_TYPE -> ArtistHeaderViewHolder( ARTIST_DETAIL_ITEM_TYPE -> ArtistDetailViewHolder(
ItemDetailBinding.inflate(parent.context.inflater) ItemDetailBinding.inflate(parent.context.inflater)
) )
@ -95,7 +95,7 @@ class ArtistDetailAdapter(
val item = getItem(position) val item = getItem(position)
when (item) { when (item) {
is Artist -> (holder as ArtistHeaderViewHolder).bind(item) is Artist -> (holder as ArtistDetailViewHolder).bind(item)
is Album -> (holder as ArtistAlbumViewHolder).bind(item) is Album -> (holder as ArtistAlbumViewHolder).bind(item)
is Song -> (holder as ArtistSongViewHolder).bind(item) is Song -> (holder as ArtistSongViewHolder).bind(item)
is Header -> (holder as HeaderViewHolder).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 private val binding: ItemDetailBinding
) : BaseViewHolder<Artist>(binding) { ) : BaseViewHolder<Artist>(binding) {
@ -241,8 +241,8 @@ class ArtistDetailAdapter(
} }
companion object { companion object {
const val ARTIST_HEADER_ITEM_TYPE = 0xA009 const val ARTIST_DETAIL_ITEM_TYPE = 0xA008
const val ARTIST_ALBUM_ITEM_TYPE = 0xA00A const val ARTIST_ALBUM_ITEM_TYPE = 0xA009
const val ARTIST_SONG_ITEM_TYPE = 0xA00C const val ARTIST_SONG_ITEM_TYPE = 0xA00A
} }
} }

View file

@ -51,7 +51,7 @@ class GenreDetailAdapter(
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return when (getItem(position)) { return when (getItem(position)) {
is Genre -> GENRE_HEADER_ITEM_TYPE is Genre -> GENRE_DETAIL_ITEM_TYPE
is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE
is Song -> GENRE_SONG_ITEM_TYPE is Song -> GENRE_SONG_ITEM_TYPE
@ -61,7 +61,7 @@ class GenreDetailAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) { return when (viewType) {
GENRE_HEADER_ITEM_TYPE -> GenreHeaderViewHolder( GENRE_DETAIL_ITEM_TYPE -> GenreDetailViewHolder(
ItemDetailBinding.inflate(parent.context.inflater) ItemDetailBinding.inflate(parent.context.inflater)
) )
@ -79,7 +79,7 @@ class GenreDetailAdapter(
val item = getItem(position) val item = getItem(position)
when (item) { when (item) {
is Genre -> (holder as GenreHeaderViewHolder).bind(item) is Genre -> (holder as GenreDetailViewHolder).bind(item)
is ActionHeader -> (holder as ActionHeaderViewHolder).bind(item) is ActionHeader -> (holder as ActionHeaderViewHolder).bind(item)
is Song -> (holder as GenreSongViewHolder).bind(item) is Song -> (holder as GenreSongViewHolder).bind(item)
else -> {} else -> {}
@ -128,7 +128,7 @@ class GenreDetailAdapter(
} }
} }
inner class GenreHeaderViewHolder( inner class GenreDetailViewHolder(
private val binding: ItemDetailBinding private val binding: ItemDetailBinding
) : BaseViewHolder<Genre>(binding) { ) : BaseViewHolder<Genre>(binding) {
override fun onBind(data: Genre) { override fun onBind(data: Genre) {
@ -173,7 +173,7 @@ class GenreDetailAdapter(
} }
companion object { companion object {
const val GENRE_HEADER_ITEM_TYPE = 0xA00D const val GENRE_DETAIL_ITEM_TYPE = 0xA00B
const val GENRE_SONG_ITEM_TYPE = 0xA00E const val GENRE_SONG_ITEM_TYPE = 0xA00C
} }
} }

View file

@ -41,6 +41,7 @@ import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.DisplayMode
import org.oxycblt.auxio.ui.SortMode
import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.applyEdge
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE import org.oxycblt.auxio.util.logE
@ -93,7 +94,7 @@ class HomeFragment : Fragment() {
item.isChecked = true item.isChecked = true
homeModel.updateCurrentSort( homeModel.updateCurrentSort(
requireNotNull(LibSortMode.fromId(item.itemId)) requireNotNull(SortMode.fromId(item.itemId))
) )
} }
} }
@ -220,7 +221,7 @@ class HomeFragment : Fragment() {
private fun updateSortMenu( private fun updateSortMenu(
item: MenuItem, item: MenuItem,
toHighlight: LibSortMode, toHighlight: SortMode,
isVisible: (Int) -> Boolean = { true } isVisible: (Int) -> Boolean = { true }
) { ) {
for (option in item.subMenu) { for (option in item.subMenu) {

View file

@ -27,6 +27,7 @@ import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.DisplayMode
import org.oxycblt.auxio.ui.SortMode
/** /**
* The ViewModel for managing [HomeFragment]'s data and sorting modes. * The ViewModel for managing [HomeFragment]'s data and sorting modes.
@ -55,16 +56,16 @@ class HomeViewModel : ViewModel() {
private val mCurTab = MutableLiveData(mTabs.value!![0]) private val mCurTab = MutableLiveData(mTabs.value!![0])
val curTab: LiveData<DisplayMode> = mCurTab val curTab: LiveData<DisplayMode> = mCurTab
var genreSortMode = LibSortMode.ASCENDING var genreSortMode = SortMode.ASCENDING
private set private set
var artistSortMode = LibSortMode.ASCENDING var artistSortMode = SortMode.ASCENDING
private set private set
var albumSortMode = LibSortMode.ASCENDING var albumSortMode = SortMode.ASCENDING
private set private set
var songSortMode = LibSortMode.ASCENDING var songSortMode = SortMode.ASCENDING
private set private set
private val musicStore = MusicStore.getInstance() 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) { when (mCurTab.value) {
DisplayMode.SHOW_SONGS -> { DisplayMode.SHOW_SONGS -> {
songSortMode = sort songSortMode = sort

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Song>): List<Song> {
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<Album>): List<Album> {
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 <T : BaseModel> sortModels(models: Collection<T>): List<T> {
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<Song> {
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<Song> {
return sortSongs(artist.songs)
}
/**
* Sort the songs in a genre.
* @see sortSongs
*/
fun sortGenre(genre: Genre): List<Song> {
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
}
}
}
}

View file

@ -331,9 +331,8 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
* Add an [Album] to the user queue * Add an [Album] to the user queue
*/ */
fun addToUserQueue(album: Album) { fun addToUserQueue(album: Album) {
val songs = SortMode.NUMERIC_DOWN.getSortedSongList(album.songs) // TODO: Make this reflect the sort mode
playbackManager.addToUserQueue(SortMode.ASCENDING.sortAlbum(album))
playbackManager.addToUserQueue(songs)
} }
/** /**

View file

@ -169,7 +169,6 @@ class QueueAdapter(
} }
companion object { companion object {
const val QUEUE_SONG_ITEM_TYPE = 0xA005 const val QUEUE_SONG_ITEM_TYPE = 0xA00D
const val USER_QUEUE_HEADER_ITEM_TYPE = 0xA006
} }
} }

View file

@ -28,6 +28,7 @@ import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Parent import org.oxycblt.auxio.music.Parent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.ui.SortMode
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE import org.oxycblt.auxio.util.logE
@ -731,21 +732,21 @@ class PlaybackStateManager private constructor() {
* Create an ordered queue based on an [Album]. * Create an ordered queue based on an [Album].
*/ */
private fun orderSongsInAlbum(album: Album): MutableList<Song> { private fun orderSongsInAlbum(album: Album): MutableList<Song> {
return settingsManager.albumSortMode.getSortedSongList(album.songs).toMutableList() return SortMode.ASCENDING.sortAlbum(album).toMutableList()
} }
/** /**
* Create an ordered queue based on an [Artist]. * Create an ordered queue based on an [Artist].
*/ */
private fun orderSongsInArtist(artist: Artist): MutableList<Song> { private fun orderSongsInArtist(artist: Artist): MutableList<Song> {
return settingsManager.artistSortMode.getSortedArtistSongList(artist.songs).toMutableList() return SortMode.YEAR.sortArtist(artist).toMutableList()
} }
/** /**
* Create an ordered queue based on a [Genre]. * Create an ordered queue based on a [Genre].
*/ */
private fun orderSongsInGenre(genre: Genre): MutableList<Song> { private fun orderSongsInGenre(genre: Genre): MutableList<Song> {
return settingsManager.genreSortMode.getSortedSongList(genre.songs).toMutableList() return SortMode.ASCENDING.sortGenre(genre).toMutableList()
} }
/** /**

View file

@ -26,7 +26,6 @@ import org.oxycblt.auxio.accent.ACCENTS
import org.oxycblt.auxio.accent.Accent import org.oxycblt.auxio.accent.Accent
import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.DisplayMode
import org.oxycblt.auxio.ui.SortMode
/** /**
* Wrapper around the [SharedPreferences] class that writes & reads values without a context. * 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 val pauseOnLoop: Boolean
get() = sharedPrefs.getBoolean(KEY_LOOP_PAUSE, false) 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 */ /** The current filter mode of the search tab */
var searchFilterMode: DisplayMode? var searchFilterMode: DisplayMode?
get() = sharedPrefs.getData(KEY_SEARCH_FILTER_MODE, DisplayMode::fromSearchInt) get() = sharedPrefs.getData(KEY_SEARCH_FILTER_MODE, DisplayMode::fromSearchInt)

View file

@ -29,7 +29,7 @@ enum class DisplayMode {
SHOW_SONGS; SHOW_SONGS;
companion object { 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_GENRES = 0xA108
private const val CONST_SHOW_ARTISTS = 0xA109 private const val CONST_SHOW_ARTISTS = 0xA109
private const val CONST_SHOW_ALBUMS = 0xA10A private const val CONST_SHOW_ALBUMS = 0xA10A
@ -41,7 +41,7 @@ enum class DisplayMode {
SHOW_ALBUMS -> CONST_SHOW_ALBUMS SHOW_ALBUMS -> CONST_SHOW_ALBUMS
SHOW_ARTISTS -> CONST_SHOW_ARTISTS SHOW_ARTISTS -> CONST_SHOW_ARTISTS
SHOW_GENRES -> CONST_SHOW_GENRES SHOW_GENRES -> CONST_SHOW_GENRES
null -> CONST_SHOW_ALL null -> CONST_NULL
} }
} }

View file

@ -18,125 +18,146 @@
package org.oxycblt.auxio.ui package org.oxycblt.auxio.ui
import androidx.annotation.DrawableRes import androidx.annotation.IdRes
import org.oxycblt.auxio.R 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.music.Song
/** /**
* The legacy enum for sorting. This is set to be removed soon. * The enum for the current sort state.
* @property iconRes The icon for this [SortMode] * 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 * @author OxygenCobalt
*/ */
enum class SortMode(@DrawableRes val iconRes: Int) { enum class SortMode(@IdRes val itemId: Int) {
// Icons for each mode are assigned to the enums themselves ASCENDING(R.id.option_sort_asc),
NONE(R.drawable.ic_sort), DESCENDING(R.id.option_sort_dsc),
ALPHA_UP(R.drawable.ic_sort), ARTIST(R.id.option_sort_artist),
ALPHA_DOWN(R.drawable.ic_sort), ALBUM(R.id.option_sort_album),
NUMERIC_UP(R.drawable.ic_sort), YEAR(R.id.option_sort_year);
NUMERIC_DOWN(R.drawable.ic_sort);
/** /**
* Get a sorted list of songs for a SortMode. Supports alpha + numeric sorting. * Sort a list of songs.
* @param songs An unsorted list of songs. *
* @return The sorted 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<Song>): List<Song> { fun sortSongs(songs: Collection<Song>): List<Song> {
return when (this) { return when (this) {
ALPHA_UP -> songs.sortedWith( ASCENDING, DESCENDING -> sortModels(songs)
compareByDescending(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle() else -> sortAlbums(songs.groupBy { it.album }.keys).flatMap { album ->
ASCENDING.sortAlbum(album)
} }
)
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
} }
} }
/** /**
* Get a sorted list of songs with regards to an artist. * Sort a list of albums.
* @param songs An unsorted list of songs *
* @return The sorted list of songs * **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<Song>): List<Song> { fun sortAlbums(albums: Collection<Album>): List<Album> {
return when (this) { return when (this) {
ALPHA_UP -> songs.sortedWith( ASCENDING, DESCENDING -> sortModels(albums)
compareByDescending(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
ALPHA_DOWN -> songs.sortedWith( ARTIST -> ASCENDING.sortModels(albums.groupBy { it.artist }.keys)
compareBy(String.CASE_INSENSITIVE_ORDER) { .flatMap { YEAR.sortAlbums(it.albums) }
it.name.sliceArticle()
}
)
NUMERIC_UP -> { ALBUM -> ASCENDING.sortModels(albums)
val list = mutableListOf<Song>()
songs.groupBy { it.album }.entries.sortedBy { it.key.year }.forEach { entry -> YEAR -> albums.sortedByDescending { it.year }
list.addAll(entry.value.sortedWith(compareBy { it.track }))
}
list
}
NUMERIC_DOWN -> {
val list = mutableListOf<Song>()
songs.groupBy { it.album }.entries.sortedWith(compareByDescending { it.key.year }).forEach { entry ->
list.addAll(entry.value.sortedWith(compareBy { it.track }))
}
list
}
else -> songs
} }
} }
/** /**
* Get the constant for this mode. Used to write a compressed variant to SettingsManager * Sort a list of generic [BaseModel] instances.
* @return The int constant for this mode. *
* **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 <T : BaseModel> sortModels(models: Collection<T>): List<T> {
return when (this) { return when (this) {
NONE -> CONST_NONE ASCENDING -> models.sortedWith(
ALPHA_UP -> CONST_ALPHA_UP compareBy(String.CASE_INSENSITIVE_ORDER) { model ->
ALPHA_DOWN -> CONST_ALPHA_DOWN model.name.sliceArticle()
NUMERIC_UP -> CONST_NUMERIC_UP
NUMERIC_DOWN -> CONST_NUMERIC_DOWN
} }
)
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<Song> {
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<Song> {
return sortSongs(artist.songs)
}
/**
* Sort the songs in a genre.
* @see sortSongs
*/
fun sortGenre(genre: Genre): List<Song> {
return sortSongs(genre.songs)
} }
companion object { 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 * Convert a menu [id] to an instance of [SortMode].
* @return The [SortMode] if the constant is valid, null otherwise.
*/ */
fun fromInt(value: Int): SortMode? { fun fromId(@IdRes id: Int): SortMode? {
return when (value) { return when (id) {
CONST_NONE -> NONE ASCENDING.itemId -> ASCENDING
CONST_ALPHA_UP -> ALPHA_UP DESCENDING.itemId -> DESCENDING
CONST_ALPHA_DOWN -> ALPHA_DOWN ARTIST.itemId -> ARTIST
CONST_NUMERIC_UP -> NUMERIC_UP ALBUM.itemId -> ALBUM
CONST_NUMERIC_DOWN -> NUMERIC_DOWN YEAR.itemId -> YEAR
else -> null else -> null
} }
} }

View file

@ -266,7 +266,7 @@ class ActionHeaderViewHolder private constructor(
} }
companion object { companion object {
const val ITEM_TYPE = 0xA999 // TODO: Give this an ID const val ITEM_TYPE = 0xA005
/** /**
* Create an instance of [ActionHeaderViewHolder] * Create an instance of [ActionHeaderViewHolder]

View file

@ -45,18 +45,17 @@ To prevent any strange bugs, all integer representations must be unique. A table
0xA002 | ArtistViewHolder 0xA002 | ArtistViewHolder
0xA003 | GenreViewHolder 0xA003 | GenreViewHolder
0xA004 | HeaderViewHolder 0xA004 | HeaderViewHolder
0xA005 | ActionHeaderViewHolder
0xA005 | QueueSongViewHolder 0xA005 | AlbumDetailViewHolder
0xA006 | UserQueueHeaderViewHolder 0xA006 | AlbumSongViewHolder
0xA007 | ArtistDetailViewHolder
0xA008 | ArtistAlbumViewHolder
0xA009 | ArtistSongViewHolder
0xA010 | GenreDetailViewHolder
0xA011 | GenreSongViewHolder
0xA007 | AlbumHeaderViewHolder 0xA00A | QueueSongViewHolder
0xA008 | AlbumSongViewHolder
0xA009 | ArtistHeaderViewHolder
0xA00A | ArtistAlbumViewHolder
0xA00B | ArtistSongHeaderViewHolder
0xA00C | ArtistSongViewHolder
0xA00D | GenreHeaderViewHolder
0xA00E | GenreSongViewHolder
0xA0A0 | Auxio notification code 0xA0A0 | Auxio notification code
0xA0C0 | Auxio request 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 0xA109 | DisplayMode.SHOW_ARTISTS
0xA10A | DisplayMode.SHOW_ALBUMS 0xA10A | DisplayMode.SHOW_ALBUMS
0xA10B | DisplayMode.SHOW_SONGS 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 #### Package structure overview