diff --git a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt index 73a14d6f..f4f281f0 100644 --- a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt +++ b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt @@ -86,6 +86,12 @@ private data class ReloadUndo( override val current: Long? = null } +private data class PendingPlay( + val entries: List, + 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, 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, 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, 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) diff --git a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt index 2fcc6213..e7cfa82a 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt @@ -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, diff --git a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailViewModel.kt b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailViewModel.kt index 4fb2411c..4e1970cd 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailViewModel.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailViewModel.kt @@ -39,6 +39,12 @@ class AlbumDetailViewModel( } } + fun playAll() { + viewModelScope.launch { + playbackController.playAlbumInOrder(sourceId.first(), albumId) + } + } + fun shuffle() { viewModelScope.launch { playbackController.shuffleAlbum(sourceId.first(), albumId) diff --git a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt index 6a767430..06770828 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt @@ -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 = {}, diff --git a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailViewModel.kt b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailViewModel.kt index 2c6e60be..c160d9a0 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailViewModel.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailViewModel.kt @@ -44,6 +44,12 @@ class PlaylistDetailViewModel( } } + fun playAll() { + viewModelScope.launch { + playbackController.playPlaylistInOrder(sourceId.first(), playlistId) + } + } + fun shuffle() { viewModelScope.launch { playbackController.shufflePlaylist(sourceId.first(), playlistId) diff --git a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt index e82d1300..52460581 100644 --- a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt +++ b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt @@ -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,