Updated on 2026-08-14
This commit is contained in:
parent
8ba59403f4
commit
18d4a01642
7 changed files with 159 additions and 0 deletions
|
|
@ -398,4 +398,12 @@ internal object WalletsDomainModule {
|
||||||
fun provideSyncWalletWithRemoteUseCase(walletsRepository: WalletsRepository): SyncWalletWithRemoteUseCase {
|
fun provideSyncWalletWithRemoteUseCase(walletsRepository: WalletsRepository): SyncWalletWithRemoteUseCase {
|
||||||
return SyncWalletWithRemoteUseCase(walletsRepository = walletsRepository)
|
return SyncWalletWithRemoteUseCase(walletsRepository = walletsRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideApplyUserWalletListSortingUseCase(
|
||||||
|
userWalletsListRepository: UserWalletsListRepository,
|
||||||
|
): ApplyUserWalletListSortingUseCase {
|
||||||
|
return ApplyUserWalletListSortingUseCase(userWalletsListRepository = userWalletsListRepository)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||||
|
import com.tangem.domain.common.wallets.UserWalletTransformAction
|
||||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||||
import com.tangem.domain.common.wallets.UserWalletsListRepository.LockMethod
|
import com.tangem.domain.common.wallets.UserWalletsListRepository.LockMethod
|
||||||
import com.tangem.domain.common.wallets.error.*
|
import com.tangem.domain.common.wallets.error.*
|
||||||
|
|
@ -31,6 +32,8 @@ import com.tangem.sdk.api.TangemSdkManager
|
||||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||||
import com.tangem.tap.domain.userWalletList.utils.encryptionKey
|
import com.tangem.tap.domain.userWalletList.utils.encryptionKey
|
||||||
import com.tangem.tap.domain.userWalletList.utils.lock
|
import com.tangem.tap.domain.userWalletList.utils.lock
|
||||||
|
import com.tangem.tap.domain.userWalletList.utils.publicInformation
|
||||||
|
import com.tangem.tap.domain.userWalletList.utils.sensitiveInformation
|
||||||
import com.tangem.tap.domain.userWalletList.utils.toUserWallets
|
import com.tangem.tap.domain.userWalletList.utils.toUserWallets
|
||||||
import com.tangem.tap.domain.userWalletList.utils.updateWith
|
import com.tangem.tap.domain.userWalletList.utils.updateWith
|
||||||
import com.tangem.utils.Provider
|
import com.tangem.utils.Provider
|
||||||
|
|
@ -38,10 +41,12 @@ import com.tangem.utils.ProviderSuspend
|
||||||
import com.tangem.utils.coroutines.runSuspendCatching
|
import com.tangem.utils.coroutines.runSuspendCatching
|
||||||
import com.tangem.utils.extensions.addOrReplace
|
import com.tangem.utils.extensions.addOrReplace
|
||||||
import com.tangem.utils.extensions.indexOfFirstOrNull
|
import com.tangem.utils.extensions.indexOfFirstOrNull
|
||||||
|
import kotlinx.coroutines.NonCancellable
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@Suppress("LongParameterList", "LargeClass")
|
@Suppress("LongParameterList", "LargeClass")
|
||||||
internal class DefaultUserWalletsListRepository(
|
internal class DefaultUserWalletsListRepository(
|
||||||
|
|
@ -384,6 +389,44 @@ internal class DefaultUserWalletsListRepository(
|
||||||
return userWallets.any { it.walletId !in unsecuredWalletIds }
|
return userWallets.any { it.walletId !in unsecuredWalletIds }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun transform(action: UserWalletTransformAction) {
|
||||||
|
val wallets = userWalletsSync()
|
||||||
|
val walletsMap = wallets.associateBy { it.walletId }
|
||||||
|
val transformedWallets = action.transform(wallets)
|
||||||
|
val transformedWalletsMap = transformedWallets.associateBy { it.walletId }
|
||||||
|
|
||||||
|
require(walletsMap.keys == transformedWalletsMap.keys) {
|
||||||
|
"The transformation action must not change the set of wallet IDs." +
|
||||||
|
"Original IDs: ${walletsMap.keys}, Transformed IDs: ${transformedWalletsMap.keys}"
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWallets { transformedWallets }
|
||||||
|
|
||||||
|
withContext(NonCancellable) {
|
||||||
|
if (savePersistentInformation()) {
|
||||||
|
publicInformationRepository.transform {
|
||||||
|
transformedWallets.map { wallet -> wallet.publicInformation }
|
||||||
|
}
|
||||||
|
|
||||||
|
val changedSensitiveInfoWallets = wallets.filter { wallet ->
|
||||||
|
val transformedWallet = transformedWalletsMap[wallet.walletId]
|
||||||
|
transformedWallet != null && transformedWallet.sensitiveInformation != wallet.sensitiveInformation
|
||||||
|
}
|
||||||
|
|
||||||
|
changedSensitiveInfoWallets.forEach { wallet ->
|
||||||
|
if (wallet.isLocked.not()) {
|
||||||
|
sensitiveInformationRepository.save(wallet, wallet.encryptionKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpgradeAndDeleteHotWalletIfNeeded(
|
||||||
|
newUserWallet = wallet,
|
||||||
|
oldUserWallet = walletsMap[wallet.walletId] ?: error("This should never happen"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun checkForUpgradeAndDeleteHotWalletIfNeeded(
|
private suspend fun checkForUpgradeAndDeleteHotWalletIfNeeded(
|
||||||
newUserWallet: UserWallet,
|
newUserWallet: UserWallet,
|
||||||
oldUserWallet: UserWallet,
|
oldUserWallet: UserWallet,
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,8 @@ internal interface UserWalletsPublicInformationRepository {
|
||||||
|
|
||||||
suspend fun delete(walletIds: List<UserWalletId>): CompletionResult<Unit>
|
suspend fun delete(walletIds: List<UserWalletId>): CompletionResult<Unit>
|
||||||
suspend fun clear(): CompletionResult<Unit>
|
suspend fun clear(): CompletionResult<Unit>
|
||||||
|
|
||||||
|
suspend fun transform(
|
||||||
|
block: (List<UserWalletPublicInformation>?) -> List<UserWalletPublicInformation>?,
|
||||||
|
): CompletionResult<Unit>
|
||||||
}
|
}
|
||||||
|
|
@ -77,6 +77,21 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun transform(
|
||||||
|
block: (List<UserWalletPublicInformation>?) -> List<UserWalletPublicInformation>?,
|
||||||
|
): CompletionResult<Unit> {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
getAll().flatMap { currentInfo ->
|
||||||
|
val transformed = block(currentInfo)
|
||||||
|
if (transformed != null) {
|
||||||
|
save(transformed)
|
||||||
|
} else {
|
||||||
|
CompletionResult.Success(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmName("saveWithPublicInformation")
|
@JvmName("saveWithPublicInformation")
|
||||||
private suspend fun save(publicInformation: List<UserWalletPublicInformation>): CompletionResult<Unit> = catching {
|
private suspend fun save(publicInformation: List<UserWalletPublicInformation>): CompletionResult<Unit> = catching {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.tangem.domain.common.wallets
|
||||||
|
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sealed class representing actions that can transform the user wallets list.
|
||||||
|
*/
|
||||||
|
sealed class UserWalletTransformAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The transformation block to apply to the current wallets list.
|
||||||
|
*/
|
||||||
|
abstract fun transform(list: List<UserWallet>): List<UserWallet>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorders user wallets
|
||||||
|
*
|
||||||
|
* @param action The transformation block that takes the current list of user wallets
|
||||||
|
* and returns a list of user wallet IDs in the desired order.
|
||||||
|
*/
|
||||||
|
data class Reorder(
|
||||||
|
private val action: (List<UserWallet>) -> List<UserWalletId>,
|
||||||
|
) : UserWalletTransformAction() {
|
||||||
|
|
||||||
|
override fun transform(list: List<UserWallet>): List<UserWallet> {
|
||||||
|
val walletById = list.associateBy { it.walletId }
|
||||||
|
val newOrderIds = action(list)
|
||||||
|
require(walletById.keys == newOrderIds.toSet()) {
|
||||||
|
"Reorder action must return the same set of wallet IDs as the input list"
|
||||||
|
}
|
||||||
|
return newOrderIds.mapNotNull { walletById[it] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -123,6 +123,14 @@ interface UserWalletsListRepository {
|
||||||
*/
|
*/
|
||||||
suspend fun clearPersistentData()
|
suspend fun clearPersistentData()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms user wallets list according to the provided action.
|
||||||
|
*
|
||||||
|
* @param action The transformation action to apply.
|
||||||
|
* @throws IllegalArgumentException if the transformation action is invalid (e.g. reordering with missing or extra wallet IDs).
|
||||||
|
*/
|
||||||
|
suspend fun transform(action: UserWalletTransformAction)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if there are any secured wallets (wallets that are not locked with [LockMethod.NoLock]).
|
* Checks if there are any secured wallets (wallets that are not locked with [LockMethod.NoLock]).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.tangem.domain.wallets.usecase
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import arrow.core.raise.catch
|
||||||
|
import arrow.core.raise.either
|
||||||
|
import arrow.core.raise.ensure
|
||||||
|
import com.tangem.domain.common.wallets.UserWalletTransformAction
|
||||||
|
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use case to apply a specific sorting order to a list of user wallets.
|
||||||
|
*
|
||||||
|
* @property userWalletsListRepository Repository for managing user wallets list.
|
||||||
|
*/
|
||||||
|
class ApplyUserWalletListSortingUseCase(
|
||||||
|
private val userWalletsListRepository: UserWalletsListRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the sorting order of the provided list of user wallet IDs.
|
||||||
|
*
|
||||||
|
* @param userWalletIds List of [UserWalletId] representing the desired order.
|
||||||
|
* @return Either an [Error] or Unit on successful completion.
|
||||||
|
*/
|
||||||
|
suspend operator fun invoke(userWalletIds: List<UserWalletId>): Either<Error, Unit> = either {
|
||||||
|
ensure(userWalletIds.size > 1) { Error.UnableToSortSingleWallet }
|
||||||
|
catch(
|
||||||
|
block = {
|
||||||
|
userWalletsListRepository.transform(UserWalletTransformAction.Reorder { userWalletIds })
|
||||||
|
},
|
||||||
|
catch = { raise(Error.ReorderError) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sealed interface representing possible errors that can occur during the application
|
||||||
|
* of user wallet list sorting.
|
||||||
|
*/
|
||||||
|
sealed interface Error {
|
||||||
|
|
||||||
|
data object UnableToSortSingleWallet : Error
|
||||||
|
|
||||||
|
data object ReorderError : Error
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue