From 0a7b1458409193d78a4beb6bf711f2637d5a39b2 Mon Sep 17 00:00:00 2001 From: Joseph Hale Date: Sat, 24 Feb 2024 00:05:01 -0700 Subject: [PATCH] refactor: Lift navigation back up to controller Effectively reverts e9f977a5ac809073a71acc2226cc8bb219d7e8db The Jetpack Navigation docs [1] specifically recommend NOT passing the navController object into any other Composable because it makes them much more difficult to test. I also took the liberty to rename `MainNavigator` to `StartActivityNavigator`. We'll eventually create tiles and complications which might have different navigation flows. Choosing a more precise name for the navigator subtly informs future devs that it's okay to create a new navigator for a new experience. [1]: https://developer.android.com/jetpack/compose/navigation#testing --- .../presentation/MainActivity.kt | 4 +- .../presentation/navigation/MainNavigator.kt | 32 ------------- .../navigation/StartActivityNavigator.kt | 45 +++++++++++++++++++ .../presentation/screens/ActivitiesScreen.kt | 4 +- .../presentation/screens/TagsScreen.kt | 18 +------- 5 files changed, 51 insertions(+), 52 deletions(-) delete mode 100644 wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/MainNavigator.kt create mode 100644 wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/StartActivityNavigator.kt diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/MainActivity.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/MainActivity.kt index 4cf34277..b86533a3 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/MainActivity.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/MainActivity.kt @@ -9,7 +9,7 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.runtime.Composable -import com.example.util.simpletimetracker.presentation.navigation.MainNavigator +import com.example.util.simpletimetracker.presentation.navigation.StartActivityNavigator import com.example.util.simpletimetracker.presentation.theme.SimpleTimeTrackerForWearOSTheme class MainActivity : ComponentActivity() { @@ -24,6 +24,6 @@ class MainActivity : ComponentActivity() { @Composable fun WearApp() { SimpleTimeTrackerForWearOSTheme { - MainNavigator() + StartActivityNavigator() } } diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/MainNavigator.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/MainNavigator.kt deleted file mode 100644 index be5ccc21..00000000 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/MainNavigator.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ -package com.example.util.simpletimetracker.presentation.navigation - -import androidx.compose.runtime.Composable -import androidx.wear.compose.navigation.SwipeDismissableNavHost -import androidx.wear.compose.navigation.composable -import androidx.wear.compose.navigation.rememberSwipeDismissableNavController -import com.example.util.simpletimetracker.presentation.screens.ActivitiesScreen -import com.example.util.simpletimetracker.presentation.screens.TagsScreen - -@Composable -fun MainNavigator() { - val navController = rememberSwipeDismissableNavController() - SwipeDismissableNavHost( - navController = navController, - startDestination = "activities", - ) { - composable("activities") { - ActivitiesScreen(navController) - } - composable("activities/{id}/tags") { - TagsScreen( - activityId = it.arguments?.getString("id")?.toLong()!!, - navigation = navController, - ) - } - } -} \ No newline at end of file diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/StartActivityNavigator.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/StartActivityNavigator.kt new file mode 100644 index 00000000..412f8961 --- /dev/null +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/navigation/StartActivityNavigator.kt @@ -0,0 +1,45 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +package com.example.util.simpletimetracker.presentation.navigation + +import androidx.compose.runtime.Composable +import androidx.wear.compose.navigation.SwipeDismissableNavHost +import androidx.wear.compose.navigation.composable +import androidx.wear.compose.navigation.rememberSwipeDismissableNavController +import com.example.util.simpletimetracker.presentation.screens.ActivitiesScreen +import com.example.util.simpletimetracker.presentation.screens.TagsScreen + +object Route { + const val Activities = "activities" + const val Tags = "activities/{id}/tags" +} + +@Composable +fun StartActivityNavigator() { + val navigation = rememberSwipeDismissableNavController() + SwipeDismissableNavHost( + navController = navigation, + startDestination = Route.Activities, + ) { + composable(Route.Activities) { + ActivitiesScreen(onRequestTagSelection = { + navigation.navigate(Route.Tags.replace("{id}", it.toString())) + }) + } + composable(Route.Tags) { + TagsScreen( + activityId = it.arguments?.getString("id")?.toLong()!!, + onComplete = { + // Inspired by: https://stackoverflow.com/a/72856761/14765128 + navigation.navigate(Route.Activities) { + popUpTo(navigation.graph.startDestinationId) { inclusive = true } + navigation.graph.setStartDestination(Route.Activities) + } + }, + ) + } + } +} diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt index ccfbc69d..363685c7 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt @@ -20,7 +20,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @Composable -fun ActivitiesScreen(navigation: NavController) { +fun ActivitiesScreen(onRequestTagSelection: (activityId: Long) -> Unit) { val coroutineScope = rememberCoroutineScope() val rpc = rememberRPCClient() val (activities, refreshActivities) = rememberActivities() @@ -40,7 +40,7 @@ fun ActivitiesScreen(navigation: NavController) { val startActivityWithTags: (Activity) -> Unit = { coroutineScope.launch(Dispatchers.Main) { Log.d("ActivitiesScreen", "Starting ${it.name} (#${it.id}) with tags") - navigation.navigate("activities/${it.id}/tags") + onRequestTagSelection(it.id) } } val stopActivity: (Activity) -> Unit = { diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt index ca749e43..59a9ead8 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt @@ -7,8 +7,6 @@ package com.example.util.simpletimetracker.presentation.screens import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope -import androidx.navigation.NavController -import androidx.navigation.NavHostController import com.example.util.simpletimetracker.presentation.components.TagList import com.example.util.simpletimetracker.presentation.components.TagSelectionMode import com.example.util.simpletimetracker.presentation.mediators.CurrentActivitiesMediator @@ -19,14 +17,8 @@ import com.example.util.simpletimetracker.presentation.remember.rememberTags import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -fun NavHostController.navigateAndReplaceStartRoute(newHomeRoute: String) { - popBackStack(graph.startDestinationId, true) - graph.setStartDestination(newHomeRoute) - navigate(newHomeRoute) -} - @Composable -fun TagsScreen(activityId: Long, navigation: NavController) { +fun TagsScreen(activityId: Long, onComplete: () -> Unit) { val coroutineScope = rememberCoroutineScope() val rpc = rememberRPCClient() val (settings) = rememberSettings() @@ -44,13 +36,7 @@ fun TagsScreen(activityId: Long, navigation: NavController) { onSelectionComplete = { coroutineScope.launch(Dispatchers.Default) { currentActivitiesMediator.start(activityId, it) - coroutineScope.launch(Dispatchers.Main) { - // Inspired by: https://stackoverflow.com/a/72856761/14765128 - navigation.navigate("activities") { - popUpTo(navigation.graph.startDestinationId) { inclusive = true } - navigation.graph.setStartDestination("activities") - } - } + coroutineScope.launch(Dispatchers.Main) { onComplete() } } }, ) -- 2.51.2