Loading cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt +63 −61 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ fun DirectionsScreen( // Track pending location request for auto-retry after permission grant var pendingLocationRequest by remember { mutableStateOf<FieldFocusState?>(null) } var pendingNavigationStart by remember { mutableStateOf(false) } // Get route result from ViewModel val routeState = viewModel.routeState Loading @@ -130,6 +131,18 @@ fun DirectionsScreen( appPreferences = appPreferences, onCompletion = { fieldFocusState = FieldFocusState.NONE }) AutoRetryNavigationStart( viewModel = viewModel, navController = navController, hasLocationPermission = hasLocationPermission, hasNotificationPermission = hasNotificationPermission, pendingNavigation = pendingNavigationStart, onRequestLocationPermission = onRequestLocationPermission, onRequestNotificationPermission = onRequestNotificationPermission, onPendingNavigationChange = { pendingNavigationStart = it } ) Loading Loading @@ -167,9 +180,9 @@ fun DirectionsScreen( routeState = routeState, availableProfiles = availableProfiles, appPreferences = appPreferences, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission ) onPendingNavigationChange = { pendingNavigationStart = it }) } } } Loading Loading @@ -208,6 +221,39 @@ private fun AutoRetryMyLocation( } } @Composable private fun AutoRetryNavigationStart( viewModel: DirectionsViewModel, navController: NavController, hasLocationPermission: Boolean, hasNotificationPermission: Boolean, pendingNavigation: Boolean, onRequestLocationPermission: () -> Unit, onRequestNotificationPermission: () -> Unit, onPendingNavigationChange: (Boolean) -> Unit, ) { var showNotificationDialog by remember { mutableStateOf(false) } NotificationRequestDialog( showDialog = showNotificationDialog, onDismiss = { showNotificationDialog = false onPendingNavigationChange(false) }, onConfirm = { showNotificationDialog = false onRequestNotificationPermission() }) LaunchedEffect(hasNotificationPermission, hasLocationPermission, pendingNavigation) { if (pendingNavigation && hasNotificationPermission && hasLocationPermission) { viewModel.startNavigation(navController) } else if (pendingNavigation && !hasNotificationPermission) { showNotificationDialog = true } else if (pendingNavigation) { onRequestLocationPermission() } } } @Composable private fun DirectionsScreenFullUI( viewModel: DirectionsViewModel, Loading @@ -219,8 +265,7 @@ private fun DirectionsScreenFullUI( routeState: RouteState, availableProfiles: List<RoutingProfile>, appPreferences: AppPreferenceRepository, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { val density = androidx.compose.ui.platform.LocalDensity.current Loading Loading @@ -331,8 +376,7 @@ private fun DirectionsScreenFullUI( routeState = routeState, navController = navController, appPreferences = appPreferences, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission onPendingNavigationChange = onPendingNavigationChange, ) } Loading @@ -342,8 +386,7 @@ private fun DirectionsRouteResults( routeState: RouteState, navController: NavController, appPreferences: AppPreferenceRepository, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { val planState = viewModel.planState if (viewModel.selectedRoutingMode == RoutingMode.PUBLIC_TRANSPORT) { Loading @@ -357,10 +400,8 @@ private fun DirectionsRouteResults( NonTransitRouteResults( routeState = routeState, viewModel = viewModel, navController = navController, appPreferences = appPreferences, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission onPendingNavigationChange = onPendingNavigationChange, ) } } Loading Loading @@ -418,10 +459,8 @@ private fun TransitRouteResults( private fun NonTransitRouteResults( routeState: RouteState, viewModel: DirectionsViewModel, navController: NavController, appPreferences: AppPreferenceRepository, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { when { routeState.isLoading -> { Loading @@ -448,12 +487,10 @@ private fun NonTransitRouteResults( ferrostarRoute = routeState.route, viewModel = viewModel, modifier = Modifier.fillMaxWidth(), navController = navController, distanceUnit = appPreferences.distanceUnit.collectAsState().value, availableProfiles = viewModel.getAvailableProfilesForCurrentMode() .collectAsState(initial = emptyList()).value, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission onPendingNavigationChange = onPendingNavigationChange, ) } Loading Loading @@ -581,14 +618,10 @@ private fun QuickSuggestionsContent( onRequestLocationPermission = onRequestLocationPermission, coroutineScope = coroutineScope, onFieldFocusStateChange = onFieldFocusStateChange, ), savedPlaces = savedPlaces, onSavedPlaceSelected = { place -> ), savedPlaces = savedPlaces, onSavedPlaceSelected = { place -> updatePlaceForField(viewModel, fieldFocusState, place) onFieldFocusStateChange(FieldFocusState.NONE) }, isGettingLocation = viewModel.isGettingLocation, modifier = Modifier.fillMaxWidth() }, isGettingLocation = viewModel.isGettingLocation, modifier = Modifier.fillMaxWidth() ) } Loading @@ -610,9 +643,7 @@ private fun SearchResultsContent( } private fun updatePlaceForField( viewModel: DirectionsViewModel, fieldFocusState: FieldFocusState, place: Place viewModel: DirectionsViewModel, fieldFocusState: FieldFocusState, place: Place ) { if (fieldFocusState == FieldFocusState.FROM) { viewModel.updateFromPlace(place) Loading Loading @@ -884,24 +915,13 @@ private fun FerrostarRouteResults( ferrostarRoute: Route, viewModel: DirectionsViewModel, modifier: Modifier = Modifier, navController: NavController, distanceUnit: Int, availableProfiles: List<RoutingProfile>, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { var showProfileDialog by remember { mutableStateOf(false) } var showNotificationDialog by remember { mutableStateOf(false) } var pendingNavigation by remember { mutableStateOf(false) } val selectedProfile = viewModel.selectedRoutingProfile LaunchedEffect(hasNotificationPermission, pendingNavigation) { if (pendingNavigation && hasNotificationPermission) { pendingNavigation = false viewModel.startNavigation(navController) } } LazyColumn(modifier = modifier) { item { Card( Loading Loading @@ -953,11 +973,7 @@ private fun FerrostarRouteResults( Button( onClick = { if (hasNotificationPermission) { viewModel.startNavigation(navController) } else { showNotificationDialog = true } onPendingNavigationChange(true) }, modifier = Modifier.fillMaxWidth(), enabled = true ) { Text(stringResource(string.start_navigation)) Loading Loading @@ -1022,18 +1038,7 @@ private fun FerrostarRouteResults( onProfileSelected = { profile -> viewModel.selectRoutingProfile(profile) showProfileDialog = false } ) NotificationRequestDialog( showDialog = showNotificationDialog, onDismiss = { showNotificationDialog = false }, onConfirm = { showNotificationDialog = false pendingNavigation = true onRequestNotificationPermission() } ) }) } @Composable Loading @@ -1052,8 +1057,7 @@ private fun ProfileSelectionDialog( Column { // Default option TextButton( onClick = { onProfileSelected(null) }, modifier = Modifier.fillMaxWidth() onClick = { onProfileSelected(null) }, modifier = Modifier.fillMaxWidth() ) { Text( text = stringResource(string.default_profile), Loading Loading @@ -1085,9 +1089,7 @@ private fun ProfileSelectionDialog( @Composable private fun NotificationRequestDialog( showDialog: Boolean, onDismiss: () -> Unit, onConfirm: () -> Unit showDialog: Boolean, onDismiss: () -> Unit, onConfirm: () -> Unit ) { if (showDialog) { AlertDialog( Loading Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt +63 −61 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ fun DirectionsScreen( // Track pending location request for auto-retry after permission grant var pendingLocationRequest by remember { mutableStateOf<FieldFocusState?>(null) } var pendingNavigationStart by remember { mutableStateOf(false) } // Get route result from ViewModel val routeState = viewModel.routeState Loading @@ -130,6 +131,18 @@ fun DirectionsScreen( appPreferences = appPreferences, onCompletion = { fieldFocusState = FieldFocusState.NONE }) AutoRetryNavigationStart( viewModel = viewModel, navController = navController, hasLocationPermission = hasLocationPermission, hasNotificationPermission = hasNotificationPermission, pendingNavigation = pendingNavigationStart, onRequestLocationPermission = onRequestLocationPermission, onRequestNotificationPermission = onRequestNotificationPermission, onPendingNavigationChange = { pendingNavigationStart = it } ) Loading Loading @@ -167,9 +180,9 @@ fun DirectionsScreen( routeState = routeState, availableProfiles = availableProfiles, appPreferences = appPreferences, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission ) onPendingNavigationChange = { pendingNavigationStart = it }) } } } Loading Loading @@ -208,6 +221,39 @@ private fun AutoRetryMyLocation( } } @Composable private fun AutoRetryNavigationStart( viewModel: DirectionsViewModel, navController: NavController, hasLocationPermission: Boolean, hasNotificationPermission: Boolean, pendingNavigation: Boolean, onRequestLocationPermission: () -> Unit, onRequestNotificationPermission: () -> Unit, onPendingNavigationChange: (Boolean) -> Unit, ) { var showNotificationDialog by remember { mutableStateOf(false) } NotificationRequestDialog( showDialog = showNotificationDialog, onDismiss = { showNotificationDialog = false onPendingNavigationChange(false) }, onConfirm = { showNotificationDialog = false onRequestNotificationPermission() }) LaunchedEffect(hasNotificationPermission, hasLocationPermission, pendingNavigation) { if (pendingNavigation && hasNotificationPermission && hasLocationPermission) { viewModel.startNavigation(navController) } else if (pendingNavigation && !hasNotificationPermission) { showNotificationDialog = true } else if (pendingNavigation) { onRequestLocationPermission() } } } @Composable private fun DirectionsScreenFullUI( viewModel: DirectionsViewModel, Loading @@ -219,8 +265,7 @@ private fun DirectionsScreenFullUI( routeState: RouteState, availableProfiles: List<RoutingProfile>, appPreferences: AppPreferenceRepository, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { val density = androidx.compose.ui.platform.LocalDensity.current Loading Loading @@ -331,8 +376,7 @@ private fun DirectionsScreenFullUI( routeState = routeState, navController = navController, appPreferences = appPreferences, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission onPendingNavigationChange = onPendingNavigationChange, ) } Loading @@ -342,8 +386,7 @@ private fun DirectionsRouteResults( routeState: RouteState, navController: NavController, appPreferences: AppPreferenceRepository, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { val planState = viewModel.planState if (viewModel.selectedRoutingMode == RoutingMode.PUBLIC_TRANSPORT) { Loading @@ -357,10 +400,8 @@ private fun DirectionsRouteResults( NonTransitRouteResults( routeState = routeState, viewModel = viewModel, navController = navController, appPreferences = appPreferences, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission onPendingNavigationChange = onPendingNavigationChange, ) } } Loading Loading @@ -418,10 +459,8 @@ private fun TransitRouteResults( private fun NonTransitRouteResults( routeState: RouteState, viewModel: DirectionsViewModel, navController: NavController, appPreferences: AppPreferenceRepository, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { when { routeState.isLoading -> { Loading @@ -448,12 +487,10 @@ private fun NonTransitRouteResults( ferrostarRoute = routeState.route, viewModel = viewModel, modifier = Modifier.fillMaxWidth(), navController = navController, distanceUnit = appPreferences.distanceUnit.collectAsState().value, availableProfiles = viewModel.getAvailableProfilesForCurrentMode() .collectAsState(initial = emptyList()).value, hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission onPendingNavigationChange = onPendingNavigationChange, ) } Loading Loading @@ -581,14 +618,10 @@ private fun QuickSuggestionsContent( onRequestLocationPermission = onRequestLocationPermission, coroutineScope = coroutineScope, onFieldFocusStateChange = onFieldFocusStateChange, ), savedPlaces = savedPlaces, onSavedPlaceSelected = { place -> ), savedPlaces = savedPlaces, onSavedPlaceSelected = { place -> updatePlaceForField(viewModel, fieldFocusState, place) onFieldFocusStateChange(FieldFocusState.NONE) }, isGettingLocation = viewModel.isGettingLocation, modifier = Modifier.fillMaxWidth() }, isGettingLocation = viewModel.isGettingLocation, modifier = Modifier.fillMaxWidth() ) } Loading @@ -610,9 +643,7 @@ private fun SearchResultsContent( } private fun updatePlaceForField( viewModel: DirectionsViewModel, fieldFocusState: FieldFocusState, place: Place viewModel: DirectionsViewModel, fieldFocusState: FieldFocusState, place: Place ) { if (fieldFocusState == FieldFocusState.FROM) { viewModel.updateFromPlace(place) Loading Loading @@ -884,24 +915,13 @@ private fun FerrostarRouteResults( ferrostarRoute: Route, viewModel: DirectionsViewModel, modifier: Modifier = Modifier, navController: NavController, distanceUnit: Int, availableProfiles: List<RoutingProfile>, hasNotificationPermission: Boolean, onRequestNotificationPermission: () -> Unit onPendingNavigationChange: (Boolean) -> Unit, ) { var showProfileDialog by remember { mutableStateOf(false) } var showNotificationDialog by remember { mutableStateOf(false) } var pendingNavigation by remember { mutableStateOf(false) } val selectedProfile = viewModel.selectedRoutingProfile LaunchedEffect(hasNotificationPermission, pendingNavigation) { if (pendingNavigation && hasNotificationPermission) { pendingNavigation = false viewModel.startNavigation(navController) } } LazyColumn(modifier = modifier) { item { Card( Loading Loading @@ -953,11 +973,7 @@ private fun FerrostarRouteResults( Button( onClick = { if (hasNotificationPermission) { viewModel.startNavigation(navController) } else { showNotificationDialog = true } onPendingNavigationChange(true) }, modifier = Modifier.fillMaxWidth(), enabled = true ) { Text(stringResource(string.start_navigation)) Loading Loading @@ -1022,18 +1038,7 @@ private fun FerrostarRouteResults( onProfileSelected = { profile -> viewModel.selectRoutingProfile(profile) showProfileDialog = false } ) NotificationRequestDialog( showDialog = showNotificationDialog, onDismiss = { showNotificationDialog = false }, onConfirm = { showNotificationDialog = false pendingNavigation = true onRequestNotificationPermission() } ) }) } @Composable Loading @@ -1052,8 +1057,7 @@ private fun ProfileSelectionDialog( Column { // Default option TextButton( onClick = { onProfileSelected(null) }, modifier = Modifier.fillMaxWidth() onClick = { onProfileSelected(null) }, modifier = Modifier.fillMaxWidth() ) { Text( text = stringResource(string.default_profile), Loading Loading @@ -1085,9 +1089,7 @@ private fun ProfileSelectionDialog( @Composable private fun NotificationRequestDialog( showDialog: Boolean, onDismiss: () -> Unit, onConfirm: () -> Unit showDialog: Boolean, onDismiss: () -> Unit, onConfirm: () -> Unit ) { if (showDialog) { AlertDialog( Loading