From d5c100903b6e8b188fe53ad13f45c9c9fdc8d491 Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Tue, 22 Sep 2026 11:05:47 +0800 Subject: [PATCH] fix(mutual,passes): map Match prefill opens at time-range card; whats-new dialog scrollable - Match prefill now positions the LazyColumn via its initial state (queryMutualPasses(initialScrollIndex = 1)) instead of a post-layout scrollToItem, so the page reliably opens with the time-range card at the top while the 24h query runs. - The install-time what's new dialog text now scrolls inside a bounded box (max 360dp) instead of overflowing the fixed dialog frame. --- .../look4sat/feature/mutual/MutualScreen.kt | 11 ------- .../feature/mutual/MutualViewModel.kt | 30 ++++++++----------- .../look4sat/feature/passes/PassesScreen.kt | 10 ++++++- 3 files changed, 21 insertions(+), 30 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 7257fe44..da4aa5f9 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,17 +369,6 @@ private fun MutualContent( ) } } - - // Prefill from the map's grid-QSO dialog "Match" button: 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). - 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 8f261746..90c054be 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,11 +55,7 @@ data class MutualUiState( val hasSearched: Boolean = false, val selectedPassIndex: Int = -1, val isUtc: Boolean = false, - val errorMessage: String? = null, - // One-shot flag set by prefillMatchFromGrid() (map grid → Match button): - // the page scrolls to the time-range card, then consumeScrollToTimeRange() - // clears it. - val scrollToTimeRange: Boolean = false + val errorMessage: String? = null ) class MutualViewModel( @@ -190,9 +186,10 @@ 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, flag the page to scroll - * straight to the time-range card, and start the query immediately so - * results are ready when the page opens. + * 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. */ fun prefillMatchFromGrid(grid: String) { val g = grid.trim().uppercase() @@ -202,18 +199,13 @@ 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, - scrollToTimeRange = true + hoursAhead = 24 ) } - queryMutualPasses() + queryMutualPasses(initialScrollIndex = 1) } - fun consumeScrollToTimeRange() { - _uiState.update { it.copy(scrollToTimeRange = false) } - } - - fun queryMutualPasses() { + fun queryMutualPasses(initialScrollIndex: Int = 0) { val state = _uiState.value // Resolve positions from lat/lon or grid @@ -241,8 +233,10 @@ class MutualViewModel( ) } // The results list is about to be replaced, so the scroll position must - // not leak from the previous query's list. - listScrollIndex = 0 + // not leak from the previous query's list. A prefill from the map + // (grid-QSO dialog "Match" button) instead starts at the time-range + // card so the page opens with it at the top. + listScrollIndex = initialScrollIndex listScrollOffset = 0 queryGeneration += 1 diff --git a/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesScreen.kt b/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesScreen.kt index b3449f41..7a66b6ad 100644 --- a/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesScreen.kt +++ b/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesScreen.kt @@ -30,12 +30,15 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider @@ -145,11 +148,16 @@ private fun PassesScreen( onAccept = dismiss, titleFontSize = 18 ) { padding -> + // The changelog is long; keep the dialog frame fixed and let the + // text scroll inside it (matches the update-checker page pattern). Text( text = stringResource(R.string.pass_whatsnew_message), fontSize = 16.sp, color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.padding(horizontal = padding) + modifier = Modifier + .padding(horizontal = padding) + .heightIn(max = 360.dp) + .verticalScroll(rememberScrollState()) ) } }