Skip to content

Commit 1573103

Browse files
committed
fix: speed up deeplink handling
cold: 6s to 500ms Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 613c16e commit 1573103

5 files changed

Lines changed: 113 additions & 102 deletions

File tree

app/src/main/java/com/getcode/CodeApp.kt

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,11 @@ fun CodeApp() {
4545
CodeTheme {
4646
val appState = rememberCodeAppState()
4747
AppNavHost {
48+
val codeNavigator = LocalCodeNavigator.current
49+
4850
CodeScaffold(
4951
scaffoldState = appState.scaffoldState
5052
) { innerPaddingModifier ->
51-
val codeNavigator = LocalCodeNavigator.current
52-
var replacingStackFromDeepLink by remember {
53-
mutableStateOf(false)
54-
}
5553

5654
Navigator(
5755
screen = MainRoot,
@@ -77,39 +75,28 @@ fun CodeApp() {
7775
modifier = Modifier
7876
.padding(innerPaddingModifier)
7977
) {
80-
if (replacingStackFromDeepLink) {
81-
CurrentScreen()
82-
replacingStackFromDeepLink = false
83-
} else {
84-
when (navigator.lastItem) {
85-
is LoginScreen, is MainRoot -> {
86-
CrossfadeTransition(navigator = navigator)
87-
}
88-
89-
else -> {
90-
SlideTransition(navigator = navigator)
91-
}
92-
}
78+
when (navigator.lastItem) {
79+
is LoginScreen, is MainRoot -> CrossfadeTransition(navigator = navigator)
80+
else -> SlideTransition(navigator = navigator)
9381
}
9482
}
9583
}
84+
}
9685

97-
//Listen for authentication changes here
98-
AuthCheck(
99-
navigator = codeNavigator,
100-
onNavigate = { screens, fromDeeplink ->
101-
replacingStackFromDeepLink = fromDeeplink
102-
codeNavigator.replaceAll(screens, inSheet = false)
103-
},
104-
onSwitchAccounts = { seed ->
105-
activity?.let {
106-
tlvm.logout(it) {
107-
appState.navigator.replaceAll(LoginScreen(seed))
108-
}
86+
//Listen for authentication changes here
87+
AuthCheck(
88+
navigator = codeNavigator,
89+
onNavigate = { screens ->
90+
codeNavigator.replaceAll(screens, inSheet = false)
91+
},
92+
onSwitchAccounts = { seed ->
93+
activity?.let {
94+
tlvm.logout(it) {
95+
appState.navigator.replaceAll(LoginScreen(seed))
10996
}
11097
}
111-
)
112-
}
98+
}
99+
)
113100
}
114101

115102
TopBarContainer(appState)

app/src/main/java/com/getcode/navigation/screens/MainScreens.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.getcode.model.KinAmount
1818
import com.getcode.navigation.core.LocalCodeNavigator
1919
import com.getcode.util.RepeatOnLifecycle
2020
import com.getcode.util.getActivityScopedViewModel
21+
import com.getcode.view.components.startupLog
2122
import com.getcode.view.main.account.AccountHome
2223
import com.getcode.view.main.account.AccountSheetViewModel
2324
import com.getcode.view.main.balance.BalanceSheet
@@ -41,6 +42,7 @@ sealed interface HomeResult {
4142

4243
@Parcelize
4344
data class HomeScreen(
45+
val seed: String? = null,
4446
val cashLink: String? = null,
4547
val requestPayload: String? = null,
4648
) : AppScreen(), MainGraph {
@@ -50,6 +52,7 @@ data class HomeScreen(
5052
@Composable
5153
override fun Content() {
5254
val vm = getActivityScopedViewModel<HomeViewModel>()
55+
startupLog("home rendered")
5356
HomeScreen(vm, cashLink, requestPayload)
5457

5558
OnScreenResult<HomeResult> { result ->

app/src/main/java/com/getcode/view/components/AuthCheck.kt

Lines changed: 77 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import androidx.compose.runtime.collectAsState
77
import androidx.compose.runtime.getValue
88
import androidx.compose.runtime.mutableStateOf
99
import androidx.compose.runtime.remember
10-
import androidx.compose.runtime.rememberCoroutineScope
1110
import androidx.compose.runtime.setValue
1211
import androidx.compose.ui.platform.LocalContext
1312
import cafe.adriel.voyager.core.screen.Screen
@@ -22,7 +21,9 @@ import com.getcode.navigation.screens.LoginGraph
2221
import com.getcode.navigation.screens.LoginScreen
2322
import com.getcode.util.DeeplinkHandler
2423
import com.getcode.util.getActivity
24+
import kotlinx.coroutines.CoroutineScope
2525
import kotlinx.coroutines.delay
26+
import kotlinx.coroutines.flow.Flow
2627
import kotlinx.coroutines.flow.combine
2728
import kotlinx.coroutines.flow.distinctUntilChanged
2829
import kotlinx.coroutines.flow.filter
@@ -36,12 +37,13 @@ import kotlinx.coroutines.flow.onEach
3637
import kotlinx.coroutines.launch
3738
import timber.log.Timber
3839

39-
const val AUTH_NAV = "Authentication Navigation"
40+
private const val APP_STARTUP_TAG = "app-startup"
41+
private typealias DeeplinkFlowState = Pair<Pair<DeeplinkHandler.Type, List<Screen>>, SessionManager.SessionState>
4042

4143
@Composable
4244
fun AuthCheck(
4345
navigator: CodeNavigator,
44-
onNavigate: (List<Screen>, Boolean) -> Unit,
46+
onNavigate: (List<Screen>) -> Unit,
4547
onSwitchAccounts: (String) -> Unit,
4648
) {
4749
val deeplinkHandler = LocalDeeplinks.current
@@ -60,18 +62,18 @@ fun AuthCheck(
6062
// Allow the seed input screen to complete and avoid
6163
// premature navigation
6264
if (currentRoute is AccessKeyLoginScreen) {
63-
log("No navigation within seed input")
65+
startupLog("No navigation within seed input")
6466
return@LaunchedEffect
6567
}
6668
if (currentRoute is LoginGraph) {
67-
log("No navigation within account creation and onboarding")
68-
} else {
69+
startupLog("No navigation within account creation and onboarding")
70+
} else {
6971
if (authenticated) {
70-
log("Navigating to home")
71-
onNavigate(listOf(HomeScreen()), false)
72+
startupLog("Navigating to home")
73+
onNavigate(listOf(HomeScreen()))
7274
} else {
73-
log("Navigating to login")
74-
onNavigate(listOf(LoginScreen()), false)
75+
startupLog("Navigating to login")
76+
onNavigate(listOf(LoginScreen()))
7577
}
7678
}
7779
} else {
@@ -86,58 +88,80 @@ fun AuthCheck(
8688
LaunchedEffect(deeplinkHandler) {
8789
val scope = this
8890
deeplinkHandler.intent
89-
.filterNotNull()
90-
.distinctUntilChanged()
91-
.mapNotNull { deeplinkHandler.handle() }
92-
.flatMapLatest { combine(flowOf(it), SessionManager.authState) { a, b -> a to b } }
93-
.filter { (data, authState) ->
94-
if (data.first is DeeplinkHandler.Type.Cash || data.first is DeeplinkHandler.Type.Sdk) {
95-
return@filter authState.isAuthenticated == true
96-
}
97-
return@filter true
98-
}
99-
.mapNotNull { (data, auth) ->
100-
val (type, screens) = data
101-
if (type is DeeplinkHandler.Type.Login) {
102-
if (auth.isAuthenticated == true) {
103-
val entropy = (screens.first() as? LoginScreen)?.seed
104-
log("showing logout confirm")
105-
if (entropy != null) {
106-
deeplinkRouted = true
107-
context.getActivity()?.intent = null
108-
deeplinkHandler.debounceIntent = null
109-
showLogoutMessage(
110-
context = context,
111-
entropyB64 = entropy,
112-
onSwitchAccounts = {
113-
scope.launch {
114-
delay(300) // wait for dismiss
115-
onSwitchAccounts(it)
116-
deeplinkRouted = false
117-
}
118-
},
119-
onCancel = {
120-
deeplinkRouted = false
121-
}
122-
)
123-
return@mapNotNull null
124-
}
125-
}
126-
}
127-
screens
91+
.flatMapLatest { combine(flowOf(deeplinkHandler.handle(it)), SessionManager.authState) { a, b -> a to b } }
92+
.filter { (result, authState) ->
93+
startupLog("checking auth state=${authState.isAuthenticated}")
94+
// wait for authentication
95+
return@filter result != null && authState.isAuthenticated == true
96+
}.mapNotNull { (result, state) ->
97+
result ?: return@mapNotNull null
98+
result to state
12899
}
129-
.onEach { screens ->
100+
.mapSeedToHome()
101+
.map { it.first }
102+
.onEach { (_, screens) ->
130103
deeplinkRouted = true
131-
log("navigated")
132-
onNavigate(screens, true)
104+
startupLog("navigating from deep link")
105+
onNavigate(screens)
133106
deeplinkHandler.debounceIntent = null
134107
context.getActivity()?.intent = null
135108
}
109+
.showLogoutConfirmationIfNeeded(
110+
context = context,
111+
scope = scope,
112+
onSwitchAccounts = {
113+
onSwitchAccounts(it)
114+
deeplinkRouted = false
115+
},
116+
onCancel = {
117+
deeplinkRouted = false
118+
}
119+
)
136120
.launchIn(this)
137121
}
138122
}
139123

140-
private fun log(message: String) = Timber.tag(AUTH_NAV).d(message)
124+
fun startupLog(message: String) = Timber.tag(APP_STARTUP_TAG).d(message)
125+
126+
private fun Flow<DeeplinkFlowState>.mapSeedToHome(): Flow<DeeplinkFlowState> =
127+
map { (data, auth) ->
128+
startupLog("checking type")
129+
val (type, screens) = data
130+
if (type is DeeplinkHandler.Type.Login && auth.isAuthenticated == true) {
131+
// send the user to home screen
132+
val entropy = (screens.first() as? LoginScreen)?.seed
133+
val updatedData = type to listOf(HomeScreen(seed = entropy))
134+
updatedData to auth
135+
} else {
136+
data to auth
137+
}
138+
}
139+
140+
141+
private fun Flow<Pair<DeeplinkHandler.Type, List<Screen>>>.showLogoutConfirmationIfNeeded(
142+
context: Context,
143+
scope: CoroutineScope,
144+
onSwitchAccounts: (String) -> Unit,
145+
onCancel: () -> Unit
146+
): Flow<Pair<DeeplinkHandler.Type, List<Screen>>> = onEach { (type, screens) ->
147+
if (type is DeeplinkHandler.Type.Login) {
148+
val entropy = (screens.first() as? HomeScreen)?.seed
149+
startupLog("showing logout confirm")
150+
if (entropy != null) {
151+
showLogoutMessage(
152+
context = context,
153+
entropyB64 = entropy,
154+
onSwitchAccounts = {
155+
scope.launch {
156+
delay(300) // wait for dismiss
157+
onSwitchAccounts(it)
158+
}
159+
},
160+
onCancel = onCancel
161+
)
162+
}
163+
}
164+
}
141165

142166
private fun showLogoutMessage(
143167
context: Context,

app/src/main/java/com/getcode/view/components/BottomBarView.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import androidx.compose.material.LocalContentColor
1414
import androidx.compose.material.Text
1515
import androidx.compose.runtime.Composable
1616
import androidx.compose.runtime.CompositionLocalProvider
17+
import androidx.compose.runtime.LaunchedEffect
1718
import androidx.compose.ui.Alignment
1819
import androidx.compose.ui.Modifier
1920
import com.getcode.manager.BottomBarManager
@@ -30,6 +31,9 @@ fun BottomBarView(
3031
) {
3132
bottomBarMessage ?: return
3233

34+
LaunchedEffect(bottomBarMessage) {
35+
startupLog("bottom bar message shown=${bottomBarMessage.title}")
36+
}
3337
BackHandler {
3438
onBackPressed()
3539
}

0 commit comments

Comments
 (0)