Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-04 14:46:26 +04:00
parent 3d5a8654a5
commit 67ca192c16
19 changed files with 90 additions and 52 deletions

View file

@ -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.Basic
import com.tangem.core.analytics.models.event.SignIn
import com.tangem.domain.card.analytics.IntroductionProcess
import com.tangem.domain.card.analytics.ParamCardCurrencyConverter
@ -31,6 +32,7 @@ class CardContextInterceptor(
is IntroductionProcess.ButtonScanCardLegacy,
is SignIn.ScreenOpened,
is SignIn.ButtonAddWallet,
is Basic.CardWasScanned,
-> false
is SignIn.ErrorBiometricUpdated -> !event.isFromUnlockAll
else -> true

View file

@ -7,11 +7,8 @@ import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsEvent
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.analytics.utils.TrackingContextProxy
import com.tangem.core.decompose.di.GlobalUiMessageSender
@ -28,7 +25,6 @@ import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
import com.tangem.sdk.extensions.localizedDescriptionRes
import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.mainScope
import com.tangem.tap.tangemSdkManager
@ -61,6 +57,7 @@ internal class LegacyScanProcessor @Inject constructor(
cardId = cardId,
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated,
source = analyticsSource,
)
.doOnFailure { error ->
onScanFailure(analyticsSource = analyticsSource, error = error, onFailure = {}, onCancel = {})
@ -85,10 +82,9 @@ internal class LegacyScanProcessor @Inject constructor(
val result = tangemSdkManager.scanProduct(
cardId = cardId,
shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated,
source = analyticsSource,
)
val analyticsEvent = Basic.CardWasScanned(analyticsSource)
result
.doOnFailure { error ->
scanFailsCounter.onScanFailure(
@ -111,8 +107,6 @@ internal class LegacyScanProcessor @Inject constructor(
scanFailsCounter.reset()
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
sendAnalytics(analyticsEvent, scanResponse)
onScanSuccess(
scanResponse = scanResponse,
onProgressStateChange = onProgressStateChange,
@ -122,16 +116,6 @@ internal class LegacyScanProcessor @Inject constructor(
}
}
private fun sendAnalytics(analyticsEvent: AnalyticsEvent, scanResponse: ScanResponse) {
// this workaround needed to send CardWasScannedEvent without adding a context
val interceptor = CardContextInterceptor(scanResponse)
val params = analyticsEvent.params.toMutableMap()
interceptor.intercept(params)
analyticsEvent.params = params.toMap()
Analytics.send(analyticsEvent)
}
private suspend inline fun onScanFailure(
analyticsSource: AnalyticsParam.ScreensSources,
error: TangemError,

View file

@ -18,11 +18,13 @@ internal class DefaultScanCardRepository(
allowRequestAccessCodeFromStorage: Boolean,
shouldCheckIsAlreadyActivated: Boolean,
): ScanResponse {
@Suppress("UnreachableCode")
return when (
val result = tangemSdkManager.scanProduct(
cardId = cardId,
allowsRequestAccessCodeFromRepository = allowRequestAccessCodeFromStorage,
shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated,
source = TODO("Fix when enable NEW_CARD_SCANNING_ENABLED"),
)
) {
is CompletionResult.Success -> result.data

View file

@ -18,6 +18,8 @@ import com.tangem.common.usersCode.UserCodeRepository
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.api.AnalyticsErrorHandler
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.res.getStringSafe
import com.tangem.crypto.bip39.DefaultMnemonic
import com.tangem.crypto.hdWallet.DerivationPath
@ -25,13 +27,13 @@ import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.card.repository.CardRepository
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.dynamicaddresses.DynamicAddressesFeatureToggles
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.pay.WithdrawalSignatureResult
import com.tangem.domain.visa.model.*
import com.tangem.domain.wallets.derivations.derivationStyleProvider
import com.tangem.domain.dynamicaddresses.DynamicAddressesFeatureToggles
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
import com.tangem.operations.ScanTask
import com.tangem.operations.derivation.DerivationTaskResponse
@ -46,6 +48,7 @@ import com.tangem.sdk.api.TangemSdkManager
import com.tangem.sdk.api.visa.VisaCardActivationResponse
import com.tangem.sdk.api.visa.VisaCardActivationTaskMode
import com.tangem.tap.common.analytics.events.TangemSdkErrorEvent
import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
import com.tangem.tap.domain.tasks.product.*
import com.tangem.tap.domain.tasks.visa.TangemPayGenerateAddressAndSignChallengeTask
import com.tangem.tap.domain.tasks.visa.TangemPaySignWithdrawalHashTask
@ -135,6 +138,7 @@ internal class DefaultTangemSdkManager(
messageRes: Int?,
allowsRequestAccessCodeFromRepository: Boolean,
shouldCheckIsAlreadyActivated: Boolean,
source: AnalyticsParam.ScreensSources,
): CompletionResult<ScanResponse> {
val message = Message(resources.getStringSafe(messageRes ?: R.string.initial_message_scan_header))
return coroutineScope {
@ -152,7 +156,7 @@ internal class DefaultTangemSdkManager(
),
cardId = cardId,
initialMessage = message,
).also { sendScanResultsToAnalytics(it) }
).also { sendAnalytics(result = it, source = source) }
}
}
@ -225,12 +229,24 @@ internal class DefaultTangemSdkManager(
.doOnResult { tangemSdk.config.setupForProduct(ProductType.ANY) }
}
private fun sendScanResultsToAnalytics(result: CompletionResult<ScanResponse>) {
if (result is CompletionResult.Failure) {
(result.error as? TangemSdkError)?.let { error ->
Analytics.sendErrorEvent(TangemSdkErrorEvent(error))
private fun sendAnalytics(result: CompletionResult<ScanResponse>, source: AnalyticsParam.ScreensSources) {
result
.doOnSuccess { scanResponse ->
// We don't use the standard analytics event enrichment mechanism with card context params here,
// because we've just scanned a new card that may not yet be selected as the current one
val analyticsEvent = Basic.CardWasScanned(source)
val interceptor = CardContextInterceptor(scanResponse)
val params = analyticsEvent.params.toMutableMap()
interceptor.intercept(params)
analyticsEvent.params = params.toMap()
Analytics.send(event = analyticsEvent)
}
.doOnFailure { tangemError ->
(tangemError as? TangemSdkError)?.let { error ->
Analytics.sendErrorEvent(TangemSdkErrorEvent(error))
}
}
}
}
override suspend fun derivePublicKeys(

View file

@ -14,6 +14,7 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.common.core.UserCodeRequestPolicy
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.services.InMemoryStorage
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.res.getStringSafe
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
@ -63,6 +64,7 @@ class MockTangemSdkManager(
messageRes: Int?,
allowsRequestAccessCodeFromRepository: Boolean,
shouldCheckIsAlreadyActivated: Boolean,
source: AnalyticsParam.ScreensSources,
): CompletionResult<ScanResponse> {
if (!MockProvider.isPreset) {
val activity = foregroundActivityObserver.foregroundActivity

View file

@ -302,11 +302,14 @@ internal class DefaultUserWalletsListRepository(
}
val scanResponse = unlockMethod.scanResponse ?: run {
when (val res = tangemSdkManagerProvider().scanProduct(
val tangemSdkManager = tangemSdkManagerProvider()
val result = tangemSdkManager.scanProduct(
shouldCheckIsAlreadyActivated = false,
)) {
source = unlockMethod.source,
)
when (result) {
is CompletionResult.Failure -> raise(UnlockWalletError.UserCancelled)
is CompletionResult.Success -> res.data
is CompletionResult.Success -> result.data
}
}