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
}
private data class PendingPlay(
val entries: List<QueueEntry>,
val position: Long,
val disableShuffle: Boolean,
)
class PlaybackController(
private val sourceRepository: SourceRepository,
private val queueRepository: QueueRepository,
@@ -98,7 +104,7 @@ class PlaybackController(
private var player: PlayerHandle? = null
private var connecting = false
private var pendingPlay: Pair<List<QueueEntry>, Long>? = null
private var pendingPlay: PendingPlay? = null
private var pendingShuffle: QueueEntry? = null
private var positionJob: Job? = null
private var windowJob: Job? = null
@@ -144,7 +150,7 @@ class PlaybackController(
val shuffle = pendingShuffle
pendingShuffle = null
when {
pending != null -> start(pending.first, pending.second)
pending != null -> start(pending.entries, pending.position, pending.disableShuffle)
shuffle != null -> startShuffled(shuffle)
else -> restore()
}
@@ -170,6 +176,16 @@ class PlaybackController(
startPosition: Long,
) = 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(
sourceId: Long,
startPosition: Long,
@@ -551,18 +567,20 @@ class PlaybackController(
private fun play(
entries: List<QueueEntry>,
startPosition: Long,
disableShuffle: Boolean = false,
) {
if (player == null) {
pendingPlay = entries to startPosition
pendingPlay = PendingPlay(entries, startPosition, disableShuffle)
connect()
return
}
scope.launch { start(entries, startPosition) }
scope.launch { start(entries, startPosition, disableShuffle) }
}
private suspend fun start(
entries: List<QueueEntry>,
startPosition: Long,
disableShuffle: Boolean = false,
) = startLock.withLock {
windowJob?.cancel()
windowStart = 0
@@ -572,7 +590,7 @@ class PlaybackController(
lastEdit = null
endedHandled = false
val modes = queueRepository.modes()
shuffleEnabled = modes.shuffle
shuffleEnabled = !disableShuffle && modes.shuffle
repeatMode = modes.repeat.toRepeatMode()
player?.setRepeatOne(repeatMode == RepeatMode.One)
queueRepository.replace(entries)
@@ -44,6 +44,7 @@ fun AlbumDetailRoute(
onBack = onBack,
onSongClick = viewModel::play,
onShuffle = viewModel::shuffle,
onPlay = viewModel::playAll,
playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Album && context.refId == albumId },
)
}
@@ -56,8 +57,9 @@ fun AlbumDetailScreen(
artwork: ArtworkColors?,
onBack: () -> Unit,
onSongClick: (Int) -> Unit,
onDownload: () -> Unit = {},
onShuffle: () -> Unit = {},
onPlay: () -> Unit = { onSongClick(0) },
onDownload: () -> Unit = {},
onMore: () -> Unit = {},
playingSongId: String? = null,
modifier: Modifier = Modifier,
@@ -77,7 +79,7 @@ fun AlbumDetailScreen(
album?.year?.takeIf { it > 0 }?.toString(),
).joinToString(" $DOT "),
hasSongs = songs.isNotEmpty(),
onPlay = { onSongClick(0) },
onPlay = onPlay,
onShuffle = onShuffle,
onDownload = onDownload,
onMore = onMore,
@@ -39,6 +39,12 @@ class AlbumDetailViewModel(
}
}
fun playAll() {
viewModelScope.launch {
playbackController.playAlbumInOrder(sourceId.first(), albumId)
}
}
fun shuffle() {
viewModelScope.launch {
playbackController.shuffleAlbum(sourceId.first(), albumId)
@@ -42,6 +42,7 @@ fun PlaylistDetailRoute(
onBack = onBack,
onSongClick = viewModel::play,
onShuffle = viewModel::shuffle,
onPlay = viewModel::playAll,
playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Playlist && context.refId == playlistId },
)
}
@@ -55,6 +56,7 @@ fun PlaylistDetailScreen(
onBack: () -> Unit,
onSongClick: (Int) -> Unit,
onShuffle: () -> Unit = {},
onPlay: () -> Unit = { onSongClick(0) },
playingSongId: String? = null,
modifier: Modifier = Modifier,
) {
@@ -70,7 +72,7 @@ fun PlaylistDetailScreen(
subtitle = playlistSummary(playlist),
comment = playlist?.comment,
hasSongs = songs.itemCount > 0,
onPlay = { onSongClick(0) },
onPlay = onPlay,
onShuffle = onShuffle,
onDownload = {},
onMore = {},
@@ -44,6 +44,12 @@ class PlaylistDetailViewModel(
}
}
fun playAll() {
viewModelScope.launch {
playbackController.playPlaylistInOrder(sourceId.first(), playlistId)
}
}
fun shuffle() {
viewModelScope.launch {
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(
count: Int,
sourceId: Long,