Updated on 2026-08-14
This commit is contained in:
commit
7c629b68d1
1179 changed files with 24718 additions and 16703 deletions
|
|
@ -9,7 +9,7 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
class UserWalletBuilder @AssistedInject constructor(
|
||||
class ColdUserWalletBuilder @AssistedInject constructor(
|
||||
@Assisted private val scanResponse: ScanResponse,
|
||||
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
||||
) {
|
||||
|
|
@ -36,12 +36,12 @@ class UserWalletBuilder @AssistedInject constructor(
|
|||
this.hasBackupError = hasBackupError
|
||||
}
|
||||
|
||||
fun build(): UserWallet? {
|
||||
fun build(): UserWallet.Cold? {
|
||||
return with(scanResponse) {
|
||||
UserWalletIdBuilder.scanResponse(scanResponse)
|
||||
.build()
|
||||
?.let {
|
||||
UserWallet(
|
||||
UserWallet.Cold(
|
||||
walletId = it,
|
||||
name = generateWalletNameUseCase(
|
||||
productType = productType,
|
||||
|
|
@ -60,6 +60,6 @@ class UserWalletBuilder @AssistedInject constructor(
|
|||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(scanResponse: ScanResponse): UserWalletBuilder
|
||||
fun create(scanResponse: ScanResponse): ColdUserWalletBuilder
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
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.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
import com.tangem.domain.wallets.models.copy
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DefaultUserWalletsSyncDelegate(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : UserWalletsSyncDelegate {
|
||||
|
||||
override suspend fun syncWallet(userWalletId: UserWalletId, name: String): Either<UpdateWalletError, UserWallet> {
|
||||
return renameUserWallet(userWalletId, name)
|
||||
}
|
||||
|
||||
override suspend fun syncWallets(list: List<UserWalletRemoteInfo>): Either<UpdateWalletError, Unit> = either {
|
||||
list.forEach { userWallet ->
|
||||
renameUserWallet(userWallet.walletId, userWallet.name).bind()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO remove dispatchers whnen UserWalletsListManager will be main safe
|
||||
private suspend fun renameUserWallet(
|
||||
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)
|
||||
}
|
||||
|
||||
return@withContext when (
|
||||
val result =
|
||||
userWalletsListManager.update(userWalletId) { it.copy(name = name) }
|
||||
) {
|
||||
is CompletionResult.Failure -> raise(UpdateWalletError.DataError(result.error))
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.domain.wallets.delegate
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
|
||||
interface UserWalletsSyncDelegate {
|
||||
|
||||
suspend fun syncWallet(userWalletId: UserWalletId, name: String): Either<UpdateWalletError, UserWallet>
|
||||
|
||||
suspend fun syncWallets(list: List<UserWalletRemoteInfo>): Either<UpdateWalletError, Unit>
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
package com.tangem.domain.wallets.repository
|
||||
|
||||
import com.tangem.domain.wallets.models.SeedPhraseNotificationsStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
interface WalletsRepository {
|
||||
|
||||
suspend fun shouldSaveUserWalletsSync(): Boolean
|
||||
|
|
@ -38,9 +41,21 @@ interface WalletsRepository {
|
|||
|
||||
suspend fun disableNFT(userWalletId: UserWalletId)
|
||||
|
||||
@Throws
|
||||
suspend fun isNotificationsEnabled(userWalletId: UserWalletId, force: Boolean): Boolean
|
||||
fun notificationsEnabledStatus(userWalletId: UserWalletId): Flow<Boolean>
|
||||
|
||||
suspend fun isNotificationsEnabled(userWalletId: UserWalletId): Boolean
|
||||
|
||||
suspend fun setNotificationsEnabled(userWalletId: UserWalletId, isEnabled: Boolean)
|
||||
|
||||
@Throws
|
||||
suspend fun setNotificationsEnabled(userWalletId: UserWalletId, isEnabled: Boolean)
|
||||
suspend fun setWalletName(walletId: String, walletName: String)
|
||||
|
||||
@Throws
|
||||
suspend fun getWalletInfo(walletId: String): UserWalletRemoteInfo
|
||||
|
||||
@Throws
|
||||
suspend fun getWalletsInfo(applicationId: String, updateCache: Boolean = true): List<UserWalletRemoteInfo>
|
||||
|
||||
@Throws
|
||||
suspend fun associateWallets(applicationId: String, wallets: List<UserWallet>)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
||||
class AssociateWalletsWithApplicationIdUseCase(
|
||||
private val walletsRepository: WalletsRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(applicationId: ApplicationId, wallets: List<UserWallet>): Either<Throwable, Unit> =
|
||||
Either.catch {
|
||||
walletsRepository.associateWallets(applicationId.value, wallets)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ package com.tangem.domain.wallets.usecase
|
|||
|
||||
import arrow.core.raise.catch
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,9 @@ class GetIsNotificationsEnabledUseCase(
|
|||
private val walletsRepository: WalletsRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, force: Boolean): Either<Throwable, Boolean> = Either.catch {
|
||||
suspend operator fun invoke(userWalletId: UserWalletId): Either<Throwable, Boolean> = Either.catch {
|
||||
walletsRepository.isNotificationsEnabled(
|
||||
userWalletId = userWalletId,
|
||||
force = force,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
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.wallets.models.UserWallet
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
||||
class GetSavedWalletChangesUseCase(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
) {
|
||||
|
||||
operator fun invoke(): Flow<List<UserWallet>> {
|
||||
return userWalletsListManager.userWallets
|
||||
.filter {
|
||||
userWalletsListManager.asLockable() ?: return@filter false
|
||||
return@filter if (userWalletsListManager.isLockedSync.not()) {
|
||||
it.isNotEmpty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class GetWalletNotificationsEnabledUseCase(
|
||||
private val walletsRepository: WalletsRepository,
|
||||
) {
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId): Flow<Boolean> = walletsRepository
|
||||
.notificationsEnabledStatus(userWalletId)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.domain.wallets.usecase
|
|||
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
|
@ -20,7 +21,7 @@ class IsNeedToBackupUseCase(private val userWalletsListManager: UserWalletsListM
|
|||
if (wallet == null) {
|
||||
false
|
||||
} else {
|
||||
wallet.scanResponse.card.backupStatus is CardDTO.BackupStatus.NoBackup
|
||||
wallet is UserWallet.Cold && wallet.scanResponse.card.backupStatus is CardDTO.BackupStatus.NoBackup
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,38 +2,23 @@ package com.tangem.domain.wallets.usecase
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.ensure
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
||||
/**
|
||||
* Use case for rename user wallet
|
||||
*
|
||||
* @property userWalletsListManager user wallets list manager
|
||||
*/
|
||||
class RenameWalletUseCase(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val userWalletsSyncDelegate: UserWalletsSyncDelegate,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(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
|
||||
}
|
||||
|
||||
when (val result = userWalletsListManager.update(userWalletId) { it.copy(name = name) }) {
|
||||
is CompletionResult.Failure -> raise(UpdateWalletError.DataError(result.error))
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
either {
|
||||
runCatching {
|
||||
walletsRepository.setWalletName(userWalletId.stringValue, name)
|
||||
}
|
||||
|
||||
userWalletsSyncDelegate.syncWallet(userWalletId, name).bind()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
||||
class SetNotificationsEnabledUseCase(
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, isEnabled: Boolean): Either<Throwable, Unit> =
|
||||
|
|
@ -14,5 +16,11 @@ class SetNotificationsEnabledUseCase(
|
|||
userWalletId = userWalletId,
|
||||
isEnabled = isEnabled,
|
||||
)
|
||||
currenciesRepository.syncTokens(userWalletId)
|
||||
}.onLeft {
|
||||
walletsRepository.setNotificationsEnabled(
|
||||
userWalletId = userWalletId,
|
||||
isEnabled = !isEnabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
||||
class UpdateRemoteWalletsInfoUseCase(
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val userWalletsSyncDelegate: UserWalletsSyncDelegate,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(applicationId: ApplicationId): Either<Throwable, Unit> = Either.catch {
|
||||
val walletsInfo = walletsRepository.getWalletsInfo(applicationId.value)
|
||||
userWalletsSyncDelegate.syncWallets(walletsInfo)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
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.wallets.models.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 GetSavedWalletChangesUseCaseTest {
|
||||
|
||||
private lateinit var useCase: GetSavedWalletChangesUseCase
|
||||
private lateinit var userWalletsListManager: UserWalletsListManager
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
userWalletsListManager = mockk()
|
||||
useCase = GetSavedWalletChangesUseCase(userWalletsListManager)
|
||||
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.userWallets } returns flowOf(emptyList())
|
||||
every { userWalletsListManager.isLockedSync } returns false
|
||||
every { userWalletsListManager.asLockable() } returns null
|
||||
|
||||
// WHEN
|
||||
val result = useCase().firstOrNull()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@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.userWallets } returns flowOf(emptyList())
|
||||
every { userWalletsListManager.isLockedSync } returns true
|
||||
every { userWalletsListManager.asLockable() } returns mockLockable
|
||||
|
||||
// WHEN
|
||||
val result = useCase().firstOrNull()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@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.userWallets } returns flowOf(wallets)
|
||||
every { userWalletsListManager.isLockedSync } returns false
|
||||
every { userWalletsListManager.asLockable() } returns mockLockable
|
||||
|
||||
// WHEN
|
||||
val result = useCase().firstOrNull()
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(wallets)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue