11package com.flipcash.app.internal.ui.navigation
22
3+ import androidx.activity.compose.BackHandler
4+ import androidx.compose.animation.slideInHorizontally
5+ import androidx.compose.animation.slideOutHorizontally
6+ import androidx.compose.animation.togetherWith
37import androidx.compose.runtime.Composable
4- import cafe.adriel.voyager.core.registry.ScreenRegistry
5- import cafe.adriel.voyager.core.screen.Screen
8+ import androidx.compose.runtime.CompositionLocalProvider
9+ import androidx.compose.runtime.remember
10+ import androidx.navigation3.runtime.NavEntry
11+ import androidx.navigation3.runtime.NavKey
12+ import androidx.navigation3.runtime.rememberNavBackStack
13+ import androidx.navigation3.scene.SinglePaneSceneStrategy
614import com.flipcash.app.advanced.AdvancedFeaturesScreen
715import com.flipcash.app.appsettings.AppSettingsScreen
816import com.flipcash.app.backupkey.BackupKeyScreen
@@ -13,6 +21,7 @@ import com.flipcash.app.contact.verification.VerificationFlowScreen
1321import com.flipcash.app.core.AppRoute
1422import com.flipcash.app.currency.RegionSelectionScreen
1523import com.flipcash.app.deposit.DepositScreen
24+ import com.flipcash.app.internal.ui.navigation.decorators.rememberNavMessagingEntryDecorator
1625import com.flipcash.app.lab.LabsScreen
1726import com.flipcash.app.lab.PreloadLabs
1827import com.flipcash.app.lab.StandaloneLabsScreen
@@ -39,151 +48,211 @@ import com.flipcash.app.withdrawal.WithdrawalConfirmationScreen
3948import com.flipcash.app.withdrawal.WithdrawalDestinationScreen
4049import com.flipcash.app.withdrawal.WithdrawalEntryScreen
4150import com.flipcash.app.withdrawal.WithdrawalFlow
42- import com.getcode.navigation.screens.ModalScreen
51+ import com.getcode.navigation.AppNavHost
52+ import com.getcode.navigation.core.LocalCodeNavigator
53+ import com.getcode.navigation.core.rememberCodeNavigator
54+ import com.getcode.navigation.metadata
55+ import com.getcode.navigation.results.NavResultStateRegistry
56+ import com.getcode.navigation.scenes.LocalBottomSheetDismissDispatcher
57+ import com.getcode.navigation.scenes.ModalBottomSheetSceneStrategy
58+ import com.getcode.ui.components.bars.BarManager
59+ import dev.theolm.rinku.DeepLink
4360
4461@Composable
45- internal fun AppScreenContent (content : @Composable () -> Unit ) {
46- ScreenRegistry {
47- register<AppRoute .Onboarding .Login > {
48- LoginRouter (it.seed, it.fromDeeplink)
62+ fun AppPreloads () {
63+ PreloadBalance ()
64+ PreloadLabs ()
65+ }
66+
67+ fun appEntryProvider (
68+ key : NavKey ,
69+ resultStateRegistry : NavResultStateRegistry ,
70+ barManager : BarManager ,
71+ deepLink : () -> DeepLink ? ,
72+ ): NavEntry <NavKey > {
73+ return when (key) {
74+ is AppRoute .Loading -> NavEntry (key = key, metadata = key.metadata()) {
75+ MainRoot (deepLink)
4976 }
5077
51- register<AppRoute .Onboarding .SeedInput > {
78+ is AppRoute .Onboarding .Login -> NavEntry (key = key, metadata = key.metadata()) {
79+ LoginRouter (key.seed, key.fromDeeplink)
80+ }
81+ is AppRoute .Onboarding .SeedInput -> NavEntry (key = key, metadata = key.metadata()) {
5282 SeedInputScreen ()
5383 }
54-
55- register<AppRoute .Onboarding .AccessKey > {
84+ is AppRoute .Onboarding .AccessKey -> NavEntry (key = key, metadata = key.metadata()) {
5685 AccessKeyScreen ()
5786 }
58-
59- register<AppRoute .Onboarding .AccessKeySavedLocation > {
87+ is AppRoute .Onboarding .AccessKeySavedLocation -> NavEntry (key = key, metadata = key.metadata()) {
6088 PhotoAccessKeyScreen ()
6189 }
62-
63- register<AppRoute .Onboarding .Purchase > {
64- PurchaseAccountScreen (it.fromLogin)
90+ is AppRoute .Onboarding .Purchase -> NavEntry (key = key, metadata = key.metadata()) {
91+ PurchaseAccountScreen (key.fromLogin)
6592 }
66-
67- register< AppRoute .Sheets . Lab > {
68- StandaloneLabsScreen ()
93+ is AppRoute . Onboarding . NotificationPermission ,
94+ is AppRoute .Onboarding . CameraPermission -> NavEntry (key = key, metadata = key.metadata()) {
95+ // Deprecated — permissions requested at time of use
6996 }
7097
71- register<AppRoute .Main .AppRestricted > {
72- AppRestrictedScreen (it.restrictionType)
98+ is AppRoute .Main .Sheet -> sheetEntry(key, resultStateRegistry, barManager)
99+ is AppRoute .Main .AppRestricted -> NavEntry (key = key, metadata = key.metadata()) {
100+ AppRestrictedScreen (key.restrictionType)
73101 }
74-
75- register<AppRoute .Main .Scanner > {
76- ScannerScreen (it.deeplink)
102+ is AppRoute .Main .Scanner -> NavEntry (key = key, metadata = key.metadata()) {
103+ ScannerScreen (key.deeplink)
77104 }
78-
79- register<AppRoute .Main .Give > {
80- CashScreen (it.mint, it.fromTokenInfo)
105+ is AppRoute .Sheets .Give -> NavEntry (key = key, metadata = key.metadata()) {
106+ CashScreen (key.mint, key.fromTokenInfo)
81107 }
82-
83- register<AppRoute .Token .Info > {
84- TokenInfoScreen (it.mint, it.forNeededFunds, it.fromDeeplink)
108+ is AppRoute .Main .RegionSelection -> NavEntry (key = key, metadata = key.metadata()) {
109+ RegionSelectionScreen (key.kind)
85110 }
86111
87- register< AppRoute .Token .Transactions > {
88- TransactionHistoryScreen (it .mint)
112+ is AppRoute .Token .Info -> NavEntry (key = key, metadata = key.metadata()) {
113+ TokenInfoScreen (key .mint, key.forNeededFunds, key.fromDeeplink )
89114 }
90-
91- register<AppRoute .Token .SwapTransact > {
92- BuySellFlow .start(it.forNeededFunds)
93- TokenBuySellEntryScreen (it.purpose)
115+ is AppRoute .Token .Transactions -> NavEntry (key = key, metadata = key.metadata()) {
116+ TransactionHistoryScreen (key.mint)
94117 }
95-
96- register< AppRoute . Token . TxProcessing > {
97- TokenTxProcessingScreen (it.swapId, it.awaitExternalWallet )
118+ is AppRoute . Token . SwapTransact -> NavEntry (key = key, metadata = key.metadata()) {
119+ remember { BuySellFlow .start(key.forNeededFunds) }
120+ TokenBuySellEntryScreen (key.purpose )
98121 }
99-
100- register<AppRoute .Token .SellReceipt > {
122+ is AppRoute .Token .TxProcessing -> NavEntry (key = key, metadata = key.metadata()) {
123+ TokenTxProcessingScreen (key.swapId, key.awaitExternalWallet)
124+ }
125+ is AppRoute .Token .SellReceipt -> NavEntry (key = key, metadata = key.metadata()) {
101126 TokenSellReceiptScreen ()
102127 }
103128
104- register< AppRoute .Sheets .TokenSelection > {
105- TokenSelectScreen (it .purpose)
129+ is AppRoute .Sheets .TokenSelection -> NavEntry (key = key, metadata = key.metadata()) {
130+ TokenSelectScreen (key .purpose)
106131 }
107-
108- register<AppRoute .Sheets .Wallet > {
132+ is AppRoute .Sheets .Wallet -> NavEntry (key = key, metadata = key.metadata()) {
109133 BalanceScreen ()
110134 }
111-
112- register<AppRoute .Main .RegionSelection > {
113- RegionSelectionScreen (it.kind)
114- }
115-
116- register<AppRoute .Sheets .ShareApp > {
135+ is AppRoute .Sheets .ShareApp -> NavEntry (key = key, metadata = key.metadata()) {
117136 ShareAppScreen ()
118137 }
138+ is AppRoute .Sheets .Menu -> NavEntry (key = key, metadata = key.metadata()) {
139+ MenuScreen ()
140+ }
141+ is AppRoute .Sheets .Lab -> NavEntry (key = key, metadata = key.metadata()) {
142+ StandaloneLabsScreen ()
143+ }
119144
120- register< AppRoute .Verification > {
145+ is AppRoute .Verification -> NavEntry (key = key, metadata = key.metadata()) {
121146 VerificationFlowScreen (
122- origin = it .origin,
123- target = it .target,
124- includePhone = it .includePhone,
125- includeEmail = it .includeEmail,
126- emailAddress = it .email,
127- emailVerificationCode = it .emailVerificationCode
147+ origin = key .origin,
148+ target = key .target,
149+ includePhone = key .includePhone,
150+ includeEmail = key .includeEmail,
151+ emailAddress = key .email,
152+ emailVerificationCode = key .emailVerificationCode,
128153 )
129154 }
130155
131- register< AppRoute .OnRamp .ProviderList > {
132- OnRampFlowTracker .start(it .from)
156+ is AppRoute .OnRamp .ProviderList -> NavEntry (key = key, metadata = key.metadata()) {
157+ remember { OnRampFlowTracker .start(key .from) }
133158 OnRampProviderListScreen (
134- neededAmount = it .neededAmount?.quarks,
135- neededCurrency = it .neededAmount?.currencyCode
159+ neededAmount = key .neededAmount?.quarks,
160+ neededCurrency = key .neededAmount?.currencyCode,
136161 )
137162 }
138-
139- register<AppRoute .OnRamp .AmountEntry > {
163+ is AppRoute .OnRamp .AmountEntry -> NavEntry (key = key, metadata = key.metadata()) {
140164 OnRampCustomAmountScreen ()
141165 }
142166
143- register<AppRoute .Sheets .Menu > {
144- MenuScreen ()
145- }
146-
147- register<AppRoute .Menu .AppSettings > {
167+ is AppRoute .Menu .AppSettings -> NavEntry (key = key, metadata = key.metadata()) {
148168 AppSettingsScreen ()
149169 }
150-
151- register<AppRoute .Menu .Lab > {
170+ is AppRoute .Menu .Lab -> NavEntry (key = key, metadata = key.metadata()) {
152171 LabsScreen ()
153172 }
154-
155- register<AppRoute .Transfers .Withdrawal .Amount > {
156- WithdrawalFlow .start()
157- WithdrawalEntryScreen (it.mint)
173+ is AppRoute .Menu .MyAccount -> NavEntry (key = key, metadata = key.metadata()) {
174+ MyAccountScreen ()
175+ }
176+ is AppRoute .Menu .Deposit -> NavEntry (key = key, metadata = key.metadata()) {
177+ DepositScreen (key.mint)
178+ }
179+ is AppRoute .Menu .BackupKey -> NavEntry (key = key, metadata = key.metadata()) {
180+ BackupKeyScreen ()
181+ }
182+ is AppRoute .Menu .AdvancedFeatures -> NavEntry (key = key, metadata = key.metadata()) {
183+ AdvancedFeaturesScreen ()
158184 }
159185
160- register<AppRoute .Transfers .Withdrawal .Destination > {
186+ is AppRoute .Transfers .Withdrawal .Amount -> NavEntry (key = key, metadata = key.metadata()) {
187+ remember { WithdrawalFlow .start() }
188+ WithdrawalEntryScreen (key.mint)
189+ }
190+ is AppRoute .Transfers .Withdrawal .Destination -> NavEntry (key = key, metadata = key.metadata()) {
161191 WithdrawalDestinationScreen ()
162192 }
163-
164- register<AppRoute .Transfers .Withdrawal .Confirmation > {
193+ is AppRoute .Transfers .Withdrawal .Confirmation -> NavEntry (key = key, metadata = key.metadata()) {
165194 WithdrawalConfirmationScreen ()
166195 }
167196
168- register<AppRoute .Menu .MyAccount > {
169- MyAccountScreen ()
170- }
171-
172- register<AppRoute .Menu .Deposit > {
173- DepositScreen (it.mint)
197+ else -> error(" Unknown route: $key " )
198+ }
199+ }
200+
201+ /* *
202+ * Sheet entry with nested [AppNavHost] for inner-sheet navigation.
203+ * Uses slide transitions for intra-sheet navigation.
204+ */
205+ private fun sheetEntry (
206+ key : AppRoute .Main .Sheet ,
207+ resultStateRegistry : NavResultStateRegistry ,
208+ barManager : BarManager ,
209+ ): NavEntry <NavKey > {
210+ return NavEntry (key = key, metadata = key.metadata()) {
211+ val sheetDismissDispatcher = LocalBottomSheetDismissDispatcher .current
212+ val backStack = rememberNavBackStack(key.initialRoute)
213+ val navigator = rememberCodeNavigator(
214+ backStack = backStack,
215+ resultStateRegistry = resultStateRegistry,
216+ onRootReached = { sheetDismissDispatcher() },
217+ )
218+
219+ val onBack = {
220+ if (backStack.size > 1 ) {
221+ backStack.removeAt(backStack.lastIndex)
222+ } else {
223+ sheetDismissDispatcher()
224+ }
174225 }
175226
176- register<AppRoute .Menu .BackupKey > {
177- BackupKeyScreen ()
178- }
227+ CompositionLocalProvider (LocalCodeNavigator provides navigator) {
228+ AppNavHost (
229+ navigator = navigator,
230+ resultStateRegistry = resultStateRegistry,
231+ decorators = listOf (
232+ rememberNavMessagingEntryDecorator(navigator.backStack, barManager)
233+ ),
234+ sceneStrategy = ModalBottomSheetSceneStrategy <NavKey >(navigator.resultStore) {
235+ navigator.backStack.getOrNull(navigator.backStack.lastIndex - 1 )
236+ } then SinglePaneSceneStrategy (),
237+ transitionSpec = {
238+ slideInHorizontally(initialOffsetX = { it }) togetherWith
239+ slideOutHorizontally(targetOffsetX = { - it })
240+ },
241+ popTransitionSpec = {
242+ slideInHorizontally(initialOffsetX = { - it }) togetherWith
243+ slideOutHorizontally(targetOffsetX = { it })
244+ },
245+ predictivePopTransitionSpec = {
246+ slideInHorizontally(initialOffsetX = { - it }) togetherWith
247+ slideOutHorizontally(targetOffsetX = { it })
248+ },
249+ onBack = { onBack() },
250+ entryProvider = { innerKey ->
251+ appEntryProvider(innerKey, resultStateRegistry, barManager, deepLink = { null })
252+ }
253+ )
179254
180- register<AppRoute .Menu .AdvancedFeatures > {
181- AdvancedFeaturesScreen ()
255+ BackHandler { onBack() }
182256 }
183257 }
184-
185- PreloadBalance ()
186- PreloadLabs ()
187-
188- content()
189- }
258+ }
0 commit comments