mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
start the queue unshuffled from the play buttons
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user