@@ -5,6 +5,10 @@ import android.os.Bundle
55import androidx.activity.ComponentActivity
66import androidx.activity.compose.setContent
77import androidx.activity.enableEdgeToEdge
8+ import androidx.compose.animation.core.tween
9+ import androidx.compose.animation.slideInHorizontally
10+ import androidx.compose.animation.slideOutHorizontally
11+ import androidx.compose.animation.togetherWith
812import androidx.compose.foundation.layout.Box
913import androidx.compose.foundation.layout.WindowInsets
1014import androidx.compose.foundation.layout.WindowInsetsSides
@@ -13,46 +17,47 @@ import androidx.compose.foundation.layout.only
1317import androidx.compose.foundation.layout.safeDrawing
1418import androidx.compose.foundation.layout.statusBarsPadding
1519import androidx.compose.foundation.layout.windowInsetsPadding
16- import androidx.compose.material3.DrawerState
1720import androidx.compose.material3.DrawerValue
1821import androidx.compose.material3.Scaffold
1922import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
2023import androidx.compose.material3.rememberDrawerState
24+ import androidx.compose.runtime.CompositionLocalProvider
2125import androidx.compose.runtime.getValue
26+ import androidx.compose.runtime.remember
2227import androidx.compose.runtime.rememberCoroutineScope
2328import androidx.compose.ui.Modifier
2429import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
2530import androidx.lifecycle.compose.collectAsStateWithLifecycle
26- import androidx.navigation.compose.NavHost
27- import androidx.navigation.compose.rememberNavController
31+ import androidx.navigation3.ui.NavDisplay
2832import androidx.window.core.layout.WindowWidthSizeClass
2933import kotlinx.coroutines.launch
3034import net.frozendevelopment.openletters.data.sqldelight.LetterQueries
31- import net.frozendevelopment.openletters.extensions.newRoot
32- import net.frozendevelopment.openletters.feature.category.categories
3335import net.frozendevelopment.openletters.feature.category.form.CategoryFormDestination
3436import net.frozendevelopment.openletters.feature.category.manage.ManageCategoryDestination
35- import net.frozendevelopment.openletters.feature.letter.letters
3637import net.frozendevelopment.openletters.feature.letter.list.LetterListDestination
37- import net.frozendevelopment.openletters.feature.letter.scan.ScanLetterDestination
3838import net.frozendevelopment.openletters.feature.reminder.form.ReminderFormDestination
3939import net.frozendevelopment.openletters.feature.reminder.list.ReminderListDestination
40- import net.frozendevelopment.openletters.feature.reminder.reminders
4140import net.frozendevelopment.openletters.feature.settings.SettingsDestination
42- import net.frozendevelopment.openletters.feature.settings.settings
4341import net.frozendevelopment.openletters.ui.animation.navigationEnterTransition
44- import net.frozendevelopment.openletters.ui.animation.navigationExitTransition
45- import net.frozendevelopment.openletters.ui.animation.navigationPopEnterTransition
46- import net.frozendevelopment.openletters.ui.animation.navigationPopExitTransition
47- import net.frozendevelopment.openletters.ui.components.LettersNavDrawer
42+ import net.frozendevelopment.openletters.ui.navigation.EntryProvider
43+ import net.frozendevelopment.openletters.ui.navigation.LettersNavDrawer
44+ import net.frozendevelopment.openletters.ui.navigation.LocalDrawerState
45+ import net.frozendevelopment.openletters.ui.navigation.LocalNavigationState
46+ import net.frozendevelopment.openletters.ui.navigation.LocalNavigator
47+ import net.frozendevelopment.openletters.ui.navigation.Navigator
48+ import net.frozendevelopment.openletters.ui.navigation.koinEntryProvider
49+ import net.frozendevelopment.openletters.ui.navigation.rememberNavigationState
50+ import net.frozendevelopment.openletters.ui.navigation.toEntries
4851import net.frozendevelopment.openletters.ui.theme.OpenLettersTheme
4952import net.frozendevelopment.openletters.util.ThemeManagerType
5053import org.koin.android.ext.android.inject
54+ import org.koin.core.annotation.KoinExperimentalAPI
5155
5256class MainActivity : ComponentActivity () {
5357 private val themeManager: ThemeManagerType by inject()
5458 private val letterQueries: LetterQueries by inject()
5559
60+ @OptIn(KoinExperimentalAPI ::class )
5661 override fun onCreate (savedInstanceState : Bundle ? ) {
5762 installSplashScreen()
5863
@@ -68,8 +73,14 @@ class MainActivity : ComponentActivity() {
6873 colorPalette = currentTheme.second,
6974 ) {
7075 val coroutineScope = rememberCoroutineScope()
71- val drawerState: DrawerState = rememberDrawerState(initialValue = DrawerValue .Closed )
72- val navHostController = rememberNavController()
76+ val drawerState = rememberDrawerState(DrawerValue .Closed )
77+ val navigationState =
78+ rememberNavigationState(
79+ LetterListDestination ,
80+ setOf (LetterListDestination , ManageCategoryDestination , ReminderListDestination ),
81+ )
82+ val navigator = remember { Navigator (navigationState) }
83+ val entryProvider: EntryProvider = koinEntryProvider()
7384
7485 // lock the app to portrait for phone users
7586 if (currentWindowAdaptiveInfo().windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass .COMPACT ) {
@@ -80,27 +91,27 @@ class MainActivity : ComponentActivity() {
8091 drawerState = drawerState,
8192 goToMail = {
8293 coroutineScope.launch { drawerState.close() }
83- navHostController.newRoot (LetterListDestination )
94+ navigator.navigate (LetterListDestination )
8495 },
8596 goToManageCategories = {
8697 coroutineScope.launch { drawerState.close() }
87- navHostController.newRoot (ManageCategoryDestination )
98+ navigator.navigate (ManageCategoryDestination )
8899 },
89100 goToCreateCategory = {
90101 coroutineScope.launch { drawerState.close() }
91- navHostController .navigate(CategoryFormDestination ())
102+ navigator .navigate(CategoryFormDestination ())
92103 },
93104 goToReminders = {
94105 coroutineScope.launch { drawerState.close() }
95- navHostController.newRoot (ReminderListDestination )
106+ navigator.navigate (ReminderListDestination )
96107 },
97108 goToCreateReminder = {
98109 coroutineScope.launch { drawerState.close() }
99- navHostController .navigate(ReminderFormDestination ())
110+ navigator .navigate(ReminderFormDestination ())
100111 },
101112 goToSettings = {
102113 coroutineScope.launch { drawerState.close() }
103- navHostController .navigate(SettingsDestination )
114+ navigator .navigate(SettingsDestination )
104115 },
105116 ) {
106117 Scaffold (modifier = Modifier .fillMaxSize()) { _ ->
@@ -115,23 +126,40 @@ class MainActivity : ComponentActivity() {
115126 ),
116127 ),
117128 ) {
118- NavHost (
119- navController = navHostController,
120- startDestination =
121- if (letterQueries.hasLetters().executeAsOne() == 1L ) {
122- LetterListDestination
123- } else {
124- ScanLetterDestination (canNavigateBack = false )
125- },
126- enterTransition = { navigationEnterTransition() },
127- exitTransition = { navigationExitTransition() },
128- popEnterTransition = { navigationPopEnterTransition() },
129- popExitTransition = { navigationPopExitTransition() },
130- ) {
131- categories(navHostController, drawerState)
132- letters(navHostController, drawerState)
133- reminders(navHostController, drawerState)
134- settings(navHostController)
129+ CompositionLocalProvider (LocalDrawerState provides drawerState) {
130+ CompositionLocalProvider (LocalNavigationState provides navigationState) {
131+ CompositionLocalProvider (
132+ LocalNavigator provides navigator,
133+ ) {
134+ NavDisplay (
135+ entries = navigationState.toEntries(entryProvider),
136+ onBack = { navigator.pop() },
137+ transitionSpec = { navigationEnterTransition() },
138+ popTransitionSpec = {
139+ // Slide in from left when navigating back
140+ slideInHorizontally(
141+ initialOffsetX = { - it },
142+ animationSpec = tween(400 ),
143+ ) togetherWith
144+ slideOutHorizontally(
145+ targetOffsetX = { it },
146+ animationSpec = tween(400 ),
147+ )
148+ },
149+ predictivePopTransitionSpec = {
150+ // Slide in from left when navigating back
151+ slideInHorizontally(
152+ initialOffsetX = { - it },
153+ animationSpec = tween(400 ),
154+ ) togetherWith
155+ slideOutHorizontally(
156+ targetOffsetX = { it },
157+ animationSpec = tween(400 ),
158+ )
159+ },
160+ )
161+ }
162+ }
135163 }
136164 }
137165 }
0 commit comments