Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-18 16:24:15 +05:00
parent 3ac26a45b7
commit 294df69e93
21 changed files with 427 additions and 100 deletions

View file

@ -51,9 +51,6 @@ dependencies {
implementation(deps.compose.coil)
implementation(deps.decompose.ext.compose)
/** Firebase */
implementation(deps.firebase.analytics)
/** Tangem libraries */
implementation(tangemDeps.card.android)
implementation(tangemDeps.card.core)

View file

@ -1,9 +0,0 @@
package com.tangem.features.home.impl.analytics
internal sealed class AnalyticsParam {
sealed class CurrencyType(val value: String) {
class Blockchain(blockchain: com.tangem.blockchain.common.Blockchain) : CurrencyType(blockchain.currency)
class Token(token: com.tangem.blockchain.common.Token) : CurrencyType(token.symbol)
}
}

View file

@ -1,14 +0,0 @@
package com.tangem.features.home.impl.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
sealed class IntroductionProcess(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent("Introduction Process", event, params) {
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")
}

View file

@ -1,23 +0,0 @@
package com.tangem.features.home.impl.analytics
import com.tangem.blockchain.common.Blockchain
import com.tangem.domain.card.CardTypesResolver
import com.tangem.utils.converter.Converter
import com.tangem.core.analytics.models.AnalyticsParam as CoreAnalyticsParam
internal class ParamCardCurrencyConverter : Converter<CardTypesResolver, CoreAnalyticsParam.WalletType?> {
override fun convert(value: CardTypesResolver): CoreAnalyticsParam.WalletType? {
if (value.isMultiwalletAllowed()) return CoreAnalyticsParam.WalletType.MultiCurrency
val type = when {
value.isTangemNote() -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain())
value.isTangemTwins() -> AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin)
value.getBlockchain() != Blockchain.Unknown -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain())
value.getPrimaryToken() != null -> AnalyticsParam.CurrencyType.Token(value.getPrimaryToken()!!)
else -> null
} ?: return null
return CoreAnalyticsParam.WalletType.SingleCurrency(type.value)
}
}

View file

@ -1,11 +0,0 @@
package com.tangem.features.home.impl.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
internal sealed class Shop(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent("Shop", event, params) {
object ScreenOpened : Shop("Shop Screen Opened")
}

View file

@ -1,7 +1,5 @@
package com.tangem.features.home.impl.model
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.routing.AppRoute
@ -23,20 +21,22 @@ 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.IntroductionProcess
import com.tangem.domain.card.analytics.ParamCardCurrencyConverter
import com.tangem.domain.card.analytics.Shop
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.core.wallets.error.SaveWalletError
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.settings.repositories.SettingsRepository
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.usecase.GenerateBuyTangemCardLinkUseCase
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.domain.wallets.usecase.SelectWalletUseCase
import com.tangem.features.home.api.HomeComponent
import com.tangem.features.home.impl.analytics.IntroductionProcess
import com.tangem.features.home.impl.analytics.ParamCardCurrencyConverter
import com.tangem.features.home.impl.analytics.Shop
import com.tangem.features.home.impl.ui.state.HomeUM
import com.tangem.features.home.impl.ui.state.Stories
import com.tangem.features.home.impl.ui.state.getRestrictedStories
@ -64,16 +64,17 @@ internal class HomeModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val scanCardProcessor: ScanCardProcessor,
private val saveWalletUseCase: SaveWalletUseCase,
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val settingsRepository: SettingsRepository,
private val urlOpener: UrlOpener,
private val analyticsEventHandler: AnalyticsEventHandler,
private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory,
private val router: Router,
private val selectWalletUseCase: SelectWalletUseCase,
private val appRouter: AppRouter,
private val getUserCountryUseCase: GetUserCountryUseCase,
private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory,
private val saveWalletUseCase: SaveWalletUseCase,
private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase,
private val urlOpener: UrlOpener,
private val userWalletsListManager: UserWalletsListManager,
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
) : Model() {
@ -135,10 +136,9 @@ internal class HomeModel @Inject constructor(
private fun onShopClick() {
analyticsEventHandler.send(IntroductionProcess.ButtonBuyCards)
analyticsEventHandler.send(Shop.ScreenOpened)
Firebase.analytics.appInstanceId
.addOnSuccessListener { urlOpener.openUrl(url = "$NEW_BUY_WALLET_URL&app_instance_id=$it") }
.addOnFailureListener { urlOpener.openUrl(url = NEW_BUY_WALLET_URL) }
modelScope.launch {
generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) }
}
}
private fun onSearchTokensClick() {
@ -198,24 +198,17 @@ internal class HomeModel @Inject constructor(
saveWalletUseCase(userWallet).fold(
ifLeft = {
Timber.e(it.toString(), "Unable to save user wallet")
delay(HIDE_PROGRESS_DELAY)
setLoading(false)
when (it) {
is SaveWalletError.DataError -> Timber.e(it.toString(), "Unable to save user wallet")
is SaveWalletError.WalletAlreadySaved -> appRouter.replaceAll(AppRoute.Wallet)
}
},
ifRight = {
setLoading(false)
sendSignedInCardAnalyticsEvent(scanResponse)
// Select the wallet using new mechanism
selectWalletUseCase(userWallet.walletId).fold(
ifLeft = {
Timber.e("Unable to select user wallet: $it")
setLoading(false)
},
ifRight = {
delay(HIDE_PROGRESS_DELAY)
setLoading(false)
appRouter.replaceAll(AppRoute.Wallet)
},
)
appRouter.replaceAll(AppRoute.Wallet)
},
)
}
@ -228,7 +221,7 @@ internal class HomeModel @Inject constructor(
currency = currency,
batch = scanResponse.card.batchId,
signInType = SignInType.Card,
walletsCount = "1",
walletsCount = userWalletsListManager.walletsCount.toString(),
hasBackup = scanResponse.card.backupStatus?.isActive,
),
)
@ -241,15 +234,9 @@ internal class HomeModel @Inject constructor(
fun handleScanError(error: TangemError) {
when (error) {
is TangemSdkError.NfcFeatureIsUnavailable -> {
handleNfcFeatureUnavailable()
}
is TangemSdkError -> {
Timber.e(error, "Scan error occurred")
}
else -> {
Timber.e(error, "Error happened")
}
is TangemSdkError.NfcFeatureIsUnavailable -> handleNfcFeatureUnavailable()
is TangemSdkError -> Timber.e(error, "Scan error occurred")
else -> Timber.e(error, "Error happened")
}
}
@ -261,8 +248,4 @@ internal class HomeModel @Inject constructor(
),
)
}
companion object {
const val NEW_BUY_WALLET_URL = "https://buy.tangem.com/?utm_source=tangem-app&utm_medium=app"
}
}