From db588875678f3700390b0a1bc79be2fdc70816f5 Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Thu, 24 Sep 2026 13:54:28 +0000 Subject: [PATCH] load the queue around the current track and scroll to it --- .../com/subtracks/ui/playback/QueueScreen.kt | 10 ++++++++- .../ui/playback/QueueViewModelTest.kt | 22 ++++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt b/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt index fb9a6e75..41b46f82 100644 --- a/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt @@ -66,6 +66,7 @@ import sh.calvin.reorderable.ReorderableItem import sh.calvin.reorderable.rememberReorderableLazyListState private const val LOAD_THRESHOLD = 5 +private const val OLDER_LOAD = 30 private const val POSITION_TIMEOUT_MS = 1_000L data class QueueRow( @@ -83,6 +84,9 @@ class QueueViewModel( var ready by mutableStateOf(false) private set + var initialIndex by mutableStateOf(0) + private set + private var nextId = 0L private val mutex = Mutex() private var size = 0L @@ -104,11 +108,12 @@ class QueueViewModel( withTimeoutOrNull(POSITION_TIMEOUT_MS) { playbackController.state.first { it.position != null }.position }?.coerceIn(0, size - 1) ?: 0L - val start = cursor + val start = (cursor - OLDER_LOAD).coerceAtLeast(0) val end = (start + QUEUE_CHUNK - 1).coerceAtMost(size - 1) rows.addAll(queueRepository.range(snapshot, start, end).map(::newRow)) first = rows.firstOrNull()?.position ?: 0 last = rows.lastOrNull()?.position ?: -1 + initialIndex = (cursor - first).toInt().coerceAtLeast(0) } ready = true } @@ -254,6 +259,7 @@ fun QueueRoute( QueueScreen( rows = viewModel.rows, ready = viewModel.ready, + initialIndex = viewModel.initialIndex, currentSongId = playback.item?.id, coverArt = sourceRepository::coverArt, onBack = onBack, @@ -284,6 +290,7 @@ fun QueueScreen( onLoadNewer: () -> Unit, onUndo: () -> Unit, modifier: Modifier = Modifier, + initialIndex: Int = 0, ) { val listState = rememberLazyListState() val fill = rememberViewportFill(listState) @@ -299,6 +306,7 @@ fun QueueScreen( LaunchedEffect(listState, ready) { if (!ready) return@LaunchedEffect + if (initialIndex > 0) listState.scrollToItem(initialIndex) snapshotFlow { val info = listState.layoutInfo val firstVisible = info.visibleItemsInfo.firstOrNull()?.index ?: -1 diff --git a/app/src/test/kotlin/com/subtracks/ui/playback/QueueViewModelTest.kt b/app/src/test/kotlin/com/subtracks/ui/playback/QueueViewModelTest.kt index ce9c8398..48ad0783 100644 --- a/app/src/test/kotlin/com/subtracks/ui/playback/QueueViewModelTest.kt +++ b/app/src/test/kotlin/com/subtracks/ui/playback/QueueViewModelTest.kt @@ -72,19 +72,20 @@ class QueueViewModelTest { viewModel.open() await { viewModel.ready } - assertEquals((100L..159L).toList(), viewModel.rows.map { it.position }) + assertEquals((70L..129L).toList(), viewModel.rows.map { it.position }) + assertEquals(30, viewModel.initialIndex) viewModel.loadNewer() - await { viewModel.rows.lastOrNull()?.position == 199L } - assertEquals((100L..199L).toList(), viewModel.rows.map { it.position }) + await { viewModel.rows.lastOrNull()?.position == 189L } + assertEquals((70L..189L).toList(), viewModel.rows.map { it.position }) viewModel.loadOlder() - await { viewModel.rows.firstOrNull()?.position == 40L } - assertEquals((40L..199L).toList(), viewModel.rows.map { it.position }) + await { viewModel.rows.firstOrNull()?.position == 10L } + assertEquals((10L..189L).toList(), viewModel.rows.map { it.position }) } @Test - fun openingAtTheEndLoadsASingleRowAndExtendsOlder() { + fun openingAtTheEndLoadsAWindowAndExtendsOlder() { runBlocking { seedSongs(200) } controller.playSongs(1, 199) await { controller.state.value.position == 199L } @@ -92,11 +93,12 @@ class QueueViewModelTest { viewModel.open() await { viewModel.ready } - assertEquals(listOf(199L), viewModel.rows.map { it.position }) + assertEquals((169L..199L).toList(), viewModel.rows.map { it.position }) + assertEquals(30, viewModel.initialIndex) viewModel.loadOlder() - await { viewModel.rows.firstOrNull()?.position == 139L } - assertEquals((139L..199L).toList(), viewModel.rows.map { it.position }) + await { viewModel.rows.firstOrNull()?.position == 109L } + assertEquals((109L..199L).toList(), viewModel.rows.map { it.position }) } @Test @@ -118,7 +120,7 @@ class QueueViewModelTest { viewModel.reorder(fromIndex = 0, toIndex = 2) val positions = viewModel.rows.map { it.position } - assertEquals(listOf(101L, 102L, 100L), positions.take(3)) + assertEquals(listOf(71L, 72L, 70L), positions.take(3)) } private fun row(position: Int) =