From 8b9bc76b75f69913103e8edace07654ff6c05246 Mon Sep 17 00:00:00 2001 From: Alex Vanyo Date: Mon, 15 Apr 2024 17:03:04 -0700 Subject: [PATCH] Recreate nested nav to work with AnimatedPane Change-Id: I6b526331b7fc62b968ac39e91753a8a1e5343023 --- .../InterestsListDetailScreen.kt | 82 +++++++++++++------ .../topic/navigation/TopicNavigation.kt | 9 +- gradle/libs.versions.toml | 2 +- 3 files changed, 62 insertions(+), 31 deletions(-) diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt index 4cc4345efd..87a6f48fad 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt @@ -18,14 +18,19 @@ package com.google.samples.apps.nowinandroid.ui.interests2pane import androidx.activity.compose.BackHandler import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi +import androidx.compose.material3.adaptive.layout.AnimatedPane import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole import androidx.compose.material3.adaptive.layout.PaneAdaptedValue +import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.key +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder @@ -39,8 +44,10 @@ import com.google.samples.apps.nowinandroid.feature.interests.navigation.INTERES import com.google.samples.apps.nowinandroid.feature.interests.navigation.TOPIC_ID_ARG import com.google.samples.apps.nowinandroid.feature.topic.TopicDetailPlaceholder import com.google.samples.apps.nowinandroid.feature.topic.navigation.TOPIC_ROUTE +import com.google.samples.apps.nowinandroid.feature.topic.navigation.createTopicRoute import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen +import java.util.UUID private const val DETAIL_PANE_NAVHOST_ROUTE = "detail_pane_route" @@ -76,17 +83,38 @@ internal fun InterestsListDetailScreen( selectedTopicId: String?, onTopicClick: (String) -> Unit, ) { - val listDetailNavigator = rememberListDetailPaneScaffoldNavigator() + val listDetailNavigator = rememberListDetailPaneScaffoldNavigator( + initialDestinationHistory = listOfNotNull( + ThreePaneScaffoldDestinationItem(ListDetailPaneScaffoldRole.List), + ThreePaneScaffoldDestinationItem(ListDetailPaneScaffoldRole.Detail).takeIf { + selectedTopicId != null + }, + ), + ) BackHandler(listDetailNavigator.canNavigateBack()) { listDetailNavigator.navigateBack() } - val nestedNavController = rememberNavController() + var nestedNavHostStartDestination by remember { + mutableStateOf(selectedTopicId?.let(::createTopicRoute) ?: TOPIC_ROUTE) + } + var nestedNavKey by remember { mutableStateOf(UUID.randomUUID()) } + val nestedNavController = key(nestedNavKey) { + rememberNavController() + } fun onTopicClickShowDetailPane(topicId: String) { onTopicClick(topicId) - nestedNavController.navigateToTopic(topicId) { - popUpTo(DETAIL_PANE_NAVHOST_ROUTE) + if (listDetailNavigator.isDetailPaneVisible()) { + // If the detail pane was visible, then use the nestedNavController navigate call + // directly + nestedNavController.navigateToTopic(topicId) { + popUpTo(DETAIL_PANE_NAVHOST_ROUTE) + } + } else { + // Otherwise, recreate the NavHost entirely, and start at the new destination + nestedNavHostStartDestination = createTopicRoute(topicId) + nestedNavKey = UUID.randomUUID() } listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail) } @@ -95,34 +123,34 @@ internal fun InterestsListDetailScreen( value = listDetailNavigator.scaffoldValue, directive = listDetailNavigator.scaffoldDirective, listPane = { - InterestsRoute( - onTopicClick = ::onTopicClickShowDetailPane, - highlightSelectedTopic = listDetailNavigator.isDetailPaneVisible(), - ) - }, - detailPane = { - NavHost( - navController = nestedNavController, - startDestination = TOPIC_ROUTE, - route = DETAIL_PANE_NAVHOST_ROUTE, - ) { - topicScreen( - showBackButton = !listDetailNavigator.isListPaneVisible(), - onBackClick = listDetailNavigator::navigateBack, + AnimatedPane { + InterestsRoute( onTopicClick = ::onTopicClickShowDetailPane, + highlightSelectedTopic = listDetailNavigator.isDetailPaneVisible(), ) - composable(route = TOPIC_ROUTE) { - TopicDetailPlaceholder() + } + }, + detailPane = { + AnimatedPane { + key(nestedNavKey) { + NavHost( + navController = nestedNavController, + startDestination = nestedNavHostStartDestination, + route = DETAIL_PANE_NAVHOST_ROUTE, + ) { + topicScreen( + showBackButton = !listDetailNavigator.isListPaneVisible(), + onBackClick = listDetailNavigator::navigateBack, + onTopicClick = ::onTopicClickShowDetailPane, + ) + composable(route = TOPIC_ROUTE) { + TopicDetailPlaceholder() + } + } } } }, ) - LaunchedEffect(Unit) { - if (selectedTopicId != null) { - // Initial topic ID was provided when navigating to Interests, so show its details. - onTopicClickShowDetailPane(selectedTopicId) - } - } } @OptIn(ExperimentalMaterial3AdaptiveApi::class) diff --git a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt index 41804b6342..394c533030 100644 --- a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt +++ b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt @@ -41,13 +41,16 @@ internal class TopicArgs(val topicId: String) { } fun NavController.navigateToTopic(topicId: String, navOptions: NavOptionsBuilder.() -> Unit = {}) { - val encodedId = URLEncoder.encode(topicId, URL_CHARACTER_ENCODING) - val newRoute = "$TOPIC_ROUTE/$encodedId" - navigate(newRoute) { + navigate(createTopicRoute(topicId)) { navOptions() } } +fun createTopicRoute(topicId: String): String { + val encodedId = URLEncoder.encode(topicId, URL_CHARACTER_ENCODING) + return "$TOPIC_ROUTE/$encodedId" +} + fun NavGraphBuilder.topicScreen( showBackButton: Boolean, onBackClick: () -> Unit, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c354432c4..6bc85e10e7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ androidxHiltNavigationCompose = "1.2.0" androidxLifecycle = "2.7.0" androidxMacroBenchmark = "1.2.2" androidxMetrics = "1.0.0-alpha04" -androidxNavigation = "2.7.4" +androidxNavigation = "2.8.0-alpha06" androidxProfileinstaller = "1.3.1" androidxTestCore = "1.5.0" androidxTestExt = "1.1.5"