Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-27 13:35:00 +03:00
parent 9897c63c17
commit 7d9c12f1bc
10 changed files with 123 additions and 38 deletions

View file

@ -13,6 +13,7 @@ sealed class Onboarding(
class Started : Onboarding("Onboarding", "Onboarding Started")
class Finished : Onboarding("Onboarding", "Onboarding Finished")
data object OfflineAttestationFailed : Onboarding(category = "Onboarding", event = "Offline Attestation Failed")
sealed class CreateWallet(
event: String,

View file

@ -6,6 +6,7 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
import com.tangem.tap.domain.scanCard.DefaultScanCardProcessor
import com.tangem.tap.domain.scanCard.LegacyScanProcessor
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -24,7 +25,9 @@ internal object CardLegacyDomainModule {
@Provides
@Singleton
fun provideScanCardProcessor(): ScanCardProcessor = DefaultScanCardProcessor()
fun provideScanCardProcessor(legacyScanProcessor: LegacyScanProcessor): ScanCardProcessor {
return DefaultScanCardProcessor(legacyScanProcessor = legacyScanProcessor)
}
@Provides
@Singleton

View file

@ -10,7 +10,9 @@ import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
// TODO: Remove this object after feature toggle was removed and use ScanCardUseCase instead
internal class DefaultScanCardProcessor : ScanCardProcessor {
internal class DefaultScanCardProcessor(
private val legacyScanProcessor: LegacyScanProcessor,
) : ScanCardProcessor {
private val isNewCardScanningEnabled: Boolean
get() = store.inject(DaggerGraphState::cardScanningFeatureToggles).isNewCardScanningEnabled
@ -21,7 +23,10 @@ internal class DefaultScanCardProcessor : ScanCardProcessor {
return if (isNewCardScanningEnabled) {
UseCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository)
} else {
LegacyScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository)
legacyScanProcessor.scan(
cardId = cardId,
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
)
}
}
@ -38,24 +43,24 @@ internal class DefaultScanCardProcessor : ScanCardProcessor {
) {
if (isNewCardScanningEnabled) {
UseCaseScanProcessor.scan(
analyticsSource,
cardId,
onProgressStateChange,
onWalletNotCreated,
disclaimerWillShow,
onFailure,
onSuccess,
analyticsSource = analyticsSource,
cardId = cardId,
onProgressStateChange = onProgressStateChange,
onWalletNotCreated = onWalletNotCreated,
disclaimerWillShow = disclaimerWillShow,
onFailure = onFailure,
onSuccess = onSuccess,
)
} else {
LegacyScanProcessor.scan(
analyticsSource,
cardId,
onProgressStateChange,
onWalletNotCreated,
disclaimerWillShow,
onCancel,
onFailure,
onSuccess,
legacyScanProcessor.scan(
analyticsSource = analyticsSource,
cardId = cardId,
onProgressStateChange = onProgressStateChange,
onWalletNotCreated = onWalletNotCreated,
disclaimerWillShow = disclaimerWillShow,
onCancel = onCancel,
onFailure = onFailure,
onSuccess = onSuccess,
)
}
}

View file

@ -2,13 +2,22 @@ package com.tangem.tap.domain.scanCard
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.common.routing.AppRoute
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.decompose.di.GlobalUiMessageSender
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.R
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.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
@ -18,6 +27,8 @@ import com.tangem.domain.common.util.twinsIsTwinned
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
import com.tangem.sdk.extensions.localizedDescriptionRes
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppDialog
@ -33,12 +44,15 @@ import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.*
import javax.inject.Inject
import javax.inject.Singleton
internal object LegacyScanProcessor {
@Singleton
internal class LegacyScanProcessor @Inject constructor(
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
private val analyticsEventHandler: AnalyticsEventHandler,
) {
suspend fun scan(
cardId: String? = null,
@ -72,7 +86,16 @@ internal object LegacyScanProcessor {
result
.doOnFailure { error ->
onFailure(error)
onScanFailure(
error = error,
onFailure = onFailure,
onCancel = {
mainScope.launch {
onProgressStateChange.invoke(false)
onCancel()
}
},
)
}
.doOnSuccess { scanResponse ->
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
@ -82,7 +105,6 @@ internal object LegacyScanProcessor {
showDisclaimerIfNeed(
scanResponse = scanResponse,
disclaimerWillShow = disclaimerWillShow,
onFailure = onFailure,
nextHandler = { scanResponse2 ->
onScanSuccess(
scanResponse = scanResponse2,
@ -114,7 +136,6 @@ internal object LegacyScanProcessor {
scanResponse: ScanResponse,
crossinline disclaimerWillShow: () -> Unit = {},
crossinline nextHandler: suspend (ScanResponse) -> Unit,
crossinline onFailure: suspend (error: TangemError) -> Unit,
) {
val disclaimer = scanResponse.card.createDisclaimer()
@ -135,6 +156,49 @@ internal object LegacyScanProcessor {
}
}
private suspend inline fun onScanFailure(
error: TangemError,
crossinline onFailure: suspend (TangemError) -> Unit,
crossinline onCancel: () -> Job,
) {
if (error is TangemSdkError.CardVerificationFailed) {
analyticsEventHandler.send(event = Onboarding.OfflineAttestationFailed)
val resource = error.localizedDescriptionRes()
val resId = resource.resId ?: R.string.common_unknown_error
val resArgs = resource.args.map { it.value }
uiMessageSender.send(
message = DialogMessage(
message = resourceReference(id = resId, resArgs.toWrappedList()),
title = resourceReference(id = R.string.security_alert_title),
isDismissable = false,
firstActionBuilder = {
EventMessageAction(
title = resourceReference(id = R.string.alert_button_request_support),
onClick = {
mainScope.launch {
onCancel()
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
type = FeedbackEmailType.CardAttestationFailed,
)
}
},
)
},
secondActionBuilder = {
cancelAction {
mainScope.launch { onCancel() }
}
},
),
)
} else {
onFailure(error)
}
}
@Suppress("LongMethod", "MagicNumber")
private suspend inline fun onScanSuccess(
scanResponse: ScanResponse,