From 8968f1822aeec205481cc8583bb6cdf861cd492a Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 16 Oct 2025 12:17:45 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../analytics/DefaultAnalyticsContextProxy.kt | 15 ++++++ .../HotWalletContextInterceptor.kt | 22 ++++++++ .../LinkedCardContextInterceptor.kt | 2 +- .../tangem/tap/common/extensions/Analytics.kt | 54 ++++++++++++++++--- .../analytics/utils/AnalyticsContextProxy.kt | 7 +++ .../entry/AddExistingWalletModel.kt | 11 ++++ .../CreateMobileWalletModel.kt | 11 ++++ .../CreateWalletBackupModel.kt | 11 ++++ .../entry/WalletActivationModel.kt | 11 ++++ .../model/WalletSettingsModel.kt | 9 ++++ 10 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/HotWalletContextInterceptor.kt diff --git a/app/src/main/java/com/tangem/tap/common/analytics/DefaultAnalyticsContextProxy.kt b/app/src/main/java/com/tangem/tap/common/analytics/DefaultAnalyticsContextProxy.kt index d1aecc29d0..b566a5472a 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/DefaultAnalyticsContextProxy.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/DefaultAnalyticsContextProxy.kt @@ -3,10 +3,13 @@ package com.tangem.tap.common.analytics import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.utils.AnalyticsContextProxy import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.models.wallet.UserWallet import com.tangem.tap.common.extensions.addContext +import com.tangem.tap.common.extensions.addHotWalletContext import com.tangem.tap.common.extensions.eraseContext import com.tangem.tap.common.extensions.removeContext import com.tangem.tap.common.extensions.setContext +import com.tangem.tap.common.extensions.setHotWalletContext /** [REDACTED_AUTHOR] @@ -17,6 +20,14 @@ internal class DefaultAnalyticsContextProxy : AnalyticsContextProxy { Analytics.setContext(scanResponse) } + override fun addContext(userWallet: UserWallet) { + Analytics.addContext(userWallet) + } + + override fun setHotWalletContext() { + Analytics.setHotWalletContext() + } + override fun eraseContext() { Analytics.eraseContext() } @@ -25,6 +36,10 @@ internal class DefaultAnalyticsContextProxy : AnalyticsContextProxy { Analytics.addContext(scanResponse) } + override fun addHotWalletContext() { + Analytics.addHotWalletContext() + } + override fun removeContext() { Analytics.removeContext() } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/HotWalletContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/HotWalletContextInterceptor.kt new file mode 100644 index 0000000000..8ed80f5e60 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/HotWalletContextInterceptor.kt @@ -0,0 +1,22 @@ +package com.tangem.tap.common.analytics.paramsInterceptor + +import com.tangem.core.analytics.api.ParamsInterceptor +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam + +class HotWalletContextInterceptor( + val parent: ParamsInterceptor? = null, +) : ParamsInterceptor { + + override fun id(): String = HotWalletContextInterceptor.id() + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = true + + override fun intercept(params: MutableMap) { + params[AnalyticsParam.PRODUCT_TYPE] = "Mobile Wallet" + } + + companion object { + fun id(): String = HotWalletContextInterceptor::class.java.simpleName + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt index 25b67c3ee0..b7309a1366 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt @@ -9,7 +9,7 @@ import com.tangem.domain.models.scan.ScanResponse */ class LinkedCardContextInterceptor( scanResponse: ScanResponse, - val parent: LinkedCardContextInterceptor? = null, + val parent: ParamsInterceptor? = null, ) : ParamsInterceptor { private val contextInterceptor = CardContextInterceptor(scanResponse) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt b/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt index e09ba24e78..be2a667bb0 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt @@ -4,6 +4,7 @@ import com.tangem.core.analytics.Analytics import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.wallets.builder.UserWalletIdBuilder +import com.tangem.tap.common.analytics.paramsInterceptor.HotWalletContextInterceptor import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor /** @@ -24,19 +25,46 @@ fun Analytics.setContext(scanResponse: ScanResponse) { fun Analytics.setContext(userWallet: UserWallet) { setUserId(userWallet.walletId.stringValue) - // TODO add product type for hot ([REDACTED_TASK_KEY] [Hot Wallet] Analytics) - if (userWallet is UserWallet.Cold) { - addParamsInterceptor(LinkedCardContextInterceptor(userWallet.scanResponse)) + when (userWallet) { + is UserWallet.Cold -> { + removeParamsInterceptor(HotWalletContextInterceptor.id()) + addParamsInterceptor(LinkedCardContextInterceptor(userWallet.scanResponse)) + } + is UserWallet.Hot -> { + removeParamsInterceptor(LinkedCardContextInterceptor.id()) + addParamsInterceptor(HotWalletContextInterceptor()) + } } } +fun Analytics.setHotWalletContext() { + addParamsInterceptor(HotWalletContextInterceptor()) +} + /** * Erases the context */ fun Analytics.eraseContext() { clearUserId() removeParamsInterceptor(LinkedCardContextInterceptor.id()) + removeParamsInterceptor(HotWalletContextInterceptor.id()) +} + +/** + * Adds a new context and keeps a previous context as the parent of the new one + */ +fun Analytics.addContext(userWallet: UserWallet) { + val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) + ?: removeParamsInterceptor(HotWalletContextInterceptor.id()) + + val newContext = when (userWallet) { + is UserWallet.Cold -> LinkedCardContextInterceptor(userWallet.scanResponse, parent = currentContext) + is UserWallet.Hot -> HotWalletContextInterceptor(parent = currentContext) + } + + setUserId(userWalletId = userWallet.walletId.stringValue) + addParamsInterceptor(newContext) } /** @@ -48,18 +76,32 @@ fun Analytics.addContext(scanResponse: ScanResponse) { setUserId(userWalletId.stringValue) } - val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) as? LinkedCardContextInterceptor + val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) + ?: removeParamsInterceptor(HotWalletContextInterceptor.id()) val newContext = LinkedCardContextInterceptor(scanResponse, parent = currentContext) addParamsInterceptor(newContext) } +fun Analytics.addHotWalletContext() { + val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) as? LinkedCardContextInterceptor + val newContext = HotWalletContextInterceptor(currentContext) + + addParamsInterceptor(newContext) +} + /** * Removes the current context and restores the previous one if it was present. */ fun Analytics.removeContext() { - val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) as? LinkedCardContextInterceptor - val previousContext = currentContext?.parent ?: return + val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) + ?: removeParamsInterceptor(HotWalletContextInterceptor.id()) + + val previousContext = when (currentContext) { + is LinkedCardContextInterceptor -> currentContext.parent + is HotWalletContextInterceptor -> currentContext.parent + else -> null + } ?: return addParamsInterceptor(previousContext) } \ No newline at end of file diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/utils/AnalyticsContextProxy.kt b/core/analytics/src/main/java/com/tangem/core/analytics/utils/AnalyticsContextProxy.kt index cab4da6a7b..5ea57db8ad 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/utils/AnalyticsContextProxy.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/utils/AnalyticsContextProxy.kt @@ -1,6 +1,7 @@ package com.tangem.core.analytics.utils import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.models.wallet.UserWallet /** [REDACTED_AUTHOR] @@ -9,9 +10,15 @@ interface AnalyticsContextProxy { fun setContext(scanResponse: ScanResponse) + fun addContext(userWallet: UserWallet) + + fun setHotWalletContext() + fun eraseContext() fun addContext(scanResponse: ScanResponse) + fun addHotWalletContext() + fun removeContext() } \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt index 925be8bdc1..22d2db296e 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt @@ -2,6 +2,7 @@ package com.tangem.features.hotwallet.addexistingwallet.entry import com.arkivanov.decompose.router.stack.* import com.tangem.common.routing.AppRoute +import com.tangem.core.analytics.utils.AnalyticsContextProxy import com.tangem.core.decompose.di.GlobalUiMessageSender import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model @@ -32,6 +33,7 @@ internal class AddExistingWalletModel @Inject constructor( private val router: Router, private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, + private val analyticsContextProxy: AnalyticsContextProxy, ) : Model() { val hotWalletStepperComponentModelCallback = HotWalletStepperComponentModelCallback() @@ -45,6 +47,15 @@ internal class AddExistingWalletModel @Inject constructor( val startRoute = AddExistingWalletRoute.Import val currentRoute: MutableStateFlow = MutableStateFlow(startRoute) + init { + analyticsContextProxy.addHotWalletContext() + } + + override fun onDestroy() { + super.onDestroy() + analyticsContextProxy.removeContext() + } + fun onChildBack() { when (currentRoute.value) { is AddExistingWalletRoute.Import -> router.pop() diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt index 5f8dae3197..8607a0715b 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt @@ -1,6 +1,7 @@ package com.tangem.features.hotwallet.createmobilewallet import com.tangem.common.routing.AppRoute +import com.tangem.core.analytics.utils.AnalyticsContextProxy import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.navigation.Router @@ -25,6 +26,7 @@ internal class CreateMobileWalletModel @Inject constructor( private val saveUserWalletUseCase: SaveWalletUseCase, private val router: Router, private val tangemHotSdk: TangemHotSdk, + private val analyticsContextProxy: AnalyticsContextProxy, ) : Model() { internal val uiState: StateFlow @@ -37,6 +39,15 @@ internal class CreateMobileWalletModel @Inject constructor( ), ) + init { + analyticsContextProxy.addHotWalletContext() + } + + override fun onDestroy() { + super.onDestroy() + analyticsContextProxy.removeContext() + } + private fun onImportClick() { router.push(AppRoute.AddExistingWallet) } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createwalletbackup/CreateWalletBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createwalletbackup/CreateWalletBackupModel.kt index 9b0a2821e7..41d158f6f9 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createwalletbackup/CreateWalletBackupModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createwalletbackup/CreateWalletBackupModel.kt @@ -3,6 +3,7 @@ package com.tangem.features.hotwallet.createwalletbackup import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.router.stack.push +import com.tangem.core.analytics.utils.AnalyticsContextProxy import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -23,6 +24,7 @@ internal class CreateWalletBackupModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, private val router: Router, + private val analyticsContextProxy: AnalyticsContextProxy, ) : Model() { val params = paramsContainer.require() @@ -36,6 +38,15 @@ internal class CreateWalletBackupModel @Inject constructor( val startRoute = CreateWalletBackupRoute.RecoveryPhraseStart val currentRoute: MutableStateFlow = MutableStateFlow(startRoute) + init { + analyticsContextProxy.addHotWalletContext() + } + + override fun onDestroy() { + super.onDestroy() + analyticsContextProxy.removeContext() + } + fun onBack() { when (currentRoute.value) { is CreateWalletBackupRoute.RecoveryPhraseStart -> router.pop() diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt index 1f151f2514..e437b475da 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt @@ -4,6 +4,7 @@ import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.router.stack.push import com.arkivanov.decompose.router.stack.replaceAll +import com.tangem.core.analytics.utils.AnalyticsContextProxy import com.tangem.core.decompose.di.GlobalUiMessageSender import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model @@ -39,6 +40,7 @@ internal class WalletActivationModel @Inject constructor( private val router: Router, private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, + private val analyticsContextProxy: AnalyticsContextProxy, ) : Model() { val params = paramsContainer.require() @@ -56,6 +58,15 @@ internal class WalletActivationModel @Inject constructor( val startRoute = WalletActivationRoute.ManualBackupStart val currentRoute: MutableStateFlow = MutableStateFlow(startRoute) + init { + analyticsContextProxy.addHotWalletContext() + } + + override fun onDestroy() { + super.onDestroy() + analyticsContextProxy.removeContext() + } + fun onChildBack() { when (currentRoute.value) { is WalletActivationRoute.ManualBackupStart -> router.pop() diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt index 5453245f07..cce7ff570d 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt @@ -121,6 +121,10 @@ internal class WalletSettingsModel @Inject constructor( } init { + getUserWalletUseCase.invoke(params.userWalletId).onRight { + analyticsContextProxy.addContext(it) + } + fun combineUI(wallet: UserWallet) = combine( getWalletNFTEnabledUseCase.invoke(params.userWalletId), getWalletNotificationsEnabledUseCase(params.userWalletId), @@ -155,6 +159,11 @@ internal class WalletSettingsModel @Inject constructor( .launchIn(modelScope) } + override fun onDestroy() { + super.onDestroy() + analyticsContextProxy.removeContext() + } + private fun isNotificationsPermissionGranted(): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { permissionsRepository.hasRuntimePermission(