diff --git a/app/src/main/java/com/tangem/tap/common/analytics/DefaultTrackingContextProxy.kt b/app/src/main/java/com/tangem/tap/common/analytics/DefaultTrackingContextProxy.kt index a32012ca51..923b26cbf5 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/DefaultTrackingContextProxy.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/DefaultTrackingContextProxy.kt @@ -25,8 +25,6 @@ internal class DefaultTrackingContextProxy(private val abTestsManager: ABTestsMa override fun setContext(scanResponse: ScanResponse) { val userWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build() - Analytics.setContext(userWalletId, scanResponse) - abTestsManager.setUserProperties( userId = calculateUserIdHash(userWalletId), batch = scanResponse.card.batchId, @@ -73,6 +71,12 @@ internal class DefaultTrackingContextProxy(private val abTestsManager: ABTestsMa Analytics.removeContext() } + override fun proceedWithContext(userWallet: UserWallet, action: () -> Unit) { + setContext(userWallet) + action() + eraseContext() + } + private fun calculateUserIdHash(userWalletId: UserWalletId?): String? { return userWalletId?.value ?.calculateSha256() diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index 1608ebc3f4..c7bc17f8e9 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -30,6 +30,7 @@ class CardContextInterceptor( override fun canBeAppliedTo(event: AnalyticsEvent): Boolean { return when (event) { + is IntroductionProcess.ButtonScanCardLegacy -> false is IntroductionProcess.ButtonScanCard -> false else -> true } 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 index b7be0155f7..ab9c9d3b54 100644 --- 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 @@ -14,6 +14,9 @@ class HotWalletContextInterceptor( override fun intercept(params: MutableMap) { params[AnalyticsParam.PRODUCT_TYPE] = AnalyticsParam.ProductType.MobileWallet.value + params.remove(AnalyticsParam.BATCH) + params.remove(AnalyticsParam.FIRMWARE) + params.remove(AnalyticsParam.CURRENCY) } companion object { diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/di/UserWalletsListManagerModule.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/di/UserWalletsListManagerModule.kt index e0b08af719..abe6b49ded 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/di/UserWalletsListManagerModule.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/di/UserWalletsListManagerModule.kt @@ -7,6 +7,7 @@ import com.tangem.common.authentication.storage.AuthenticatedStorage import com.tangem.common.json.TangemSdkAdapter import com.tangem.common.services.secure.SecureStorage import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.utils.TrackingContextProxy import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.models.scan.serialization.* @@ -124,6 +125,8 @@ internal object UserWalletsListManagerModule { appPreferencesStore: AppPreferencesStore, hotWalletAccessCodeAttemptsRepository: HotWalletAccessCodeAttemptsRepository, tangemHotSdk: TangemHotSdk, + trackingContextProxy: TrackingContextProxy, + analyticsEventHandler: AnalyticsEventHandler, ): UserWalletsListRepository { val moshi = buildMoshi() val secureStorage = buildSecureStorage(applicationContext = applicationContext) @@ -171,6 +174,8 @@ internal object UserWalletsListManagerModule { savePersistentInformation = ProviderSuspend { true }, // Always save persistent information for now hotWalletAccessCodeAttemptsRepository = hotWalletAccessCodeAttemptsRepository, tangemHotSdk = tangemHotSdk, + trackingContextProxy = trackingContextProxy, + analyticsEventHandler = analyticsEventHandler, ) } diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt index af0ce672e0..29f19ffb75 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt @@ -7,6 +7,9 @@ import arrow.core.raise.either import arrow.core.right import com.tangem.common.* import com.tangem.common.core.TangemSdkError +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.Basic +import com.tangem.core.analytics.utils.TrackingContextProxy import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getSyncOrDefault @@ -50,6 +53,8 @@ internal class DefaultUserWalletsListRepository( private val appPreferencesStore: AppPreferencesStore, private val hotWalletAccessCodeAttemptsRepository: HotWalletAccessCodeAttemptsRepository, private val tangemHotSdk: TangemHotSdk, + private val trackingContextProxy: TrackingContextProxy, + private val analyticsEventHandler: AnalyticsEventHandler, ) : UserWalletsListRepository { override val userWallets = MutableStateFlow?>(null) @@ -235,6 +240,7 @@ internal class DefaultUserWalletsListRepository( when (unlockMethod) { UserWalletsListRepository.UnlockMethod.Biometric -> { unlockAllWallets().bind() + trackSignInEvent(userWallet, Basic.SignedIn.SignInType.Biometric) select(userWalletId) } UserWalletsListRepository.UnlockMethod.AccessCode -> { @@ -263,7 +269,10 @@ internal class DefaultUserWalletsListRepository( removePasswordAttempts(userWallet) sensitiveInformationRepository.getAll(listOf(encryptionKey)) - .doOnSuccess { sensitiveInfo -> updateWallets { it?.updateWith(sensitiveInfo) } } + .doOnSuccess { sensitiveInfo -> + updateWallets { it?.updateWith(sensitiveInfo) } + trackSignInEvent(userWallet, Basic.SignedIn.SignInType.AccessCode) + } .doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock.RawException(error)) } } is UserWalletsListRepository.UnlockMethod.Scan -> { @@ -291,7 +300,10 @@ internal class DefaultUserWalletsListRepository( ) sensitiveInformationRepository.getAll(listOf(encryptionKey)) - .doOnSuccess { sensitiveInfo -> updateWallets { it?.updateWith(sensitiveInfo) } } + .doOnSuccess { sensitiveInfo -> + updateWallets { it?.updateWith(sensitiveInfo) } + trackSignInEvent(userWallet, Basic.SignedIn.SignInType.Card) + } .doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock.RawException(error)) } } } @@ -332,6 +344,9 @@ internal class DefaultUserWalletsListRepository( sensitiveInformationRepository.getAll(allKeys) .doOnSuccess { sensitiveInfo -> updateWallets { wallets -> wallets?.updateWith(sensitiveInfo) } + selectedUserWallet.value?.let { + trackSignInEvent(it, Basic.SignedIn.SignInType.Biometric) + } } .doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock.RawException(error)) } } @@ -508,4 +523,15 @@ internal class DefaultUserWalletsListRepository( return lastOrNull() } + + private fun trackSignInEvent(userWallet: UserWallet, type: Basic.SignedIn.SignInType) { + trackingContextProxy.proceedWithContext(userWallet) { + analyticsEventHandler.send( + event = Basic.SignedIn( + signInType = type, + walletsCount = userWallets.value?.size ?: 0, + ), + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index f912f0948a..3fea04772f 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -58,7 +58,7 @@ internal class WelcomeMiddleware { .doOnSuccess { selectedUserWallet -> sendSignedInAnalyticsEvent( userWallet = selectedUserWallet, - signInType = Basic.SignedIn.SignInType.Biometric, + signInType = Basic.SignedInLegacy.SignInType.Biometric, ) store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) } @@ -80,7 +80,7 @@ internal class WelcomeMiddleware { store.dispatchWithMain(WelcomeAction.ProceedWithCard.Error(error)) } .doOnSuccess { - sendSignedInAnalyticsEvent(userWallet, signInType = Basic.SignedIn.SignInType.Card) + sendSignedInAnalyticsEvent(userWallet, signInType = Basic.SignedInLegacy.SignInType.Card) store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) } store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success) @@ -89,9 +89,7 @@ internal class WelcomeMiddleware { } } - private fun sendSignedInAnalyticsEvent(userWallet: UserWallet, signInType: Basic.SignedIn.SignInType) { - // TODO [REDACTED_TASK_KEY] [Hot Wallet] Analytics - + private fun sendSignedInAnalyticsEvent(userWallet: UserWallet, signInType: Basic.SignedInLegacy.SignInType) { if (userWallet !is UserWallet.Cold) { return } @@ -108,7 +106,7 @@ internal class WelcomeMiddleware { val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) Analytics.send( - event = Basic.SignedIn( + event = Basic.SignedInLegacy( currency = currency, batch = scanResponse.card.batchId, signInType = signInType, diff --git a/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt b/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt index 7025664f0b..483891f435 100644 --- a/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt +++ b/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt @@ -10,6 +10,9 @@ import com.arkivanov.essenty.lifecycle.subscribe import com.google.android.material.snackbar.Snackbar import com.tangem.common.routing.AppRoute import com.tangem.common.routing.entity.InitScreenLaunchMode +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.Basic +import com.tangem.core.analytics.utils.TrackingContextProxy import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.child import com.tangem.core.decompose.context.childByContext @@ -23,6 +26,7 @@ import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.models.wallet.isLocked import com.tangem.domain.onboarding.repository.OnboardingRepository import com.tangem.features.hotwallet.HotAccessCodeRequestComponent +import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.features.hotwallet.accesscoderequest.proxy.HotWalletPasswordRequesterProxy import com.tangem.features.walletconnect.components.WcRoutingComponent import com.tangem.hot.sdk.TangemHotSdk @@ -59,6 +63,9 @@ internal class DefaultRoutingComponent @AssistedInject constructor( private val userWalletsListRepository: UserWalletsListRepository, private val cardRepository: CardRepository, private val onboardingRepository: OnboardingRepository, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val trackingContextProxy: TrackingContextProxy, + private val analyticsEventHandler: AnalyticsEventHandler, ) : RoutingComponent, AppComponentContext by context, SnackbarHandler { @@ -130,6 +137,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor( ) } else -> { + trackSignInEvent() AppRoute.Wallet } }.also { @@ -214,4 +222,19 @@ internal class DefaultRoutingComponent @AssistedInject constructor( store.dispatch(GlobalAction.ShowDialog(BackupDialog.UnfinishedBackupFound(onboardingScanResponse))) } } + + private suspend fun trackSignInEvent() { + if (hotWalletFeatureToggles.isHotWalletEnabled) { + val userWallets = userWalletsListRepository.userWalletsSync() + val selectedWallet = userWalletsListRepository.selectedUserWalletSync() ?: return + trackingContextProxy.proceedWithContext(selectedWallet) { + analyticsEventHandler.send( + event = Basic.SignedIn( + signInType = Basic.SignedIn.SignInType.NoSecurity, + walletsCount = userWallets.size, + ), + ) + } + } + } } \ No newline at end of file diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index 47d586e92e..b0114af14c 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -83,12 +83,14 @@ sealed class AnalyticsParam { data object Onboarding : ScreensSources("Onboarding") data object LongTap : ScreensSources("Long Tap") data object Markets : ScreensSources("Markets") - data object HotWallet : ScreensSources("Hot Wallet") data object TangemPay : ScreensSources("Tangem Pay") data object WalletSettings : ScreensSources("Wallet Settings") data object Upgrade : ScreensSources("Upgrade") data object HardwareWallet : ScreensSources("Hardware Wallet") data object ImportWallet : ScreensSources("Import Wallet") + data object CreateNewWallet : ScreensSources("Create New Wallet") + data object AddNewWallet : ScreensSources("Add New Wallet") + data object CreateWallet : ScreensSources("Create Wallet") } sealed class TxSentFrom(val value: String) { diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt index 9d2974a077..c59513d2fa 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt @@ -10,11 +10,11 @@ sealed class Basic( ) : Basic( event = "Card Was Scanned", params = mapOf( - AnalyticsParam.SOURCE to source.value, + AnalyticsParam.Key.SOURCE to source.value, ), ) - class SignedIn( + class SignedInLegacy( currency: AnalyticsParam.WalletType, batch: String, signInType: SignInType, @@ -24,8 +24,8 @@ sealed class Basic( ) : Basic( event = "Signed in", params = buildMap { - put(AnalyticsParam.CURRENCY, currency.value) - put(AnalyticsParam.BATCH, batch) + put(AnalyticsParam.Key.CURRENCY, currency.value) + put(AnalyticsParam.Key.BATCH, batch) put("Wallet Type", if (isImported) "Seed Phrase" else "Seedless") put("Sign in type", signInType.name) put("Wallets Count", walletsCount) @@ -39,10 +39,37 @@ sealed class Basic( } } + class SignedIn( + signInType: SignInType, + walletsCount: Int, + ) : Basic( + event = "Signed in", + params = buildMap { + put("Sign in type", signInType.value) + put("Wallets Count", walletsCount.toString()) + }, + ) { + enum class SignInType(val value: String) { + Card("Card"), + Biometric("Biometric"), + NoSecurity("No Security"), + AccessCode("Access Code"), + } + } + + class ButtonBuy( + source: AnalyticsParam.ScreensSources, + ) : Basic( + event = "Button - Buy", + params = buildMap { + put(AnalyticsParam.Key.SOURCE, source.value) + }, + ) + class ToppedUp(userWalletId: String, currency: AnalyticsParam.WalletType) : Basic( event = "Topped up", - params = mapOf(AnalyticsParam.CURRENCY to currency.value), + params = mapOf(AnalyticsParam.Key.CURRENCY to currency.value), ), OneTimeAnalyticsEvent { @@ -53,16 +80,16 @@ sealed class Basic( Basic( event = "Transaction sent", params = buildMap { - this[AnalyticsParam.SOURCE] = sentFrom.value + this[AnalyticsParam.Key.SOURCE] = sentFrom.value if (sentFrom is AnalyticsParam.TxData) { - this[AnalyticsParam.BLOCKCHAIN] = sentFrom.blockchain - this[AnalyticsParam.TOKEN_PARAM] = sentFrom.token + this[AnalyticsParam.Key.BLOCKCHAIN] = sentFrom.blockchain + this[AnalyticsParam.Key.TOKEN_PARAM] = sentFrom.token sentFrom.feeType?.value?.let { - this[AnalyticsParam.FEE_TYPE] = it + this[AnalyticsParam.Key.FEE_TYPE] = it } } if (sentFrom is AnalyticsParam.TxSentFrom.Approve) { - this[AnalyticsParam.PERMISSION_TYPE] = sentFrom.permissionType + this[AnalyticsParam.Key.PERMISSION_TYPE] = sentFrom.permissionType } this["Memo"] = memoType.name }, @@ -79,7 +106,7 @@ sealed class Basic( class ButtonSupport(source: AnalyticsParam.ScreensSources) : Basic( event = "Request Support", params = mapOf( - AnalyticsParam.SOURCE to source.value, + AnalyticsParam.Key.SOURCE to source.value, ), ) @@ -89,7 +116,7 @@ sealed class Basic( ) : Basic( event = "Biometry Failed", params = mapOf( - AnalyticsParam.SOURCE to source.value, + AnalyticsParam.Key.SOURCE to source.value, "Reason" to reason.value, ), ) { diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/SignIn.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/SignIn.kt new file mode 100644 index 0000000000..5d0e483b1c --- /dev/null +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/SignIn.kt @@ -0,0 +1,46 @@ +package com.tangem.core.analytics.models.event + +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam + +sealed class SignIn( + event: String, + params: Map = emptyMap(), +) : AnalyticsEvent("Sign In", event, params) { + + data class ScreenOpened( + val walletsCount: Int, + ) : SignIn( + event = "Sign In Screen Opened", + params = mapOf( + "Wallets Count" to walletsCount.toString(), + ), + ) + + class ButtonUnlockAllWithBiometric : SignIn(event = "Button - Unlock All With Biometric") + + class ButtonWallet( + signInType: SignInType, + ) : SignIn( + event = "Button - Wallet", + params = buildMap { + put("Sign in type", signInType.value) + }, + ) { + enum class SignInType(val value: String) { + Card("Card"), + Biometric("Biometric"), + NoSecurity("No Security"), + AccessCode("Access Code"), + } + } + + data class ButtonAddWallet( + val sources: AnalyticsParam.ScreensSources, + ) : SignIn( + event = "Button - Add Wallet", + params = mapOf( + AnalyticsParam.SOURCE to sources.value, + ), + ) +} \ No newline at end of file diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/utils/TrackingContextProxy.kt b/core/analytics/src/main/java/com/tangem/core/analytics/utils/TrackingContextProxy.kt index 23be99e1fd..30671f81d0 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/utils/TrackingContextProxy.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/utils/TrackingContextProxy.kt @@ -23,4 +23,6 @@ interface TrackingContextProxy { fun addHotWalletContext() fun removeContext() + + fun proceedWithContext(userWallet: UserWallet, action: () -> Unit) } \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt index 15916c16cf..06b18ef403 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt @@ -1,6 +1,7 @@ package com.tangem.domain.card.analytics import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam sealed class IntroductionProcess( event: String, @@ -10,5 +11,14 @@ sealed class IntroductionProcess( object ScreenOpened : IntroductionProcess("Introduction Process Screen Opened") object ButtonTokensList : IntroductionProcess("Button - Tokens List") object ButtonBuyCards : IntroductionProcess("Button - Buy Cards") - object ButtonScanCard : IntroductionProcess("Button - Scan Card") + object ButtonScanCardLegacy : IntroductionProcess("Button - Scan Card") + + class ButtonScanCard( + val source: AnalyticsParam.ScreensSources, + ) : IntroductionProcess( + event = "Button - Scan Card", + params = mapOf( + AnalyticsParam.Key.SOURCE to source.value, + ), + ) } \ No newline at end of file diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt index bc586d7d95..7e9fcbc7f5 100644 --- a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt @@ -2,6 +2,8 @@ package com.tangem.features.createwalletselection import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.navigation.Router @@ -9,8 +11,6 @@ import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.components.label.entity.LabelStyle import com.tangem.core.ui.components.label.entity.LabelUM import com.tangem.core.ui.extensions.resourceReference -import com.tangem.domain.card.analytics.IntroductionProcess -import com.tangem.domain.card.analytics.Shop import com.tangem.domain.wallets.usecase.GenerateBuyTangemCardLinkUseCase import com.tangem.features.createwalletselection.entity.CreateWalletSelectionUM import com.tangem.features.createwalletselection.impl.R @@ -101,8 +101,7 @@ internal class CreateWalletSelectionModel @Inject constructor( } private fun onBuyClick() { - analyticsEventHandler.send(IntroductionProcess.ButtonBuyCards) - analyticsEventHandler.send(Shop.ScreenOpened) + analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.AddNewWallet)) modelScope.launch { generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } } diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt index 4d1739bbe3..6e138c594d 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt @@ -6,8 +6,7 @@ import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic.SignedIn -import com.tangem.core.analytics.models.Basic.SignedIn.SignInType +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.GlobalUiMessageSender import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model @@ -19,8 +18,7 @@ import com.tangem.core.ui.R import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.card.ScanCardProcessor -import com.tangem.domain.card.analytics.ParamCardCurrencyConverter -import com.tangem.domain.card.common.util.cardTypesResolver +import com.tangem.domain.card.analytics.IntroductionProcess import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.error.SaveWalletError @@ -51,7 +49,6 @@ internal class CreateWalletStartModel @Inject constructor( private val scanCardProcessor: ScanCardProcessor, private val cardSdkConfigRepository: CardSdkConfigRepository, private val settingsRepository: SettingsRepository, - private val analyticsEventHandler: AnalyticsEventHandler, private val appRouter: AppRouter, private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, private val saveWalletUseCase: SaveWalletUseCase, @@ -59,6 +56,7 @@ internal class CreateWalletStartModel @Inject constructor( @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase, private val urlOpener: UrlOpener, + private val analyticsEventHandler: AnalyticsEventHandler, ) : Model() { private val params = paramsContainer.require() @@ -126,6 +124,9 @@ internal class CreateWalletStartModel @Inject constructor( ) private fun onScanClick() { + analyticsEventHandler.send( + event = IntroductionProcess.ButtonScanCard(AnalyticsParam.ScreensSources.CreateNewWallet), + ) scanCard() } @@ -134,6 +135,7 @@ internal class CreateWalletStartModel @Inject constructor( } private fun onBuyClick() { + analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.CreateNewWallet)) modelScope.launch { generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } } @@ -199,28 +201,11 @@ internal class CreateWalletStartModel @Inject constructor( }, ifRight = { setLoading(false) - sendSignedInCardAnalyticsEvent(scanResponse = scanResponse, isImported = userWallet.isImported) appRouter.replaceAll(AppRoute.Wallet) }, ) } - private suspend fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse, isImported: Boolean) { - val currency = ParamCardCurrencyConverter().convert(value = scanResponse.cardTypesResolver) - if (currency != null) { - analyticsEventHandler.send( - SignedIn( - currency = currency, - batch = scanResponse.card.batchId, - signInType = SignInType.Card, - walletsCount = userWalletsListRepository.userWalletsSync().size.toString(), - isImported = isImported, - hasBackup = scanResponse.card.backupStatus?.isActive, - ), - ) - } - } - private fun setLoading(isLoading: Boolean) { uiState.update { it.copy(isScanInProgress = isLoading) } } diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index cf7047bb68..be5d74ca8e 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -4,6 +4,9 @@ import android.content.res.Resources import arrow.core.getOrElse import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.AppInstanceIdProvider +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -13,13 +16,14 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.domain.card.common.TapWorkarounds.isVisa import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase -import com.tangem.domain.feedback.models.WalletMetaInfo import com.tangem.domain.feedback.models.FeedbackEmailType +import com.tangem.domain.feedback.models.WalletMetaInfo import com.tangem.domain.feedback.repository.FeedbackFeatureToggles +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.redux.LegacyAction import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.walletconnect.CheckIsWalletConnectAvailableUseCase -import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.wallets.usecase.GenerateBuyTangemCardLinkUseCase import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.details.component.DetailsComponent @@ -29,6 +33,7 @@ import com.tangem.features.details.entity.DetailsUM import com.tangem.features.details.entity.SelectEmailFeedbackTypeBS import com.tangem.features.details.utils.ItemsBuilder import com.tangem.features.details.utils.SocialsBuilder +import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.version.AppVersionProvider import kotlinx.collections.immutable.ImmutableList @@ -60,6 +65,9 @@ internal class DetailsModel @Inject constructor( private val getWalletsUseCase: GetWalletsUseCase, private val feedbackFeatureToggles: FeedbackFeatureToggles, override val dispatchers: CoroutineDispatcherProvider, + private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val analyticsEventHandler: AnalyticsEventHandler, ) : Model() { private val params: DetailsComponent.Params = paramsContainer.require() @@ -216,7 +224,12 @@ internal class DetailsModel @Inject constructor( private fun onBuyClick() { modelScope.launch { - urlOpener.openUrl(buildBuyLink()) + if (hotWalletFeatureToggles.isHotWalletEnabled) { + analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.Settings)) + generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + } else { + urlOpener.openUrl(buildBuyLink()) + } } } diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt index f82b96124a..a02c3c4543 100644 --- a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt @@ -8,8 +8,8 @@ import com.tangem.common.routing.AppRouter import com.tangem.common.routing.entity.InitScreenLaunchMode import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic.SignedIn -import com.tangem.core.analytics.models.Basic.SignedIn.SignInType +import com.tangem.core.analytics.models.Basic.SignedInLegacy +import com.tangem.core.analytics.models.Basic.SignedInLegacy.SignInType import com.tangem.core.decompose.di.GlobalUiMessageSender import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model @@ -127,7 +127,7 @@ internal class HomeModel @Inject constructor( } private fun onScanClick() { - analyticsEventHandler.send(IntroductionProcess.ButtonScanCard) + analyticsEventHandler.send(IntroductionProcess.ButtonScanCardLegacy) scanCard() } @@ -212,7 +212,7 @@ internal class HomeModel @Inject constructor( val currency = ParamCardCurrencyConverter().convert(value = scanResponse.cardTypesResolver) if (currency != null) { analyticsEventHandler.send( - SignedIn( + SignedInLegacy( currency = currency, batch = scanResponse.card.batchId, signInType = SignInType.Card, diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt index da08951a67..fabdc48487 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt @@ -5,8 +5,7 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic.SignedIn -import com.tangem.core.analytics.models.Basic.SignedIn.SignInType +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.navigation.Router @@ -16,8 +15,7 @@ import com.tangem.core.ui.R import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.card.ScanCardProcessor -import com.tangem.domain.card.analytics.ParamCardCurrencyConverter -import com.tangem.domain.card.common.util.cardTypesResolver +import com.tangem.domain.card.analytics.IntroductionProcess import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.error.SaveWalletError @@ -74,12 +72,16 @@ internal class CreateHardwareWalletModel @Inject constructor( } private fun onBuyTangemWalletClick() { + analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.CreateWallet)) modelScope.launch { generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } } } private fun onScanDeviceClick() { + analyticsEventHandler.send( + event = IntroductionProcess.ButtonScanCard(AnalyticsParam.ScreensSources.CreateWallet), + ) scanCard() } @@ -143,28 +145,11 @@ internal class CreateHardwareWalletModel @Inject constructor( }, ifRight = { setLoading(false) - sendSignedInCardAnalyticsEvent(scanResponse = scanResponse, isImported = userWallet.isImported) router.replaceAll(AppRoute.Wallet) }, ) } - private suspend fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse, isImported: Boolean) { - val currency = ParamCardCurrencyConverter().convert(value = scanResponse.cardTypesResolver) - if (currency != null) { - analyticsEventHandler.send( - SignedIn( - currency = currency, - batch = scanResponse.card.batchId, - signInType = SignInType.Card, - walletsCount = userWalletsListRepository.userWalletsSync().size.toString(), - isImported = isImported, - hasBackup = scanResponse.card.backupStatus?.isActive, - ), - ) - } - } - private fun setLoading(isLoading: Boolean) { uiState.update { it.copy(isScanInProgress = isLoading) } } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt index de7cbe111f..dcaa94647a 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt @@ -7,6 +7,8 @@ import com.tangem.common.doOnResult import com.tangem.common.doOnSuccess import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -18,6 +20,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.toWrappedList import com.tangem.core.ui.message.DialogMessage import com.tangem.core.ui.message.EventMessageAction +import com.tangem.domain.card.analytics.IntroductionProcess import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.feedback.SendFeedbackEmailUseCase @@ -85,12 +88,14 @@ internal class UpgradeWalletModel @Inject constructor( } private fun onBuyTangemWalletClick() { + analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.Upgrade)) modelScope.launch { generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } } } private fun onContinueClick() { + analyticsEventHandler.send(IntroductionProcess.ButtonScanCard(AnalyticsParam.ScreensSources.Upgrade)) analyticsEventHandler.send(WalletSettingsAnalyticEvents.ButtonStartUpgrade) scanCard() } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt index 1e183bf849..69ed17c12f 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt @@ -3,6 +3,7 @@ package com.tangem.features.hotwallet.walletbackup.model import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -111,6 +112,7 @@ internal class WalletBackupModel @Inject constructor( ) private fun onBuyClick() { + analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.Backup)) modelScope.launch { generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt index f7e8fff31f..2e9c2580cd 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt @@ -4,6 +4,7 @@ import arrow.core.getOrElse import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -160,6 +161,7 @@ internal class WalletHardwareBackupModel @Inject constructor( } private fun onBuyClick() { + analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.HardwareWallet)) modelScope.launch { generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } } diff --git a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt index bf40c9be77..c0a06bc9e6 100644 --- a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt +++ b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt @@ -3,6 +3,11 @@ package com.tangem.features.welcome.impl.model import com.tangem.common.routing.AppRoute import com.tangem.common.ui.userwallet.handle import com.tangem.common.ui.userwallet.state.UserWalletItemUM +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic +import com.tangem.core.analytics.models.event.SignIn +import com.tangem.core.analytics.utils.TrackingContextProxy import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.navigation.Router @@ -36,6 +41,8 @@ internal class WelcomeModel @Inject constructor( private val nonBiometricUnlockWalletUseCase: NonBiometricUnlockWalletUseCase, private val canUseBiometryUseCase: CanUseBiometryUseCase, private val walletsRepository: WalletsRepository, + private val trackingContextProxy: TrackingContextProxy, + private val analyticsEventHandler: AnalyticsEventHandler, userWalletsFetcherFactory: UserWalletsFetcher.Factory, ) : Model() { @@ -51,6 +58,14 @@ internal class WelcomeModel @Inject constructor( modelScope.launch { val userWallets = userWalletsListRepository.userWalletsSync() val userWallet = userWallets.first { it.walletId == walletId } + trackingContextProxy.proceedWithContext(userWallet) { + val signInType = when { + !userWallet.isLocked -> SignIn.ButtonWallet.SignInType.NoSecurity + userWallet is UserWallet.Cold -> SignIn.ButtonWallet.SignInType.Card + else -> SignIn.ButtonWallet.SignInType.AccessCode + } + analyticsEventHandler.send(SignIn.ButtonWallet(signInType)) + } onUserWalletClick(userWallet) } }, @@ -64,6 +79,8 @@ internal class WelcomeModel @Inject constructor( userWalletsListRepository.load() wallets.value = walletsFetcher.userWallets.first() + analyticsEventHandler.send(SignIn.ScreenOpened(wallets.value.size)) + launch { walletsFetcher.userWallets .collectLatest { @@ -119,6 +136,7 @@ internal class WelcomeModel @Inject constructor( showUnlockWithBiometricButton = canUnlockWithBiometrics(), addWalletClick = ::addWalletClick, onUnlockWithBiometricClick = { + analyticsEventHandler.send(SignIn.ButtonUnlockAllWithBiometric()) modelScope.launch { userWalletsListRepository.unlockAllWallets() .onRight { @@ -140,6 +158,7 @@ internal class WelcomeModel @Inject constructor( } private fun addWalletClick() { + analyticsEventHandler.send(SignIn.ButtonAddWallet(AnalyticsParam.ScreensSources.SignIn)) router.push(AppRoute.CreateWalletSelection) } @@ -154,6 +173,7 @@ internal class WelcomeModel @Inject constructor( if (userWallet.isLocked.not()) { // If the wallet is not locked, we can proceed to the wallet screen directly userWalletsListRepository.select(userWallet.walletId) + trackSignInEvent(userWallet, Basic.SignedIn.SignInType.NoSecurity) router.replaceAll(AppRoute.Wallet) return@launch } @@ -203,4 +223,16 @@ internal class WelcomeModel @Inject constructor( } } } + + private suspend fun trackSignInEvent(userWallet: UserWallet, type: Basic.SignedIn.SignInType) { + val walletsCount = userWalletsListRepository.userWalletsSync().size + trackingContextProxy.proceedWithContext(userWallet) { + analyticsEventHandler.send( + event = Basic.SignedIn( + signInType = type, + walletsCount = walletsCount, + ), + ) + } + } } \ No newline at end of file