Updated on 2026-08-14
This commit is contained in:
parent
7bcadd9f4c
commit
e1480e005e
10 changed files with 154 additions and 116 deletions
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.domain.userWalletList.implementation
|
||||||
import com.tangem.common.*
|
import com.tangem.common.*
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||||
|
|
@ -56,8 +57,8 @@ internal class BiometricUserWalletsListManager(
|
||||||
override val walletsCount: Int
|
override val walletsCount: Int
|
||||||
get() = state.value.userWallets.size
|
get() = state.value.userWallets.size
|
||||||
|
|
||||||
override suspend fun unlock(throwIfNotAllWalletsUnlocked: Boolean): CompletionResult<UserWallet> {
|
override suspend fun unlock(type: UnlockType): CompletionResult<UserWallet> {
|
||||||
return unlockWithBiometryInternal()
|
return unlockAndSetSelectedUserWallet(type)
|
||||||
.mapFailure { error ->
|
.mapFailure { error ->
|
||||||
Timber.e(error, "Unable to unlock user wallets")
|
Timber.e(error, "Unable to unlock user wallets")
|
||||||
if (error is UserWalletsListError) {
|
if (error is UserWalletsListError) {
|
||||||
|
|
@ -66,16 +67,8 @@ internal class BiometricUserWalletsListManager(
|
||||||
UserWalletsListError.UnableToUnlockUserWallets(error)
|
UserWalletsListError.UnableToUnlockUserWallets(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map {
|
.map { selectedUserWallet ->
|
||||||
val userWallets = state.value.userWallets
|
if (selectedUserWallet == null || selectedUserWallet.isLocked) {
|
||||||
|
|
||||||
if (throwIfNotAllWalletsUnlocked && userWallets.any(UserWallet::isLocked)) {
|
|
||||||
Timber.e("Some user wallets remain locked")
|
|
||||||
throw UserWalletsListError.NotAllUserWalletsUnlocked
|
|
||||||
}
|
|
||||||
|
|
||||||
val selectedUserWallet = selectedUserWalletSync
|
|
||||||
if (selectedUserWallet == null) {
|
|
||||||
Timber.e("Unable to find selected user wallet")
|
Timber.e("Unable to find selected user wallet")
|
||||||
throw UserWalletsListError.NoUserWalletSelected
|
throw UserWalletsListError.NoUserWalletSelected
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -186,99 +179,116 @@ internal class BiometricUserWalletsListManager(
|
||||||
changeSelectedUserWallet: Boolean,
|
changeSelectedUserWallet: Boolean,
|
||||||
canOverridePublicInfo: Boolean,
|
canOverridePublicInfo: Boolean,
|
||||||
): CompletionResult<Unit> {
|
): CompletionResult<Unit> {
|
||||||
return saveEncryptionKeyIfNotNull(userWallet)
|
|
||||||
.flatMap { sensitiveInformationRepository.save(userWallet, encryptionKey = it) }
|
|
||||||
.flatMap { publicInformationRepository.save(userWallet, canOverridePublicInfo) }
|
|
||||||
.map {
|
|
||||||
if (changeSelectedUserWallet) {
|
|
||||||
selectedUserWalletRepository.set(userWallet.walletId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.flatMap { loadModels() }
|
|
||||||
.doOnSuccess {
|
|
||||||
state.update { prevState ->
|
|
||||||
prevState.copy(
|
|
||||||
selectedUserWalletId = if (changeSelectedUserWallet) {
|
|
||||||
userWallet.walletId
|
|
||||||
} else {
|
|
||||||
prevState.selectedUserWalletId
|
|
||||||
},
|
|
||||||
isLocked = prevState.userWallets.any { it.isLocked },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun unlockWithBiometryInternal(): CompletionResult<Unit> {
|
|
||||||
return keysRepository.getAll()
|
|
||||||
.map { keys ->
|
|
||||||
state.update { prevState ->
|
|
||||||
prevState.copy(
|
|
||||||
encryptionKeys = (keys + prevState.encryptionKeys).distinctBy { it.walletId },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.flatMap { loadModels() }
|
|
||||||
.map {
|
|
||||||
state.update { prevState ->
|
|
||||||
val hasLockedUserWallets = prevState.userWallets.any { it.isLocked }
|
|
||||||
prevState.copy(isLocked = hasLockedUserWallets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun saveEncryptionKeyIfNotNull(userWallet: UserWallet): CompletionResult<ByteArray?> {
|
|
||||||
val encryptionKey = userWallet.scanResponse.card.encryptionKey
|
val encryptionKey = userWallet.scanResponse.card.encryptionKey
|
||||||
?.let { UserWalletEncryptionKey(userWallet.walletId, it) }
|
?.let { UserWalletEncryptionKey(userWallet.walletId, it) }
|
||||||
|
?: return CompletionResult.Success(Unit) // No encryption key, no need to save
|
||||||
|
|
||||||
return if (encryptionKey != null) {
|
return keysRepository.save(encryptionKey)
|
||||||
keysRepository.save(encryptionKey)
|
.flatMap { sensitiveInformationRepository.save(userWallet, encryptionKey = encryptionKey.encryptionKey) }
|
||||||
.doOnSuccess {
|
.flatMap { publicInformationRepository.save(userWallet, canOverridePublicInfo) }
|
||||||
state.update { prevState ->
|
.flatMap {
|
||||||
prevState.copy(
|
loadUserWallets(
|
||||||
encryptionKeys = prevState.encryptionKeys
|
encryptionKeys = state.value.encryptionKeys
|
||||||
.plus(encryptionKey)
|
.plus(encryptionKey)
|
||||||
.distinctBy { it.walletId },
|
.distinctBy(UserWalletEncryptionKey::walletId),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.doOnSuccess { loadedState ->
|
||||||
|
if (changeSelectedUserWallet) {
|
||||||
|
selectedUserWalletRepository.set(userWallet.walletId)
|
||||||
|
|
||||||
|
state.value = loadedState.copy(
|
||||||
|
selectedUserWalletId = userWallet.walletId,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
state.value = loadedState
|
||||||
}
|
}
|
||||||
.map { encryptionKey.encryptionKey }
|
}
|
||||||
} else {
|
.map { /* Type erasing */ }
|
||||||
CompletionResult.Success(data = null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadModels(): CompletionResult<Unit> {
|
private suspend fun unlockAndSetSelectedUserWallet(type: UnlockType): CompletionResult<UserWallet?> {
|
||||||
return getSavedUserWallets()
|
return keysRepository.getAll()
|
||||||
.map { userWallets ->
|
.flatMap { encryptionKeys ->
|
||||||
if (userWallets.isNotEmpty()) {
|
loadUserWallets(
|
||||||
state.update { prevState ->
|
encryptionKeys = state.value.encryptionKeys
|
||||||
val wallets = (userWallets + prevState.userWallets).distinctBy { it.walletId }
|
.plus(encryptionKeys)
|
||||||
|
.distinctBy(UserWalletEncryptionKey::walletId),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.map { loadedState ->
|
||||||
|
when (type) {
|
||||||
|
UnlockType.ALL -> {
|
||||||
|
if (loadedState.isLocked) {
|
||||||
|
Timber.e("Some user wallets remain locked")
|
||||||
|
|
||||||
prevState.copy(
|
state.value = loadedState
|
||||||
userWallets = wallets,
|
|
||||||
selectedUserWalletId = findOrSetSelectedWalletId(prevState.selectedUserWalletId, wallets),
|
throw UserWalletsListError.NotAllUserWalletsUnlocked
|
||||||
|
} else {
|
||||||
|
val selectedWallet = findOrSetSelectedWallet(
|
||||||
|
state.value.selectedUserWalletId,
|
||||||
|
loadedState.userWallets,
|
||||||
|
)
|
||||||
|
|
||||||
|
state.value = loadedState.copy(
|
||||||
|
selectedUserWalletId = selectedWallet?.walletId,
|
||||||
|
)
|
||||||
|
|
||||||
|
selectedWallet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnlockType.ANY -> {
|
||||||
|
val selectedWallet = findOrSetSelectedWallet(
|
||||||
|
state.value.selectedUserWalletId,
|
||||||
|
loadedState.userWallets,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
state.value = loadedState.copy(
|
||||||
|
selectedUserWalletId = selectedWallet?.walletId,
|
||||||
|
)
|
||||||
|
|
||||||
|
selectedWallet
|
||||||
|
}
|
||||||
|
UnlockType.ALL_WITHOUT_SELECT -> {
|
||||||
|
state.value = loadedState
|
||||||
|
|
||||||
|
findSelectedUserWallet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSavedUserWallets(): CompletionResult<List<UserWallet>> {
|
private suspend fun loadUserWallets(encryptionKeys: List<UserWalletEncryptionKey>): CompletionResult<State> {
|
||||||
return publicInformationRepository.getAll()
|
return publicInformationRepository.getAll()
|
||||||
.map { it.toUserWallets() }
|
.map { it.toUserWallets() }
|
||||||
.flatMap { userWallets ->
|
.flatMap { userWallets ->
|
||||||
sensitiveInformationRepository.getAll(state.value.encryptionKeys)
|
sensitiveInformationRepository.getAll(encryptionKeys)
|
||||||
.map { walletIdToSensitiveInformation ->
|
.map { walletIdToSensitiveInformation ->
|
||||||
userWallets.updateWith(walletIdToSensitiveInformation)
|
userWallets.updateWith(walletIdToSensitiveInformation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.map { userWallets ->
|
||||||
|
val prevState = state.value
|
||||||
|
|
||||||
|
if (userWallets.isNotEmpty()) {
|
||||||
|
val newUserWallets = (userWallets + prevState.userWallets)
|
||||||
|
.distinctBy(UserWallet::walletId)
|
||||||
|
|
||||||
|
prevState.copy(
|
||||||
|
userWallets = newUserWallets,
|
||||||
|
isLocked = newUserWallets.any(UserWallet::isLocked),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
prevState
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findOrSetSelectedWalletId(
|
private fun findOrSetSelectedWallet(
|
||||||
prevSelectedWalletId: UserWalletId?,
|
prevSelectedWalletId: UserWalletId?,
|
||||||
userWallets: List<UserWallet>,
|
userWallets: List<UserWallet>,
|
||||||
): UserWalletId? {
|
): UserWallet? {
|
||||||
val selectedWalletId = prevSelectedWalletId ?: selectedUserWalletRepository.get()
|
val selectedWalletId = prevSelectedWalletId ?: selectedUserWalletRepository.get()
|
||||||
var possibleSelectedUserWallet = findSelectedUserWallet(userWallets, selectedWalletId)
|
var possibleSelectedUserWallet = findSelectedUserWallet(userWallets, selectedWalletId)
|
||||||
|
|
||||||
|
|
@ -290,7 +300,7 @@ internal class BiometricUserWalletsListManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return possibleSelectedUserWallet?.walletId
|
return possibleSelectedUserWallet
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeSelectedUserWalletIdIfNeeded(walletsIdsToRemove: List<UserWalletId>) {
|
private fun changeSelectedUserWalletIdIfNeeded(walletsIdsToRemove: List<UserWalletId>) {
|
||||||
|
|
|
||||||
|
|
@ -100,10 +100,10 @@ internal class GeneralUserWalletsListManager(
|
||||||
return implementation.value.get(userWalletId)
|
return implementation.value.get(userWalletId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun unlock(throwIfNotAllWalletsUnlocked: Boolean): CompletionResult<UserWallet> {
|
override suspend fun unlock(type: UserWalletsListManager.Lockable.UnlockType): CompletionResult<UserWallet> {
|
||||||
val implementation = implementation.value
|
val implementation = implementation.value
|
||||||
return if (implementation is UserWalletsListManager.Lockable) {
|
return if (implementation is UserWalletsListManager.Lockable) {
|
||||||
implementation.unlock()
|
implementation.unlock(type)
|
||||||
} else {
|
} else {
|
||||||
error("RuntimeUserWalletsListManager is not lockable")
|
error("RuntimeUserWalletsListManager is not lockable")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ internal class DelegatedKeystoreManager(
|
||||||
|
|
||||||
override suspend fun get(
|
override suspend fun get(
|
||||||
masterKeyConfig: KeystoreManager.MasterKeyConfig,
|
masterKeyConfig: KeystoreManager.MasterKeyConfig,
|
||||||
keyAliases: Collection<String>,
|
keyAliases: Set<String>,
|
||||||
): Map<String, SecretKey> {
|
): Map<String, SecretKey> {
|
||||||
return keystoreManagerProvider().get(masterKeyConfig, keyAliases)
|
return keystoreManagerProvider().get(masterKeyConfig, keyAliases)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,6 @@ internal class BiometricUserWalletsKeysRepository(
|
||||||
.doOnFailure { error ->
|
.doOnFailure { error ->
|
||||||
when (error) {
|
when (error) {
|
||||||
is TangemSdkError.KeystoreInvalidated -> {
|
is TangemSdkError.KeystoreInvalidated -> {
|
||||||
// If the biometric cryptography key was invalidated, then delete all encryption keys
|
|
||||||
getUserWalletsIds().forEach { userWalletId ->
|
getUserWalletsIds().forEach { userWalletId ->
|
||||||
deleteEncryptionKey(userWalletId)
|
deleteEncryptionKey(userWalletId)
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +119,7 @@ internal class BiometricUserWalletsKeysRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteEncryptionKey(userWalletId: UserWalletId) {
|
private fun deleteEncryptionKey(userWalletId: UserWalletId) {
|
||||||
return authenticatedStorage.delete(StorageKey.UserWalletEncryptionKey(userWalletId).name)
|
authenticatedStorage.delete(StorageKey.UserWalletEncryptionKey(userWalletId).name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getUserWalletsIds(): List<UserWalletId> {
|
private suspend fun getUserWalletsIds(): List<UserWalletId> {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import com.tangem.core.navigation.NavigationAction
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||||
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
||||||
import com.tangem.domain.wallets.legacy.unlockIfLockable
|
import com.tangem.domain.wallets.legacy.unlockIfLockable
|
||||||
import com.tangem.tap.*
|
import com.tangem.tap.*
|
||||||
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
|
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
|
||||||
|
|
@ -86,7 +87,7 @@ internal class WelcomeMiddleware {
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
)
|
)
|
||||||
|
|
||||||
userWalletsListManager.unlockIfLockable()
|
userWalletsListManager.unlockIfLockable(type = UnlockType.ANY)
|
||||||
.doOnFailure { error ->
|
.doOnFailure { error ->
|
||||||
Timber.e(error, "Unable to unlock user wallets with biometrics")
|
Timber.e(error, "Unable to unlock user wallets with biometrics")
|
||||||
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Error(error))
|
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Error(error))
|
||||||
|
|
|
||||||
|
|
@ -105,16 +105,42 @@ interface UserWalletsListManager {
|
||||||
/**
|
/**
|
||||||
* Receive saved [UserWallet]s, populate [userWallets] flow with it and set [isLocked] as false.
|
* Receive saved [UserWallet]s, populate [userWallets] flow with it and set [isLocked] as false.
|
||||||
*
|
*
|
||||||
* @param throwIfNotAllWalletsUnlocked Indicates that the function must throw
|
* @param type Defines the behavior of the operation.
|
||||||
* [UserWalletsListError.NotAllUserWalletsUnlocked] if not all user wallets are unlocked.
|
|
||||||
*
|
*
|
||||||
* @return [CompletionResult] of operation, with selected [UserWallet]
|
* @return [CompletionResult] of operation, with selected [UserWallet]
|
||||||
* or null if there is no selected [UserWallet]
|
* or null if there is no selected [UserWallet]
|
||||||
*/
|
*/
|
||||||
suspend fun unlock(throwIfNotAllWalletsUnlocked: Boolean = false): CompletionResult<UserWallet>
|
suspend fun unlock(type: UnlockType): CompletionResult<UserWallet>
|
||||||
|
|
||||||
/** Remove [UserWallet]s from [userWallets] and set [isLocked] as true */
|
/** Remove [UserWallet]s from [userWallets] and set [isLocked] as true */
|
||||||
fun lock()
|
fun lock()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the behavior of the [unlock] operation.
|
||||||
|
* */
|
||||||
|
enum class UnlockType {
|
||||||
|
/**
|
||||||
|
* Ensures that all stored [UserWallet]s are unlocked,
|
||||||
|
* or throws [UserWalletsListError.NotAllUserWalletsUnlocked].
|
||||||
|
*
|
||||||
|
* In this type [selectedUserWallet] is either a previously selected [UserWallet] or the first stored
|
||||||
|
* [UserWallet].
|
||||||
|
* */
|
||||||
|
ALL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that at least one stored [UserWallet] is unlocked,
|
||||||
|
* or throws [UserWalletsListError.NoUserWalletSelected].
|
||||||
|
*
|
||||||
|
* In this type [selectedUserWallet] is the first stored and unlocked [UserWallet].
|
||||||
|
* */
|
||||||
|
ANY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as [ALL] type, but this type can not change [selectedUserWallet] while unlocking.
|
||||||
|
* */
|
||||||
|
ALL_WITHOUT_SELECT,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For provider
|
// For provider
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.tangem.domain.wallets.legacy
|
package com.tangem.domain.wallets.legacy
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
|
@ -43,8 +44,8 @@ val UserWalletsListManager.isLockedSync: Boolean
|
||||||
*
|
*
|
||||||
* @see UserWalletsListManager.Lockable.unlock
|
* @see UserWalletsListManager.Lockable.unlock
|
||||||
* */
|
* */
|
||||||
suspend fun UserWalletsListManager.unlockIfLockable(): CompletionResult<UserWallet> {
|
suspend fun UserWalletsListManager.unlockIfLockable(type: UnlockType = UnlockType.ANY): CompletionResult<UserWallet> {
|
||||||
return asLockable()?.unlock() ?: CompletionResult.Failure(UserWalletsListError.UnableToUnlockUserWallets())
|
return asLockable()?.unlock(type) ?: CompletionResult.Failure(UserWalletsListError.UnableToUnlockUserWallets())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import arrow.core.raise.either
|
||||||
import arrow.core.raise.ensureNotNull
|
import arrow.core.raise.ensureNotNull
|
||||||
import com.tangem.common.doOnFailure
|
import com.tangem.common.doOnFailure
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||||
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
||||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||||
import com.tangem.domain.wallets.legacy.asLockable
|
import com.tangem.domain.wallets.legacy.asLockable
|
||||||
import com.tangem.domain.wallets.models.UnlockWalletsError
|
import com.tangem.domain.wallets.models.UnlockWalletsError
|
||||||
|
|
@ -18,27 +19,26 @@ import com.tangem.domain.wallets.models.UnlockWalletsError
|
||||||
*/
|
*/
|
||||||
class UnlockWalletsUseCase(private val walletsStateHolder: WalletsStateHolder) {
|
class UnlockWalletsUseCase(private val walletsStateHolder: WalletsStateHolder) {
|
||||||
|
|
||||||
suspend operator fun invoke(throwIfNotAllWalletsUnlocked: Boolean = false): Either<UnlockWalletsError, Unit> =
|
suspend operator fun invoke(type: UnlockType = UnlockType.ANY): Either<UnlockWalletsError, Unit> = either {
|
||||||
either {
|
val userWalletsListManager = ensureNotNull(
|
||||||
val userWalletsListManager = ensureNotNull(
|
value = walletsStateHolder.userWalletsListManager?.asLockable(),
|
||||||
value = walletsStateHolder.userWalletsListManager?.asLockable(),
|
raise = {
|
||||||
raise = {
|
UnlockWalletsError.DataError(
|
||||||
UnlockWalletsError.DataError(
|
cause = IllegalStateException("The lockable user wallets list manager could not be found"),
|
||||||
cause = IllegalStateException("The lockable user wallets list manager could not be found"),
|
)
|
||||||
)
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
|
|
||||||
userWalletsListManager.unlock(throwIfNotAllWalletsUnlocked)
|
userWalletsListManager.unlock(type)
|
||||||
.doOnFailure { error ->
|
.doOnFailure { error ->
|
||||||
val e = when (error) {
|
val e = when (error) {
|
||||||
is UserWalletsListError.NoUserWalletSelected -> UnlockWalletsError.NoUserWalletSelected
|
is UserWalletsListError.NoUserWalletSelected -> UnlockWalletsError.NoUserWalletSelected
|
||||||
is UserWalletsListError.NotAllUserWalletsUnlocked ->
|
is UserWalletsListError.NotAllUserWalletsUnlocked ->
|
||||||
UnlockWalletsError.NotAllUserWalletsUnlocked
|
UnlockWalletsError.NotAllUserWalletsUnlocked
|
||||||
else -> UnlockWalletsError.UnableToUnlockWallets
|
else -> UnlockWalletsError.UnableToUnlockWallets
|
||||||
}
|
|
||||||
|
|
||||||
raise(e)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
raise(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.settings.RemindToRateAppLaterUseCase
|
||||||
import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase
|
import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase
|
||||||
import com.tangem.domain.tokens.FetchTokenListUseCase
|
import com.tangem.domain.tokens.FetchTokenListUseCase
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
||||||
import com.tangem.domain.wallets.models.UnlockWalletsError
|
import com.tangem.domain.wallets.models.UnlockWalletsError
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
|
|
@ -135,7 +136,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
||||||
analyticsEventHandler.send(MainScreen.UnlockAllWithBiometrics)
|
analyticsEventHandler.send(MainScreen.UnlockAllWithBiometrics)
|
||||||
|
|
||||||
viewModelScope.launch(dispatchers.main) {
|
viewModelScope.launch(dispatchers.main) {
|
||||||
unlockWalletsUseCase(throwIfNotAllWalletsUnlocked = true)
|
unlockWalletsUseCase(type = UnlockType.ALL_WITHOUT_SELECT)
|
||||||
.onRight { stateHolder.update(CloseBottomSheetTransformer(stateHolder.getSelectedWalletId())) }
|
.onRight { stateHolder.update(CloseBottomSheetTransformer(stateHolder.getSelectedWalletId())) }
|
||||||
.onLeft(::handleUnlockWalletsError)
|
.onLeft(::handleUnlockWalletsError)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ web3j = "4.10.1"
|
||||||
# region Tangem
|
# region Tangem
|
||||||
tangemBlockchainSdk = "release-app_5.8-533"
|
tangemBlockchainSdk = "release-app_5.8-533"
|
||||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||||
tangemCardSdk = "release-app_5.8-335"
|
tangemCardSdk = "release-app_5.8-336"
|
||||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||||
# endregion Tangem
|
# endregion Tangem
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue