From 332d1d0170af37e1749f245b1204b11308e3cbd2 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Tue, 5 Jan 2021 09:42:36 -0700 Subject: [PATCH] Update shuffling system Optimize the shuffling system in PlaybackStateManager. --- .../oxycblt/auxio/detail/DetailViewModel.kt | 1 - .../playback/state/PlaybackStateManager.kt | 129 +++++++++++------- app/src/main/res/layout/fragment_songs.xml | 2 - 3 files changed, 77 insertions(+), 55 deletions(-) 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 49acac6b4..e2ce1a406 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -12,7 +12,6 @@ import org.oxycblt.auxio.recycler.SortMode /** * ViewModel that stores data for the [DetailFragment]s, such as what they're showing & what * [SortMode] they are currently on. - * TODO: Preserve previous backstack when doing playing item navigation */ class DetailViewModel : ViewModel() { private var mIsNavigating = false 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 c58d81160..a07ed912e 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 @@ -93,7 +93,6 @@ class PlaybackStateManager private constructor() { } private var mIsRestored = false private var mHasPlayed = false - private var mShuffleSeed = -1L /** The currently playing song. Null if there isn't one */ val song: Song? get() = mSong @@ -121,6 +120,7 @@ class PlaybackStateManager private constructor() { val hasPlayed: Boolean get() = mHasPlayed private val settingsManager = SettingsManager.getInstance() + private val musicStore = MusicStore.getInstance() // --- CALLBACKS --- @@ -151,45 +151,60 @@ class PlaybackStateManager private constructor() { fun playSong(song: Song, mode: PlaybackMode) { logD("Updating song to ${song.name} and mode to $mode") - val musicStore = MusicStore.getInstance() + val shouldShuffle = settingsManager.keepShuffle && mIsShuffling when (mode) { PlaybackMode.ALL_SONGS -> { mParent = null - mQueue = musicStore.songs.toMutableList() + + mQueue = if (shouldShuffle) { + musicStore.songs.toMutableList() + } else { + genShuffle(musicStore.songs.toMutableList(), false) + } } PlaybackMode.IN_GENRE -> { - mParent = song.genre - mQueue = orderSongsInGenre(song.genre!!) + if (song.genre != null) { + mParent = song.genre + mQueue = if (shouldShuffle) { + genShuffle(song.genre!!.songs.toMutableList(), false) + } else { + orderSongsInGenre(song.genre!!) + } + } else { + // I really don't know what to do if the song doesn't have a genre, so just + // ignore it. + logE("Song doesn't have a genre. Not playing.") + return + } } PlaybackMode.IN_ARTIST -> { mParent = song.album.artist - mQueue = orderSongsInArtist(song.album.artist) + mQueue = if (shouldShuffle) { + genShuffle(song.album.artist.songs.toMutableList(), false) + } else { + orderSongsInArtist(song.album.artist) + } } PlaybackMode.IN_ALBUM -> { mParent = song.album - mQueue = orderSongsInAlbum(song.album) + mQueue = if (shouldShuffle) { + genShuffle(song.album.songs.toMutableList(), false) + } else { + orderSongsInAlbum(song.album) + } } } mMode = mode + mIsShuffling = shouldShuffle resetLoopMode() updatePlayback(song) - if (settingsManager.keepShuffle) { - if (mIsShuffling) { - genShuffle(true) - } else { - resetShuffle() - } - } else { - setShuffleStatus(false) - } - mIndex = mQueue.indexOf(song) } @@ -214,15 +229,30 @@ class PlaybackStateManager private constructor() { when (baseModel) { is Album -> { - mQueue = orderSongsInAlbum(baseModel) + mQueue = if (mIsShuffling) { + genShuffle(baseModel.songs.toMutableList(), false) + } else { + orderSongsInAlbum(baseModel) + } + mMode = PlaybackMode.IN_ALBUM } is Artist -> { - mQueue = orderSongsInArtist(baseModel) + mQueue = if (mIsShuffling) { + genShuffle(baseModel.songs.toMutableList(), false) + } else { + orderSongsInArtist(baseModel) + } + mMode = PlaybackMode.IN_ARTIST } is Genre -> { - mQueue = orderSongsInGenre(baseModel) + mQueue = if (mIsShuffling) { + genShuffle(baseModel.songs.toMutableList(), false) + } else { + orderSongsInGenre(baseModel) + } + mMode = PlaybackMode.IN_GENRE } @@ -233,12 +263,6 @@ class PlaybackStateManager private constructor() { resetLoopMode() updatePlayback(mQueue[0]) - - if (mIsShuffling) { - genShuffle(false) - } else { - resetShuffle() - } } /** @@ -504,38 +528,44 @@ class PlaybackStateManager private constructor() { val musicStore = MusicStore.getInstance() mIsShuffling = true - mQueue = musicStore.songs.toMutableList() + mQueue = genShuffle(musicStore.songs.toMutableList(), false) mMode = PlaybackMode.ALL_SONGS mIndex = 0 - genShuffle(false) updatePlayback(mQueue[0]) } /** * Generate a new shuffled queue. + * @param queueToShuffle The queue to shuffle * @param keepSong Whether to keep the currently playing song or to dispose of it - * @param useLastSong (Optional, defaults to false) Whether to use the previous song for the index calculations caused by the above parameter. + * @param useLastSong (Optional, defaults to false) Whether to use the last song in the queue instead of the current one + * @return A new shuffled queue */ - private fun genShuffle(keepSong: Boolean, useLastSong: Boolean = false) { - mShuffleSeed = Random.Default.nextLong() + private fun genShuffle( + queueToShuffle: MutableList, + keepSong: Boolean, + useLastSong: Boolean = false + ): MutableList { + val newSeed = Random.Default.nextLong() - logD("Shuffling queue with seed $mShuffleSeed") + val lastSong = - val lastSong = if (useLastSong) mQueue[mIndex] else mSong + logD("Shuffling queue with seed $newSeed") - mQueue.shuffle(Random(mShuffleSeed)) + queueToShuffle.shuffle(Random(newSeed)) mIndex = 0 // If specified, make the current song the first member of the queue. if (keepSong) { - moveQueueItems(mQueue.indexOf(lastSong), 0) + val song = queueToShuffle.removeAt(queueToShuffle.indexOf(mSong)) + queueToShuffle.add(0, song) } else { // Otherwise, just start from the zeroth position in the queue. mSong = mQueue[0] } - forceQueueUpdate() + return queueToShuffle } /** @@ -543,11 +573,14 @@ class PlaybackStateManager private constructor() { * @param useLastSong (Optional, defaults to false) Whether to use the previous song for the index calculations. */ private fun resetShuffle(useLastSong: Boolean = false) { - mShuffleSeed = -1L - val lastSong = if (useLastSong) mQueue[mIndex] else mSong - setupOrderedQueue() + mQueue = when (mMode) { + PlaybackMode.IN_ARTIST -> orderSongsInArtist(mParent as Artist) + PlaybackMode.IN_ALBUM -> orderSongsInAlbum(mParent as Album) + PlaybackMode.IN_GENRE -> orderSongsInGenre(mParent as Genre) + PlaybackMode.ALL_SONGS -> MusicStore.getInstance().songs.toMutableList() + } mIndex = mQueue.indexOf(lastSong) @@ -578,7 +611,11 @@ class PlaybackStateManager private constructor() { mIsShuffling = value if (mIsShuffling) { - genShuffle(true, mIsInUserQueue) + mQueue = genShuffle( + mQueue, + keepSong = true, + useLastSong = mIsInUserQueue + ) } else { resetShuffle(mIsInUserQueue) } @@ -795,18 +832,6 @@ class PlaybackStateManager private constructor() { // --- ORDERING FUNCTIONS --- - /** - * Set up an ordered queue. - */ - private fun setupOrderedQueue() { - mQueue = when (mMode) { - PlaybackMode.IN_ARTIST -> orderSongsInArtist(mParent as Artist) - PlaybackMode.IN_ALBUM -> orderSongsInAlbum(mParent as Album) - PlaybackMode.IN_GENRE -> orderSongsInGenre(mParent as Genre) - PlaybackMode.ALL_SONGS -> MusicStore.getInstance().songs.toMutableList() - } - } - /** * Create an ordered queue based on an [Album]. */ diff --git a/app/src/main/res/layout/fragment_songs.xml b/app/src/main/res/layout/fragment_songs.xml index 4f52c69d2..0a05b159a 100644 --- a/app/src/main/res/layout/fragment_songs.xml +++ b/app/src/main/res/layout/fragment_songs.xml @@ -35,8 +35,6 @@ android:id="@+id/song_fast_scroll" android:layout_width="wrap_content" android:layout_height="0dp" - android:layout_marginTop="@dimen/margin_small" - android:layout_marginBottom="@dimen/margin_small" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/song_toolbar" />