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 @@ -227,6 +227,28 @@ internal fun App(
resultStateRegistry = resultStateRegistry,
barManager = barManager,
deepLink = { deepLink },
onPendingAction = { action ->
deeplinkHandled = true
when (action) {
is DeeplinkAction.OpenCashLink ->
session.openCashLink(action.entropy)
is DeeplinkAction.Login ->
viewModel.handleLoginEntropy(
action.entropy,
onSwitchAccount = {
codeNavigator.replaceAll(
AppRoute.OnboardingFlow(
seed = action.entropy,
fromDeeplink = true
)
)
},
onDismissed = { }
)
else -> {}
}
deepLink = null
},
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.flipcash.app.cash.CashScreen
import com.flipcash.app.contact.verification.VerificationFlowScreen
import com.flipcash.app.currencycreator.CurrencyCreatorFlowScreen
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.navigation.DeeplinkAction
import com.flipcash.app.currency.RegionSelectionScreen
import com.flipcash.app.deposit.DepositFlowScreen
import com.flipcash.app.directsend.SendFlowScreen
Expand Down Expand Up @@ -67,10 +68,11 @@ fun appEntryProvider(
resultStateRegistry: NavResultStateRegistry,
barManager: BarManager,
deepLink: () -> DeepLink?,
onPendingAction: (DeeplinkAction) -> Unit = {},
): (NavKey) -> NavEntry<NavKey> = entryProvider {

// Loading / splash
annotatedEntry<AppRoute.Loading> { MainRoot(deepLink) }
annotatedEntry<AppRoute.Loading> { MainRoot(deepLink, onPendingAction) }

// Onboarding flow
annotatedEntry<AppRoute.OnboardingFlow> { key ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ import kotlinx.coroutines.flow.onEach
import kotlin.time.Duration.Companion.seconds

@Composable
internal fun MainRoot(deepLink: () -> DeepLink?) {
internal fun MainRoot(
deepLink: () -> DeepLink?,
onPendingAction: (DeeplinkAction) -> Unit = {},
) {
val navigator = LocalCodeNavigator.current
val userManager = LocalUserManager.current!!
var showLoading by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -129,6 +132,13 @@ internal fun MainRoot(deepLink: () -> DeepLink?) {
navigator.navigateAll(launch.deeplinkRoutes)
}
}

// Fire eagerly so the claim/login starts in parallel
// with the nav transition instead of waiting for
// App.kt's LaunchedEffect to see a non-Loading route.
if (launch.pendingAction != null) {
onPendingAction(launch.pendingAction)
}
}
}.launchIn(this)
}
Expand All @@ -144,6 +154,7 @@ internal fun MainRoot(deepLink: () -> DeepLink?) {
internal data class LaunchNavGraph(
val baseRoutes: List<NavKey>,
val deeplinkRoutes: List<AppRoute> = emptyList(),
val pendingAction: DeeplinkAction? = null,
) {
/**
* Predict the final backstack that [baseRoutes] + [navigateTo(deeplinkRoutes)] will produce.
Expand Down Expand Up @@ -192,8 +203,13 @@ internal fun buildNavGraphForLaunch(
baseRoutes = listOf(AppRoute.Main.Scanner),
deeplinkRoutes = action.routes,
)
// OpenCashLink/Login/ExternalWallet are handled by App.kt's
// LaunchedEffect(deepLink, currentRoute) once we leave Loading.

is DeeplinkAction.OpenCashLink,
is DeeplinkAction.Login -> LaunchNavGraph(
baseRoutes = listOf(AppRoute.Main.Scanner),
pendingAction = action,
)

else -> LaunchNavGraph(listOf(AppRoute.Main.Scanner))
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,29 @@ class BuildNavGraphForLaunchTest {
}

@Test
fun `logged in with OpenCashLink defers to App for dispatch`() {
fun `logged in with OpenCashLink fires eagerly via pendingAction`() {
val action = DeeplinkAction.OpenCashLink("testEntropy")
val result = build(
state = AuthState.Ready,
action = DeeplinkAction.OpenCashLink("testEntropy"),
action = action,
deepLink = dummyLink,
)!!
assertEquals(listOf(AppRoute.Main.Scanner), result.baseRoutes)
assertTrue(result.deeplinkRoutes.isEmpty(), "OpenCashLink must not be consumed by MainRoot")
assertTrue(result.deeplinkRoutes.isEmpty())
assertEquals(action, result.pendingAction)
}

@Test
fun `logged in with Login action defers to App for dispatch`() {
fun `logged in with Login action fires eagerly via pendingAction`() {
val action = DeeplinkAction.Login("seed")
val result = build(
state = AuthState.Ready,
action = DeeplinkAction.Login("seed"),
action = action,
deepLink = dummyLink,
)!!
assertEquals(listOf(AppRoute.Main.Scanner), result.baseRoutes)
assertTrue(result.deeplinkRoutes.isEmpty(), "Login must not be consumed by MainRoot")
assertTrue(result.deeplinkRoutes.isEmpty())
assertEquals(action, result.pendingAction)
}

@Test
Expand Down
Loading