diff --git a/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt b/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt index 7cb5b744..c5a246bc 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainScreen.kt @@ -51,7 +51,6 @@ 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 @@ -94,16 +93,11 @@ 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 } @@ -124,9 +118,7 @@ fun NavRoot(deeplink: String? = null) { entryProvider = entryProvider { entry { MainScreen( - navigateToRadar = navigateToRadar, - openMapRequest = openMapRequest, - onOpenMapRequestHandled = { openMapRequest = 0 } + navigateToRadar = navigateToRadar ) } entry { @@ -134,7 +126,7 @@ fun NavRoot(deeplink: String? = null) { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - RadarDestination(navigateUp = navigateBack, navigateToMap = navigateToMap) + RadarDestination(navigateUp = navigateBack) } } } @@ -143,23 +135,11 @@ fun NavRoot(deeplink: String? = null) { @Composable fun MainScreen( - navigateToRadar: () -> Unit = {}, - openMapRequest: Int = 0, - onOpenMapRequestHandled: () -> Unit = {} + navigateToRadar: () -> Unit = {} ) { val backStack = rememberNavBackStack(Screen.Passes) val currentKey = backStack.lastOrNull() val navigateBack: () -> Unit = { backStack.removeLastOrNull() } - val navigateToMap: () -> 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)) // Map sits at position 4 from the left, matching the upstream nav order // (Satellites, Passes, AMSAT/Status, Map, ...), with the fork's Mutual tab 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 ace6618e..1155cf19 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 @@ -156,7 +156,7 @@ private fun PassesScreen( TopBar( isVerticalLayout = isVerticalLayout, startAction = { - IconCard(action = { onAction(PassesAction.ToggleRadiosDialog) }, resId = R.drawable.ic_radios) + IconCard(action = { onAction(PassesAction.TogglePassesDialog) }, resId = R.drawable.ic_filter) }, topInfo = { TimerRow(timeString = uiState.nextTime, isTimeAos = uiState.isNextTimeAos) @@ -165,7 +165,19 @@ private fun PassesScreen( NextPassRow(pass = uiState.nextPass, isUtc = uiState.isUtc) }, endAction = { - IconCard(action = { onAction(PassesAction.TogglePassesDialog) }, resId = R.drawable.ic_filter) + // 日程功能: 把下个过境写入系统日历 (原仓库雷达页的 addToCalendar). + IconCard( + action = { + onAction( + PassesAction.AddToCalendar( + uiState.nextPass.name, + uiState.nextPass.aosTime, + uiState.nextPass.losTime + ) + ) + }, + resId = R.drawable.ic_calendar + ) } ) } diff --git a/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesState.kt b/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesState.kt index 3aef6726..85c7ccc7 100644 --- a/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesState.kt +++ b/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesState.kt @@ -61,4 +61,6 @@ sealed interface PassesAction { data object ToggleRadiosDialog : PassesAction data class FocusCatNum(val catNum: Int) : PassesAction data object ClearFocus : PassesAction + /** 日程功能: 把下个过境写入系统日历 (ic_calendar 按钮). */ + data class AddToCalendar(val name: String, val aosTime: Long, val losTime: Long) : PassesAction } diff --git a/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesViewModel.kt b/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesViewModel.kt index e7468801..a0f78fc7 100644 --- a/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesViewModel.kt +++ b/feature/passes/src/main/java/com/rtbishop/look4sat/feature/passes/PassesViewModel.kt @@ -28,6 +28,7 @@ import com.rtbishop.look4sat.core.domain.predict.OrbitalPass import com.rtbishop.look4sat.core.domain.repository.IMainContainer import com.rtbishop.look4sat.core.domain.repository.ISatelliteRepo import com.rtbishop.look4sat.core.domain.repository.ISettingsRepo +import com.rtbishop.look4sat.core.domain.usecase.IAddToCalendar import com.rtbishop.look4sat.core.domain.utility.round import com.rtbishop.look4sat.core.domain.utility.toTimerString import com.rtbishop.look4sat.core.presentation.getDefaultPass @@ -46,7 +47,8 @@ import java.util.TimeZone class PassesViewModel( private val satelliteRepo: ISatelliteRepo, - private val settingsRepo: ISettingsRepo + private val settingsRepo: ISettingsRepo, + private val addToCalendar: IAddToCalendar ) : ViewModel() { private val defaultPass = getDefaultPass() @@ -151,6 +153,8 @@ class PassesViewModel( _uiState.update { it.copy(isRadiosDialogShown = !it.isRadiosDialogShown) } is PassesAction.FocusCatNum -> _uiState.update { it.copy(focusedCatNum = action.catNum) } PassesAction.ClearFocus -> _uiState.update { it.copy(focusedCatNum = null) } + is PassesAction.AddToCalendar -> + addToCalendar(action.name, action.aosTime, action.losTime) } } @@ -345,7 +349,8 @@ class PassesViewModel( initializer { PassesViewModel( satelliteRepo = container.satelliteRepo, - settingsRepo = container.settingsRepo + settingsRepo = container.settingsRepo, + addToCalendar = container.provideAddToCalendar() ) } } 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 fb1223cb..2e9f8224 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, navigateToMap: () -> Unit) { +fun RadarDestination(navigateUp: () -> Unit) { val context = LocalContext.current val container = (context.applicationContext as IContainerProvider).getMainContainer() val viewModel: RadarViewModel = viewModel(factory = RadarViewModel.factory(container)) @@ -96,12 +96,6 @@ fun RadarDestination(navigateUp: () -> Unit, navigateToMap: () -> 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) { @@ -127,7 +121,7 @@ fun RadarDestination(navigateUp: () -> Unit, navigateToMap: () -> Unit) { viewModel.onAction(RadarAction.SstvPermissionResult(granted)) viewModel.onAction(RadarAction.CwPermissionResult(granted)) } - RadarScreen(uiState, viewModel::onAction, navigateUpAndClearMutual, navigateToMapAndClearMutual, mutualData, requestMicPermission = { + RadarScreen(uiState, viewModel::onAction, navigateUpAndClearMutual, mutualData, requestMicPermission = { permissionLauncher.launch(Manifest.permission.RECORD_AUDIO) }) } @@ -137,11 +131,14 @@ private fun RadarScreen( uiState: RadarState, onAction: (RadarAction) -> Unit, navigateUp: () -> Unit, - navigateToMap: () -> Unit, mutualData: MutualPassData, requestMicPermission: () -> Unit ) { val upcomingPass = uiState.currentPass ?: getDefaultPass() + // 日程功能: 把当前过境写入系统日历(原仓库的 addToCalendar, ic_calendar 按钮) + 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) { @@ -177,7 +174,7 @@ private fun RadarScreen( TopBar { IconCard(action = navigateUp, resId = R.drawable.ic_back) TimerRow(timeString = uiState.currentTime, isTimeAos = uiState.isTimeAos) - IconCard(action = navigateToMap, resId = R.drawable.ic_map) + IconCard(action = addToCalendar, resId = R.drawable.ic_calendar) } TopBar { NextPassRow(pass = upcomingPass, isUtc = uiState.isUtc) } } else { @@ -185,7 +182,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 = navigateToMap, resId = R.drawable.ic_map) + IconCard(action = addToCalendar, resId = R.drawable.ic_calendar) } } if (isVertical) {