Updated on 2026-08-14

This commit is contained in:
Tangem 2023-04-18 12:44:38 +04:00
commit 53efbb730f
8 changed files with 107 additions and 0 deletions

View file

@ -31,6 +31,7 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.pins.CheckUserCodesCommand
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.operations.pins.SetUserCodeCommand
import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
import com.tangem.tap.domain.tasks.product.CreateProductWalletTask
@ -173,6 +174,14 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
)
}
suspend fun setAccessCodeRecoveryEnabled(cardId: String?, enabled: Boolean): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeRecoveryAllowedTask(enabled),
cardId,
initialMessage = Message(context.getString(R.string.initial_message_tap_header)),
)
}
suspend fun scanCard(
cardId: String? = null,
allowRequestAccessCodeFromRepository: Boolean = false,

View file

@ -29,6 +29,15 @@ sealed class DetailsAction : Action {
data class PrepareCardSettingsData(val card: CardDTO, val cardTypesResolver: CardTypesResolver) : DetailsAction()
object ResetCardSettingsData : DetailsAction()
sealed class AccessCodeRecovery : DetailsAction() {
object Open : AccessCodeRecovery()
data class SaveChanges(val enabled: Boolean) : AccessCodeRecovery() {
data class Success(val enabled: Boolean) : AccessCodeRecovery()
}
data class SelectOption(val enabled: Boolean) : AccessCodeRecovery()
}
sealed class ManageSecurity : DetailsAction() {
object OpenSecurity : ManageSecurity()
data class SelectOption(val option: SecurityOption) : ManageSecurity()

View file

@ -51,6 +51,7 @@ class DetailsMiddleware {
private val eraseWalletMiddleware = EraseWalletMiddleware()
private val manageSecurityMiddleware = ManageSecurityMiddleware()
private val managePrivacyMiddleware = ManagePrivacyMiddleware()
private val accessCodeRecoveryMiddleware = AccessCodeRecoveryMiddleware()
val detailsMiddleware: Middleware<AppState> = { _, stateProvider ->
{ next ->
{ action ->
@ -74,6 +75,7 @@ class DetailsMiddleware {
store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet))
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins))
}
is DetailsAction.AccessCodeRecovery -> accessCodeRecoveryMiddleware.handle(state, action)
DetailsAction.ScanCard -> {
scope.launch {
tangemSdkManager.scanProduct(
@ -418,4 +420,28 @@ class DetailsMiddleware {
)
}
}
class AccessCodeRecoveryMiddleware {
fun handle(state: DetailsState, action: DetailsAction.AccessCodeRecovery) {
when (action) {
is DetailsAction.AccessCodeRecovery.Open -> {
// store.dispatch(NavigationAction.NavigateTo(AppScreen.AccessCodeRecovery)) Todo: next PR
}
is DetailsAction.AccessCodeRecovery.SaveChanges -> {
scope.launch {
tangemSdkManager
.setAccessCodeRecoveryEnabled(state.cardSettingsState?.card?.cardId, action.enabled)
.doOnSuccess {
store.dispatchOnMain(NavigationAction.PopBackTo())
store.dispatchOnMain(
DetailsAction.AccessCodeRecovery.SaveChanges.Success(action.enabled),
)
}
}
}
is DetailsAction.AccessCodeRecovery.SelectOption -> Unit
is DetailsAction.AccessCodeRecovery.SaveChanges.Success -> Unit
}
}
}
}

View file

@ -40,6 +40,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
}
is DetailsAction.ChangeAppCurrency ->
detailsState.copy(appCurrency = action.fiatCurrency)
is DetailsAction.AccessCodeRecovery -> handleAccessCodeRecoveryAction(action, detailsState)
else -> detailsState
}
}
@ -68,6 +69,15 @@ private fun handlePrepareCardSettingsScreen(
manageSecurityState = prepareSecurityOptions(card, cardTypesResolver),
card = card,
resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypesResolver),
accessCodeRecovery = if (cardTypesResolver.isWallet2()) {
val enabled = card.userSettings?.isUserCodeRecoveryAllowed ?: false
AccessCodeRecoveryState(
enabledOnCard = enabled,
enabledSelection = enabled,
)
} else {
null
},
)
return state.copy(cardSettingsState = cardSettingsState)
}
@ -189,6 +199,34 @@ private fun handlePrivacyAction(action: DetailsAction.AppSettings, state: Detail
}
}
private fun handleAccessCodeRecoveryAction(
action: DetailsAction.AccessCodeRecovery,
state: DetailsState,
): DetailsState {
return when (action) {
DetailsAction.AccessCodeRecovery.Open -> {
val accessCodeRecovery = state.cardSettingsState?.accessCodeRecovery?.copy(
enabledSelection = state.cardSettingsState.accessCodeRecovery.enabledOnCard,
)
state.copy(cardSettingsState = state.cardSettingsState?.copy(accessCodeRecovery = accessCodeRecovery))
}
is DetailsAction.AccessCodeRecovery.SaveChanges -> state
is DetailsAction.AccessCodeRecovery.SelectOption -> {
val accessCodeRecovery = state.cardSettingsState?.accessCodeRecovery?.copy(
enabledSelection = action.enabled,
)
state.copy(cardSettingsState = state.cardSettingsState?.copy(accessCodeRecovery = accessCodeRecovery))
}
is DetailsAction.AccessCodeRecovery.SaveChanges.Success -> {
val accessCodeRecovery = state.cardSettingsState?.accessCodeRecovery?.copy(
enabledOnCard = action.enabled,
enabledSelection = action.enabled,
)
state.copy(cardSettingsState = state.cardSettingsState?.copy(accessCodeRecovery = accessCodeRecovery))
}
}
}
private fun prepareAllowedSecurityOptions(
cardTypesResolver: CardTypesResolver,
currentSecurityOption: SecurityOption?,

View file

@ -26,12 +26,22 @@ data class CardInfo(
val hasBackup: Boolean,
)
/**
* @property enabledOnCard whether access code recovery is enabled on card
* @property enabledSelection current selected option in app (not saved on card yet)
*/
data class AccessCodeRecoveryState(
val enabledOnCard: Boolean,
val enabledSelection: Boolean,
)
data class CardSettingsState(
val cardInfo: CardInfo,
val card: CardDTO,
val manageSecurityState: ManageSecurityState?,
val resetCardAllowed: Boolean,
val resetConfirmed: Boolean = false,
val accessCodeRecovery: AccessCodeRecoveryState? = null,
)
data class ManageSecurityState(

View file

@ -23,6 +23,7 @@ data class CardDTO(
val manufacturer: Manufacturer,
val issuer: Issuer,
val settings: Settings,
val userSettings: UserSettings?,
val linkedTerminalStatus: LinkedTerminalStatus,
val isAccessCodeSet: Boolean,
val isPasscodeSet: Boolean?,
@ -39,6 +40,7 @@ data class CardDTO(
manufacturer = Manufacturer(card.manufacturer),
issuer = Issuer(card.issuer),
settings = Settings(card.settings),
userSettings = UserSettings(card.userSettings),
linkedTerminalStatus = LinkedTerminalStatus.fromSdkStatus(card.linkedTerminalStatus),
isAccessCodeSet = card.isAccessCodeSet,
isPasscodeSet = card.isPasscodeSet,
@ -60,6 +62,7 @@ data class CardDTO(
if (manufacturer != other.manufacturer) return false
if (issuer != other.issuer) return false
if (settings != other.settings) return false
if (userSettings != other.userSettings) return false
if (linkedTerminalStatus != other.linkedTerminalStatus) return false
if (isAccessCodeSet != other.isAccessCodeSet) return false
if (isPasscodeSet != other.isPasscodeSet) return false
@ -78,6 +81,7 @@ data class CardDTO(
result = 31 * result + manufacturer.hashCode()
result = 31 * result + issuer.hashCode()
result = 31 * result + settings.hashCode()
result = 31 * result + userSettings.hashCode()
result = 31 * result + linkedTerminalStatus.hashCode()
result = 31 * result + isAccessCodeSet.hashCode()
result = 31 * result + (isPasscodeSet?.hashCode() ?: 0)
@ -114,6 +118,15 @@ data class CardDTO(
)
}
@JsonClass(generateAdapter = true)
data class UserSettings(
val isUserCodeRecoveryAllowed: Boolean,
) {
constructor(userSettings: com.tangem.common.card.UserSettings) : this(
userSettings.isUserCodeRecoveryAllowed,
)
}
@JsonClass(generateAdapter = true)
data class FirmwareVersion(
val major: Int,

View file

@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Token
interface CardTypesResolver {
fun isTangemNote(): Boolean
fun isTangemWallet(): Boolean
fun isWallet2(): Boolean
fun isSaltPay(): Boolean
fun isSaltPayVisa(): Boolean
fun isSaltPayWallet(): Boolean

View file

@ -24,6 +24,7 @@ class TangemCardTypesResolver(
card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable &&
!card.isSaltPay
override fun isWallet2(): Boolean = card.firmwareVersion >= FirmwareVersion.KeysImportAvailable
override fun isSaltPay(): Boolean = productType == ProductType.SaltPay
override fun isSaltPayVisa(): Boolean = card.isSaltPayVisa
override fun isSaltPayWallet(): Boolean = card.isSaltPayWallet