Skip to content

Commit 67c8ed4

Browse files
committed
ref(android-nav3): clarify observer nav state helpers
1 parent 76a9013 commit 67c8ed4

1 file changed

Lines changed: 42 additions & 40 deletions

File tree

‎sentry-android-navigation3/src/main/kotlin/io/sentry/compose/navigation3/BackStackObserver.kt‎

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ import io.sentry.protocol.TransactionNameSource
2222
import io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion
2323
import java.lang.ref.WeakReference
2424

25-
private const val BACKSTACK_KEY = "backstack"
26-
private const val NAVIGATION_CONTEXT_KEY = "navigation"
2725
private const val NAVIGATION_OP: String = "navigation"
28-
private const val TRANSACTION_ORIGIN = "auto.navigation.nav3"
2926

3027
/**
3128
* Observes the back stack managed by a single [SentryNavEffect] and records Sentry state as the
@@ -61,7 +58,7 @@ internal class BackStackObserver<T : Any>(
6158

6259
private val routeTranslator = RouteTranslator(extractors, scopes.options.logger)
6360

64-
private val navTransaction = NavTransaction(scopes, NAVIGATION_OP, TRANSACTION_ORIGIN)
61+
private val navTransaction = NavTransaction(scopes)
6562
private val navContext = NavContext(scopes, options)
6663
private val navScreen = NavScreen()
6764
private val navBreadcrumbs = NavBreadcrumbs(scopes)
@@ -127,7 +124,7 @@ internal class BackStackObserver<T : Any>(
127124
// replaces one observer with another, there may be a brief gap where events lack nav
128125
// context. Apps should keep the observer at the nav root so cleanup only runs when the
129126
// navigation session is ending, not during normal destination changes.
130-
navContext.update(scope, emptyList())
127+
navContext.clear(scope)
131128
}
132129
}
133130
}
@@ -147,15 +144,8 @@ internal class BackStackObserver<T : Any>(
147144
when (change) {
148145
is BackStackIsEmpty -> handleEmptyBackStack(scope)
149146

150-
is BackStackHasNewTop -> {
151-
handleNewTop(scope, change.previousTop, change.backStack)
152-
storeAsPreviousTop(change.backStack.topEntry, change.backStack.topRoute)
153-
}
154-
155-
is BackStackHasSameTop -> {
156-
handleSameTop(scope, change.backStack)
157-
storeAsPreviousTop(change.backStack.topEntry, change.backStack.topRoute)
158-
}
147+
is BackStackHasNewTop -> handleNewTop(scope, change.previousTop, change.backStack)
148+
is BackStackHasSameTop -> handleSameTop(scope, change.backStack)
159149
}
160150
}
161151

@@ -230,24 +220,31 @@ internal class BackStackObserver<T : Any>(
230220
// Rotate the propagation context.
231221
scope.withPropagationContext { scope.setPropagationContext(PropagationContext()) }
232222
}
223+
224+
storeAsPreviousTop(currentBackStack.topEntry, currentBackStack.topRoute)
233225
}
234226

235227
private fun handleSameTop(scope: IScope, backStack: BackStackData<T>) {
236228
navContext.update(scope, backStack.capturedRoutes)
229+
storeAsPreviousTop(backStack.topEntry, backStack.topRoute)
237230
}
238231

239232
private fun handleEmptyBackStack(scope: IScope) {
240233
navTransaction.stop(scope)
234+
navContext.clear(scope)
241235
navScreen.clear(scope)
242-
navContext.update(scope, emptyList())
243-
previousTopEntry = null
244-
previousTopRoute = null
236+
clearPreviousTop()
245237
}
246238

247239
private fun storeAsPreviousTop(topEntry: T, topRoute: Route) {
248240
previousTopEntry = WeakReference(topEntry)
249241
previousTopRoute = topRoute
250242
}
243+
244+
private fun clearPreviousTop() {
245+
previousTopEntry = null
246+
previousTopRoute = null
247+
}
251248
}
252249

253250
/**
@@ -287,27 +284,27 @@ private data class BackStackData<T>(
287284
)
288285

289286
/** A helper class for managing nav transactions. */
290-
private class NavTransaction(
291-
private val scopes: IScopes,
292-
private val navigationOp: String,
293-
private val transactionOrigin: String,
294-
) {
287+
private class NavTransaction(private val scopes: IScopes) {
288+
289+
private companion object {
290+
private const val TRANSACTION_ORIGIN = "auto.navigation.nav3"
291+
}
295292

296293
private var activeNavTransaction: ITransaction? = null
297294

298295
/** Starts an idle navigation transaction, or no-ops if another transaction is already active. */
299296
fun start(
300297
scope: IScope,
301-
routeName: String,
298+
name: String,
302299
arguments: Map<String, Any?>,
303300
): ITransaction? {
304-
clearFinishedScopeTransaction(scope)
301+
clearTransactionIfFinished(scope)
305302

306303
if (scope.transaction != null) {
307304
scopes.options.logger.log(
308305
DEBUG,
309306
"Nav3 transaction for route %s won't be created because another transaction is active.",
310-
routeName,
307+
name,
311308
)
312309

313310
return null
@@ -320,12 +317,12 @@ private class NavTransaction(
320317
val deadlineTimeoutMillis = scopes.options.deadlineTimeout
321318
it.deadlineTimeout = if (deadlineTimeoutMillis <= 0) null else deadlineTimeoutMillis
322319
it.isTrimEnd = true
323-
it.origin = transactionOrigin
320+
it.origin = TRANSACTION_ORIGIN
324321
}
325322

326323
val transaction =
327324
scopes.startTransaction(
328-
TransactionContext(routeName, TransactionNameSource.ROUTE, navigationOp),
325+
TransactionContext(name, TransactionNameSource.ROUTE, NAVIGATION_OP),
329326
transactionOptions,
330327
)
331328

@@ -362,7 +359,7 @@ private class NavTransaction(
362359
}
363360

364361
/** Clears a stale finished transaction that's still bound to the default scope. */
365-
private fun clearFinishedScopeTransaction(scope: IScope) {
362+
private fun clearTransactionIfFinished(scope: IScope) {
366363
scope.withTransaction { tx ->
367364
if (tx?.isFinished == true) {
368365
scope.clearTransaction()
@@ -374,12 +371,24 @@ private class NavTransaction(
374371
/** A helper class for updating [nav context][NAVIGATION_CONTEXT_KEY]. */
375372
private class NavContext(private val scopes: IScopes, private val options: SentryNavOptions) {
376373

374+
private companion object {
375+
private const val BACKSTACK_KEY = "backstack"
376+
private const val NAVIGATION_CONTEXT_KEY = "navigation"
377+
}
378+
377379
fun update(scope: IScope, backStackRoutes: List<Route>) {
378380
if (backStackRoutes.isEmpty()) {
379-
removeNavContext(scope)
380-
} else {
381-
scope.setContexts(NAVIGATION_CONTEXT_KEY, backStackRoutes.toNavigationContext())
381+
clear(scope)
382+
return
382383
}
384+
385+
scope.setContexts(NAVIGATION_CONTEXT_KEY, backStackRoutes.toBackStackMap())
386+
}
387+
388+
fun clear(scope: IScope) {
389+
// We purposefully don't call IScope.removeContexts(), as it doesn't notify IScopeObserver and
390+
// therefore doesn't write its updates to disk ¯\_ (ツ)_/¯.
391+
scope.setContexts(NAVIGATION_CONTEXT_KEY, null as Any?)
383392
}
384393

385394
/**
@@ -405,19 +414,12 @@ private class NavContext(private val scopes: IScopes, private val options: Sentr
405414
}
406415

407416
if (options.captureBackStack && backStack.capturedRoutes.isNotEmpty()) {
408-
transaction.setContext(NAVIGATION_CONTEXT_KEY, backStack.capturedRoutes.toNavigationContext())
417+
transaction.setContext(NAVIGATION_CONTEXT_KEY, backStack.capturedRoutes.toBackStackMap())
409418
}
410419
}
411420

412-
private fun removeNavContext(scope: IScope) {
413-
// We purposefully don't call IScope.removeContexts(), as it doesn't notify IScopeObserver and
414-
// therefore doesn't write its updates to disk ¯\_ (ツ)_/¯.
415-
scope.setContexts(NAVIGATION_CONTEXT_KEY, null as Any?)
416-
}
417-
418421
/** Builds the `{"backstack": [...]}` map bound under [NAVIGATION_CONTEXT_KEY]. */
419-
private fun List<Route>.toNavigationContext(): Map<String, Any?> =
420-
mapOf(BACKSTACK_KEY to serialize())
422+
private fun List<Route>.toBackStackMap(): Map<String, Any?> = mapOf(BACKSTACK_KEY to serialize())
421423
}
422424

423425
/** A helper class for updating the tracked screen name. */

0 commit comments

Comments
 (0)