Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-24 23:46:56 +07:00
parent 60e697282b
commit caa1429175
6 changed files with 41 additions and 78 deletions

View file

@ -19,15 +19,15 @@ 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.dialog.Dialogs
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.card.common.util.twinsIsTwinned
import com.tangem.domain.common.extensions.withMainContext
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.paramsInterceptor.CardContextInterceptor
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.extensions.dispatchNavigationAction
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.disclaimer.createDisclaimer
import com.tangem.tap.features.onboarding.OnboardingHelper
@ -113,7 +113,6 @@ internal class LegacyScanProcessor @Inject constructor(
onProgressStateChange = onProgressStateChange,
onSuccess = onSuccess,
onWalletNotCreated = onWalletNotCreated,
onCancel = onCancel,
)
},
)
@ -198,90 +197,38 @@ internal class LegacyScanProcessor @Inject constructor(
scanResponse: ScanResponse,
crossinline onProgressStateChange: suspend (showProgress: Boolean) -> Unit,
crossinline onWalletNotCreated: suspend () -> Unit,
crossinline onCancel: suspend () -> Unit,
crossinline onSuccess: suspend (ScanResponse) -> Unit,
) {
checkCardWasUsedInApp(
scanResponse = scanResponse,
onCancel = {
mainScope.launch {
onProgressStateChange.invoke(false)
onCancel()
}
},
) {
if (OnboardingHelper.isOnboardingCase(scanResponse)) {
trackingContextProxy.addContext(scanResponse)
if (OnboardingHelper.isOnboardingCase(scanResponse)) {
trackingContextProxy.addContext(scanResponse)
onWalletNotCreated()
navigateTo(
AppRoute.Onboarding(
scanResponse = scanResponse,
mode = AppRoute.Onboarding.Mode.Onboarding,
),
) { onProgressStateChange(it) }
} else {
trackingContextProxy.setContext(scanResponse)
val wasTwinsOnboardingShown =
store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase).invokeSync()
if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) {
onWalletNotCreated()
navigateTo(
AppRoute.Onboarding(
scanResponse = scanResponse,
mode = AppRoute.Onboarding.Mode.Onboarding,
mode = AppRoute.Onboarding.Mode.WelcomeOnlyTwin,
),
) { onProgressStateChange(it) }
} else {
trackingContextProxy.setContext(scanResponse)
val wasTwinsOnboardingShown =
store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase).invokeSync()
if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) {
onWalletNotCreated()
navigateTo(
AppRoute.Onboarding(
scanResponse = scanResponse,
mode = AppRoute.Onboarding.Mode.WelcomeOnlyTwin,
),
) { onProgressStateChange(it) }
} else {
delay(DELAY_SDK_DIALOG_CLOSE)
onSuccess(scanResponse)
}
delay(DELAY_SDK_DIALOG_CLOSE)
onSuccess(scanResponse)
}
}
}
/**
* Checks if card has password and never login at this app
* Show alert in this case
*/
private suspend fun checkCardWasUsedInApp(
scanResponse: ScanResponse,
onCancel: () -> Unit,
onSuccess: suspend () -> Unit,
) {
val userWalletId = runCatching { UserWalletIdBuilder.card(scanResponse.card).build() }.getOrNull()
if (userWalletId == null) {
onSuccess()
return
}
val userTokensResponseStore = store.inject(DaggerGraphState::userTokensResponseStore)
val tokens = userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId)
if (scanResponse.card.isAccessCodeSet && tokens == null) {
store.dispatchDialogShow(
AppDialog.WalletAlreadyWasUsedDialog(
onOk = { mainScope.launch { onSuccess() } },
onSupportClick = {
val cardInfo =
store.inject(DaggerGraphState::getWalletMetaInfoUseCase).invoke(scanResponse).getOrNull()
?: error("CardInfo must be not null")
scope.launch {
store.inject(DaggerGraphState::sendFeedbackEmailUseCase)
.invoke(type = FeedbackEmailType.PreActivatedWallet(cardInfo))
}
onCancel()
},
onCancel = { onCancel() },
),
)
} else {
onSuccess()
}
}
private suspend inline fun navigateTo(route: AppRoute, onProgressStateChange: (showProgress: Boolean) -> Unit) {
delay(DELAY_SDK_DIALOG_CLOSE)
store.dispatchNavigationAction { push(route) }

View file

@ -176,6 +176,7 @@ internal class DefaultTangemSdkManager(
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
visaCardScanHandler = visaCardScanHandler,
visaCoroutineScope = this,
shouldCheckIsAlreadyActivated = true,
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
),
cardId = cardId,

View file

@ -27,6 +27,7 @@ internal class ResetBackupCardTask(
PreflightReadTask(
readMode = PreflightReadMode.FullCardRead,
filter = UserWalletIdPreflightReadFilter(expectedUserWalletId = userWalletId),
secureStorage = session.environment.secureStorage,
).run(session) { result ->
when (result) {
is CompletionResult.Success -> resetCard(session, callback)

View file

@ -29,6 +29,7 @@ import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_PREFIX
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.ScanTask
import com.tangem.operations.backup.PrimaryCard
import com.tangem.operations.backup.StartPrimaryCardLinkingTask
@ -52,6 +53,7 @@ internal class ScanProductTask(
private val visaCardScanHandler: VisaCardScanHandler?,
private val visaCoroutineScope: CoroutineScope?,
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles?,
private val shouldCheckIsAlreadyActivated: Boolean,
override val allowsRequestAccessCodeFromRepository: Boolean = false,
) : CardSessionRunnable<ScanResponse> {
@ -109,6 +111,14 @@ internal class ScanProductTask(
}
}
override fun preflightReadMode(): PreflightReadMode {
return if (shouldCheckIsAlreadyActivated) {
PreflightReadMode.FullCardReadWithAccessCodeCheck
} else {
return super.preflightReadMode()
}
}
private fun getErrorIfExcludedCard(cardDto: CardDTO, card: Card): TangemError? {
if (cardDto.isExcluded) return TapSdkError.CardForDifferentApp()
if (cardDto.isNotSupportedInThatRelease) return TapSdkError.CardNotSupportedByRelease()

View file

@ -20,7 +20,10 @@ class FinalizeTwinTask(
WriteProtectedIssuerDataTask(twinPublicKey, issuerKeys).run(session) { result ->
when (result) {
is CompletionResult.Success ->
PreflightReadTask(PreflightReadMode.FullCardRead).run(session) { readResult ->
PreflightReadTask(
readMode = PreflightReadMode.FullCardRead,
secureStorage = session.environment.secureStorage,
).run(session) { readResult ->
when (readResult) {
is CompletionResult.Success ->
ScanProductTask(
@ -28,6 +31,7 @@ class FinalizeTwinTask(
derivationsFinder = null,
visaCardScanHandler = null,
visaCoroutineScope = null,
shouldCheckIsAlreadyActivated = false,
onboardingV2FeatureToggles = null,
).run(session, callback)
is CompletionResult.Failure ->

View file

@ -7,7 +7,7 @@
tangemBlockchainSdk = "releases-5.34-1430"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "releases-5.34-579"
tangemCardSdk = "releases-5.34-580"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
tangemVico = "2.0.0-alpha.25-tangem12"
#tangemVico = "0.0.1" # Keep it! - used for local builds ^