Adding conversion from NavBackStackEntry to route instance

dt/nav3-c
Don Turner 2 months ago
parent 995e1ab13d
commit 16d8d46405

@ -16,15 +16,17 @@
package com.google.samples.apps.nowinandroid.navigation package com.google.samples.apps.nowinandroid.navigation
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation3.runtime.NavEntry import androidx.navigation3.runtime.NavEntry
import androidx.navigation3.runtime.entry import androidx.navigation3.runtime.entry
import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.ui.NavDisplay import androidx.navigation3.ui.NavDisplay
import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.BookmarksScreen import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.BookmarksScreenStateful
import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.navigation.bookmarksScreen import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.navigation.BookmarksRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouBaseRoute import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouBaseRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.forYouSection import com.google.samples.apps.nowinandroid.feature.foryou.navigation.forYouSection
import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests
@ -50,10 +52,11 @@ fun NiaNavHost(
) { ) {
val navController = appState.navController val navController = appState.navController
NavDisplay( NavDisplay(
backStack = listOf(Unit), backStack = appState.nav3Navigator.backStack,
onBack = { }, onBack = { },
entryProvider = entryProvider( entryProvider = entryProvider(
fallback = { key -> fallback = { key ->
println("$key not found, using fallback entry")
NavEntry(key = key) { NavEntry(key = key) {
NavHost( NavHost(
navController = navController, navController = navController,
@ -69,10 +72,9 @@ fun NiaNavHost(
onTopicClick = navController::navigateToTopic, onTopicClick = navController::navigateToTopic,
) )
} }
bookmarksScreen( composable<BookmarksRoute> {
onTopicClick = navController::navigateToInterests, Text("Legacy route")
onShowSnackbar = onShowSnackbar, }
)
searchScreen( searchScreen(
onBackClick = navController::popBackStack, onBackClick = navController::popBackStack,
onInterestsClick = { appState.navigateToTopLevelDestination(INTERESTS) }, onInterestsClick = { appState.navigateToTopLevelDestination(INTERESTS) },
@ -83,7 +85,12 @@ fun NiaNavHost(
} }
}, },
) { ) {
entry<BookmarksRoute>{
BookmarksScreenStateful(
{ it: String -> navController.navigateToInterests(it) },
onShowSnackbar
)
}
}, },
) )
} }

@ -18,25 +18,32 @@ package com.google.samples.apps.nowinandroid.ui
import android.os.Bundle import android.os.Bundle
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions import androidx.navigation.navOptions
import androidx.navigation.toRoute
import androidx.tracing.trace import androidx.tracing.trace
import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import com.google.samples.apps.nowinandroid.core.ui.TrackDisposableJank import com.google.samples.apps.nowinandroid.core.ui.TrackDisposableJank
import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.navigation.BookmarksRoute
import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.navigation.navigateToBookmarks import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.navigation.navigateToBookmarks
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.navigateToForYou import com.google.samples.apps.nowinandroid.feature.foryou.navigation.navigateToForYou
import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests
import com.google.samples.apps.nowinandroid.feature.search.navigation.navigateToSearch import com.google.samples.apps.nowinandroid.feature.search.navigation.navigateToSearch
@ -45,6 +52,7 @@ import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.BOOKM
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.FOR_YOU import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.FOR_YOU
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.INTERESTS import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.INTERESTS
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -77,6 +85,7 @@ fun rememberNiaAppState(
) { ) {
NiaAppState( NiaAppState(
navController = navController, navController = navController,
nav3Navigator = nav3Navigator,
coroutineScope = coroutineScope, coroutineScope = coroutineScope,
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
@ -88,6 +97,7 @@ fun rememberNiaAppState(
@Stable @Stable
class NiaAppState( class NiaAppState(
val navController: NavHostController, val navController: NavHostController,
val nav3Navigator: Nav3NavigatorSimple,
coroutineScope: CoroutineScope, coroutineScope: CoroutineScope,
networkMonitor: NetworkMonitor, networkMonitor: NetworkMonitor,
userNewsResourceRepository: UserNewsResourceRepository, userNewsResourceRepository: UserNewsResourceRepository,
@ -208,22 +218,53 @@ private fun NavigationTrackingSideEffect(navController: NavHostController) {
class Nav3NavigatorSimple(val navController: NavHostController){ class Nav3NavigatorSimple(val navController: NavHostController){
val backStack = mutableStateListOf<Any>() // TODO: We are using Dispatchers.Main so that we can access SavedStateHandle in toRoute,
// however, this may be unnecessary if we can just deserialize the route from memory
val coroutineScope = CoroutineScope(Job() + Dispatchers.Main)
val coroutineScope = CoroutineScope(Job()) // We need a single element to avoid "backStack cannot be empty" error b/430023647
val backStack = mutableStateListOf<Any>(Unit)
init { init {
coroutineScope.launch { coroutineScope.launch {
navController.currentBackStack.collect { nav2BackStack -> navController.currentBackStack.collect { nav2BackStack ->
println("Nav2 back stack changed") with(backStack) {
backStack.clear()
nav2BackStack.forEach { nav2Entry ->
nav2Entry.savedStateHandle.toRoute()
}
println("Nav2 backstack changed, size: ${backStack.size}")
if (backStack.isNotEmpty()){
clear()
for (nav2Entry in nav2BackStack){ for (nav2Entry in nav2BackStack){
println("Adding destination: ${nav2Entry.destination}") val routeClass = nav2Entry.toNav3Route()
backStack.add(nav2Entry.destination) if (routeClass != null){
add(routeClass)
} else {
add(nav2Entry)
}
}
println("Nav3 backstack updated")
}
}
} }
} }
} }
fun goTo(route: Any, navOptions: NavOptions? = null){
navController.navigate(route, navOptions)
}
fun goBack(){
navController.popBackStack()
}
}
private fun NavBackStackEntry.toNav3Route() : Any? {
return when(this.destination.route){
BookmarksRoute::class.qualifiedName -> { this.savedStateHandle.toRoute<BookmarksRoute>() }
else -> null
} }
} }

@ -76,7 +76,7 @@ import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParam
import com.google.samples.apps.nowinandroid.core.ui.newsFeed import com.google.samples.apps.nowinandroid.core.ui.newsFeed
@Composable @Composable
internal fun BookmarksRoute( fun BookmarksScreenStateful(
onTopicClick: (String) -> Unit, onTopicClick: (String) -> Unit,
onShowSnackbar: suspend (String, String?) -> Boolean, onShowSnackbar: suspend (String, String?) -> Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,

@ -20,7 +20,7 @@ import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.BookmarksRoute import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.BookmarksScreenStateful
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable object BookmarksRoute @Serializable object BookmarksRoute
@ -33,6 +33,6 @@ fun NavGraphBuilder.bookmarksScreen(
onShowSnackbar: suspend (String, String?) -> Boolean, onShowSnackbar: suspend (String, String?) -> Boolean,
) { ) {
composable<BookmarksRoute> { composable<BookmarksRoute> {
BookmarksRoute(onTopicClick, onShowSnackbar) BookmarksScreenStateful(onTopicClick, onShowSnackbar)
} }
} }

Loading…
Cancel
Save