From 2aa9858660854ce3e6641ed7b913438a189527bc Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Fri, 28 Aug 2026 00:42:00 +0800 Subject: [PATCH] feat: open map from radar header Replace the radar page calendar action with the map icon and route the action through the Passes map flow so the Passes navigation item remains selected. --- .../java/com/rtbishop/look4sat/MainScreen.kt | 30 +++++++++++++++++-- .../look4sat/feature/radar/RadarScreen.kt | 18 ++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt b/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt index 23013615..10b58db2 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt @@ -51,6 +51,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -91,11 +94,16 @@ import com.rtbishop.look4sat.feature.status.SatStatusDestination fun NavRoot(deeplink: String? = null) { val rootBackStack = rememberNavBackStack(Screen.Passes) val deeplinkResolver = DeeplinkResolver() + var openMapRequest by remember { mutableIntStateOf(0) } LaunchedEffect(deeplink) { deeplink?.let { rootBackStack.add(deeplinkResolver.resolve(it)) } } val navigateBack: () -> Unit = { rootBackStack.removeLastOrNull() } val navigateToRadar: () -> Unit = { rootBackStack.add(RadarDestination) } + val navigateToMap: () -> Unit = { + while (rootBackStack.size > 1) rootBackStack.removeAt(rootBackStack.size - 1) + openMapRequest += 1 + } // Incoming screen slides in from the right, outgoing drifts left at 1/3 speed (API35+ style) val pushTransition = slideInHorizontally(tween(300)) { it } togetherWith slideOutHorizontally(tween(300)) { -it / 3 } @@ -114,13 +122,19 @@ fun NavRoot(deeplink: String? = null) { rememberViewModelStoreNavEntryDecorator() ), entryProvider = entryProvider { - entry { MainScreen(navigateToRadar = navigateToRadar) } + entry { + MainScreen( + navigateToRadar = navigateToRadar, + openMapRequest = openMapRequest, + onOpenMapRequestHandled = { openMapRequest = 0 } + ) + } entry { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - RadarDestination(navigateUp = navigateBack) + RadarDestination(navigateUp = navigateBack, navigateToMap = navigateToMap) } } } @@ -128,7 +142,11 @@ fun NavRoot(deeplink: String? = null) { } @Composable -fun MainScreen(navigateToRadar: () -> Unit = {}) { +fun MainScreen( + navigateToRadar: () -> Unit = {}, + openMapRequest: Int = 0, + onOpenMapRequestHandled: () -> Unit = {} +) { val backStack = rememberNavBackStack(Screen.Passes) val currentKey = backStack.lastOrNull() val navigateBack: () -> Unit = { backStack.removeLastOrNull() } @@ -136,6 +154,12 @@ fun MainScreen(navigateToRadar: () -> Unit = {}) { while (backStack.size > 1) backStack.removeAt(backStack.size - 1) backStack.add(Screen.Map) } + LaunchedEffect(openMapRequest) { + if (openMapRequest > 0) { + navigateToMap() + onOpenMapRequestHandled() + } + } val fadeTransition = fadeIn(animationSpec = tween(350)) togetherWith fadeOut(animationSpec = tween(350)) val navItems = listOf(Screen.Satellites, Screen.Passes, Screen.AMSAT, Screen.Mutual, Screen.Settings) diff --git a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt index b0d3281b..fb1223cb 100644 --- a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt +++ b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt @@ -84,7 +84,7 @@ private enum class RadarPage(val title: String) { } @Composable -fun RadarDestination(navigateUp: () -> Unit) { +fun RadarDestination(navigateUp: () -> Unit, navigateToMap: () -> Unit) { val context = LocalContext.current val container = (context.applicationContext as IContainerProvider).getMainContainer() val viewModel: RadarViewModel = viewModel(factory = RadarViewModel.factory(container)) @@ -96,6 +96,12 @@ fun RadarDestination(navigateUp: () -> Unit) { } navigateUp() } + val navigateToMapAndClearMutual = { + if (container.mutualPassData.value.endTime > 0L) { + container.setMutualPassData(MutualPassData()) + } + navigateToMap() + } LaunchedEffect(mutualData.endTime) { if (mutualData.endTime <= 0L) return@LaunchedEffect while (true) { @@ -121,7 +127,7 @@ fun RadarDestination(navigateUp: () -> Unit) { viewModel.onAction(RadarAction.SstvPermissionResult(granted)) viewModel.onAction(RadarAction.CwPermissionResult(granted)) } - RadarScreen(uiState, viewModel::onAction, navigateUpAndClearMutual, mutualData, requestMicPermission = { + RadarScreen(uiState, viewModel::onAction, navigateUpAndClearMutual, navigateToMapAndClearMutual, mutualData, requestMicPermission = { permissionLauncher.launch(Manifest.permission.RECORD_AUDIO) }) } @@ -131,13 +137,11 @@ private fun RadarScreen( uiState: RadarState, onAction: (RadarAction) -> Unit, navigateUp: () -> Unit, + navigateToMap: () -> Unit, mutualData: MutualPassData, requestMicPermission: () -> Unit ) { val upcomingPass = uiState.currentPass ?: getDefaultPass() - val addToCalendar: () -> Unit = { - uiState.currentPass?.let { onAction(RadarAction.AddToCalendar(it.name, it.aosTime, it.losTime)) } - } // Station-B overlay: full track line (only where B's elevation > 0) + live position dot // at the current moment, same display mode as the local station. val trackB = remember(mutualData.trackSamples) { @@ -173,7 +177,7 @@ private fun RadarScreen( TopBar { IconCard(action = navigateUp, resId = R.drawable.ic_back) TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isTimeAos) - IconCard(action = addToCalendar, resId = R.drawable.ic_calendar) + IconCard(action = navigateToMap, resId = R.drawable.ic_map) } TopBar { NextPassRow(pass = upcomingPass, isUtc = uiState.isUtc) } } else { @@ -181,7 +185,7 @@ private fun RadarScreen( IconCard(action = navigateUp, resId = R.drawable.ic_back) TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isTimeAos) NextPassRow(pass = upcomingPass, modifier = Modifier.weight(1f), isUtc = uiState.isUtc) - IconCard(action = addToCalendar, resId = R.drawable.ic_calendar) + IconCard(action = navigateToMap, resId = R.drawable.ic_map) } } if (isVertical) {