Updated on 2026-08-14
This commit is contained in:
parent
facd6bb2ca
commit
cf0bce7e61
16 changed files with 91 additions and 51 deletions
|
|
@ -71,12 +71,6 @@ 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()
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ sealed class SignIn(
|
|||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent("Sign In", event, params) {
|
||||
|
||||
class ScreenOpened : SignIn(event = "Sign In Screen Opened")
|
||||
|
||||
class ButtonBiometricSignIn : SignIn(event = "Button - Biometric Sign In")
|
||||
class ButtonCardSignIn : SignIn(event = "Button - Card Sign In")
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ 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
|
||||
import com.tangem.core.analytics.models.event.SignIn
|
||||
import com.tangem.domain.card.analytics.IntroductionProcess
|
||||
import com.tangem.domain.card.analytics.ParamCardCurrencyConverter
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
|
|
@ -30,8 +31,11 @@ class CardContextInterceptor(
|
|||
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean {
|
||||
return when (event) {
|
||||
is IntroductionProcess.ButtonScanCardLegacy -> false
|
||||
is IntroductionProcess.ButtonScanCard -> false
|
||||
is IntroductionProcess.ButtonScanCard,
|
||||
is IntroductionProcess.ButtonScanCardLegacy,
|
||||
is SignIn.ScreenOpened,
|
||||
is SignIn.ButtonAddWallet,
|
||||
-> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ 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
|
||||
import com.tangem.core.analytics.models.event.SignIn
|
||||
import com.tangem.domain.card.analytics.IntroductionProcess
|
||||
|
||||
class HotWalletContextInterceptor(
|
||||
val parent: ParamsInterceptor? = null,
|
||||
|
|
@ -10,7 +12,16 @@ class HotWalletContextInterceptor(
|
|||
|
||||
override fun id(): String = HotWalletContextInterceptor.id()
|
||||
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = true
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean {
|
||||
return when (event) {
|
||||
is SignIn.ScreenOpened,
|
||||
is SignIn.ButtonAddWallet,
|
||||
is SignIn.ButtonUnlockAllWithBiometric,
|
||||
is IntroductionProcess.ButtonScanCard,
|
||||
-> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
override fun intercept(params: MutableMap<String, String>) {
|
||||
params[AnalyticsParam.PRODUCT_TYPE] = AnalyticsParam.ProductType.MobileWallet.value
|
||||
|
|
|
|||
|
|
@ -525,13 +525,12 @@ internal class DefaultUserWalletsListRepository(
|
|||
}
|
||||
|
||||
private fun trackSignInEvent(userWallet: UserWallet, type: Basic.SignedIn.SignInType) {
|
||||
trackingContextProxy.proceedWithContext(userWallet) {
|
||||
analyticsEventHandler.send(
|
||||
event = Basic.SignedIn(
|
||||
signInType = type,
|
||||
walletsCount = userWallets.value?.size ?: 0,
|
||||
),
|
||||
)
|
||||
}
|
||||
trackingContextProxy.addContext(userWallet)
|
||||
analyticsEventHandler.send(
|
||||
event = Basic.SignedIn(
|
||||
signInType = type,
|
||||
walletsCount = userWallets.value?.size ?: 0,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -227,14 +227,13 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
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,
|
||||
),
|
||||
)
|
||||
}
|
||||
trackingContextProxy.addContext(selectedWallet)
|
||||
analyticsEventHandler.send(
|
||||
event = Basic.SignedIn(
|
||||
signInType = Basic.SignedIn.SignInType.NoSecurity,
|
||||
walletsCount = userWallets.size,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.common.ui.userwallet
|
||||
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.event.SignIn
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -13,6 +15,7 @@ import com.tangem.domain.common.wallets.error.UnlockWalletError.UnableToUnlock.R
|
|||
inline fun UnlockWalletError.handle(
|
||||
onAlreadyUnlocked: () -> Unit = {},
|
||||
onUserCancelled: () -> Unit = {},
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
noinline showMessage: (EventMessage) -> Unit,
|
||||
) {
|
||||
when (this) {
|
||||
|
|
@ -30,15 +33,20 @@ inline fun UnlockWalletError.handle(
|
|||
// This should never happen in this flow, as we always check for the wallet existence before unlocking
|
||||
showMessage(SnackbarMessage(TextReference.Res(R.string.generic_error)))
|
||||
}
|
||||
is UnlockWalletError.UnableToUnlock -> handleUnableToUnlock(this, showMessage)
|
||||
is UnlockWalletError.UnableToUnlock -> handleUnableToUnlock(this, analyticsEventHandler, showMessage)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleUnableToUnlock(error: UnlockWalletError.UnableToUnlock, showDialog: (DialogMessage) -> Unit) {
|
||||
fun handleUnableToUnlock(
|
||||
error: UnlockWalletError.UnableToUnlock,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
showDialog: (DialogMessage) -> Unit,
|
||||
) {
|
||||
val dialogMessage = when (error) {
|
||||
is UnlockWalletError.UnableToUnlock.WithReason -> {
|
||||
when (error.reason) {
|
||||
Reason.AllKeysInvalidated -> {
|
||||
analyticsEventHandler.send(SignIn.ErrorBiometricUpdated())
|
||||
DialogMessage(
|
||||
title = resourceReference(R.string.biometric_updated_warning_title),
|
||||
message = resourceReference(R.string.biometric_updated_warning_description),
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ sealed class AnalyticsParam {
|
|||
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 CreateWalletIntro : ScreensSources("Create Wallet Intro")
|
||||
data object AddNewWallet : ScreensSources("Add New Wallet")
|
||||
data object CreateWallet : ScreensSources("Create Wallet")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,19 @@ sealed class SignIn(
|
|||
),
|
||||
)
|
||||
|
||||
class ButtonBiometricSignIn : SignIn(event = "Button - Biometric Sign In")
|
||||
|
||||
class ButtonUnlockAllWithBiometric : SignIn(event = "Button - Unlock All With Biometric")
|
||||
|
||||
class ErrorBiometricUpdated : SignIn(event = "Error - Biometric Updated")
|
||||
|
||||
class ButtonWallet(
|
||||
signInType: SignInType,
|
||||
walletsCount: Int,
|
||||
) : SignIn(
|
||||
event = "Button - Wallet",
|
||||
params = buildMap {
|
||||
put("Wallets Count", walletsCount.toString())
|
||||
put("Sign in type", signInType.value)
|
||||
},
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,4 @@ interface TrackingContextProxy {
|
|||
fun addHotWalletContext()
|
||||
|
||||
fun removeContext()
|
||||
|
||||
fun proceedWithContext(userWallet: UserWallet, action: () -> Unit)
|
||||
}
|
||||
|
|
@ -13,6 +13,8 @@ sealed class IntroductionProcess(
|
|||
class ButtonBuyCards : IntroductionProcess("Button - Buy Cards")
|
||||
class ButtonScanCardLegacy : IntroductionProcess("Button - Scan Card")
|
||||
|
||||
class CreateWalletIntroScreenOpened : IntroductionProcess("Create Wallet Intro Screen Opened")
|
||||
|
||||
class ButtonScanCard(
|
||||
val source: AnalyticsParam.ScreensSources,
|
||||
) : IntroductionProcess(
|
||||
|
|
|
|||
|
|
@ -127,9 +127,15 @@ internal class CreateWalletStartModel @Inject constructor(
|
|||
},
|
||||
)
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(
|
||||
event = IntroductionProcess.CreateWalletIntroScreenOpened(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun onScanClick() {
|
||||
analyticsEventHandler.send(
|
||||
event = IntroductionProcess.ButtonScanCard(AnalyticsParam.ScreensSources.CreateNewWallet),
|
||||
event = IntroductionProcess.ButtonScanCard(AnalyticsParam.ScreensSources.CreateWalletIntro),
|
||||
)
|
||||
scanCard()
|
||||
}
|
||||
|
|
@ -137,7 +143,7 @@ internal class CreateWalletStartModel @Inject constructor(
|
|||
private fun onStartWithMobileWalletClick() {
|
||||
analyticsEventHandler.send(
|
||||
event = OnboardingAnalyticsEvent.Onboarding.ButtonMobileWallet(
|
||||
source = AnalyticsParam.ScreensSources.CreateNewWallet.value,
|
||||
source = AnalyticsParam.ScreensSources.CreateWalletIntro.value,
|
||||
),
|
||||
)
|
||||
if (!isHotWalletCreationSupported()) {
|
||||
|
|
@ -147,11 +153,11 @@ internal class CreateWalletStartModel @Inject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
router.push(AppRoute.CreateMobileWallet(AnalyticsParam.ScreensSources.CreateNewWallet.value))
|
||||
router.push(AppRoute.CreateMobileWallet(AnalyticsParam.ScreensSources.CreateWalletIntro.value))
|
||||
}
|
||||
|
||||
private fun onBuyClick() {
|
||||
analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.CreateNewWallet))
|
||||
analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.CreateWalletIntro))
|
||||
modelScope.launch {
|
||||
generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ package com.tangem.features.details.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.event.SignIn
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
|
|
@ -39,6 +42,7 @@ internal class UserWalletListModel @Inject constructor(
|
|||
private val userWalletSaver: UserWalletSaver,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
private val unlockWalletUseCase: UnlockWalletUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val isWalletSavingInProgress: MutableStateFlow<Boolean> = MutableStateFlow(value = false)
|
||||
|
|
@ -87,6 +91,7 @@ internal class UserWalletListModel @Inject constructor(
|
|||
|
||||
private fun onAddNewWalletClick() {
|
||||
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||
analyticsEventHandler.send(SignIn.ButtonAddWallet(AnalyticsParam.ScreensSources.SignIn))
|
||||
router.push(AppRoute.CreateWalletSelection)
|
||||
} else {
|
||||
withProgress(isWalletSavingInProgress) {
|
||||
|
|
@ -105,6 +110,7 @@ internal class UserWalletListModel @Inject constructor(
|
|||
error.handle(
|
||||
onUserCancelled = {},
|
||||
onAlreadyUnlocked = { router.push(AppRoute.WalletSettings(userWalletId)) },
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
showMessage = messageSender::send,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.features.hotwallet.accesscoderequest
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.event.SignIn
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.ui.components.fields.PinTextColor
|
||||
|
|
@ -33,6 +35,7 @@ internal class HotAccessCodeRequestModel @Inject constructor(
|
|||
private val hotAccessCodeAttemptsRepository: HotWalletAccessCodeAttemptsRepository,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val canUseBiometryUseCase: CanUseBiometryUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
private val result = MutableStateFlow<HotWalletPasswordRequester.Result?>(null)
|
||||
|
|
@ -108,6 +111,7 @@ internal class HotAccessCodeRequestModel @Inject constructor(
|
|||
onAccessCodeChange = ::onAccessCodeChange,
|
||||
accessCode = "",
|
||||
useBiometricClick = {
|
||||
analyticsEventHandler.send(SignIn.ButtonBiometricSignIn())
|
||||
dismissState()
|
||||
result.value = HotWalletPasswordRequester.Result.UseBiometry
|
||||
},
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
error.handle(
|
||||
onAlreadyUnlocked = {},
|
||||
onUserCancelled = {},
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
showMessage = uiMessageSender::send,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,14 +58,18 @@ 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))
|
||||
trackingContextProxy.addContext(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(
|
||||
event = SignIn.ButtonWallet(
|
||||
signInType = signInType,
|
||||
walletsCount = userWallets.size,
|
||||
),
|
||||
)
|
||||
onUserWalletClick(userWallet)
|
||||
}
|
||||
},
|
||||
|
|
@ -210,6 +214,7 @@ internal class WelcomeModel @Inject constructor(
|
|||
router.replaceAll(AppRoute.Wallet)
|
||||
},
|
||||
onUserCancelled = { onUserCancelled() },
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
showMessage = uiMessageSender::send,
|
||||
)
|
||||
}
|
||||
|
|
@ -226,13 +231,12 @@ 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,
|
||||
),
|
||||
)
|
||||
}
|
||||
trackingContextProxy.addContext(userWallet)
|
||||
analyticsEventHandler.send(
|
||||
event = Basic.SignedIn(
|
||||
signInType = type,
|
||||
walletsCount = walletsCount,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue