start the queue unshuffled from the play buttons

This commit is contained in:
austinried
2026-10-04 00:29:55 +00:00
parent a8f1b30d67
commit 88d0113191
6 changed files with 73 additions and 8 deletions
@@ -86,6 +86,12 @@ private data class ReloadUndo(
override val current: Long? = null override val current: Long? = null
} }
private data class PendingPlay(
val entries: List<QueueEntry>,
val position: Long,
val disableShuffle: Boolean,
)
class PlaybackController( class PlaybackController(
private val sourceRepository: SourceRepository, private val sourceRepository: SourceRepository,
private val queueRepository: QueueRepository, private val queueRepository: QueueRepository,
@@ -98,7 +104,7 @@ class PlaybackController(
private var player: PlayerHandle? = null private var player: PlayerHandle? = null
private var connecting = false private var connecting = false
private var pendingPlay: Pair<List<QueueEntry>, Long>? = null private var pendingPlay: PendingPlay? = null
private var pendingShuffle: QueueEntry? = null private var pendingShuffle: QueueEntry? = null
private var positionJob: Job? = null private var positionJob: Job? = null
private var windowJob: Job? = null private var windowJob: Job? = null
@@ -144,7 +150,7 @@ class PlaybackController(
val shuffle = pendingShuffle val shuffle = pendingShuffle
pendingShuffle = null pendingShuffle = null
when { when {
pending != null -> start(pending.first, pending.second) pending != null -> start(pending.entries, pending.position, pending.disableShuffle)
shuffle != null -> startShuffled(shuffle) shuffle != null -> startShuffled(shuffle)
else -> restore() else -> restore()
} }
@@ -170,6 +176,16 @@ class PlaybackController(
startPosition: Long, startPosition: Long,
) = play(listOf(queueRepository.playlistEntry(sourceId, playlistId)), startPosition) ) = play(listOf(queueRepository.playlistEntry(sourceId, playlistId)), startPosition)
fun playAlbumInOrder(
sourceId: Long,
albumId: String,
) = play(listOf(queueRepository.albumEntry(sourceId, albumId)), 0, disableShuffle = true)
fun playPlaylistInOrder(
sourceId: Long,
playlistId: String,
) = play(listOf(queueRepository.playlistEntry(sourceId, playlistId)), 0, disableShuffle = true)
fun playSongs( fun playSongs(
sourceId: Long, sourceId: Long,
startPosition: Long, startPosition: Long,
@@ -551,18 +567,20 @@ class PlaybackController(
private fun play( private fun play(
entries: List<QueueEntry>, entries: List<QueueEntry>,
startPosition: Long, startPosition: Long,
disableShuffle: Boolean = false,
) { ) {
if (player == null) { if (player == null) {
pendingPlay = entries to startPosition pendingPlay = PendingPlay(entries, startPosition, disableShuffle)
connect() connect()
return return
} }
scope.launch { start(entries, startPosition) } scope.launch { start(entries, startPosition, disableShuffle) }
} }
private suspend fun start( private suspend fun start(
entries: List<QueueEntry>, entries: List<QueueEntry>,
startPosition: Long, startPosition: Long,
disableShuffle: Boolean = false,
) = startLock.withLock { ) = startLock.withLock {
windowJob?.cancel() windowJob?.cancel()
windowStart = 0 windowStart = 0
@@ -572,7 +590,7 @@ class PlaybackController(
lastEdit = null lastEdit = null
endedHandled = false endedHandled = false
val modes = queueRepository.modes() val modes = queueRepository.modes()
shuffleEnabled = modes.shuffle shuffleEnabled = !disableShuffle && modes.shuffle
repeatMode = modes.repeat.toRepeatMode() repeatMode = modes.repeat.toRepeatMode()
player?.setRepeatOne(repeatMode == RepeatMode.One) player?.setRepeatOne(repeatMode == RepeatMode.One)
queueRepository.replace(entries) queueRepository.replace(entries)
@@ -44,6 +44,7 @@ fun AlbumDetailRoute(
onBack = onBack, onBack = onBack,
onSongClick = viewModel::play, onSongClick = viewModel::play,
onShuffle = viewModel::shuffle, onShuffle = viewModel::shuffle,
onPlay = viewModel::playAll,
playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Album && context.refId == albumId }, playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Album && context.refId == albumId },
) )
} }
@@ -56,8 +57,9 @@ fun AlbumDetailScreen(
artwork: ArtworkColors?, artwork: ArtworkColors?,
onBack: () -> Unit, onBack: () -> Unit,
onSongClick: (Int) -> Unit, onSongClick: (Int) -> Unit,
onDownload: () -> Unit = {},
onShuffle: () -> Unit = {}, onShuffle: () -> Unit = {},
onPlay: () -> Unit = { onSongClick(0) },
onDownload: () -> Unit = {},
onMore: () -> Unit = {}, onMore: () -> Unit = {},
playingSongId: String? = null, playingSongId: String? = null,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@@ -77,7 +79,7 @@ fun AlbumDetailScreen(
album?.year?.takeIf { it > 0 }?.toString(), album?.year?.takeIf { it > 0 }?.toString(),
).joinToString(" $DOT "), ).joinToString(" $DOT "),
hasSongs = songs.isNotEmpty(), hasSongs = songs.isNotEmpty(),
onPlay = { onSongClick(0) }, onPlay = onPlay,
onShuffle = onShuffle, onShuffle = onShuffle,
onDownload = onDownload, onDownload = onDownload,
onMore = onMore, onMore = onMore,
@@ -39,6 +39,12 @@ class AlbumDetailViewModel(
} }
} }
fun playAll() {
viewModelScope.launch {
playbackController.playAlbumInOrder(sourceId.first(), albumId)
}
}
fun shuffle() { fun shuffle() {
viewModelScope.launch { viewModelScope.launch {
playbackController.shuffleAlbum(sourceId.first(), albumId) playbackController.shuffleAlbum(sourceId.first(), albumId)
@@ -42,6 +42,7 @@ fun PlaylistDetailRoute(
onBack = onBack, onBack = onBack,
onSongClick = viewModel::play, onSongClick = viewModel::play,
onShuffle = viewModel::shuffle, onShuffle = viewModel::shuffle,
onPlay = viewModel::playAll,
playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Playlist && context.refId == playlistId }, playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Playlist && context.refId == playlistId },
) )
} }
@@ -55,6 +56,7 @@ fun PlaylistDetailScreen(
onBack: () -> Unit, onBack: () -> Unit,
onSongClick: (Int) -> Unit, onSongClick: (Int) -> Unit,
onShuffle: () -> Unit = {}, onShuffle: () -> Unit = {},
onPlay: () -> Unit = { onSongClick(0) },
playingSongId: String? = null, playingSongId: String? = null,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@@ -70,7 +72,7 @@ fun PlaylistDetailScreen(
subtitle = playlistSummary(playlist), subtitle = playlistSummary(playlist),
comment = playlist?.comment, comment = playlist?.comment,
hasSongs = songs.itemCount > 0, hasSongs = songs.itemCount > 0,
onPlay = { onSongClick(0) }, onPlay = onPlay,
onShuffle = onShuffle, onShuffle = onShuffle,
onDownload = {}, onDownload = {},
onMore = {}, onMore = {},
@@ -44,6 +44,12 @@ class PlaylistDetailViewModel(
} }
} }
fun playAll() {
viewModelScope.launch {
playbackController.playPlaylistInOrder(sourceId.first(), playlistId)
}
}
fun shuffle() { fun shuffle() {
viewModelScope.launch { viewModelScope.launch {
playbackController.shufflePlaylist(sourceId.first(), playlistId) playbackController.shufflePlaylist(sourceId.first(), playlistId)
@@ -874,6 +874,37 @@ class PlaybackControllerTest {
) )
} }
@Test
fun playInOrderTurnsOffShuffle() {
seedAlbum(3, sourceId = 1)
controller.shuffleAlbum(1, "al1")
await { controller.state.value.shuffle }
controller.playAlbumInOrder(1, "al1")
await { !controller.state.value.shuffle }
assertEquals(
"s1",
controller.state.value.item
?.id,
)
assertEquals(0L, controller.state.value.position)
}
@Test
fun shufflePlayOnASingleTrackAlbumPlaysIt() {
seedAlbum(1, sourceId = 1)
controller.shuffleAlbum(1, "al1")
await {
controller.state.value.item
?.id == "s1"
}
assertTrue(controller.state.value.shuffle)
}
private fun seedAlbum( private fun seedAlbum(
count: Int, count: Int,
sourceId: Long, sourceId: Long,