From 1e03463246199a3c8fc5085d9d06eca4d807819a Mon Sep 17 00:00:00 2001 From: Ellen Poe Date: Tue, 30 Sep 2025 15:34:53 -0700 Subject: [PATCH 1/2] fix: directions endpoint modification --- .../ui/directions/DirectionsScreen.kt | 71 ++++++++++++------- .../app/src/main/res/values/strings.xml | 1 + 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt index 7e41430..bd7d3b0 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt @@ -148,19 +148,31 @@ fun DirectionsScreen( } } - stringResource(string.change_start_location_to_my_location) - Column( modifier = Modifier .fillMaxSize() .padding(horizontal = dimensionResource(dimen.padding)) ) { - if (!isAnyFieldFocused) { + if (isAnyFieldFocused) { + DirectionsScreenFocusedField( + viewModel = viewModel, + fieldFocusState = fieldFocusState, + onFieldFocusStateChange = { + fieldFocusState = it + if (fieldFocusState != FieldFocusState.NONE) { + onFullExpansionRequired() + } + }, + savedPlaces = savedPlaces, + hasLocationPermission = hasLocationPermission, + onRequestLocationPermission = onRequestLocationPermission, + coroutineScope = coroutineScope + ) + } else { DirectionsScreenFullUI( viewModel = viewModel, onPeekHeightChange = onPeekHeightChange, onBack = onBack, - onFullExpansionRequired = onFullExpansionRequired, navController = navController, onFieldFocusStateChange = { fieldFocusState = it }, fieldFocusState = fieldFocusState, @@ -170,16 +182,6 @@ fun DirectionsScreen( hasNotificationPermission = hasNotificationPermission, onRequestNotificationPermission = onRequestNotificationPermission ) - } else { - DirectionsScreenFocusedField( - viewModel = viewModel, - fieldFocusState = fieldFocusState, - savedPlaces = savedPlaces, - hasLocationPermission = hasLocationPermission, - onRequestLocationPermission = onRequestLocationPermission, - pendingLocationRequest = pendingLocationRequest, - coroutineScope = coroutineScope - ) } } } @@ -189,7 +191,6 @@ private fun DirectionsScreenFullUI( viewModel: DirectionsViewModel, onPeekHeightChange: (Dp) -> Unit, onBack: () -> Unit, - onFullExpansionRequired: () -> Job, navController: NavController, onFieldFocusStateChange: (FieldFocusState) -> Unit, fieldFocusState: FieldFocusState, @@ -324,7 +325,12 @@ private fun DirectionsRouteResults( ) { val planState = viewModel.planState if (viewModel.selectedRoutingMode == RoutingMode.PUBLIC_TRANSPORT) { - TransitRouteResults(planState = planState, navController = navController, viewModel = viewModel, appPreferences = appPreferences) + TransitRouteResults( + planState = planState, + navController = navController, + viewModel = viewModel, + appPreferences = appPreferences + ) } else { NonTransitRouteResults( routeState = routeState, @@ -445,10 +451,10 @@ private fun NonTransitRouteResults( private fun DirectionsScreenFocusedField( viewModel: DirectionsViewModel, fieldFocusState: FieldFocusState, + onFieldFocusStateChange: (FieldFocusState) -> Unit, savedPlaces: List, hasLocationPermission: Boolean, onRequestLocationPermission: () -> Unit, - pendingLocationRequest: FieldFocusState?, coroutineScope: CoroutineScope ) { // Show only the focused field and search results when a field is focused @@ -464,7 +470,11 @@ private fun DirectionsScreenFocusedField( }, onTextChange = { viewModel.updateSearchQuery(it) }, onTextFieldFocusChange = { isFocused -> - + if (isFocused) { + onFieldFocusStateChange(fieldFocusState) + } else { + onFieldFocusStateChange(FieldFocusState.NONE) + } }, isFocused = true, modifier = Modifier @@ -479,8 +489,8 @@ private fun DirectionsScreenFocusedField( savedPlaces = savedPlaces, hasLocationPermission = hasLocationPermission, onRequestLocationPermission = onRequestLocationPermission, - pendingLocationRequest = pendingLocationRequest, - coroutineScope = coroutineScope + coroutineScope = coroutineScope, + onFieldFocusStateChange = onFieldFocusStateChange, ) } @@ -488,10 +498,10 @@ private fun DirectionsScreenFocusedField( private fun FocusedFieldContent( viewModel: DirectionsViewModel, fieldFocusState: FieldFocusState, + onFieldFocusStateChange: (FieldFocusState) -> Unit, savedPlaces: List, hasLocationPermission: Boolean, onRequestLocationPermission: () -> Unit, - pendingLocationRequest: FieldFocusState?, coroutineScope: CoroutineScope ) { when { @@ -506,15 +516,16 @@ private fun FocusedFieldContent( savedPlaces = savedPlaces, hasLocationPermission = hasLocationPermission, onRequestLocationPermission = onRequestLocationPermission, - pendingLocationRequest = pendingLocationRequest, - coroutineScope = coroutineScope + coroutineScope = coroutineScope, + onFieldFocusStateChange = onFieldFocusStateChange, ) } else -> { SearchResultsContent( viewModel = viewModel, - fieldFocusState = fieldFocusState + fieldFocusState = fieldFocusState, + onFieldFocusStateChange = onFieldFocusStateChange, ) } } @@ -523,7 +534,7 @@ private fun FocusedFieldContent( @Composable private fun SearchingIndicator() { Text( - text = "Searching...", + text = stringResource(string.searching), modifier = Modifier .fillMaxWidth() .padding(dimensionResource(dimen.padding)) @@ -534,10 +545,10 @@ private fun SearchingIndicator() { private fun QuickSuggestionsContent( viewModel: DirectionsViewModel, fieldFocusState: FieldFocusState, + onFieldFocusStateChange: (FieldFocusState) -> Unit, savedPlaces: List, hasLocationPermission: Boolean, onRequestLocationPermission: () -> Unit, - pendingLocationRequest: FieldFocusState?, coroutineScope: CoroutineScope ) { QuickSuggestions( @@ -546,11 +557,13 @@ private fun QuickSuggestionsContent( fieldFocusState = fieldFocusState, hasLocationPermission = hasLocationPermission, onRequestLocationPermission = onRequestLocationPermission, - coroutineScope = coroutineScope + coroutineScope = coroutineScope, + onFieldFocusStateChange = onFieldFocusStateChange, ), savedPlaces = savedPlaces, onSavedPlaceSelected = { place -> updatePlaceForField(viewModel, fieldFocusState, place) + onFieldFocusStateChange(FieldFocusState.NONE) }, isGettingLocation = viewModel.isGettingLocation, modifier = Modifier.fillMaxWidth() @@ -560,6 +573,7 @@ private fun QuickSuggestionsContent( @Composable private fun SearchResultsContent( viewModel: DirectionsViewModel, + onFieldFocusStateChange: (FieldFocusState) -> Unit, fieldFocusState: FieldFocusState ) { SearchResults( @@ -567,6 +581,7 @@ private fun SearchResultsContent( geocodeResults = deduplicateSearchResults(viewModel.geocodeResults.value), onPlaceSelected = { place -> updatePlaceForField(viewModel, fieldFocusState, place) + onFieldFocusStateChange(FieldFocusState.NONE) }, modifier = Modifier.fillMaxWidth() ) @@ -589,6 +604,7 @@ private fun handleMyLocationSelected( fieldFocusState: FieldFocusState, hasLocationPermission: Boolean, onRequestLocationPermission: () -> Unit, + onFieldFocusStateChange: (FieldFocusState) -> Unit, coroutineScope: CoroutineScope ): () -> Unit = { if (hasLocationPermission) { @@ -596,6 +612,7 @@ private fun handleMyLocationSelected( val myLocationPlace = viewModel.getCurrentLocationAsPlace() myLocationPlace?.let { place -> updatePlaceForField(viewModel, fieldFocusState, place) + onFieldFocusStateChange(FieldFocusState.NONE) } } } else { diff --git a/cardinal-android/app/src/main/res/values/strings.xml b/cardinal-android/app/src/main/res/values/strings.xml index 4bb6165..c68e443 100644 --- a/cardinal-android/app/src/main/res/values/strings.xml +++ b/cardinal-android/app/src/main/res/values/strings.xml @@ -247,4 +247,5 @@ Imperial Zoom in Zoom out + Searching… From 3c659c645235c8d85b378c8509d80f617ce428de Mon Sep 17 00:00:00 2001 From: Ellen Poe Date: Tue, 30 Sep 2025 15:58:30 -0700 Subject: [PATCH 2/2] refactor: make detekt happy --- .../ui/directions/DirectionsScreen.kt | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt index bd7d3b0..78c3cb1 100644 --- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt +++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/DirectionsScreen.kt @@ -122,31 +122,16 @@ fun DirectionsScreen( val coroutineScope = rememberCoroutineScope() // Auto-retry location request when permissions are granted - LaunchedEffect(hasLocationPermission, pendingLocationRequest) { - if (hasLocationPermission && pendingLocationRequest != null) { - val targetField = pendingLocationRequest!! - pendingLocationRequest = null // Clear the pending request - - // Automatically fetch location for the target field - coroutineScope.launch { - val myLocationPlace = viewModel.getCurrentLocationAsPlace() - myLocationPlace?.let { place -> - // Update the appropriate place based on which field was focused - if (targetField == FieldFocusState.FROM) { - viewModel.updateFromPlace(place) - } else { - viewModel.updateToPlace(place) - } - // Clear focus state after selection - fieldFocusState = FieldFocusState.NONE - } - } - } else if (hasLocationPermission && appPreferences.continuousLocationTracking.value) { - coroutineScope.launch { - viewModel.initializeDeparture() - } + AutoRetryMyLocation( + hasLocationPermission = hasLocationPermission, + pendingLocationRequest = pendingLocationRequest, + coroutineScope = coroutineScope, + viewModel = viewModel, + appPreferences = appPreferences, + onCompletion = { + fieldFocusState = FieldFocusState.NONE } - } + ) Column( modifier = Modifier @@ -165,7 +150,10 @@ fun DirectionsScreen( }, savedPlaces = savedPlaces, hasLocationPermission = hasLocationPermission, - onRequestLocationPermission = onRequestLocationPermission, + onRequestLocationPermission = { + pendingLocationRequest = fieldFocusState + onRequestLocationPermission() + }, coroutineScope = coroutineScope ) } else { @@ -186,6 +174,40 @@ fun DirectionsScreen( } } +@Composable +private fun AutoRetryMyLocation( + hasLocationPermission: Boolean, + pendingLocationRequest: FieldFocusState?, + coroutineScope: CoroutineScope, + viewModel: DirectionsViewModel, + appPreferences: AppPreferenceRepository, + onCompletion: () -> Unit, +) { + LaunchedEffect(hasLocationPermission, pendingLocationRequest) { + if (hasLocationPermission && pendingLocationRequest != null) { + val targetField = pendingLocationRequest + + // Automatically fetch location for the target field + coroutineScope.launch { + val myLocationPlace = viewModel.getCurrentLocationAsPlace() + myLocationPlace?.let { place -> + // Update the appropriate place based on which field was focused + if (targetField == FieldFocusState.FROM) { + viewModel.updateFromPlace(place) + } else { + viewModel.updateToPlace(place) + } + onCompletion() + } + } + } else if (hasLocationPermission && appPreferences.continuousLocationTracking.value) { + coroutineScope.launch { + viewModel.initializeDeparture() + } + } + } +} + @Composable private fun DirectionsScreenFullUI( viewModel: DirectionsViewModel,