Updated on 2026-08-14
This commit is contained in:
parent
9897c63c17
commit
7d9c12f1bc
10 changed files with 123 additions and 38 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class SendFeedbackEmailUseCase(
|
|||
is FeedbackEmailType.ScanningProblem,
|
||||
is FeedbackEmailType.CurrencyDescriptionError,
|
||||
is FeedbackEmailType.PreActivatedWallet,
|
||||
is FeedbackEmailType.CardAttestationFailed,
|
||||
-> this
|
||||
is FeedbackEmailType.DirectUserRequest,
|
||||
is FeedbackEmailType.RateCanBeBetter,
|
||||
|
|
|
|||
|
|
@ -48,4 +48,8 @@ sealed interface FeedbackEmailType {
|
|||
}
|
||||
|
||||
data class PreActivatedWallet(override val cardInfo: CardInfo) : FeedbackEmailType
|
||||
|
||||
data object CardAttestationFailed : FeedbackEmailType {
|
||||
override val cardInfo: CardInfo? = null
|
||||
}
|
||||
}
|
||||
|
|
@ -21,12 +21,14 @@ internal class EmailMessageBodyResolver(
|
|||
when (type) {
|
||||
is FeedbackEmailType.DirectUserRequest -> addUserRequestBody(type.cardInfo)
|
||||
is FeedbackEmailType.RateCanBeBetter -> addCardAndPhoneInfo(type.cardInfo)
|
||||
is FeedbackEmailType.ScanningProblem -> addScanningProblemBody()
|
||||
is FeedbackEmailType.TransactionSendingProblem -> addTransactionSendingProblemBody(type.cardInfo)
|
||||
is FeedbackEmailType.StakingProblem -> addStakingProblemBody(type)
|
||||
is FeedbackEmailType.SwapProblem -> addSwapProblemBody(type)
|
||||
is FeedbackEmailType.CurrencyDescriptionError -> addTokenInfo(type)
|
||||
is FeedbackEmailType.PreActivatedWallet -> addUserRequestBody(type.cardInfo)
|
||||
is FeedbackEmailType.ScanningProblem,
|
||||
is FeedbackEmailType.CardAttestationFailed,
|
||||
-> addPhoneInfoBody()
|
||||
}
|
||||
|
||||
return build()
|
||||
|
|
@ -50,7 +52,7 @@ internal class EmailMessageBodyResolver(
|
|||
addPhoneInfo(phoneInfo = feedbackRepository.getPhoneInfo())
|
||||
}
|
||||
|
||||
private fun FeedbackDataBuilder.addScanningProblemBody() {
|
||||
private fun FeedbackDataBuilder.addPhoneInfoBody() {
|
||||
addPhoneInfo(phoneInfo = feedbackRepository.getPhoneInfo())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ internal class EmailMessageTitleResolver(private val resources: Resources) {
|
|||
return when (type) {
|
||||
is FeedbackEmailType.DirectUserRequest,
|
||||
is FeedbackEmailType.CurrencyDescriptionError,
|
||||
is FeedbackEmailType.CardAttestationFailed,
|
||||
-> R.string.feedback_preface_support
|
||||
is FeedbackEmailType.RateCanBeBetter -> R.string.feedback_preface_rate_negative
|
||||
is FeedbackEmailType.ScanningProblem -> R.string.feedback_preface_scan_failed
|
||||
|
|
|
|||
|
|
@ -19,20 +19,24 @@ internal class EmailSubjectResolver(private val resources: Resources) {
|
|||
return when (type) {
|
||||
is FeedbackEmailType.DirectUserRequest -> {
|
||||
if (type.cardInfo.isStart2Coin) {
|
||||
R.string.feedback_subject_support
|
||||
resources.getStringSafe(R.string.feedback_subject_support)
|
||||
} else {
|
||||
R.string.feedback_subject_support_tangem
|
||||
resources.getStringSafe(R.string.feedback_subject_support_tangem)
|
||||
}
|
||||
}
|
||||
is FeedbackEmailType.RateCanBeBetter -> R.string.feedback_subject_rate_negative
|
||||
is FeedbackEmailType.ScanningProblem -> R.string.feedback_subject_scan_failed
|
||||
is FeedbackEmailType.RateCanBeBetter -> resources.getStringSafe(R.string.feedback_subject_rate_negative)
|
||||
is FeedbackEmailType.ScanningProblem -> resources.getStringSafe(R.string.feedback_subject_scan_failed)
|
||||
is FeedbackEmailType.TransactionSendingProblem,
|
||||
is FeedbackEmailType.StakingProblem,
|
||||
is FeedbackEmailType.SwapProblem,
|
||||
-> R.string.feedback_subject_tx_failed
|
||||
is FeedbackEmailType.PreActivatedWallet -> R.string.feedback_subject_pre_activated_wallet
|
||||
is FeedbackEmailType.CurrencyDescriptionError -> R.string.feedback_token_description_error
|
||||
-> resources.getStringSafe(R.string.feedback_subject_tx_failed)
|
||||
is FeedbackEmailType.PreActivatedWallet -> {
|
||||
resources.getStringSafe(R.string.feedback_subject_pre_activated_wallet)
|
||||
}
|
||||
is FeedbackEmailType.CurrencyDescriptionError -> {
|
||||
resources.getStringSafe(R.string.feedback_token_description_error)
|
||||
}
|
||||
FeedbackEmailType.CardAttestationFailed -> "Card attestation failed"
|
||||
}
|
||||
.let(resources::getStringSafe)
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ markdownComposeView = "0.5.4"
|
|||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-900"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-420"
|
||||
tangemCardSdk = "develop-421"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
tangemVico = "2.0.0-alpha.25-tangem17"
|
||||
#tangemVico = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue