Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-03 18:00:38 +08:00
parent b538cc76e1
commit dbb8ab5d50
11 changed files with 133 additions and 53 deletions

View file

@ -3,14 +3,14 @@ package com.tangem.tap.domain.card
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.right
import com.tangem.common.CompletionResult
import com.tangem.common.UserCodeType
import com.tangem.common.*
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.core.UserCodeRequestPolicy
import com.tangem.common.doOnResult
import com.tangem.domain.card.ResetCardUseCase
import com.tangem.domain.card.models.ResetCardError
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.tap.domain.sdk.TangemSdkManager
internal class DefaultResetCardUseCase(
@ -18,25 +18,37 @@ internal class DefaultResetCardUseCase(
) : ResetCardUseCase {
override suspend fun invoke(card: CardDTO): Either<ResetCardError, Unit> = either {
enterRequiredAccessCode(card) {
tangemSdkManager.resetToFactorySettings(
cardId = card.cardId,
allowsRequestAccessCodeFromRepository = true,
)
.doOnSuccess { Unit.right() }
.doOnFailure { raise(it.mapToDomainError()) }
}
}
override suspend fun invoke(
cardNumber: Int,
card: CardDTO,
userWalletId: UserWalletId,
): Either<ResetCardError, Unit> = either {
enterRequiredAccessCode(card) {
tangemSdkManager.resetBackupCard(cardNumber, userWalletId)
.doOnSuccess { Unit.right() }
.doOnFailure { raise(it.mapToDomainError()) }
}
}
private suspend fun enterRequiredAccessCode(
card: CardDTO,
task: suspend TangemSdkManager.() -> CompletionResult<*>,
) {
val policyBeforeReset = tangemSdkManager.userCodeRequestPolicy
requestMandatoryAccessCodeEntry(card)
val result = tangemSdkManager.resetToFactorySettings(
cardId = card.cardId,
allowsRequestAccessCodeFromRepository = true,
)
tangemSdkManager.task()
.doOnResult { tangemSdkManager.setUserCodeRequestPolicy(policyBeforeReset) }
when (result) {
is CompletionResult.Success -> Unit.right()
is CompletionResult.Failure -> {
if (result.error is TangemSdkError.UserCancelled) {
raise(ResetCardError.UserCanceled)
} else {
raise(ResetCardError.AnotherSdkError)
}
}
}
}
private fun requestMandatoryAccessCodeEntry(card: CardDTO) {
@ -52,4 +64,8 @@ internal class DefaultResetCardUseCase(
tangemSdkManager.setUserCodeRequestPolicy(policy = UserCodeRequestPolicy.Always(type))
}
}
private fun TangemError.mapToDomainError(): ResetCardError {
return if (this is TangemSdkError.UserCancelled) ResetCardError.UserCanceled else ResetCardError.AnotherSdkError
}
}

View file

@ -68,7 +68,7 @@ interface TangemSdkManager {
allowsRequestAccessCodeFromRepository: Boolean,
): CompletionResult<CardDTO>
suspend fun resetBackupCard(userWalletId: UserWalletId): CompletionResult<Unit>
suspend fun resetBackupCard(cardNumber: Int, userWalletId: UserWalletId): CompletionResult<Unit>
suspend fun saveAccessCode(accessCode: String, cardsIds: Set<String>): CompletionResult<Unit>

View file

@ -170,10 +170,15 @@ class DefaultTangemSdkManager(
.map { CardDTO(it) }
}
override suspend fun resetBackupCard(userWalletId: UserWalletId): CompletionResult<Unit> {
override suspend fun resetBackupCard(cardNumber: Int, userWalletId: UserWalletId): CompletionResult<Unit> {
return runTaskAsyncReturnOnMain(
runnable = ResetBackupCardTask(userWalletId),
initialMessage = Message(resources.getString(R.string.card_settings_reset_card_to_factory)),
initialMessage = Message(
resources.getString(
R.string.initial_message_reset_backup_card_header,
cardNumber.toString(),
),
),
)
}

View file

@ -87,7 +87,7 @@ class MockTangemSdkManager(
return MockProvider.getCardDto()
}
override suspend fun resetBackupCard(userWalletId: UserWalletId): CompletionResult<Unit> {
override suspend fun resetBackupCard(cardNumber: Int, userWalletId: UserWalletId): CompletionResult<Unit> {
return CompletionResult.Success(Unit)
}

View file

@ -2,12 +2,13 @@ package com.tangem.tap.features.details.ui.resetcard
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import arrow.core.raise.either
import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
import com.tangem.domain.card.ResetCardUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
import com.tangem.tap.common.extensions.onUserWalletSelected
import com.tangem.tap.features.details.redux.CardSettingsState
import com.tangem.tap.features.details.redux.DetailsAction.ResetToFactory
@ -15,7 +16,9 @@ import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.details.ui.resetcard.featuretoggles.ResetCardFeatureToggles
import com.tangem.tap.features.details.ui.utils.toResetCardDescriptionText
import com.tangem.tap.store
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
import com.tangem.tap.features.details.redux.CardSettingsState.Dialog as CardSettingsDialog
@ -29,6 +32,13 @@ internal class ResetCardViewModel @Inject constructor(
private val deleteWalletUseCase: DeleteWalletUseCase,
) : ViewModel() {
private val currentUserWallet = getSelectedWalletSyncUseCase().getOrNull()
?: error("Selected user wallet can't be null")
// TODO: move logic to separate domain entity
private val backupCardsCount = (currentUserWallet.getCardsCount() ?: 0) - 1
private var resetCardsCount = 0
fun updateState(state: CardSettingsState?): ResetCardScreenState.ResetCardScreenContent {
val descriptionText = state?.cardInfo
?.toResetCardDescriptionText()
@ -94,14 +104,19 @@ internal class ResetCardViewModel @Inject constructor(
}
private fun makeFullReset() {
val currentUserWallet = getSelectedWalletSyncUseCase().getOrNull() ?: return
viewModelScope.launch {
resetCurrentCard(userWallet = currentUserWallet).onRight {
resetCardUseCase(card = currentUserWallet.scanResponse.card).onRight {
deleteSavedAccessCodesUseCase(currentUserWallet.cardId)
deleteWalletUseCase(currentUserWallet.walletId)
val newSelectedWallet = getSelectedWalletSyncUseCase().getOrNull()
if (newSelectedWallet != null) {
store.onUserWalletSelected(newSelectedWallet)
}
delay(DELAY_SDK_DIALOG_CLOSE)
checkRemainingBackupCards()
}
}
}
@ -109,7 +124,21 @@ internal class ResetCardViewModel @Inject constructor(
private fun onContinueResetClick() {
dismissDialog()
// TODO: [REDACTED_TASK_KEY]
viewModelScope.launch {
resetCardUseCase(
cardNumber = resetCardsCount + 1,
card = currentUserWallet.scanResponse.card,
userWalletId = currentUserWallet.walletId,
)
.onRight {
resetCardsCount++
delay(DELAY_SDK_DIALOG_CLOSE)
checkRemainingBackupCards()
}
.onLeft { showDialog(CardSettingsDialog.InterruptedResetDialog) }
}
}
private fun onContinueResetDialogDismiss() {
@ -118,16 +147,28 @@ internal class ResetCardViewModel @Inject constructor(
showDialog(CardSettingsDialog.InterruptedResetDialog)
}
private suspend fun resetCurrentCard(userWallet: UserWallet) = either {
resetCardUseCase(userWallet.scanResponse.card).bind()
deleteSavedAccessCodesUseCase(userWallet.cardId).bind()
deleteWalletUseCase(userWallet.walletId).bind()
private fun checkRemainingBackupCards() {
when {
backupCardsCount > resetCardsCount -> showDialog(CardSettingsDialog.ContinueResetDialog)
backupCardsCount == resetCardsCount -> showDialog(CardSettingsDialog.CompletedResetDialog)
else -> finishFullReset()
}
}
private fun dismissAndFinishFullReset() {
dismissDialog()
// TODO: [REDACTED_TASK_KEY]
finishFullReset()
}
private fun finishFullReset() {
val newSelectedWallet = getSelectedWalletSyncUseCase().getOrNull()
if (newSelectedWallet != null) {
store.dispatch(NavigationAction.PopBackTo(AppScreen.Wallet))
} else {
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
}
}
private fun showDialog(dialog: CardSettingsDialog) {