Updated on 2026-08-14
This commit is contained in:
commit
392576ba90
14 changed files with 237 additions and 56 deletions
|
|
@ -8,6 +8,8 @@ import com.tangem.common.routing.AppRouter
|
|||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.decompose.di.GlobalUiMessageSender
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.settings.SettingsManager
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
|
|
@ -134,4 +136,7 @@ interface ApplicationEntryPoint {
|
|||
fun getSettingsManager(): SettingsManager
|
||||
|
||||
fun getBlockchainExceptionHandler(): BlockchainExceptionHandler
|
||||
|
||||
@GlobalUiMessageSender
|
||||
fun getUiMessageSender(): UiMessageSender
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import com.tangem.core.analytics.models.Basic
|
|||
import com.tangem.core.analytics.models.Basic.TransactionSent.WalletForm
|
||||
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.settings.SettingsManager
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.datasource.api.common.MoshiConverter
|
||||
|
|
@ -210,6 +211,10 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
|
||||
private val blockchainExceptionHandler: BlockchainExceptionHandler
|
||||
get() = entryPoint.getBlockchainExceptionHandler()
|
||||
|
||||
private val uiMessageSender: UiMessageSender
|
||||
get() = entryPoint.getUiMessageSender()
|
||||
|
||||
// endregion
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
@ -308,6 +313,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
appPreferencesStore = appPreferencesStore,
|
||||
clipboardManager = clipboardManager,
|
||||
settingsManager = settingsManager,
|
||||
uiMessageSender = uiMessageSender,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ 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.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.core.ui.message.dialog.Dialogs
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
|
||||
|
|
@ -28,7 +28,6 @@ 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
|
||||
|
|
@ -168,36 +167,25 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
crossinline onCancel: () -> Unit,
|
||||
) {
|
||||
if (error is TangemSdkError.CardVerificationFailed) {
|
||||
analyticsEventHandler.send(event = Onboarding.OfflineAttestationFailed)
|
||||
analyticsEventHandler.send(event = OnboardingAnalyticsEvent.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()
|
||||
message = Dialogs.cardVerificationFailed(
|
||||
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
|
||||
onRequestSupport = {
|
||||
mainScope.launch {
|
||||
onCancel()
|
||||
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
|
||||
type = FeedbackEmailType.CardAttestationFailed,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
secondActionBuilder = {
|
||||
cancelAction {
|
||||
mainScope.launch { onCancel() }
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
|
||||
type = FeedbackEmailType.CardAttestationFailed,
|
||||
)
|
||||
}
|
||||
},
|
||||
onCancelClick = { onCancel() },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.domain.common.TwinsHelper
|
||||
import com.tangem.operations.attestation.AttestationTask
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.operations.wallet.CreateWalletTask
|
||||
import com.tangem.operations.wallet.PurgeWalletCommand
|
||||
|
|
@ -13,7 +15,7 @@ class CreateFirstTwinWalletTask(private val firstCardId: String) : CardSessionRu
|
|||
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
|
||||
override fun run(session: CardSession, callback: CompletionCallback<CreateWalletResponse>) {
|
||||
val card = session.environment.card
|
||||
val publicKey = card?.wallets?.firstOrNull()?.publicKey
|
||||
if (publicKey != null) {
|
||||
|
|
@ -29,13 +31,40 @@ class CreateFirstTwinWalletTask(private val firstCardId: String) : CardSessionRu
|
|||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
session.environment.card = session.environment.card?.setWallets(emptyList())
|
||||
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { callback(it) }
|
||||
createWallet(session, callback)
|
||||
}
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(response.error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { callback(it) }
|
||||
createWallet(session, callback)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWallet(session: CardSession, callback: CompletionCallback<CreateWalletResponse>) {
|
||||
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { createWalletResponse ->
|
||||
when (createWalletResponse) {
|
||||
is CompletionResult.Success -> {
|
||||
runAttestation(session) { attestationResponse ->
|
||||
when (attestationResponse) {
|
||||
is CompletionResult.Success -> callback(createWalletResponse)
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(attestationResponse.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(createWalletResponse.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun runAttestation(session: CardSession, callback: CompletionCallback<*>) {
|
||||
val mode = session.environment.config.attestationMode
|
||||
val secureStorage = session.environment.secureStorage
|
||||
val attestationTask = AttestationTask(mode, secureStorage)
|
||||
|
||||
attestationTask.run(session, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,13 @@ import com.tangem.common.KeyPair
|
|||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.domain.common.TwinsHelper
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.operations.wallet.CreateWalletTask
|
||||
import com.tangem.operations.wallet.PurgeWalletCommand
|
||||
import com.tangem.tap.domain.twins.CreateFirstTwinWalletTask.Companion.runAttestation
|
||||
|
||||
class CreateSecondTwinWalletTask(
|
||||
private val firstPublicKey: String,
|
||||
|
|
@ -59,12 +61,10 @@ class CreateSecondTwinWalletTask(
|
|||
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
session.environment.card = session.environment.card?.updateWallet(result.data.wallet)
|
||||
|
||||
WriteProtectedIssuerDataTask(firstPublicKey.hexToBytes(), issuerKeys).run(session) { writeResult ->
|
||||
when (writeResult) {
|
||||
is CompletionResult.Success -> callback(result)
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(writeResult.error))
|
||||
runAttestation(session) { attestationResponse ->
|
||||
when (attestationResponse) {
|
||||
is CompletionResult.Success -> writeProtectedIssuerData(session, result, callback)
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(attestationResponse.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,4 +72,19 @@ class CreateSecondTwinWalletTask(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeProtectedIssuerData(
|
||||
session: CardSession,
|
||||
result: CompletionResult.Success<CreateWalletResponse>,
|
||||
callback: CompletionCallback<CreateWalletResponse>,
|
||||
) {
|
||||
session.environment.card = session.environment.card?.updateWallet(result.data.wallet)
|
||||
|
||||
WriteProtectedIssuerDataTask(firstPublicKey.hexToBytes(), issuerKeys).run(session) { writeResult ->
|
||||
when (writeResult) {
|
||||
is CompletionResult.Success -> callback(result)
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(writeResult.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.domain.twins
|
||||
|
||||
import com.tangem.Message
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.KeyPair
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
|
|
@ -57,7 +56,7 @@ class TwinCardsManager(card: CardDTO) {
|
|||
return response
|
||||
}
|
||||
|
||||
suspend fun complete(message: Message): Result<ScanResponse> {
|
||||
suspend fun complete(message: Message): CompletionResult<ScanResponse> {
|
||||
val response = tangemSdkManager.finalizeTwin(
|
||||
secondCardPublicKey = secondCardPublicKey!!.hexToBytes(),
|
||||
issuerKeyPair = getIssuerKeys(),
|
||||
|
|
@ -65,10 +64,7 @@ class TwinCardsManager(card: CardDTO) {
|
|||
initialMessage = message,
|
||||
)
|
||||
|
||||
return when (response) {
|
||||
is CompletionResult.Success -> Result.Success(response.data)
|
||||
is CompletionResult.Failure -> Result.fromTangemSdkError(response.error)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
private suspend fun getIssuerKeys(): KeyPair {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,25 @@
|
|||
package com.tangem.tap.features.onboarding.products.twins.redux
|
||||
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
|
||||
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.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
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.domain.wallets.legacy.asLockable
|
||||
import com.tangem.sdk.extensions.localizedDescriptionRes
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.entities.ProgressState
|
||||
import com.tangem.tap.common.extensions.*
|
||||
|
|
@ -185,8 +193,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateSecondWallet))
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
}
|
||||
is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -208,8 +215,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateThirdWallet))
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
}
|
||||
is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -218,7 +224,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
|
||||
scope.launch {
|
||||
when (val result = manager.complete(action.message)) {
|
||||
is Result.Success -> {
|
||||
is CompletionResult.Success -> {
|
||||
Analytics.send(Onboarding.Twins.SetupFinished())
|
||||
updateScanResponse(result.data)
|
||||
|
||||
|
|
@ -234,8 +240,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
}
|
||||
}
|
||||
}
|
||||
is Result.Failure -> {
|
||||
}
|
||||
is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -349,6 +354,29 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun showCardVerificationFailedDialog(error: TangemError) {
|
||||
if (error is TangemSdkError.CardVerificationFailed) {
|
||||
Analytics.send(event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed)
|
||||
|
||||
val resource = error.localizedDescriptionRes()
|
||||
val resId = resource.resId ?: R.string.common_unknown_error
|
||||
val resArgs = resource.args.map { it.value }
|
||||
|
||||
store.inject(DaggerGraphState::uiMessageSender).send(
|
||||
message = Dialogs.cardVerificationFailed(
|
||||
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
|
||||
onRequestSupport = {
|
||||
mainScope.launch {
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
|
||||
type = FeedbackEmailType.CardAttestationFailed,
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPopBackScreen(): KClass<out AppRoute> {
|
||||
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,14 @@ import com.tangem.common.routing.AppRoute
|
|||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
|
||||
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.withIOContext
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_IDS
|
||||
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_PREFIX
|
||||
|
|
@ -30,6 +35,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.BackupValidator
|
|||
import com.tangem.operations.attestation.OnlineCardVerifier
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.sdk.extensions.localizedDescriptionRes
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
|
|
@ -469,6 +475,25 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
val crashlytics = FirebaseCrashlytics.getInstance()
|
||||
|
||||
when (val error = result.error) {
|
||||
is TangemSdkError.CardVerificationFailed -> {
|
||||
Analytics.send(event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed)
|
||||
|
||||
val resource = error.localizedDescriptionRes()
|
||||
val resId = resource.resId ?: com.tangem.core.ui.R.string.common_unknown_error
|
||||
val resArgs = resource.args.map { it.value }
|
||||
|
||||
store.inject(DaggerGraphState::uiMessageSender).send(
|
||||
message = Dialogs.cardVerificationFailed(
|
||||
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
|
||||
onRequestSupport = {
|
||||
mainScope.launch {
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase)
|
||||
.invoke(type = FeedbackEmailType.CardAttestationFailed)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
is TangemSdkError.BackupFailedNotEmptyWallets -> {
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.ShowDialog(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.blockchainsdk.BlockchainSDKFactory
|
|||
import com.tangem.blockchainsdk.signer.TransactionSignerFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.settings.SettingsManager
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
|
|
@ -79,4 +80,5 @@ data class DaggerGraphState(
|
|||
val appPreferencesStore: AppPreferencesStore? = null,
|
||||
val clipboardManager: ClipboardManager? = null,
|
||||
val settingsManager: SettingsManager? = null,
|
||||
val uiMessageSender: UiMessageSender? = null,
|
||||
) : StateType
|
||||
|
|
@ -173,7 +173,7 @@ object NotificationsFactory {
|
|||
val spendingAmount = if (cryptoCurrency is CryptoCurrency.Token) {
|
||||
feeAmount
|
||||
} else {
|
||||
sendingAmount
|
||||
sendingAmount + feeAmount
|
||||
}
|
||||
val diff = balance.minus(spendingAmount)
|
||||
if (existentialDeposit != null && diff >= BigDecimal.ZERO && existentialDeposit > diff) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.core.analytics.models.event
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
sealed class OnboardingAnalyticsEvent(
|
||||
category: String,
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(category, event, params) {
|
||||
|
||||
sealed class Onboarding(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : OnboardingAnalyticsEvent(category = "Onboarding", event = event, params = params) {
|
||||
|
||||
data object OfflineAttestationFailed : Onboarding(event = "Offline Attestation Failed")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.core.ui.message.dialog
|
||||
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
object Dialogs {
|
||||
|
||||
/**
|
||||
* Card verification failed dialog
|
||||
*
|
||||
* @param errorDescription sdk error description
|
||||
* @param onRequestSupport lambda be invoked when request support action is clicked
|
||||
* @param onCancelClick lambda be invoked when cancel action is clicked
|
||||
*/
|
||||
fun cardVerificationFailed(
|
||||
errorDescription: TextReference,
|
||||
onRequestSupport: () -> Unit,
|
||||
onCancelClick: () -> Unit = {},
|
||||
): DialogMessage {
|
||||
return DialogMessage(
|
||||
message = errorDescription,
|
||||
title = resourceReference(id = R.string.security_alert_title),
|
||||
isDismissable = false,
|
||||
firstActionBuilder = {
|
||||
EventMessageAction(
|
||||
title = resourceReference(id = R.string.alert_button_request_support),
|
||||
onClick = onRequestSupport,
|
||||
)
|
||||
},
|
||||
secondActionBuilder = { cancelAction(onClick = onCancelClick) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,17 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
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.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.features.onboarding.v2.impl.R
|
||||
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
|
||||
|
|
@ -21,6 +27,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.resetB
|
|||
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state.MultiWalletBackupUM
|
||||
import com.tangem.sdk.api.BackupServiceHolder
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.sdk.extensions.localizedDescriptionRes
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -31,13 +38,16 @@ import javax.inject.Inject
|
|||
|
||||
@Stable
|
||||
@ComponentScoped
|
||||
@Suppress("LongParameterList")
|
||||
class MultiWalletBackupModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val backupServiceHolder: BackupServiceHolder,
|
||||
private val cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val analyticsHandler: AnalyticsEventHandler,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
) : Model() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
|
|
@ -65,10 +75,10 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
init {
|
||||
// for wallet 1 this event is sent in Wallet1ChooseOptionModel
|
||||
if (scanResponse.productType == ProductType.Wallet2 || scanResponse.productType == ProductType.Ring) {
|
||||
analyticsHandler.send(OnboardingEvent.Backup.ScreenOpened)
|
||||
analyticsEventHandler.send(OnboardingEvent.Backup.ScreenOpened)
|
||||
}
|
||||
|
||||
analyticsHandler.send(OnboardingEvent.Backup.Started)
|
||||
analyticsEventHandler.send(OnboardingEvent.Backup.Started)
|
||||
}
|
||||
|
||||
private fun getInitState(): MultiWalletBackupUM {
|
||||
|
|
@ -153,7 +163,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
|
||||
modelScope.launch { eventFlow.emit(MultiWalletBackupComponent.Event.Done) }
|
||||
|
||||
analyticsHandler.send(OnboardingEvent.Backup.Finished(cardsCount = state.value.numberOfBackupCards + 1))
|
||||
analyticsEventHandler.send(OnboardingEvent.Backup.Finished(cardsCount = state.value.numberOfBackupCards + 1))
|
||||
}
|
||||
|
||||
private fun showOnlyOneBackupWarningDialog() {
|
||||
|
|
@ -203,6 +213,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
when (val error = result.error) {
|
||||
is TangemSdkError.CardVerificationFailed -> showCardVerificationFailedDialog(error)
|
||||
is TangemSdkError.BackupFailedNotEmptyWallets -> {
|
||||
_uiState.update { st ->
|
||||
st.copy(
|
||||
|
|
@ -212,7 +223,7 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
_uiState.update { it.copy(dialog = null) }
|
||||
},
|
||||
onDismissClick = {
|
||||
analyticsHandler.send(OnboardingEvent.Backup.ResetCancelEvent)
|
||||
analyticsEventHandler.send(OnboardingEvent.Backup.ResetCancelEvent)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
@ -234,8 +245,27 @@ class MultiWalletBackupModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun showCardVerificationFailedDialog(error: TangemSdkError.CardVerificationFailed) {
|
||||
analyticsEventHandler.send(event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed)
|
||||
|
||||
val resource = error.localizedDescriptionRes()
|
||||
val resId = resource.resId ?: com.tangem.core.ui.R.string.common_unknown_error
|
||||
val resArgs = resource.args.map { it.value }
|
||||
|
||||
uiMessageSender.send(
|
||||
message = Dialogs.cardVerificationFailed(
|
||||
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
|
||||
onRequestSupport = {
|
||||
modelScope.launch {
|
||||
sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun resetBackupCard(cardId: String) {
|
||||
analyticsHandler.send(OnboardingEvent.Backup.ResetPerformEvent)
|
||||
analyticsEventHandler.send(OnboardingEvent.Backup.ResetPerformEvent)
|
||||
|
||||
modelScope.launch {
|
||||
tangemSdkManager.resetToFactorySettings(
|
||||
|
|
|
|||
|
|
@ -88,9 +88,9 @@ markdownComposeView = "0.5.4"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "release-app_5.20-908"
|
||||
tangemBlockchainSdk = "release-app_5.20-909"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "release-app_5.20-422"
|
||||
tangemCardSdk = "release-app_5.20-423"
|
||||
#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