Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recreate nested nav to work with AnimatedPane #1380

Merged
merged 3 commits into from May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 9 additions & 9 deletions app/dependencies/prodReleaseRuntimeClasspath.txt
Expand Up @@ -17,10 +17,10 @@ androidx.compose.animation:animation-android:1.7.0-alpha06
androidx.compose.animation:animation-core-android:1.7.0-alpha06
androidx.compose.animation:animation-core:1.7.0-alpha06
androidx.compose.animation:animation:1.7.0-alpha06
androidx.compose.foundation:foundation-android:1.6.3
androidx.compose.foundation:foundation-layout-android:1.6.3
androidx.compose.foundation:foundation-layout:1.6.3
androidx.compose.foundation:foundation:1.6.3
androidx.compose.foundation:foundation-android:1.7.0-alpha06
androidx.compose.foundation:foundation-layout-android:1.7.0-alpha06
androidx.compose.foundation:foundation-layout:1.7.0-alpha06
androidx.compose.foundation:foundation:1.7.0-alpha06
androidx.compose.material3.adaptive:adaptive-android:1.0.0-alpha10
androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0-alpha10
androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha10
Expand Down Expand Up @@ -103,11 +103,11 @@ androidx.lifecycle:lifecycle-viewmodel:2.8.0-alpha04
androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-alpha04
androidx.navigation:navigation-common-ktx:2.7.7
androidx.navigation:navigation-common:2.7.7
androidx.navigation:navigation-compose:2.7.7
androidx.navigation:navigation-runtime-ktx:2.7.7
androidx.navigation:navigation-runtime:2.7.7
androidx.navigation:navigation-common-ktx:2.8.0-alpha06
androidx.navigation:navigation-common:2.8.0-alpha06
androidx.navigation:navigation-compose:2.8.0-alpha06
androidx.navigation:navigation-runtime-ktx:2.8.0-alpha06
androidx.navigation:navigation-runtime:2.8.0-alpha06
androidx.print:print:1.0.0
androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05
androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05
Expand Down
Expand Up @@ -27,7 +27,8 @@ import javax.inject.Inject
class Interests2PaneViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
val selectedTopicId: StateFlow<String?> = savedStateHandle.getStateFlow(TOPIC_ID_ARG, null)
val selectedTopicId: StateFlow<String?> =
savedStateHandle.getStateFlow(TOPIC_ID_ARG, savedStateHandle[TOPIC_ID_ARG])

fun onTopicClick(topicId: String?) {
savedStateHandle[TOPIC_ID_ARG] = topicId
Expand Down
Expand Up @@ -18,14 +18,21 @@ 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.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
Expand All @@ -39,8 +46,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"

Expand Down Expand Up @@ -76,17 +85,42 @@ internal fun InterestsListDetailScreen(
selectedTopicId: String?,
onTopicClick: (String) -> Unit,
) {
val listDetailNavigator = rememberListDetailPaneScaffoldNavigator()
val listDetailNavigator = rememberListDetailPaneScaffoldNavigator(
initialDestinationHistory = listOfNotNull(
ThreePaneScaffoldDestinationItem(ListDetailPaneScaffoldRole.List),
ThreePaneScaffoldDestinationItem<Nothing>(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 rememberSaveable(
stateSaver = Saver({ it.toString() }, UUID::fromString),
) {
mutableStateOf(UUID.randomUUID())
}
val nestedNavController = key(nestedNavKey) {
jdkoren marked this conversation as resolved.
Show resolved Hide resolved
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)
}
Expand All @@ -95,34 +129,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)
Expand Down
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Expand Up @@ -20,7 +20,7 @@ androidxHiltNavigationCompose = "1.2.0"
androidxLifecycle = "2.7.0"
androidxMacroBenchmark = "1.2.2"
androidxMetrics = "1.0.0-alpha04"
androidxNavigation = "2.7.7"
androidxNavigation = "2.8.0-alpha06"
androidxProfileinstaller = "1.3.1"
androidxTestCore = "1.5.0"
androidxTestExt = "1.1.5"
Expand Down