Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-05 11:30:05 +04:00
parent 369f3bbd44
commit aee18abe0e
23 changed files with 131 additions and 160 deletions

View file

@ -96,7 +96,7 @@ internal class CreateWalletSelectionModel @Inject constructor(
return
}
router.push(AppRoute.CreateMobileWallet(AnalyticsParam.ScreensSources.AddNewWallet.value))
router.push(AppRoute.CreateMobileWallet(AnalyticsParam.ScreensSources.AddNewWallet))
}
private fun onHardwareWalletClick() {

View file

@ -164,7 +164,7 @@ internal class CreateWalletStartModel @Inject constructor(
return
}
router.push(AppRoute.CreateMobileWallet(AnalyticsParam.ScreensSources.CreateWalletIntro.value))
router.push(AppRoute.CreateMobileWallet(AnalyticsParam.ScreensSources.CreateWalletIntro))
}
private fun onBuyClick() {

View file

@ -194,7 +194,7 @@ internal class CreateWalletStartModelTest {
verify {
router.push(
route = AppRoute.CreateMobileWallet(
source = AnalyticsParam.ScreensSources.CreateWalletIntro.value,
source = AnalyticsParam.ScreensSources.CreateWalletIntro,
),
onComplete = any(),
)

View file

@ -17,6 +17,7 @@ dependencies {
implementation(projects.domain.wallets.models)
/* Project - Core */
api(projects.core.analytics.models)
implementation(projects.core.decompose)
implementation(projects.core.ui)

View file

@ -1,11 +1,12 @@
package com.tangem.features.hotwallet
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
interface CreateMobileWalletComponent : ComposableContentComponent {
data class Params(
val source: String,
val source: AnalyticsParam.ScreensSources,
)
interface Factory : ComponentFactory<Params, CreateMobileWalletComponent>

View file

@ -129,13 +129,13 @@ internal class AddExistingWalletImportModel @Inject constructor(
analyticsEventHandler.send(
event = OnboardingAnalyticsEvent.Onboarding.Finished(
source = AnalyticsParam.ScreensSources.ImportWallet.value,
source = AnalyticsParam.ScreensSources.ImportWallet,
),
)
analyticsEventHandler.send(
event = OnboardingAnalyticsEvent.CreateWallet.WalletCreatedSuccessfully(
source = AnalyticsParam.ScreensSources.ImportWallet.value,
creationType = OnboardingAnalyticsEvent.CreateWallet.WalletCreationType.SeedImport,
source = AnalyticsParam.ScreensSources.ImportWallet,
creationType = AnalyticsParam.WalletCreationType.SeedImport,
seedPhraseLength = mnemonic.mnemonicComponents.size,
passPhraseState = if (passphrase.isNullOrBlank()) {
AnalyticsParam.EmptyFull.Empty

View file

@ -62,7 +62,9 @@ internal class CreateMobileWalletModel @Inject constructor(
init {
trackingContextProxy.addHotWalletContext()
analyticsEventHandler.send(event = OnboardingAnalyticsEvent.Onboarding.Started(source = params.source))
analyticsEventHandler.send(
event = OnboardingAnalyticsEvent.Onboarding.Started(source = params.source),
)
analyticsEventHandler.send(
event = OnboardingAnalyticsEvent.SeedPhrase.CreateMobileScreenOpened(source = params.source),
)
@ -95,11 +97,13 @@ internal class CreateMobileWalletModel @Inject constructor(
saveUserWalletUseCase(userWallet)
analyticsEventHandler.send(OnboardingAnalyticsEvent.Onboarding.Finished(source = params.source))
analyticsEventHandler.send(
OnboardingAnalyticsEvent.Onboarding.Finished(source = params.source),
)
analyticsEventHandler.send(
event = OnboardingAnalyticsEvent.CreateWallet.WalletCreatedSuccessfully(
source = params.source,
creationType = OnboardingAnalyticsEvent.CreateWallet.WalletCreationType.NewSeed,
creationType = AnalyticsParam.WalletCreationType.NewSeed,
seedPhraseLength = SEED_PHRASE_LENGTH,
passPhraseState = AnalyticsParam.EmptyFull.Empty,
referralId = appsFlyerStore.get()?.refcode,

View file

@ -2,9 +2,6 @@ package com.tangem.features.onboarding.v2.common.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.AppsFlyerIncludedEvent
import com.tangem.core.analytics.models.getReferralParams
import kotlin.collections.putAll
sealed class OnboardingEvent(
category: String,
@ -12,41 +9,6 @@ sealed class OnboardingEvent(
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(category, event, params) {
class Started : OnboardingEvent("Onboarding", "Onboarding Started")
class Finished : OnboardingEvent("Onboarding", "Onboarding Finished")
sealed class CreateWallet(
event: String,
params: Map<String, String> = mapOf(),
) : OnboardingEvent("Onboarding / Create Wallet", event, params) {
class ScreenOpened : CreateWallet("Create Wallet Screen Opened")
class ButtonCreateWallet : CreateWallet("Button - Create Wallet")
class ButtonOtherOptions : CreateWallet("Button - Other Options")
class WalletCreatedSuccessfully(
creationType: WalletCreationType = WalletCreationType.PrivateKey,
seedPhraseLength: Int? = null,
passPhraseState: AnalyticsParam.EmptyFull,
referralId: String?,
) : CreateWallet(
event = "Wallet Created Successfully",
params = buildMap {
put("Creation Type", creationType.value)
put("Passphrase", passPhraseState.value)
if (seedPhraseLength != null) {
put("Seed Phrase Length", seedPhraseLength.toString())
}
putAll(getReferralParams(referralId))
},
), AppsFlyerIncludedEvent
sealed class WalletCreationType(val value: String) {
data object PrivateKey : WalletCreationType(value = "Private Key")
data object NewSeed : WalletCreationType(value = "New Seed")
data object SeedImport : WalletCreationType(value = "Seed Import")
}
}
sealed class Backup(
event: String,
params: Map<String, String> = mapOf(),

View file

@ -19,6 +19,7 @@ import com.arkivanov.decompose.router.stack.*
import com.arkivanov.decompose.value.Value
import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
@ -28,7 +29,6 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.biometry.AskBiometryComponent
import com.tangem.features.onboarding.v2.addresssync.AddressSyncComponent
import com.tangem.features.onboarding.v2.addresssync.DefaultAddressSyncComponent
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.MultiWalletAccessCodeComponent
@ -229,7 +229,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
}
Done -> {
// final step - navigate to parent
analyticsHandler.send(OnboardingEvent.Finished())
analyticsHandler.send(OnboardingAnalyticsEvent.Onboarding.Finished())
val userWallet = childParams.multiWalletState.value.resultUserWallet ?: return
params.onDone(userWallet)
}

View file

@ -6,6 +6,7 @@ import com.tangem.common.core.TangemSdkError
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.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -19,7 +20,6 @@ import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.createwallet.ui.state.MultiWalletCreateWalletUM
@ -67,12 +67,12 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
resourceReference(R.string.onboarding_create_wallet_body)
},
onCreateWalletClick = {
analyticsHandler.send(OnboardingEvent.CreateWallet.ButtonCreateWallet())
analyticsHandler.send(OnboardingAnalyticsEvent.CreateWallet.ButtonCreateWallet())
createWallet(false)
},
showOtherOptionsButton = params.parentParams.withSeedPhraseFlow,
onOtherOptionsClick = {
analyticsHandler.send(OnboardingEvent.CreateWallet.ButtonOtherOptions())
analyticsHandler.send(OnboardingAnalyticsEvent.CreateWallet.ButtonOtherOptions())
modelScope.launch {
onDone.emit(Step.SeedPhrase)
}
@ -85,7 +85,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
val onDone = MutableSharedFlow<Step>()
init {
analyticsHandler.send(OnboardingEvent.CreateWallet.ScreenOpened())
analyticsHandler.send(OnboardingAnalyticsEvent.CreateWallet.ScreenOpened())
}
private fun createWallet(shouldReset: Boolean) {
@ -110,7 +110,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
cardRepository.startCardActivation(cardId = result.data.card.cardId)
analyticsHandler.send(
event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully(
event = OnboardingAnalyticsEvent.CreateWallet.WalletCreatedSuccessfully(
passPhraseState = AnalyticsParam.EmptyFull.Empty,
referralId = appsFlyerStore.get()?.refcode,
),

View file

@ -29,7 +29,6 @@ import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
import com.tangem.domain.wallets.usecase.IsWalletAlreadySavedUseCase
import com.tangem.features.hotwallet.MnemonicRepository
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.common.ui.OnboardingDialogUM
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
import com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase.model.builder.GenerateSeedPhraseUiStateBuilder
@ -239,11 +238,11 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
if (!isWalletAlreadySaved) {
analyticsHandler.send(
OnboardingEvent.CreateWallet.WalletCreatedSuccessfully(
OnboardingAnalyticsEvent.CreateWallet.WalletCreatedSuccessfully(
creationType = if (generatedSeedPhrase) {
OnboardingEvent.CreateWallet.WalletCreationType.NewSeed
AnalyticsParam.WalletCreationType.NewSeed
} else {
OnboardingEvent.CreateWallet.WalletCreationType.SeedImport
AnalyticsParam.WalletCreationType.SeedImport
},
seedPhraseLength = mnemonic.mnemonicComponents.size,
passPhraseState = if (passphrase.isNullOrBlank()) {

View file

@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.model
import com.tangem.common.routing.AppRoute
import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -12,7 +13,6 @@ import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.onboarding.repository.OnboardingRepository
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.common.ui.interruptBackupDialog
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
@ -60,7 +60,7 @@ internal class OnboardingMultiWalletModel @Inject constructor(
val uiState = _uiState.asStateFlow()
init {
analyticsHandler.send(OnboardingEvent.Started())
analyticsHandler.send(OnboardingAnalyticsEvent.Onboarding.Started())
initScreenTitle()
loadCardArtwork()
subscribeToBackups()

View file

@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.note.impl.child.create.model
import com.tangem.common.CompletionResult
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -10,10 +11,9 @@ import com.tangem.core.ui.components.artwork.ArtworkUM
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
import com.tangem.domain.card.repository.CardRepository
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.note.impl.child.create.OnboardingNoteCreateWalletComponent
import com.tangem.features.onboarding.v2.note.impl.child.create.ui.state.OnboardingNoteCreateWalletUM
import com.tangem.sdk.api.TangemSdkManager
@ -46,11 +46,11 @@ internal class OnboardingNoteCreateWalletModel @Inject constructor(
)
init {
analyticsEventHandler.send(OnboardingEvent.CreateWallet.ScreenOpened())
analyticsEventHandler.send(OnboardingAnalyticsEvent.CreateWallet.ScreenOpened())
modelScope.launch {
val scanResponse = params.childParams.commonState.value.scanResponse ?: return@launch
if (!cardRepository.isActivationStarted(scanResponse.card.cardId)) {
analyticsEventHandler.send(OnboardingEvent.Started())
analyticsEventHandler.send(OnboardingAnalyticsEvent.Onboarding.Started())
}
}
observeArtwork()
@ -64,11 +64,10 @@ internal class OnboardingNoteCreateWalletModel @Inject constructor(
it.copy(createWalletInProgress = true)
}
val scanResponse = params.childParams.commonState.value.scanResponse ?: return@launch
val result = tangemSdkManager.createProductWallet(scanResponse)
when (result) {
when (val result = tangemSdkManager.createProductWallet(scanResponse)) {
is CompletionResult.Success -> {
analyticsEventHandler.send(
event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully(
event = OnboardingAnalyticsEvent.CreateWallet.WalletCreatedSuccessfully(
passPhraseState = AnalyticsParam.EmptyFull.Empty,
referralId = appsFlyerStore.get()?.refcode,
),

View file

@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.note.impl.model
import com.arkivanov.decompose.router.stack.StackNavigation
import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -10,7 +11,6 @@ import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
import com.tangem.features.onboarding.v2.common.ui.exitOnboardingDialog
import com.tangem.features.onboarding.v2.note.api.OnboardingNoteComponent
import com.tangem.features.onboarding.v2.note.impl.OnboardingNoteInnerNavigationState
@ -76,7 +76,7 @@ internal class OnboardingNoteModel @Inject constructor(
}
fun onWalletCreated(userWallet: UserWallet) {
analyticsEventHandler.send(OnboardingEvent.Finished())
analyticsEventHandler.send(OnboardingAnalyticsEvent.Onboarding.Finished())
commonUiState.update {
it.copy(userWallet = userWallet)
}

View file

@ -10,6 +10,7 @@ import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toHexString
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
@ -175,7 +176,7 @@ internal class OnboardingTwinModel @Inject constructor(
}
analyticsEventHandler.send(
event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully(
event = OnboardingAnalyticsEvent.CreateWallet.WalletCreatedSuccessfully(
passPhraseState = AnalyticsParam.EmptyFull.Empty,
referralId = appsFlyerStore.get()?.refcode,
),

View file

@ -19,7 +19,7 @@ import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.onboarding.repository.OnboardingRepository
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
import com.tangem.features.onboarding.v2.TitleProvider
import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
@ -114,7 +114,7 @@ internal class OnboardingMultiWalletModelTest {
createModel(this)
advanceUntilIdle()
verify { analyticsHandler.send(match<OnboardingEvent.Started> { true }) }
verify { analyticsHandler.send(match<OnboardingAnalyticsEvent.Onboarding.Started> { true }) }
}
@Test