Skip to content
Open
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 @@ -450,7 +450,7 @@ internal data class NormalizedSentryBackStackEntry(
internal fun List<NormalizedSentryBackStackEntry>.serialize(): List<Map<String, Any?>> =
map(NormalizedSentryBackStackEntry::serialize)

/** Why host-provided arguments were unavailable in emitted navigation data. */
/** Why host-provided arguments were unavailable in emitted nav state. */
internal enum class ArgumentDropReason(
val serializedValue: String,
val exhaustsUpdateBudget: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public class SentryBackStackEntry(
*
* If [map] throws, returns `null`, or returns a blank [name][SentryBackStackEntry.name], Sentry
* records the destination as "/unknown". Doing so signals that name extraction needs to be fixed
* while avoiding misleading gaps in navigation data.
* while avoiding misleading gaps in nav state.
*
* For instance, if a user navigates from `/home -> /detail -> /settings`, but the mapper for
* `/detail` throws, the back stack record will be `/home -> /unknown -> /settings` rather than
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package io.sentry.compose.navigation3

import io.sentry.Breadcrumb
import io.sentry.Hint
import io.sentry.ITransaction
import io.sentry.SentryIntegrationPackageStorage
import io.sentry.SentryLevel.DEBUG
import io.sentry.SentryLevel.INFO
import io.sentry.SentryOptions
import io.sentry.SpanStatus
import io.sentry.TransactionContext
import io.sentry.TransactionOptions
import io.sentry.compose.navigation3.BackStackConverter.RetentionPolicy
Expand All @@ -16,6 +13,7 @@ import io.sentry.compose.navigation3.PreparedChange.BackStackHasSameTop
import io.sentry.compose.navigation3.PreparedChange.BackStackIsEmpty
import io.sentry.compose.navigation3.lifecycle.INavScope
import io.sentry.compose.navigation3.lifecycle.INavScopes
import io.sentry.compose.navigation3.lifecycle.INavTransaction
import io.sentry.compose.navigation3.lifecycle.NAVIGATION_CONTEXT_KEY
import io.sentry.protocol.App
import io.sentry.protocol.TransactionNameSource
Expand Down Expand Up @@ -59,7 +57,7 @@ internal class BackStackObserver<T : Any>(

private val backStackConverter = BackStackConverter(entryMapper, scopes.options.logger)

private val navTransaction = NavTransaction(scopes)
private val navTransactions = NavTransactions(scopes)
private val navBreadcrumbs = NavBreadcrumbs(scopes)
private val navScreen = NavScreen()
private val navContext = NavContext(scopes, options)
Expand All @@ -83,7 +81,7 @@ internal class BackStackObserver<T : Any>(
}

/**
* Updates Sentry nav data based on the provided [backStack].
* Updates Sentry nav state based on the provided [backStack].
*
* **Data generated**
*
Expand Down Expand Up @@ -113,7 +111,7 @@ internal class BackStackObserver<T : Any>(
}

/**
* Clears the nav data this observer recorded.
* Clears the nav state this observer recorded.
*
* Call it when observation ends so that no stale screen, nav context, or nav transaction outlives
* it.
Expand Down Expand Up @@ -194,10 +192,10 @@ internal class BackStackObserver<T : Any>(
navBreadcrumbs.emit(fromEntry = previousTop, toEntry = currentBackStack.topEntryNormalized)
}

navTransaction.stop(scope)
navTransactions.stop(scope)

if (areNavigationTransactionsEnabled) {
navTransaction
navTransactions
.start(
scope,
currentTop.name,
Expand Down Expand Up @@ -231,7 +229,7 @@ internal class BackStackObserver<T : Any>(
}

private fun tearDown(scope: INavScope) {
navTransaction.stop(scope)
navTransactions.stop(scope)
navContext.clear(scope)
navScreen.clear(scope)
clearPreviousTop()
Expand Down Expand Up @@ -277,32 +275,22 @@ private data class BackStackData<T>(
)

/** A helper class for managing nav transactions. */
private class NavTransaction(private val scopes: INavScopes) {
private class NavTransactions(private val scopes: INavScopes) {

private companion object {
private const val TRANSACTION_ORIGIN = "auto.navigation.nav3"
}

private var activeNavTransaction: ITransaction? = null

/** Starts an idle navigation transaction, or no-ops if another transaction is already active. */
/**
* Starts an idle navigation transaction, or no-ops if another transaction is already active.
*
* [Stop][stop] the current navigation transaction first. See [INavScope.startNavTransaction].
*/
fun start(
scope: INavScope,
name: String,
arguments: Map<String, Any?>,
): ITransaction? {
scope.clearFinishedTransaction()

if (scope.transaction != null) {
scopes.options.logger.log(
DEBUG,
"Nav3 transaction for route %s won't be created because another transaction is active.",
name,
)

return null
}

): INavTransaction? {
val transactionOptions =
TransactionOptions().also {
it.isWaitForChildren = true
Expand All @@ -314,36 +302,25 @@ private class NavTransaction(private val scopes: INavScopes) {
}

val transaction =
scopes.startTransaction(
scope.startNavTransaction(
TransactionContext(name, TransactionNameSource.ROUTE, NAVIGATION_OP),
transactionOptions,
)
) ?: return null

// Not an error: INavScopes.startTransaction may decline to start a transaction by design.
if (transaction.isNoOp) {
return null
if (arguments.isNotEmpty()) {
transaction.setData("arguments", arguments)
}

activeNavTransaction = transaction

transaction.apply {
if (arguments.isNotEmpty()) {
setData("arguments", arguments)
}
}

scope.bindTransaction(transaction)

return transaction
}

/** Finishes and unsets the active navigation transaction, if one exists. */
/**
* Finishes and unsets the active navigation transaction, if one exists.
*
* See [INavScope.finishNavTransaction].
*/
fun stop(scope: INavScope) {
val transaction = activeNavTransaction ?: return
val status = transaction.status ?: SpanStatus.OK
transaction.finish(status)
scope.unbindTransaction(transaction)
activeNavTransaction = null
scope.finishNavTransaction()
}
}

Expand Down Expand Up @@ -377,15 +354,15 @@ private class NavContext(private val scopes: INavScopes, private val options: Se
* proper values to the transaction context instead.
*/
fun <T : Any> updateTransaction(
transaction: ITransaction,
transaction: INavTransaction,
scope: INavScope,
backStack: BackStackData<T>,
) {
if (scopes.options.isEnableScreenTracking) {
val appContext = transaction.contexts.app ?: scope.app ?: App()
val appContext = scope.app ?: App()

appContext.viewNames = listOf(backStack.topEntryNormalized.name)
transaction.contexts.setApp(appContext)
transaction.setApp(appContext)
}

if (options.captureBackStack && backStack.capturedEntriesNormalized.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import io.sentry.compose.navigation3.lifecycle.NavScopes
* **Thread safety**
*
* This class is ***not*** thread-safe. Invocations should be confined to the same thread as the
* [LifecycleEventObserver] callbacks implemented by [NavScopes].
* [LifecycleEventObserver] callbacks through which the [NavLeaseCoordinator] observes the attached
* lifecycle.
*/
internal class CoordinatedBackStackObserver<T : Any>(
scopes: IScopes,
Expand Down
Loading
Loading