Update shuffling system
Finally collapse all usage of shuffle into setShuffling, instead of the mix of checks that used to be throughout PlaybackStateManager.
This commit is contained in:
parent
44fa178c34
commit
627553344c
7 changed files with 88 additions and 66 deletions
|
@ -101,7 +101,7 @@ class MosaicFetcher(private val context: Context) : Fetcher<List<Uri>> {
|
|||
* Iterate through a list of [Closeable]s, running [use] on each.
|
||||
* @param action What to do for each [Closeable]
|
||||
*/
|
||||
private fun <T : Closeable, R> List<T>.useForEach(action: (T) -> R) {
|
||||
private fun <T : Closeable> List<T>.useForEach(action: (T) -> Unit) {
|
||||
forEach {
|
||||
it.use(action)
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.takeWhile
|
||||
import kotlinx.coroutines.launch
|
||||
import org.oxycblt.auxio.coil.getBitmap
|
||||
|
@ -484,7 +484,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
// Play/Pause if any of the keys are play/pause
|
||||
KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY,
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_HEADSETHOOK -> {
|
||||
playbackManager.setPlayingStatus(!playbackManager.isPlaying)
|
||||
playbackManager.setPlaying(!playbackManager.isPlaying)
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -557,7 +557,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
player.volume = VOLUME_DUCK
|
||||
animateVolume(VOLUME_DUCK, VOLUME_FULL)
|
||||
} else if (pauseWasFromAudioFocus) {
|
||||
playbackManager.setPlayingStatus(true)
|
||||
playbackManager.setPlaying(true)
|
||||
}
|
||||
|
||||
pauseWasFromAudioFocus = false
|
||||
|
@ -567,7 +567,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
private fun onLoss() {
|
||||
if (settingsManager.doAudioFocus && playbackManager.isPlaying) {
|
||||
pauseWasFromAudioFocus = true
|
||||
playbackManager.setPlayingStatus(false)
|
||||
playbackManager.setPlaying(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -606,10 +606,10 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
NotificationUtils.ACTION_LOOP ->
|
||||
playbackManager.setLoopMode(playbackManager.loopMode.increment())
|
||||
NotificationUtils.ACTION_SHUFFLE ->
|
||||
playbackManager.setShuffleStatus(!playbackManager.isShuffling)
|
||||
playbackManager.setShuffling(!playbackManager.isShuffling, keepSong = true)
|
||||
NotificationUtils.ACTION_SKIP_PREV -> playbackManager.prev()
|
||||
NotificationUtils.ACTION_PLAY_PAUSE -> {
|
||||
playbackManager.setPlayingStatus(!playbackManager.isPlaying)
|
||||
playbackManager.setPlaying(!playbackManager.isPlaying)
|
||||
}
|
||||
NotificationUtils.ACTION_SKIP_NEXT -> playbackManager.next()
|
||||
NotificationUtils.ACTION_EXIT -> stop()
|
||||
|
@ -643,7 +643,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
if (playbackManager.song != null && settingsManager.doPlugMgt) {
|
||||
logD("Device connected, resuming...")
|
||||
|
||||
playbackManager.setPlayingStatus(true)
|
||||
playbackManager.setPlaying(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -654,7 +654,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
if (playbackManager.song != null && settingsManager.doPlugMgt) {
|
||||
logD("Device disconnected, pausing...")
|
||||
|
||||
playbackManager.setPlayingStatus(false)
|
||||
playbackManager.setPlaying(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -662,7 +662,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
* Stop if the X button was clicked from the notification
|
||||
*/
|
||||
private fun stop() {
|
||||
playbackManager.setPlayingStatus(false)
|
||||
playbackManager.setPlaying(false)
|
||||
stopForegroundAndNotification()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -279,12 +279,12 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
|||
fun invertPlayingStatus() {
|
||||
enableAnimation()
|
||||
|
||||
playbackManager.setPlayingStatus(!playbackManager.isPlaying)
|
||||
playbackManager.setPlaying(!playbackManager.isPlaying)
|
||||
}
|
||||
|
||||
/** Flip the shuffle status, e.g from on to off */
|
||||
/** Flip the shuffle status, e.g from on to off. Will keep song by default. */
|
||||
fun invertShuffleStatus() {
|
||||
playbackManager.setShuffleStatus(!playbackManager.isShuffling)
|
||||
playbackManager.setShuffling(!playbackManager.isShuffling, keepSong = true)
|
||||
}
|
||||
|
||||
/** Increment the loop status, e.g from off to loop once */
|
||||
|
|
|
@ -153,8 +153,6 @@ class PlaybackStateManager private constructor() {
|
|||
fun playSong(song: Song, mode: PlaybackMode) {
|
||||
logD("Updating song to ${song.name} and mode to $mode")
|
||||
|
||||
val shouldShuffle = settingsManager.keepShuffle && mIsShuffling
|
||||
|
||||
when (mode) {
|
||||
PlaybackMode.ALL_SONGS -> {
|
||||
mParent = null
|
||||
|
@ -190,7 +188,9 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
resetLoopMode()
|
||||
updatePlayback(song)
|
||||
setShuffleStatus(shouldShuffle)
|
||||
|
||||
// Depending on the configuration, keep the shuffle mode on.
|
||||
setShuffling(settingsManager.keepShuffle && mIsShuffling, keepSong = true)
|
||||
|
||||
mIndex = mQueue.indexOf(song)
|
||||
}
|
||||
|
@ -212,19 +212,18 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
mParent = baseModel
|
||||
mIndex = 0
|
||||
mIsShuffling = shuffled
|
||||
|
||||
when (baseModel) {
|
||||
is Album -> {
|
||||
mQueue = orderSongsInAlbum(baseModel)
|
||||
mQueue = baseModel.songs.toMutableList()
|
||||
mMode = PlaybackMode.IN_ALBUM
|
||||
}
|
||||
is Artist -> {
|
||||
mQueue = orderSongsInArtist(baseModel)
|
||||
mQueue = baseModel.songs.toMutableList()
|
||||
mMode = PlaybackMode.IN_ARTIST
|
||||
}
|
||||
is Genre -> {
|
||||
mQueue = orderSongsInGenre(baseModel)
|
||||
mQueue = baseModel.songs.toMutableList()
|
||||
mMode = PlaybackMode.IN_GENRE
|
||||
}
|
||||
|
||||
|
@ -233,14 +232,8 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
|
||||
resetLoopMode()
|
||||
|
||||
setShuffling(shuffled, keepSong = false)
|
||||
updatePlayback(mQueue[0])
|
||||
|
||||
if (mIsShuffling) {
|
||||
genShuffle(false)
|
||||
} else {
|
||||
resetShuffle()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -254,7 +247,7 @@ class PlaybackStateManager private constructor() {
|
|||
mPosition = 0
|
||||
|
||||
if (!mIsPlaying) {
|
||||
setPlayingStatus(true)
|
||||
setPlaying(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,7 +345,7 @@ class PlaybackStateManager private constructor() {
|
|||
mSong = mQueue[0]
|
||||
mPosition = 0
|
||||
|
||||
setPlayingStatus(false)
|
||||
setPlaying(false)
|
||||
|
||||
mIsInUserQueue = false
|
||||
}
|
||||
|
@ -503,25 +496,37 @@ class PlaybackStateManager private constructor() {
|
|||
* Shuffle all songs.
|
||||
*/
|
||||
fun shuffleAll() {
|
||||
mIsShuffling = true
|
||||
mMode = PlaybackMode.ALL_SONGS
|
||||
mIndex = 0
|
||||
mQueue = musicStore.songs.toMutableList()
|
||||
|
||||
genShuffle(false)
|
||||
|
||||
setShuffling(true, keepSong = false)
|
||||
updatePlayback(mQueue[0])
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the shuffle status. Updates the queue accordingly
|
||||
* @param value Whether the queue should be shuffled or not.
|
||||
* @param keepSong Whether the current song should be kept as the queue is shuffled/unshuffled
|
||||
*/
|
||||
fun setShuffling(value: Boolean, keepSong: Boolean) {
|
||||
mIsShuffling = value
|
||||
|
||||
if (mIsShuffling) {
|
||||
genShuffle(keepSong, mIsInUserQueue)
|
||||
} else {
|
||||
resetShuffle(keepSong, mIsInUserQueue)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new shuffled queue.
|
||||
* @param keepSong Whether to keep the currently playing song or to dispose of it
|
||||
* @param useLastSong (Optional, defaults to false) Whether to use the last song in the queue instead of the current one
|
||||
* @param keepSong Whether the current song should be kept as the queue is shuffled
|
||||
* @param useLastSong 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
|
||||
useLastSong: Boolean
|
||||
) {
|
||||
val lastSong = if (useLastSong) mQueue[0] else mSong
|
||||
|
||||
|
@ -543,9 +548,13 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
/**
|
||||
* Reset the queue to its normal, ordered state.
|
||||
* @param useLastSong (Optional, defaults to false) Whether to use the previous song for the index calculations.
|
||||
* @param keepSong Whether the current song should be kept as the queue is unshuffled
|
||||
* @param useLastSong Whether to use the previous song for the index calculations.
|
||||
*/
|
||||
private fun resetShuffle(useLastSong: Boolean = false) {
|
||||
private fun resetShuffle(
|
||||
keepSong: Boolean,
|
||||
useLastSong: Boolean
|
||||
) {
|
||||
val lastSong = if (useLastSong) mQueue[mIndex] else mSong
|
||||
|
||||
mQueue = when (mMode) {
|
||||
|
@ -555,7 +564,9 @@ class PlaybackStateManager private constructor() {
|
|||
PlaybackMode.ALL_SONGS -> musicStore.songs.toMutableList()
|
||||
}
|
||||
|
||||
if (keepSong) {
|
||||
mIndex = mQueue.indexOf(lastSong)
|
||||
}
|
||||
|
||||
forceQueueUpdate()
|
||||
}
|
||||
|
@ -566,7 +577,7 @@ class PlaybackStateManager private constructor() {
|
|||
* Set the current playing status
|
||||
* @param value Whether the playback should be playing or paused.
|
||||
*/
|
||||
fun setPlayingStatus(value: Boolean) {
|
||||
fun setPlaying(value: Boolean) {
|
||||
if (mIsPlaying != value) {
|
||||
if (value) {
|
||||
mHasPlayed = true
|
||||
|
@ -577,25 +588,11 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the shuffle status. Updates the queue accordingly
|
||||
* @param value Whether the queue should be shuffled or not.
|
||||
* Rewind to the beginning of a song.
|
||||
*/
|
||||
fun setShuffleStatus(value: Boolean) {
|
||||
mIsShuffling = value
|
||||
|
||||
if (mIsShuffling) {
|
||||
genShuffle(
|
||||
keepSong = true,
|
||||
useLastSong = mIsInUserQueue
|
||||
)
|
||||
} else {
|
||||
resetShuffle(mIsInUserQueue)
|
||||
}
|
||||
}
|
||||
|
||||
fun rewind() {
|
||||
seekTo(0)
|
||||
setPlayingStatus(true)
|
||||
setPlaying(true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -606,13 +603,6 @@ class PlaybackStateManager private constructor() {
|
|||
mLoopMode = mode
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the has played status as if this instance is fresh.
|
||||
*/
|
||||
fun resetHasPlayedStatus() {
|
||||
mHasPlayed = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current [LoopMode], if needed.
|
||||
* Use this instead of duplicating the code manually.
|
||||
|
@ -624,6 +614,13 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the has played status as if this instance is fresh.
|
||||
*/
|
||||
fun resetHasPlayedStatus() {
|
||||
mHasPlayed = false
|
||||
}
|
||||
|
||||
// --- PERSISTENCE FUNCTIONS ---
|
||||
|
||||
/**
|
||||
|
|
|
@ -101,8 +101,24 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
|
|||
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
|
||||
)
|
||||
|
||||
NUMERIC_UP -> songs.sortedWith(compareBy { it.album.year })
|
||||
NUMERIC_DOWN -> songs.sortedWith(compareByDescending { it.album.year })
|
||||
NUMERIC_UP -> {
|
||||
val list = mutableListOf<Song>()
|
||||
|
||||
songs.groupBy { it.album }.toSortedMap(compareBy { it.year }).values.forEach {
|
||||
list.addAll(it.sortedWith(compareBy { it.track }))
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
NUMERIC_DOWN -> {
|
||||
val list = mutableListOf<Song>()
|
||||
|
||||
songs.groupBy { it.album }.toSortedMap(compareByDescending { it.year }).values.forEach {
|
||||
list.addAll(it.sortedWith(compareBy { it.track }))
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
|
||||
else -> songs
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/background"
|
||||
android:elevation="@dimen/elevation_normal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -236,5 +236,15 @@
|
|||
<item name="android:layout_marginEnd">@dimen/margin_large</item>
|
||||
<item name="android:scaleType">fitCenter</item>
|
||||
<item name="android:padding">@dimen/padding_play_pause</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Design.BottomNavigationView" parent="">
|
||||
<item name="elevation">@dimen/design_bottom_navigation_elevation</item>
|
||||
<item name="enforceTextAppearance">false</item>
|
||||
<item name="enforceMaterialTheme">false</item>
|
||||
<item name="itemBackground">?attr/selectableItemBackgroundBorderless</item>
|
||||
<item name="itemHorizontalTranslationEnabled">true</item>
|
||||
<item name="itemIconSize">@dimen/design_bottom_navigation_icon_size</item>
|
||||
<item name="labelVisibilityMode">auto</item>
|
||||
</style>
|
||||
</resources>
|
Loading…
Reference in a new issue