diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryAdapter.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryAdapter.kt index 049989b87..9d0b19f39 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryAdapter.kt @@ -5,22 +5,22 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView 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.Parent import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder import org.oxycblt.auxio.recycler.viewholders.GenreViewHolder /** - * An adapter for displaying library items. + * An adapter for displaying library items. Supports [Parent]s only. * @author OxygenCobalt */ class LibraryAdapter( - private val doOnClick: (data: BaseModel) -> Unit, - private val doOnLongClick: (view: View, data: BaseModel) -> Unit + private val doOnClick: (data: Parent) -> Unit, + private val doOnLongClick: (view: View, data: Parent) -> Unit ) : RecyclerView.Adapter() { - private var data = listOf() + private var data = listOf() override fun getItemCount(): Int = data.size @@ -29,8 +29,6 @@ class LibraryAdapter( is Genre -> GenreViewHolder.ITEM_TYPE is Artist -> ArtistViewHolder.ITEM_TYPE is Album -> AlbumViewHolder.ITEM_TYPE - - else -> -1 } } @@ -64,7 +62,7 @@ class LibraryAdapter( * Update the data directly. [notifyDataSetChanged] will be called * @param newData The new data to be used */ - fun updateData(newData: List) { + fun updateData(newData: List) { data = newData notifyDataSetChanged() diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt index 192bb04bb..77d630a95 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -12,11 +12,10 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentLibraryBinding import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.logD -import org.oxycblt.auxio.logE 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.Parent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.ui.ActionMenu import org.oxycblt.auxio.ui.fixAnimInfoLeak @@ -81,10 +80,10 @@ class LibraryFragment : Fragment() { if (it != null) { libraryModel.updateNavigationStatus(false) - if (it is Song) { - onItemSelection(it.album) - } else { + if (it is Parent) { onItemSelection(it) + } else if (it is Song) { + onItemSelection(it.album) } } } @@ -107,34 +106,22 @@ class LibraryFragment : Fragment() { } /** - * Navigate to an item - * @param baseModel The item that should be navigated to. + * Navigate to a parent UI + * @param parent The parent that should be navigated with */ - private fun onItemSelection(baseModel: BaseModel) { - if (baseModel is Song) { - logE("onItemSelection does not support songs") - return - } - + private fun onItemSelection(parent: Parent) { requireView().rootView.clearFocus() if (!libraryModel.isNavigating) { libraryModel.updateNavigationStatus(true) - logD("Navigating to the detail fragment for ${baseModel.name}") + logD("Navigating to the detail fragment for ${parent.name}") findNavController().navigate( - when (baseModel) { - is Genre -> LibraryFragmentDirections.actionShowGenre(baseModel.id) - is Artist -> LibraryFragmentDirections.actionShowArtist(baseModel.id) - is Album -> LibraryFragmentDirections.actionShowAlbum(baseModel.id) - - // If given model wasn't valid, then reset the navigation status - // and abort the navigation. - else -> { - libraryModel.updateNavigationStatus(false) - return - } + when (parent) { + is Genre -> LibraryFragmentDirections.actionShowGenre(parent.id) + is Artist -> LibraryFragmentDirections.actionShowArtist(parent.id) + is Album -> LibraryFragmentDirections.actionShowAlbum(parent.id) } ) } diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt index 45a1a836f..6365fa64a 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt @@ -5,8 +5,8 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import org.oxycblt.auxio.R -import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.MusicStore +import org.oxycblt.auxio.music.Parent import org.oxycblt.auxio.recycler.DisplayMode import org.oxycblt.auxio.recycler.SortMode import org.oxycblt.auxio.settings.SettingsManager @@ -17,8 +17,8 @@ import org.oxycblt.auxio.settings.SettingsManager * @author OxygenCobalt */ class LibraryViewModel : ViewModel(), SettingsManager.Callback { - private val mLibraryData = MutableLiveData(listOf()) - val libraryData: LiveData> get() = mLibraryData + private val mLibraryData = MutableLiveData(listOf()) + val libraryData: LiveData> get() = mLibraryData private var mIsNavigating = false val isNavigating: Boolean get() = mIsNavigating @@ -91,17 +91,11 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback { */ private fun updateLibraryData() { mLibraryData.value = when (mDisplayMode) { - DisplayMode.SHOW_GENRES -> { - mSortMode.getSortedGenreList(musicStore.genres) - } + DisplayMode.SHOW_GENRES -> mSortMode.getSortedGenreList(musicStore.genres) - DisplayMode.SHOW_ARTISTS -> { - mSortMode.getSortedBaseModelList(musicStore.artists) - } + DisplayMode.SHOW_ARTISTS -> mSortMode.getSortedArtistList(musicStore.artists) - DisplayMode.SHOW_ALBUMS -> { - mSortMode.getSortedAlbumList(musicStore.albums) - } + DisplayMode.SHOW_ALBUMS -> mSortMode.getSortedAlbumList(musicStore.albums) else -> error("DisplayMode $mDisplayMode is unsupported.") } diff --git a/app/src/main/java/org/oxycblt/auxio/music/Models.kt b/app/src/main/java/org/oxycblt/auxio/music/Models.kt index f4ee767c4..6f7324108 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Models.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Models.kt @@ -15,6 +15,12 @@ sealed class BaseModel { abstract val name: String } +/** + * [BaseModel] variant that denotes that this object is a parent of other data objects, such + * as an [Album] or [Artist] + */ +sealed class Parent : BaseModel() + /** * The data object for a song. Inherits [BaseModel]. * @property albumId The Song's Album ID. Never use this outside of when attaching a song to its album. @@ -72,7 +78,7 @@ data class Song( } /** - * The data object for an album. Inherits [BaseModel]. + * The data object for an album. Inherits [Parent]. * @property artistName The name of the parent artist. Do not use this outside of creating the artist from albums * @property coverUri The [Uri] for the album's cover. **Load this using Coil.** * @property year The year this album was released. 0 if there is none in the metadata. @@ -87,7 +93,7 @@ data class Album( val artistName: String, val coverUri: Uri = Uri.EMPTY, val year: Int = 0 -) : BaseModel() { +) : Parent() { private var mArtist: Artist? = null val artist: Artist get() { val artist = mArtist @@ -123,7 +129,7 @@ data class Album( } /** - * The data object for an artist. Inherits [BaseModel] + * The data object for an artist. Inherits [Parent] * @property albums The list of all [Album]s in this artist * @property genre The most prominent genre for this artist * @property songs The list of all [Song]s in this artist @@ -133,7 +139,7 @@ data class Artist( override val id: Long = -1, override val name: String, val albums: List -) : BaseModel() { +) : Parent() { init { albums.forEach { it.applyArtist(this) @@ -158,7 +164,7 @@ data class Artist( } /** - * The data object for a genre. Inherits [BaseModel] + * The data object for a genre. Inherits [Parent] * @property songs The list of all [Song]s in this genre. * @property displayName A name that can be displayed without it showing up as an integer. ***USE THIS INSTEAD OF [name]!!!!*** * @author OxygenCobalt @@ -166,7 +172,7 @@ data class Artist( data class Genre( override val id: Long = -1, override val name: String, -) : BaseModel() { +) : Parent() { private val mSongs = mutableListOf() val songs: List get() = mSongs diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt index 6bcdffd2a..d39e4057d 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt @@ -25,8 +25,8 @@ class MusicStore private constructor() { val songs: List get() = mSongs /** All parent models (ex Albums, Artists) loaded by Auxio */ - val parents: MutableList by lazy { - mutableListOf().apply { + val parents: MutableList by lazy { + mutableListOf().apply { addAll(mGenres) addAll(mArtists) addAll(mAlbums) 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 220b39ac0..e42d8cfed 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -12,8 +12,8 @@ import org.oxycblt.auxio.logD import org.oxycblt.auxio.logE 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.Parent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.toDuration import org.oxycblt.auxio.playback.queue.QueueAdapter @@ -34,7 +34,7 @@ import org.oxycblt.auxio.ui.createToast class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { // Playback private val mSong = MutableLiveData() - private val mParent = MutableLiveData() + private val mParent = MutableLiveData() private val mPosition = MutableLiveData(0L) // Queue @@ -56,7 +56,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { /** The current song. */ val song: LiveData get() = mSong /** The current model that is being played from, such as an [Album] or [Artist] */ - val parent: LiveData get() = mParent + val parent: LiveData get() = mParent /** The current playback position, in seconds */ val position: LiveData get() = mPosition @@ -125,7 +125,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { return } - playbackManager.playParentModel(album, shuffled) + playbackManager.playParent(album, shuffled) } /** Play an Artist */ @@ -136,7 +136,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { return } - playbackManager.playParentModel(artist, shuffled) + playbackManager.playParent(artist, shuffled) } /** Play a genre. */ @@ -147,7 +147,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { return } - playbackManager.playParentModel(genre, shuffled) + playbackManager.playParent(genre, shuffled) } /** Shuffle all songs */ @@ -365,7 +365,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { mSong.value = song } - override fun onParentUpdate(parent: BaseModel?) { + override fun onParentUpdate(parent: Parent?) { mParent.value = parent } 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 26d61684c..28ce2390c 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 @@ -10,10 +10,9 @@ import org.oxycblt.auxio.logD import org.oxycblt.auxio.logE 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.Header import org.oxycblt.auxio.music.MusicStore +import org.oxycblt.auxio.music.Parent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.recycler.SortMode import org.oxycblt.auxio.settings.SettingsManager @@ -42,7 +41,7 @@ class PlaybackStateManager private constructor() { field = value callbacks.forEach { it.onPositionUpdate(value) } } - private var mParent: BaseModel? = null + private var mParent: Parent? = null set(value) { field = value callbacks.forEach { it.onParentUpdate(value) } @@ -98,7 +97,7 @@ class PlaybackStateManager private constructor() { /** The currently playing song. Null if there isn't one */ val song: Song? get() = mSong /** The parent the queue is based on, null if all_songs */ - val parent: BaseModel? get() = mParent + val parent: Parent? get() = mParent /** The current playback progress */ val position: Long get() = mPosition /** The current queue determined by [parent] and [mode] */ @@ -192,33 +191,26 @@ class PlaybackStateManager private constructor() { /** * Play a parent model, e.g an artist or an album. - * @param baseModel The model to use + * @param parent The model to use * @param shuffled Whether to shuffle the queue or not */ - fun playParentModel(baseModel: BaseModel, shuffled: Boolean) { - if (baseModel is Song || baseModel is Header) { - // This should never occur. - logE("playParentModel is not meant to play ${baseModel::class.simpleName}.") + fun playParent(parent: Parent, shuffled: Boolean) { + logD("Playing ${parent.name}") - return - } - - logD("Playing ${baseModel.name}") - - mParent = baseModel + mParent = parent mIndex = 0 - when (baseModel) { + when (parent) { is Album -> { - mQueue = baseModel.songs.toMutableList() + mQueue = parent.songs.toMutableList() mMode = PlaybackMode.IN_ALBUM } is Artist -> { - mQueue = baseModel.songs.toMutableList() + mQueue = parent.songs.toMutableList() mMode = PlaybackMode.IN_ARTIST } is Genre -> { - mQueue = baseModel.songs.toMutableList() + mQueue = parent.songs.toMutableList() mMode = PlaybackMode.IN_GENRE } @@ -817,7 +809,7 @@ class PlaybackStateManager private constructor() { */ interface Callback { fun onSongUpdate(song: Song?) {} - fun onParentUpdate(parent: BaseModel?) {} + fun onParentUpdate(parent: Parent?) {} fun onPositionUpdate(position: Long) {} fun onQueueUpdate(queue: MutableList) {} fun onUserQueueUpdate(userQueue: MutableList) {} diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt b/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt index 0ca470d00..066c4999e 100644 --- a/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt @@ -4,6 +4,7 @@ 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 @@ -25,8 +26,8 @@ enum class SortMode(@DrawableRes val iconRes: Int) { /** * Get a sorted list of genres for a SortMode. Only supports alphabetic sorting. - * @param genres An unsorted list of artists. - * @return The sorted list of artists. + * @param genres An unsorted list of genres. + * @return The sorted list of genres. */ fun getSortedGenreList(genres: List): List { return when (this) { @@ -42,6 +43,25 @@ enum class SortMode(@DrawableRes val iconRes: Int) { } } + /** + * Get a sorted list of artists for a SortMode. Only supports alphabetic sorting. + * @param artists An unsorted list of artists. + * @return The sorted list of artists. + */ + fun getSortedArtistList(artists: List): List { + return when (this) { + ALPHA_UP -> artists.sortedWith( + compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name } + ) + + ALPHA_DOWN -> artists.sortedWith( + compareBy(String.CASE_INSENSITIVE_ORDER) { it.name } + ) + + else -> artists + } + } + /** * Get a sorted list of albums for a SortMode. Supports alpha + numeric sorting. * @param albums An unsorted list of albums. @@ -124,28 +144,6 @@ enum class SortMode(@DrawableRes val iconRes: Int) { } } - /** - * Get a sorted list of BaseModels. Supports alpha + numeric sorting. - * @param baseModels An unsorted list of BaseModels. - * @return The sorted list of BaseModels. - */ - fun getSortedBaseModelList(baseModels: List): List { - return when (this) { - ALPHA_UP -> baseModels.sortedWith( - compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name } - ) - - ALPHA_DOWN -> baseModels.sortedWith( - compareBy(String.CASE_INSENSITIVE_ORDER) { it.name } - ) - - NUMERIC_UP -> baseModels.sortedWith(compareByDescending { it.id }) - NUMERIC_DOWN -> baseModels.sortedWith(compareBy { it.id }) - - else -> baseModels - } - } - /** * Get a sorting menu ID for this mode. Alphabetic only. * @return The action id for this mode.