mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
refactor(folio): replace custom Navigator with NavHost backstack
Wraps androidx.navigation.NavHostController behind the existing push/replace/back surface so call sites in ViewModels stay unchanged. App.kt now wires a typed NavHost with @Serializable Route entries and observes the controller's currentBackStackEntry to drive the session-based Login/Home redirect.
This commit is contained in:
1 parent
14b4e36103
commit
7187790592
3 files changed
+47
-31
No files matched your search
@@ -2,7 +2,6 @@ package app.folio
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
@@ -17,6 +16,12 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavDestination.Companion.hasRoute
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.toRoute
|
||||
import app.folio.di.AppGraph
|
||||
import app.folio.di.LocalAppGraph
|
||||
import app.folio.feature.account.AddAccountRoute
|
||||
@@ -61,24 +66,35 @@ fun App(graphBuilder: suspend () -> AppGraph) {
|
||||
@Composable
|
||||
private fun AppContent() {
|
||||
val graph = LocalAppGraph.current
|
||||
val session by graph.repository.session.collectAsState()
|
||||
val route by graph.navigator.current.collectAsState()
|
||||
val navController = rememberNavController()
|
||||
|
||||
LaunchedEffect(session, route) {
|
||||
if (session == null && route !is Route.Login) {
|
||||
LaunchedEffect(navController) { graph.navigator.attach(navController) }
|
||||
|
||||
val session by graph.repository.session.collectAsState()
|
||||
val currentEntry by navController.currentBackStackEntryAsState()
|
||||
val onLogin = currentEntry?.destination?.hasRoute(Route.Login::class) == true
|
||||
|
||||
LaunchedEffect(session, onLogin) {
|
||||
if (session == null && !onLogin) {
|
||||
graph.navigator.replace(Route.Login)
|
||||
} else if (session != null && route is Route.Login) {
|
||||
} else if (session != null && onLogin) {
|
||||
graph.navigator.replace(Route.Home)
|
||||
}
|
||||
}
|
||||
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
when (val r = route) {
|
||||
Route.Login -> LoginRoute()
|
||||
Route.Home -> HomeRoute()
|
||||
Route.AddAccount -> AddAccountRoute()
|
||||
is Route.Ledger -> LedgerRoute(accountId = r.accountId)
|
||||
is Route.AddTransaction -> AddTransactionRoute(accountId = r.accountId)
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = Route.Home,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
composable<Route.Login> { LoginRoute() }
|
||||
composable<Route.Home> { HomeRoute() }
|
||||
composable<Route.AddAccount> { AddAccountRoute() }
|
||||
composable<Route.Ledger> { entry ->
|
||||
LedgerRoute(accountId = entry.toRoute<Route.Ledger>().accountId)
|
||||
}
|
||||
composable<Route.AddTransaction> { entry ->
|
||||
AddTransactionRoute(accountId = entry.toRoute<Route.AddTransaction>().accountId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import app.folio.feature.home.HomeViewModel
|
||||
import app.folio.feature.ledger.AddTransactionViewModel
|
||||
import app.folio.feature.ledger.LedgerViewModel
|
||||
import app.folio.navigation.Navigator
|
||||
import app.folio.navigation.Route
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Binds
|
||||
import dev.zacsweers.metro.DependencyGraph
|
||||
@@ -33,7 +32,7 @@ interface AppGraph {
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
@Provides
|
||||
fun provideNavigator(): Navigator = Navigator(initial = Route.Home)
|
||||
fun provideNavigator(): Navigator = Navigator()
|
||||
|
||||
@DependencyGraph.Factory
|
||||
fun interface Factory {
|
||||
|
||||
@@ -1,30 +1,31 @@
|
||||
package app.folio.navigation
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import androidx.navigation.NavHostController
|
||||
|
||||
class Navigator(initial: Route = Route.Home) {
|
||||
private val stack = ArrayDeque<Route>().apply { addLast(initial) }
|
||||
private val _current = MutableStateFlow<Route>(initial)
|
||||
val current: StateFlow<Route> = _current.asStateFlow()
|
||||
class Navigator {
|
||||
private var controller: NavHostController? = null
|
||||
|
||||
fun attach(controller: NavHostController) {
|
||||
this.controller = controller
|
||||
}
|
||||
|
||||
fun push(route: Route) {
|
||||
stack.addLast(route)
|
||||
_current.value = route
|
||||
controller?.navigate(route) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
|
||||
fun replace(route: Route) {
|
||||
stack.clear()
|
||||
stack.addLast(route)
|
||||
_current.value = route
|
||||
val nav = controller ?: return
|
||||
nav.navigate(route) {
|
||||
popUpTo(nav.graph.id) { inclusive = true }
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
|
||||
fun back(fallback: Route) {
|
||||
if (stack.size > 1) {
|
||||
stack.removeLast()
|
||||
_current.value = stack.last()
|
||||
} else {
|
||||
val nav = controller ?: return
|
||||
if (!nav.popBackStack()) {
|
||||
replace(fallback)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user