From 466f2f60887bc5d7b5d33f791dc07768c98c62d4 Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Tue, 22 Sep 2026 12:23:50 +0800 Subject: [PATCH] fix(mutual): map Match prefill scrolls to time-range card via scrollToItem Compose ui 1.11.x (BOM 2026.06.01) ignores the LazyListState firstVisibleItemIndex constructor parameter - the list always starts at item 0. Restore the scrollToItem approach (verified effective by Robolectric Compose UI tests) and keep the auto-started query. --- .../look4sat/feature/mutual/MutualScreen.kt | 14 +++++++++++++ .../feature/mutual/MutualViewModel.kt | 20 +++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualScreen.kt b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualScreen.kt index da4aa5f9..19ccc658 100644 --- a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualScreen.kt +++ b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualScreen.kt @@ -369,6 +369,20 @@ private fun MutualContent( ) } } + + // Prefill from the map's grid-QSO dialog "Match" button: once the page is + // laid out, jump straight to the time-range card. Index accounts for the + // optional error card at the top (error = 0, station inputs = 1, time + // range = 2; else 1). scrollToItem is used instead of initializing the + // LazyListState at index 1: the constructor parameter is ignored by this + // Compose version (verified in tests), while scrollToItem lands correctly. + val matchSearchIndex = if (state.errorMessage != null) 2 else 1 + LaunchedEffect(state.scrollToTimeRange, matchSearchIndex) { + if (state.scrollToTimeRange) { + listState.scrollToItem(matchSearchIndex) + viewModel.consumeScrollToTimeRange() + } + } } @Composable diff --git a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt index 90c054be..71e95434 100644 --- a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt +++ b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt @@ -55,7 +55,11 @@ data class MutualUiState( val hasSearched: Boolean = false, val selectedPassIndex: Int = -1, val isUtc: Boolean = false, - val errorMessage: String? = null + val errorMessage: String? = null, + // One-shot flag set by prefillMatchFromGrid() (map grid → Match button): + // the page scrolls to the time-range card after the first layout, then + // consumeScrollToTimeRange() clears it. + val scrollToTimeRange: Boolean = false ) class MutualViewModel( @@ -187,9 +191,8 @@ class MutualViewModel( * Pre-fill the match page for a target grid picked from the map's grid-QSO * dialog ("Match" button): set the opposite-station grid (with its * coordinates), reset the time range to 24h, start the query immediately - * so results are ready when the page opens, and position the list at the - * time-range card (LazyColumn item 1, the card right below the station - * inputs) so the page opens showing it at the top. + * so results are ready when the page opens, and flag the page to scroll + * straight to the time-range card once it is laid out. */ fun prefillMatchFromGrid(grid: String) { val g = grid.trim().uppercase() @@ -199,10 +202,15 @@ class MutualViewModel( stationBGrid = g, stationBLat = pos?.let { p -> "%.4f".format(p.latitude) } ?: it.stationBLat, stationBLon = pos?.let { p -> "%.4f".format(p.longitude) } ?: it.stationBLon, - hoursAhead = 24 + hoursAhead = 24, + scrollToTimeRange = true ) } - queryMutualPasses(initialScrollIndex = 1) + queryMutualPasses() + } + + fun consumeScrollToTimeRange() { + _uiState.update { it.copy(scrollToTimeRange = false) } } fun queryMutualPasses(initialScrollIndex: Int = 0) {