From 4fa59892890c99b91aa734633fce90dcf7b7d9e2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Apr 2026 10:36:30 +0200 Subject: [PATCH] Updated on 2026-08-14 --- features/swap/impl/build.gradle.kts | 4 +++ .../analytics/SwapQuotePerformanceTracker.kt | 36 +++++++++++++++++++ .../tangem/feature/swap/model/SwapModel.kt | 8 +++++ 3 files changed, 48 insertions(+) create mode 100644 features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapQuotePerformanceTracker.kt diff --git a/features/swap/impl/build.gradle.kts b/features/swap/impl/build.gradle.kts index 6c456d8519..f2ab5ca458 100644 --- a/features/swap/impl/build.gradle.kts +++ b/features/swap/impl/build.gradle.kts @@ -105,6 +105,10 @@ dependencies { implementation(deps.kotlin.serialization) implementation(deps.kotlin.immutable.collections) implementation(deps.decompose.ext.compose) + implementation(deps.firebase.perf) { + exclude(group = "com.google.firebase", module = "protolite-well-known-types") + exclude(group = "com.google.protobuf", module = "protobuf-javalite") + } /** Tangem libs */ implementation(tangemDeps.blockchain) diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapQuotePerformanceTracker.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapQuotePerformanceTracker.kt new file mode 100644 index 0000000000..baec303ec2 --- /dev/null +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapQuotePerformanceTracker.kt @@ -0,0 +1,36 @@ +package com.tangem.feature.swap.analytics + +import com.google.firebase.perf.FirebasePerformance +import com.google.firebase.perf.metrics.Trace + +internal class SwapQuotePerformanceTracker { + + private var trace: Trace? = null + + fun onLoadingStarted(providersCount: Int) { + trace?.stop() + trace = FirebasePerformance.getInstance().newTrace(SWAP_QUOTES_LOADED_TRACE_NAME).apply { + putAttribute(PROVIDERS_COUNT, providersCount.toString()) + start() + } + } + + fun onLoadingFinished(hasError: Boolean) { + trace?.apply { + putAttribute(HAS_ERROR, if (hasError) "Yes" else "No") + stop() + } + trace = null + } + + fun onDestroy() { + trace?.stop() + trace = null + } + + private companion object { + const val SWAP_QUOTES_LOADED_TRACE_NAME = "Swap_quotes_loaded" + const val PROVIDERS_COUNT = "providers_count" + const val HAS_ERROR = "has_error" + } +} \ No newline at end of file diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt index ed470d4a60..1cc6c4cd61 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt @@ -68,6 +68,7 @@ import com.tangem.domain.transaction.models.TransactionFeeExtended import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNetwork import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase import com.tangem.feature.swap.analytics.SwapEvents +import com.tangem.feature.swap.analytics.SwapQuotePerformanceTracker import com.tangem.feature.swap.choosetoken.api.ChooseTokenAnalyticsPayload import com.tangem.feature.swap.choosetoken.api.ChooseTokenBridge import com.tangem.feature.swap.choosetoken.api.ChooseTokenResult @@ -192,6 +193,7 @@ internal class SwapModel @Inject constructor( private val amountDebouncer = Debouncer() private val singleTaskScheduler = SingleTaskScheduler>() + private val performanceTracker = SwapQuotePerformanceTracker() val dataStateStateFlow = MutableStateFlow(SwapProcessDataState()) var dataState @@ -295,6 +297,7 @@ internal class SwapModel @Inject constructor( override fun onDestroy() { singleTaskScheduler.cancelTask() + performanceTracker.onDestroy() super.onDestroy() } @@ -605,6 +608,7 @@ internal class SwapModel @Inject constructor( uiStateHolder = uiState, ) feeSelectorRepository.state.value = FeeSelectorUM.Loading + performanceTracker.onLoadingStarted(toProvidersList.size) } singleTaskScheduler.scheduleTask( modelScope, @@ -686,6 +690,9 @@ internal class SwapModel @Inject constructor( } }, onSuccess = { providersState -> + performanceTracker.onLoadingFinished( + hasError = providersState.values.none { it is SwapState.QuotesLoadedState }, + ) if (providersState.isNotEmpty()) { val (provider, state) = updateLoadedQuotes(providersState) setupLoadedState( @@ -715,6 +722,7 @@ internal class SwapModel @Inject constructor( }, onError = { error -> TangemLogger.e("Error when loading quotes: $error") + performanceTracker.onLoadingFinished(hasError = true) feeSelectorRepository.state.value = FeeSelectorUM.Error(GetFeeError.UnknownError, isHidden = true) uiState = stateBuilder.addNotification(uiState, null) { startLoadingQuotesFromLastState() } },