Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.flipcash.app.android.R
import com.flipcash.app.core.LocalUserManager
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.navigation.DeeplinkAction
import com.flipcash.app.core.navigation.homeRoute
import com.flipcash.app.core.extensions.navigateAll
import com.flipcash.app.core.extensions.resolveBackStack
import com.flipcash.app.featureflags.LocalFeatureFlags
Expand Down Expand Up @@ -219,7 +220,7 @@ internal fun buildNavGraphForLaunch(

AuthState.Ready -> {
// New UI opens on the Wallet tab; v1 opens on the Scanner.
val home = if (isNewUi) AppRoute.Sheets.Wallet else AppRoute.Main.Scanner
val home = homeRoute(isNewUi)
val link = deepLink()
if (link != null) {
when (val action = router.dispatch(link)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.flipcash.app.core.navigation

import com.flipcash.app.core.AppRoute

/**
* The top-level route the app releases to once there's a session — on launch and when onboarding
* finishes. v2 opens on the Wallet tab; v1 has no tab bar and opens on the Scanner.
*
* Under [isNewUi] the wallet is a flat tab home (not a sheet), so this route is applied with
* `replaceAll` / [com.getcode.navigation.core.NavOptions.PopUpTo.ClearAll], exactly like a tab
* switch from the nav bar.
*/
fun homeRoute(isNewUi: Boolean): AppRoute =
if (isNewUi) AppRoute.Sheets.Wallet else AppRoute.Main.Scanner
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.flipcash.app.core.navigation

import com.flipcash.app.core.AppRoute
import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Home is where both launch and the end of onboarding release the user to. Under v2 that's the
* Wallet tab — not the camera — so a freshly onboarded user lands on their balance.
*/
class HomeRouteTest {

@Test
fun `v2 home is the wallet tab`() {
assertEquals(AppRoute.Sheets.Wallet, homeRoute(isNewUi = true))
}

@Test
fun `v1 home is the scanner`() {
assertEquals(AppRoute.Main.Scanner, homeRoute(isNewUi = false))
}

@Test
fun `v2 home is a nav bar tab home`() {
// Guards the release path: it's applied with ClearAll, so it must map to a tab or the
// hoisted nav bar would render with no selection.
assertEquals(NavBarButton.Wallet, homeRoute(isNewUi = true).asNavBarTab())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.flipcash.app.analytics.Button
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.LocalUserManager
import com.flipcash.app.core.extensions.openAsSheet
import com.flipcash.app.core.navigation.homeRoute
import com.flipcash.app.featureflags.FeatureFlag
import com.flipcash.app.featureflags.LocalFeatureFlags
import com.flipcash.app.core.onboarding.OnboardingResult
Expand Down Expand Up @@ -80,17 +81,17 @@ import kotlin.time.Duration.Companion.milliseconds
* ```
* 1. New account (ResumePoint.Login → ProceedToVerification)
*
* Start → AccessKey ──┬────────────→ Name² → Contacts¹ → Notifications → Scanner
* Start → AccessKey ──┬────────────→ Name² → Contacts¹ → Notifications → Home³
* └→ Purchase ─┘
*
* 2. Seed restore (ResumePoint.Login → LoggedIn via SeedInput)
*
* Start → SeedInput ──┬────────────→ Name² → Contacts¹ → Notifications → Scanner
* Start → SeedInput ──┬────────────→ Name² → Contacts¹ → Notifications → Home³
* └→ Purchase ─┘
*
* 3. App resume (ResumePoint.PostAccessKey)
*
* → Notifications → Scanner
* → Notifications → Home³
* (contacts and name entry skipped — existing users encounter these in-app)
*
* 4. Mid-flow resume (ResumePoint.AccessKey / AccessKeyThenPurchase / DisplayName)
Expand All @@ -104,6 +105,8 @@ import kotlin.time.Duration.Companion.milliseconds
* [PermissionsPhaseFlowHost].
* ² Display-name entry is shown only when no display name is set. It reuses the
* UpdateUserProfile subflow, whose `target` replaces the stack with the permissions phase.
* ³ Home is the same route the app launches on — the Wallet tab under [FeatureFlag.NewUi], the
* Scanner under v1. See [homeRoute].
*/
@Composable
fun OnboardingFlowScreen(
Expand Down Expand Up @@ -149,6 +152,11 @@ private fun PermissionsPhaseFlowHost(
val userManager = LocalUserManager.current
val contactPickerMode by featureFlags.observe(FeatureFlag.ContactPickerMode).collectAsStateWithLifecycle()

// Onboarding releases to the same home the app launches on: the Wallet tab under v2, the
// Scanner under v1.
val isNewUi by featureFlags.observe(FeatureFlag.NewUi).collectAsStateWithLifecycle()
val home = homeRoute(isNewUi)

val permissionsSteps = buildList {
if (!route.skipContacts && !contactPickerMode) add(OnboardingStep.ContactPermission)
add(OnboardingStep.NotificationPermission)
Expand Down Expand Up @@ -179,20 +187,20 @@ private fun PermissionsPhaseFlowHost(
when (reason) {
is FlowExitReason.Completed -> {
analytics.action(Action.CompletedOnboarding)
trace(tag = "Onboarding", message = "Onboarding complete — releasing to scanner", type = TraceType.Process)
trace(tag = "Onboarding", message = "Onboarding complete — releasing to $home", type = TraceType.Process)
userManager?.set(AuthState.Ready)
outerNavigator.navigate(
route = AppRoute.Main.Scanner,
route = home,
options = NavOptions(popUpTo = NavOptions.PopUpTo.ClearAll),
)
}

FlowExitReason.BackedOutOfRoot -> {
// All permissions already granted
trace(tag = "Onboarding", message = "Onboarding complete (permissions already granted) — releasing to scanner", type = TraceType.Process)
trace(tag = "Onboarding", message = "Onboarding complete (permissions already granted) — releasing to $home", type = TraceType.Process)
userManager?.set(AuthState.Ready)
outerNavigator.navigate(
route = AppRoute.Main.Scanner,
route = home,
options = NavOptions(popUpTo = NavOptions.PopUpTo.ClearAll),
)
}
Expand Down
Loading