diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt index 14d306c1b..e2d7b386d 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt @@ -16,15 +16,17 @@ package com.google.samples.apps.nowinandroid.navigation +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable import androidx.navigation3.runtime.NavEntry import androidx.navigation3.runtime.entry import androidx.navigation3.runtime.entryProvider import androidx.navigation3.ui.NavDisplay -import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.BookmarksScreen -import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.navigation.bookmarksScreen +import com.google.samples.apps.nowinandroid.feature.bookmarks.impl.BookmarksScreenStateful +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.forYouSection import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests @@ -50,10 +52,11 @@ fun NiaNavHost( ) { val navController = appState.navController NavDisplay( - backStack = listOf(Unit), + backStack = appState.nav3Navigator.backStack, onBack = { }, entryProvider = entryProvider( fallback = { key -> + println("$key not found, using fallback entry") NavEntry(key = key) { NavHost( navController = navController, @@ -69,10 +72,9 @@ fun NiaNavHost( onTopicClick = navController::navigateToTopic, ) } - bookmarksScreen( - onTopicClick = navController::navigateToInterests, - onShowSnackbar = onShowSnackbar, - ) + composable { + Text("Legacy route") + } searchScreen( onBackClick = navController::popBackStack, onInterestsClick = { appState.navigateToTopLevelDestination(INTERESTS) }, @@ -83,7 +85,12 @@ fun NiaNavHost( } }, ) { - + entry{ + BookmarksScreenStateful( + { it: String -> navController.navigateToInterests(it) }, + onShowSnackbar + ) + } }, ) } diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt index 1c459aa7d..61daa3cec 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt @@ -18,25 +18,32 @@ package com.google.samples.apps.nowinandroid.ui import android.os.Bundle import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.navigation.NavBackStackEntry import androidx.navigation.NavController import androidx.navigation.NavDestination import androidx.navigation.NavDestination.Companion.hasRoute import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController +import androidx.navigation.NavOptions import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions +import androidx.navigation.toRoute import androidx.tracing.trace 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.TimeZoneMonitor 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.foryou.navigation.ForYouRoute 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.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.INTERESTS import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -77,6 +85,7 @@ fun rememberNiaAppState( ) { NiaAppState( navController = navController, + nav3Navigator = nav3Navigator, coroutineScope = coroutineScope, networkMonitor = networkMonitor, userNewsResourceRepository = userNewsResourceRepository, @@ -88,6 +97,7 @@ fun rememberNiaAppState( @Stable class NiaAppState( val navController: NavHostController, + val nav3Navigator: Nav3NavigatorSimple, coroutineScope: CoroutineScope, networkMonitor: NetworkMonitor, userNewsResourceRepository: UserNewsResourceRepository, @@ -208,23 +218,54 @@ private fun NavigationTrackingSideEffect(navController: NavHostController) { class Nav3NavigatorSimple(val navController: NavHostController){ - val backStack = mutableStateListOf() + // 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(Unit) init { coroutineScope.launch { navController.currentBackStack.collect { nav2BackStack -> - println("Nav2 back stack changed") - backStack.clear() - - for (nav2Entry in nav2BackStack){ - println("Adding destination: ${nav2Entry.destination}") - backStack.add(nav2Entry.destination) + with(backStack) { + + nav2BackStack.forEach { nav2Entry -> + nav2Entry.savedStateHandle.toRoute() + } + println("Nav2 backstack changed, size: ${backStack.size}") + if (backStack.isNotEmpty()){ + clear() + + for (nav2Entry in nav2BackStack){ + val routeClass = nav2Entry.toNav3Route() + 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() } + else -> null + } } /* diff --git a/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/BookmarksScreen.kt b/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/BookmarksScreen.kt index 5d6bc55ac..db98ba94d 100644 --- a/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/BookmarksScreen.kt +++ b/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/BookmarksScreen.kt @@ -76,7 +76,7 @@ import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParam import com.google.samples.apps.nowinandroid.core.ui.newsFeed @Composable -internal fun BookmarksRoute( +fun BookmarksScreenStateful( onTopicClick: (String) -> Unit, onShowSnackbar: suspend (String, String?) -> Boolean, modifier: Modifier = Modifier, diff --git a/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/navigation/BookmarksNavigation.kt b/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/navigation/BookmarksNavigation.kt index 856d48c55..141b03704 100644 --- a/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/navigation/BookmarksNavigation.kt +++ b/feature/bookmarks/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/impl/navigation/BookmarksNavigation.kt @@ -20,7 +20,7 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions 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 @Serializable object BookmarksRoute @@ -33,6 +33,6 @@ fun NavGraphBuilder.bookmarksScreen( onShowSnackbar: suspend (String, String?) -> Boolean, ) { composable { - BookmarksRoute(onTopicClick, onShowSnackbar) + BookmarksScreenStateful(onTopicClick, onShowSnackbar) } }