Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-30 19:33:43 +04:00
parent 6b05c5566e
commit f626613f80
118 changed files with 391 additions and 4505 deletions

View file

@ -3,22 +3,15 @@ package com.tangem.domain.wallets.delegate
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.raise.ensure
import com.tangem.common.CompletionResult
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.copy
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UpdateWalletError
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
class DefaultUserWalletsSyncDelegate(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
private val dispatchers: CoroutineDispatcherProvider,
) : UserWalletsSyncDelegate {
override suspend fun syncWallet(userWalletId: UserWalletId, name: String): Either<UpdateWalletError, UserWallet> {
@ -34,15 +27,6 @@ class DefaultUserWalletsSyncDelegate(
private suspend fun renameUserWallet(
userWalletId: UserWalletId,
name: String,
): Either<UpdateWalletError, UserWallet> = if (useNewRepository) {
renameUserWalletInNewRepository(userWalletId, name)
} else {
renameUserWalletInLegacyRepository(userWalletId, name)
}
private suspend fun renameUserWalletInNewRepository(
userWalletId: UserWalletId,
name: String,
): Either<UpdateWalletError, UserWallet> = either {
val userWallets = userWalletsListRepository.userWalletsSync()
val userWallet = userWallets.find { it.walletId == userWalletId }
@ -60,34 +44,7 @@ class DefaultUserWalletsSyncDelegate(
userWalletsListRepository.saveWithoutLock(updatedWallet, canOverride = true)
.map { updatedWallet }
.mapLeft { error -> UpdateWalletError.DataError(IllegalStateException("")) }
.mapLeft { error -> UpdateWalletError.DataError(IllegalStateException("$error")) }
.bind()
}
// TODO remove dispatchers whnen UserWalletsListManager will be main safe
private suspend fun renameUserWalletInLegacyRepository(
userWalletId: UserWalletId,
name: String,
): Either<UpdateWalletError, UserWallet> = withContext(dispatchers.io) {
either {
val existingNames = userWalletsListManager.userWalletsSync
ensure(existingNames.none { it.name == name && it.walletId != userWalletId }) {
UpdateWalletError.NameAlreadyExists
}
val previousName = existingNames.firstOrNull { it.walletId == userWalletId }?.name.orEmpty()
if (previousName == name) {
raise(UpdateWalletError.NameAlreadyExists)
}
when (
val result =
userWalletsListManager.update(userWalletId) { it.copy(name = name) }
) {
is CompletionResult.Failure -> raise(UpdateWalletError.DataError(result.error))
is CompletionResult.Success -> result.data
}
}
}
}

View file

@ -1,42 +0,0 @@
package com.tangem.domain.wallets.legacy
import com.tangem.common.core.TangemError
import com.tangem.domain.wallets.R
sealed class UserWalletsListError(code: Int) : TangemError(code) {
override val silent: Boolean
get() = (cause as? TangemError)?.silent == true
override val messageResId: Int? = null
object WalletAlreadySaved : UserWalletsListError(code = 60001) {
override var customMessage: String = "This wallet has already been saved, you can add another one"
override val messageResId: Int = R.string.user_wallet_list_error_wallet_already_saved
}
object AllKeysInvalidated : UserWalletsListError(code = 60002) {
override var customMessage: String = "Encryption key invalidated"
}
data class BiometricsAuthenticationLockout(val isPermanent: Boolean) : UserWalletsListError(code = 60003) {
override var customMessage: String = "Biometric authentication lockout, permanent: $isPermanent"
}
data class UnableToUnlockUserWallets(override val cause: Throwable? = null) : UserWalletsListError(code = 60004) {
override var customMessage: String = "An error has occurred, please scan your card to log in"
override val messageResId: Int = R.string.user_wallet_list_error_unable_to_unlock
}
object BiometricsAuthenticationDisabled : UserWalletsListError(code = 60005) {
override var customMessage: String = "Biometrics authentication disabled"
}
object NoUserWalletSelected : UserWalletsListError(code = 60006) {
override var customMessage: String = "No user wallet selected"
}
object NotAllUserWalletsUnlocked : UserWalletsListError(code = 60007) {
override var customMessage: String = "Not all user wallets was unlocked"
}
}

View file

@ -1,56 +0,0 @@
package com.tangem.domain.wallets.legacy
import com.tangem.common.CompletionResult
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
import com.tangem.domain.models.wallet.UserWallet
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
/**
* Indicates that the [UserWalletsListManager] is locked
*
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable] returns [Flow] which
* produces only one false value
*
* @see UserWalletsListManager.Lockable.isLocked
* */
val UserWalletsListManager.isLocked: Flow<Boolean>
get() = asLockable()?.lockedState ?: flowOf(false)
/**
* Indicates that the [UserWalletsListManager] is locked
*
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable] returns false
*
* @see UserWalletsListManager.Lockable.isLocked
* */
val UserWalletsListManager.isLockedSync: Boolean
get() = asLockable()?.isLocked == true
/**
* Call [UserWalletsListManager.Lockable.unlock] if [UserWalletsListManager] implements [UserWalletsListManager.Lockable]
*
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable]
* returns [CompletionResult.Failure] with [UserWalletsListError.UnableToUnlockUserWallets]
*
* If [UserWalletsListManager] implements [UserWalletsListManager.Lockable]
* returns [CompletionResult.Success] with selected [UserWallet]
*
* @see UserWalletsListManager.Lockable.unlock
* */
suspend fun UserWalletsListManager.unlockIfLockable(type: UnlockType = UnlockType.ANY): CompletionResult<UserWallet> {
return asLockable()?.unlock(type) ?: CompletionResult.Failure(UserWalletsListError.UnableToUnlockUserWallets())
}
/**
* Safe cast [UserWalletsListManager] to [UserWalletsListManager.Lockable]
*
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable] then returns null or
* [UserWalletsListManager.Lockable] otherwise
* */
fun UserWalletsListManager.asLockable(): UserWalletsListManager.Lockable? {
if (this.isLockable) {
return this as? UserWalletsListManager.Lockable
}
return null
}

View file

@ -1,12 +0,0 @@
package com.tangem.domain.wallets.models
sealed class UnlockWalletsError {
object UnableToUnlockWallets : UnlockWalletsError()
object NoUserWalletSelected : UnlockWalletsError()
object NotAllUserWalletsUnlocked : UnlockWalletsError()
data class DataError(val cause: Throwable) : UnlockWalletsError()
}

View file

@ -11,15 +11,6 @@ import kotlinx.coroutines.flow.Flow
@Suppress("TooManyFunctions")
interface WalletsRepository {
@Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method")
suspend fun shouldSaveUserWalletsSync(): Boolean
@Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method")
fun shouldSaveUserWallets(): Flow<Boolean>
@Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method")
suspend fun saveShouldSaveUserWallets(item: Boolean)
suspend fun useBiometricAuthentication(): Boolean
suspend fun setUseBiometricAuthentication(value: Boolean)

View file

@ -1,24 +1,19 @@
package com.tangem.domain.wallets.usecase
import arrow.core.Either
import arrow.core.raise.either
import com.tangem.common.doOnFailure
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.error.DeleteWalletError
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.legacy.UserWalletsListManager
/**
* Use case for deleting user wallet
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting list of user wallets
*
[REDACTED_AUTHOR]
*/
class DeleteWalletUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
) {
/**
@ -29,19 +24,8 @@ class DeleteWalletUseCase(
* @return [Either] with [com.tangem.domain.common.wallets.error.DeleteWalletError] or [Boolean] which indicates that there are still saved wallets.
* */
suspend operator fun invoke(userWalletId: UserWalletId): Either<DeleteWalletError, Boolean> {
if (useNewRepository) {
return userWalletsListRepository.delete(userWalletIds = listOf(userWalletId)).map {
userWalletsListRepository.selectedUserWallet.value != null
}
}
return either {
userWalletsListManager.delete(userWalletIds = listOf(userWalletId))
.doOnFailure {
raise(DeleteWalletError.UnableToDelete)
}
userWalletsListManager.hasUserWallets
return userWalletsListRepository.delete(userWalletIds = listOf(userWalletId)).map {
userWalletsListRepository.selectedUserWallet.value != null
}
}
}

View file

@ -1,19 +1,16 @@
package com.tangem.domain.wallets.usecase
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.requireUserWalletsSync
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.wallets.legacy.UserWalletsListManager
/**
* Use case for user wallet name generation
*/
class GenerateWalletNameUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
) {
private val CardDTO.isBackupNotAllowed: Boolean
@ -38,11 +35,7 @@ class GenerateWalletNameUseCase(
}
private fun getNamesSet(): Set<String> {
return if (useNewRepository) {
userWalletsListRepository.requireUserWalletsSync().map { it.name }.toSet()
} else {
userWalletsListManager.userWalletsSync.map { it.name }.toSet()
}
return userWalletsListRepository.requireUserWalletsSync().map { it.name }.toSet()
}
private fun suggestedWalletName(defaultName: String, existingNames: Set<String>): String {

View file

@ -2,34 +2,14 @@ package com.tangem.domain.wallets.usecase
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.asLockable
import com.tangem.domain.wallets.legacy.isLockedSync
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
class GetSavedWalletsCountUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
) {
operator fun invoke(): Flow<List<UserWallet>> {
if (useNewRepository) {
return userWalletsListRepository.userWallets.map { requireNotNull(it) }
}
return userWalletsListManager.savedWalletsCount
.filter { count ->
if (count == 0) return@filter true
userWalletsListManager.asLockable() ?: return@filter false
return@filter userWalletsListManager.isLockedSync.not()
}
.map {
userWalletsListManager.userWalletsSync
}
.distinctUntilChanged()
return userWalletsListRepository.userWallets.map { requireNotNull(it) }
}
}

View file

@ -2,39 +2,26 @@ package com.tangem.domain.wallets.usecase
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.raise.ensureNotNull
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.GetUserWalletError
/**
* Use case for getting selected wallet.
* Important! If all wallets is locked, use case returns a error.
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting list of user wallets
*
[REDACTED_AUTHOR]
*/
class GetSelectedWalletSyncUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean = false,
) {
@Deprecated("You should provide the selected wallet via routing parameters due to the scalability of the features")
operator fun invoke(): Either<GetUserWalletError, UserWallet> {
if (useNewRepository) {
return either {
userWalletsListRepository.selectedUserWallet.value ?: raise(GetUserWalletError.UserWalletNotFound)
}
}
return either {
ensureNotNull(
value = userWalletsListManager.selectedUserWalletSync,
raise = { GetUserWalletError.UserWalletNotFound },
)
userWalletsListRepository.selectedUserWallet.value ?: raise(GetUserWalletError.UserWalletNotFound)
}
}
}

View file

@ -4,7 +4,6 @@ import arrow.core.Either
import arrow.core.raise.either
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.GetUserWalletError
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
@ -12,36 +11,26 @@ import kotlinx.coroutines.flow.filterNotNull
/**
* Use case for getting flow of selected wallet.
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting list of user wallets
*
[REDACTED_AUTHOR]
*/
@Deprecated("You should provide the selected wallet via routing parameters due to the scalability of the features")
class GetSelectedWalletUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean = false,
) {
@Deprecated("You should provide the selected wallet via routing parameters due to the scalability of the features")
operator fun invoke(): Either<GetUserWalletError, Flow<UserWallet>> {
return either {
if (useNewRepository) {
userWalletsListRepository.selectedUserWallet.filterNotNull()
} else {
userWalletsListManager.selectedUserWallet
}
userWalletsListRepository.selectedUserWallet.filterNotNull()
}
}
@Deprecated("You should provide the selected wallet via routing parameters due to the scalability of the features")
fun sync(): Either<GetUserWalletError, UserWallet?> {
return either {
if (useNewRepository) {
userWalletsListRepository.selectedUserWallet.value
} else {
userWalletsListManager.selectedUserWalletSync
}
userWalletsListRepository.selectedUserWallet.value
}
}
}

View file

@ -10,24 +10,17 @@ import com.tangem.domain.common.wallets.requireUserWalletsSync
import com.tangem.domain.core.utils.EitherFlow
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.GetUserWalletError
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.transformLatest
class GetUserWalletUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewListRepository: Boolean,
) {
operator fun invoke(userWalletId: UserWalletId): Either<GetUserWalletError, UserWallet> = either {
val userWallets = if (useNewListRepository) {
userWalletsListRepository.requireUserWalletsSync()
} else {
userWalletsListManager.userWalletsSync
}
val userWallets = userWalletsListRepository.requireUserWalletsSync()
ensureNotNull(userWallets.firstOrNull { it.walletId == userWalletId }) {
raise(GetUserWalletError.UserWalletNotFound)
@ -36,11 +29,7 @@ class GetUserWalletUseCase(
@OptIn(ExperimentalCoroutinesApi::class)
fun invokeFlow(userWalletId: UserWalletId): EitherFlow<GetUserWalletError, UserWallet> {
val flow = if (useNewListRepository) {
userWalletsListRepository.userWallets.map { requireNotNull(it) }
} else {
userWalletsListManager.userWallets
}
val flow = userWalletsListRepository.userWallets.map { requireNotNull(it) }
return flow.transformLatest { userWallets ->
userWallets.firstOrNull { it.walletId == userWalletId }

View file

@ -2,22 +2,15 @@ package com.tangem.domain.wallets.usecase
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.requireUserWalletsSync
import com.tangem.domain.wallets.legacy.UserWalletsListManager
/**
* Use case for getting list of user wallets names.
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting list of user wallets
*/
class GetWalletNamesUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
) {
operator fun invoke(): List<String> = if (useNewRepository) {
userWalletsListRepository.requireUserWalletsSync().map { it.name }
} else {
userWalletsListManager.userWalletsSync.map { it.name }
}
operator fun invoke(): List<String> = userWalletsListRepository.requireUserWalletsSync().map { it.name }
}

View file

@ -2,7 +2,6 @@ package com.tangem.domain.wallets.usecase
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
@ -11,24 +10,17 @@ import kotlinx.coroutines.withContext
* * This use case filters out wallets that have already had push notifications automatically enabled
* from the complete list of user wallets, returning only those wallets that still need to have
* push notifications automatically enabled.
* @property userWalletsListManager Manager for user wallets list operations
* @property userWalletsListRepository Repository for user wallets list operations
* @property dispatchers Coroutine dispatcher provider for background operations
*/
class GetWalletsForAutomaticallyPushEnablingUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val shouldUseNewListRepository: Boolean,
private val dispatchers: CoroutineDispatcherProvider,
) {
suspend operator fun invoke(walletsListWherePushWasEnabled: List<UserWalletId>): List<UserWalletId> =
withContext(dispatchers.default) {
val allLocalWallets = if (shouldUseNewListRepository) {
userWalletsListRepository.userWalletsSync().map { it.walletId }
} else {
userWalletsListManager.userWalletsSync.map { it.walletId }
}
val allLocalWallets = userWalletsListRepository.userWalletsSync().map { it.walletId }
allLocalWallets - walletsListWherePushWasEnabled.toSet()
}
}

View file

@ -2,34 +2,23 @@ package com.tangem.domain.wallets.usecase
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/**
* Use case for getting list of user wallets
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting list of user wallets
*
[REDACTED_AUTHOR]
*/
class GetWalletsUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewListRepository: Boolean,
) {
@Throws(IllegalArgumentException::class)
operator fun invoke(): Flow<List<UserWallet>> = if (useNewListRepository) {
userWalletsListRepository.userWallets.map { requireNotNull(it) }
} else {
userWalletsListManager.userWallets
}
operator fun invoke(): Flow<List<UserWallet>> = userWalletsListRepository.userWallets.map { requireNotNull(it) }
@Throws(IllegalArgumentException::class)
fun invokeSync(): List<UserWallet> = if (useNewListRepository) {
userWalletsListRepository.userWallets.value!!
} else {
userWalletsListManager.userWalletsSync
}
fun invokeSync(): List<UserWallet> = userWalletsListRepository.userWallets.value!!
}

View file

@ -4,27 +4,20 @@ import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/**
* Use case that checks if wallet need backup cards
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting user wallets
*/
class IsNeedToBackupUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
) {
operator fun invoke(id: UserWalletId): Flow<Boolean> {
val userWalletsFlow = if (useNewRepository) {
userWalletsListRepository.userWallets
} else {
userWalletsListManager.userWallets
}
val userWalletsFlow = userWalletsListRepository.userWallets
return userWalletsFlow
.map { wallets ->

View file

@ -5,28 +5,16 @@ import arrow.core.raise.either
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.error.SaveWalletError
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.legacy.UserWalletsListManager
class IsWalletAlreadySavedUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
) {
suspend operator fun invoke(
userWallet: UserWallet,
canOverride: Boolean = false,
): Either<SaveWalletError, Boolean> {
return if (useNewRepository) {
either {
userWalletsListRepository.userWalletsSync()
.any { it.walletId == userWallet.walletId }
}
} else {
either {
userWalletsListManager.userWalletsSync
.any { it.walletId == userWallet.walletId }
}
}
): Either<SaveWalletError, Boolean> = either {
userWalletsListRepository.userWalletsSync()
.any { it.walletId == userWallet.walletId }
}
}

View file

@ -1,78 +1,52 @@
package com.tangem.domain.wallets.usecase
import arrow.core.Either
import arrow.core.left
import arrow.core.raise.either
import arrow.core.right
import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.error.SaveWalletError
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.legacy.UserWalletsListError
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.repository.WalletsRepository
/**
* Use case for saving user wallet
*
* @property userWalletsListManager user wallets list manager
*
[REDACTED_AUTHOR]
*/
class SaveWalletUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val walletsRepository: WalletsRepository,
private val useNewRepository: Boolean,
) {
suspend operator fun invoke(userWallet: UserWallet, canOverride: Boolean = false): Either<SaveWalletError, Unit> {
return if (useNewRepository) {
either {
val newUserWallet =
userWalletsListRepository.userWalletsSync().none { it.walletId == userWallet.walletId }
val userWallet = userWalletsListRepository.saveWithoutLock(userWallet, canOverride).bind()
return either {
val newUserWallet =
userWalletsListRepository.userWalletsSync().none { it.walletId == userWallet.walletId }
val userWallet = userWalletsListRepository.saveWithoutLock(userWallet, canOverride).bind()
if (newUserWallet) {
when (userWallet) {
is UserWallet.Cold -> {
if (walletsRepository.useBiometricAuthentication()) {
userWalletsListRepository.setLock(
userWallet.walletId,
UserWalletsListRepository.LockMethod.Biometric,
)
} else {
Unit.right()
}
}
is UserWallet.Hot -> {
if (newUserWallet) {
when (userWallet) {
is UserWallet.Cold -> {
if (walletsRepository.useBiometricAuthentication()) {
userWalletsListRepository.setLock(
userWallet.walletId,
UserWalletsListRepository.LockMethod.NoLock,
UserWalletsListRepository.LockMethod.Biometric,
)
} else {
Unit.right()
}
}.mapLeft {
SaveWalletError.DataError(null)
}.map {
userWalletsListRepository.select(userWallet.walletId)
}.bind()
}
}
} else {
either {
userWalletsListManager.save(userWallet, canOverride)
.doOnSuccess { return Unit.right() }
.doOnFailure {
return when (it) {
is UserWalletsListError.WalletAlreadySaved -> SaveWalletError.WalletAlreadySaved(
it.messageResId,
)
else -> SaveWalletError.DataError(it.messageResId)
}.left()
}
return Unit.right()
is UserWallet.Hot -> {
userWalletsListRepository.setLock(
userWallet.walletId,
UserWalletsListRepository.LockMethod.NoLock,
)
}
}.mapLeft {
SaveWalletError.DataError(null)
}.map {
userWalletsListRepository.select(userWallet.walletId)
}.bind()
}
}
}

View file

@ -1,47 +1,29 @@
package com.tangem.domain.wallets.usecase
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.right
import com.tangem.common.CompletionResult
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.error.SelectWalletError
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.wallets.legacy.UserWalletsListManager
/**
* Use case for selecting wallet
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting list of user wallets
* @property reduxStateHolder redux state holder
*
[REDACTED_AUTHOR]
*/
class SelectWalletUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
private val reduxStateHolder: ReduxStateHolder,
) {
suspend operator fun invoke(userWalletId: UserWalletId): Either<SelectWalletError, UserWallet> {
if (useNewRepository) {
return userWalletsListRepository.select(userWalletId).map {
reduxStateHolder.onUserWalletSelected(it)
it
}
}
return either {
return when (val result = userWalletsListManager.select(userWalletId)) {
is CompletionResult.Failure -> raise(SelectWalletError.UnableToSelectUserWallet)
is CompletionResult.Success -> {
reduxStateHolder.onUserWalletSelected(result.data)
result.data.right()
}
}
return userWalletsListRepository.select(userWalletId).map {
reduxStateHolder.onUserWalletSelected(it)
it
}
}
}

View file

@ -1,9 +0,0 @@
package com.tangem.domain.wallets.usecase
import com.tangem.domain.wallets.repository.WalletsRepository
@Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method")
class ShouldSaveUserWalletsSyncUseCase(private val walletsRepository: WalletsRepository) {
suspend operator fun invoke(): Boolean = walletsRepository.shouldSaveUserWalletsSync()
}

View file

@ -1,9 +0,0 @@
package com.tangem.domain.wallets.usecase
import com.tangem.domain.wallets.repository.WalletsRepository
import kotlinx.coroutines.flow.Flow
class ShouldSaveUserWalletsUseCase(private val walletsRepository: WalletsRepository) {
operator fun invoke(): Flow<Boolean> = walletsRepository.shouldSaveUserWallets()
}

View file

@ -1,45 +0,0 @@
package com.tangem.domain.wallets.usecase
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.raise.ensureNotNull
import com.tangem.common.doOnFailure
import com.tangem.domain.wallets.legacy.UserWalletsListError
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
import com.tangem.domain.wallets.legacy.asLockable
import com.tangem.domain.wallets.models.UnlockWalletsError
/**
* Unlock wallets use case
*
* @property userWalletsListManager user wallets list manager
*
[REDACTED_AUTHOR]
*/
@Deprecated("Use NonBiometricUnlockWalletUseCase after migrating to new wallets repository")
class UnlockWalletsUseCase(private val userWalletsListManager: UserWalletsListManager) {
suspend operator fun invoke(type: UnlockType = UnlockType.ANY): Either<UnlockWalletsError, Unit> = either {
val userWalletsListManager = ensureNotNull(
value = userWalletsListManager.asLockable(),
raise = {
UnlockWalletsError.DataError(
cause = IllegalStateException("The lockable user wallets list manager could not be found"),
)
},
)
userWalletsListManager.unlock(type)
.doOnFailure { error ->
val e = when (error) {
is UserWalletsListError.NoUserWalletSelected -> UnlockWalletsError.NoUserWalletSelected
is UserWalletsListError.NotAllUserWalletsUnlocked ->
UnlockWalletsError.NotAllUserWalletsUnlocked
else -> UnlockWalletsError.UnableToUnlockWallets
}
raise(e)
}
}
}

View file

@ -1,55 +1,41 @@
package com.tangem.domain.wallets.usecase
import arrow.core.Either
import arrow.core.raise.either
import com.tangem.common.CompletionResult
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.error.SaveWalletError
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UpdateWalletError
import com.tangem.domain.wallets.models.UpdateWalletError.DataError
/**
* Use case for updating user wallet
*
* @property userWalletsListManager user wallets list manager
* @property userWalletsListRepository repository for getting list of user wallets
*
[REDACTED_AUTHOR]
*/
class UpdateWalletUseCase(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val useNewRepository: Boolean,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
update: suspend (UserWallet) -> UserWallet,
): Either<UpdateWalletError, UserWallet> {
if (useNewRepository) {
val userWallet = userWalletsListRepository.userWallets.value?.find { it.walletId == userWalletId }
?: return Either.Left(
DataError(IllegalStateException("User wallet with id $userWalletId not found")),
)
val updatedWallet = update(userWallet)
return userWalletsListRepository.saveWithoutLock(updatedWallet, canOverride = true)
.mapLeft {
when (it) {
is SaveWalletError.DataError -> DataError(
IllegalStateException("Failed to update wallet: ${it.messageId}"),
)
is SaveWalletError.WalletAlreadySaved -> UpdateWalletError.NameAlreadyExists
}
val userWallet = userWalletsListRepository.userWallets.value?.find { it.walletId == userWalletId }
?: return Either.Left(
DataError(IllegalStateException("User wallet with id $userWalletId not found")),
)
val updatedWallet = update(userWallet)
return userWalletsListRepository.saveWithoutLock(updatedWallet, canOverride = true)
.mapLeft {
when (it) {
is SaveWalletError.DataError -> DataError(
IllegalStateException("Failed to update wallet: ${it.messageId}"),
)
is SaveWalletError.WalletAlreadySaved -> UpdateWalletError.NameAlreadyExists
}
}
return either {
when (val result = userWalletsListManager.update(userWalletId, update)) {
is CompletionResult.Failure -> raise(DataError(result.error))
is CompletionResult.Success -> result.data
}
}
}
}

View file

@ -1,141 +0,0 @@
package com.tangem.domain.wallets.usecase
import com.google.common.truth.Truth.assertThat
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.asLockable
import com.tangem.domain.wallets.legacy.isLockedSync
import com.tangem.domain.models.wallet.UserWallet
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
class GetSavedWalletsCountUseCaseTest {
private lateinit var useCase: GetSavedWalletsCountUseCase
private lateinit var userWalletsListManager: UserWalletsListManager
@Before
fun setup() {
userWalletsListManager = mockk()
useCase = GetSavedWalletsCountUseCase(
userWalletsListManager,
userWalletsListRepository = mockk(),
useNewRepository = false,
)
mockkStatic("com.tangem.domain.wallets.legacy.UserWalletsListManagerExtensionsKt")
}
@Test
fun `GIVEN manager is not lockable WHEN invoke THEN return empty list`() = runTest {
// GIVEN
every { userWalletsListManager.isLockable } returns false
every { userWalletsListManager.savedWalletsCount } returns flowOf(0)
every { userWalletsListManager.userWallets } returns flowOf(emptyList())
every { userWalletsListManager.userWalletsSync } returns emptyList()
every { userWalletsListManager.isLockedSync } returns false
every { userWalletsListManager.asLockable() } returns null
// WHEN
val result = useCase().firstOrNull()
// THEN
assertThat(result).isEmpty()
}
@Test
fun `GIVEN manager is locked WHEN invoke THEN return empty list`() = runTest {
// GIVEN
val mockLockable = mockk<UserWalletsListManager.Lockable>()
every { userWalletsListManager.isLockable } returns true
every { userWalletsListManager.savedWalletsCount } returns flowOf(0)
every { userWalletsListManager.userWallets } returns flowOf(emptyList())
every { userWalletsListManager.userWalletsSync } returns emptyList()
every { userWalletsListManager.isLockedSync } returns true
every { userWalletsListManager.asLockable() } returns mockLockable
// WHEN
val result = useCase().firstOrNull()
// THEN
assertThat(result).isEmpty()
}
@Test
fun `GIVEN manager is not locked and has wallets WHEN invoke THEN return wallets list`() = runTest {
// GIVEN
val mockLockable = mockk<UserWalletsListManager.Lockable>()
val wallets = listOf(mockk<UserWallet>(), mockk<UserWallet>())
every { userWalletsListManager.isLockable } returns true
every { userWalletsListManager.savedWalletsCount } returns flowOf(wallets.size)
every { userWalletsListManager.userWallets } returns flowOf(wallets)
every { userWalletsListManager.userWalletsSync } returns wallets
every { userWalletsListManager.isLockedSync } returns false
every { userWalletsListManager.asLockable() } returns mockLockable
// WHEN
val result = useCase().firstOrNull()
// THEN
assertThat(result).isEqualTo(wallets)
}
@Test
fun `GIVEN manager is not lockable and savedWalletsCount is zero WHEN invoke THEN return empty list`() = runTest {
// GIVEN
every { userWalletsListManager.isLockable } returns false
every { userWalletsListManager.savedWalletsCount } returns flowOf(0)
every { userWalletsListManager.userWallets } returns flowOf(emptyList())
every { userWalletsListManager.userWalletsSync } returns emptyList()
every { userWalletsListManager.isLockedSync } returns false
every { userWalletsListManager.asLockable() } returns null
// WHEN
val result = useCase().firstOrNull()
// THEN
assertThat(result).isEmpty()
}
@Test
fun `GIVEN manager is lockable and locked and savedWalletsCount is zero WHEN invoke THEN return empty list`() =
runTest {
// GIVEN
val mockLockable = mockk<UserWalletsListManager.Lockable>()
every { userWalletsListManager.isLockable } returns true
every { userWalletsListManager.savedWalletsCount } returns flowOf(0)
every { userWalletsListManager.userWallets } returns flowOf(emptyList())
every { userWalletsListManager.userWalletsSync } returns emptyList()
every { userWalletsListManager.isLockedSync } returns true
every { userWalletsListManager.asLockable() } returns mockLockable
// WHEN
val result = useCase().firstOrNull()
// THEN
assertThat(result).isEmpty()
}
@Test
fun `GIVEN manager is lockable and unlocked and savedWalletsCount is zero WHEN invoke THEN return empty list`() =
runTest {
// GIVEN
val mockLockable = mockk<UserWalletsListManager.Lockable>()
every { userWalletsListManager.isLockable } returns true
every { userWalletsListManager.savedWalletsCount } returns flowOf(0)
every { userWalletsListManager.userWallets } returns flowOf(emptyList())
every { userWalletsListManager.userWalletsSync } returns emptyList()
every { userWalletsListManager.isLockedSync } returns false
every { userWalletsListManager.asLockable() } returns mockLockable
// WHEN
val result = useCase().firstOrNull()
// THEN
assertThat(result).isEmpty()
}
}