Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-05 18:49:34 +04:00
parent 14addc169c
commit a08e090a8f
26 changed files with 216 additions and 87 deletions

View file

@ -19,6 +19,7 @@ data class GetWalletAccountsResponse(
@Json(name = "group") val group: GroupType?, @Json(name = "group") val group: GroupType?,
@Json(name = "sort") val sort: SortType?, @Json(name = "sort") val sort: SortType?,
@Json(name = "totalAccounts") val totalAccounts: Int, @Json(name = "totalAccounts") val totalAccounts: Int,
@Json(name = "totalArchivedAccounts") val totalArchivedAccounts: Int,
) )
} }

View file

@ -36,6 +36,7 @@ internal class AccountListConverter @AssistedInject constructor(
userWalletId = userWallet.walletId, userWalletId = userWallet.walletId,
accounts = value.accounts.map(cryptoPortfolioConverter::convert), accounts = value.accounts.map(cryptoPortfolioConverter::convert),
totalAccounts = value.wallet.totalAccounts, totalAccounts = value.wallet.totalAccounts,
totalArchivedAccounts = value.wallet.totalArchivedAccounts,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,
) )

View file

@ -27,6 +27,7 @@ internal class GetWalletAccountsResponseConverter @AssistedInject constructor(
group = TokensGroupTypeConverter.convertBack(value.groupType), group = TokensGroupTypeConverter.convertBack(value.groupType),
sort = TokensSortTypeConverter.convertBack(value.sortType), sort = TokensSortTypeConverter.convertBack(value.sortType),
totalAccounts = value.totalAccounts, totalAccounts = value.totalAccounts,
totalArchivedAccounts = value.totalArchivedAccounts,
), ),
accounts = value.accounts accounts = value.accounts
.filterIsInstance<Account.CryptoPortfolio>() .filterIsInstance<Account.CryptoPortfolio>()

View file

@ -43,6 +43,7 @@ internal class DefaultWalletAccountsResponseFactory @Inject constructor(
group = response.group, group = response.group,
sort = response.sort, sort = response.sort,
totalAccounts = accountDTOs.size, totalAccounts = accountDTOs.size,
totalArchivedAccounts = 0,
), ),
accounts = accountDTOs.assignTokens(userWalletId = userWalletId, tokens = response.tokens), accounts = accountDTOs.assignTokens(userWalletId = userWalletId, tokens = response.tokens),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),

View file

@ -53,6 +53,7 @@ internal fun createGetWalletAccountsResponse(
group = groupType, group = groupType,
sort = sortType, sort = sortType,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = buildList { accounts = buildList {
createWalletAccountDTO( createWalletAccountDTO(
@ -79,6 +80,7 @@ internal fun createAccountList(
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(createCryptoPortfolio(userWalletId)), accounts = listOf(createCryptoPortfolio(userWalletId)),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,
) )

View file

@ -137,6 +137,7 @@ class AccountListConverterTest {
group = UserTokensResponse.GroupType.NETWORK, group = UserTokensResponse.GroupType.NETWORK,
sort = UserTokensResponse.SortType.BALANCE, sort = UserTokensResponse.SortType.BALANCE,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = emptyList(), accounts = emptyList(),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),

View file

@ -182,6 +182,7 @@ class FetchWalletAccountsErrorHandlerTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = listOf(accountDTO), accounts = listOf(accountDTO),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),

View file

@ -179,6 +179,7 @@ class DefaultMainAccountTokensMigrationTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 2, totalAccounts = 2,
totalArchivedAccounts = 0,
), ),
accounts = listOf(mainAccount, selectedAccount), accounts = listOf(mainAccount, selectedAccount),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),

View file

@ -81,6 +81,7 @@ class DefaultWalletAccountsResponseFactoryTest {
group = UserTokensResponse.GroupType.NETWORK, group = UserTokensResponse.GroupType.NETWORK,
sort = UserTokensResponse.SortType.BALANCE, sort = UserTokensResponse.SortType.BALANCE,
totalAccounts = 0, totalAccounts = 0,
totalArchivedAccounts = 0,
), ),
accounts = emptyList(), accounts = emptyList(),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -135,6 +136,7 @@ class DefaultWalletAccountsResponseFactoryTest {
group = defaultResponse.group, group = defaultResponse.group,
sort = defaultResponse.sort, sort = defaultResponse.sort,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = listOf(accountsDTO.copy(tokens = listOf(token))), accounts = listOf(accountsDTO.copy(tokens = listOf(token))),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -190,6 +192,7 @@ class DefaultWalletAccountsResponseFactoryTest {
group = defaultResponse.group, group = defaultResponse.group,
sort = defaultResponse.sort, sort = defaultResponse.sort,
totalAccounts = 0, totalAccounts = 0,
totalArchivedAccounts = 0,
), ),
accounts = emptyList(), accounts = emptyList(),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -228,6 +231,7 @@ class DefaultWalletAccountsResponseFactoryTest {
group = userTokensResponse.group, group = userTokensResponse.group,
sort = userTokensResponse.sort, sort = userTokensResponse.sort,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = listOf(accountsDTO.copy(tokens = userTokensResponse.tokens)), accounts = listOf(accountsDTO.copy(tokens = userTokensResponse.tokens)),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),

View file

@ -32,6 +32,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 0, totalAccounts = 0,
totalArchivedAccounts = 0,
), ),
accounts = emptyList(), accounts = emptyList(),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -55,6 +56,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = listOf(account), accounts = listOf(account),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -84,6 +86,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 2, totalAccounts = 2,
totalArchivedAccounts = 0,
), ),
accounts = listOf(account1, account2, account3), accounts = listOf(account1, account2, account3),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -110,6 +113,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 0, totalAccounts = 0,
totalArchivedAccounts = 0,
), ),
accounts = emptyList(), accounts = emptyList(),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -141,6 +145,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NETWORK, group = UserTokensResponse.GroupType.NETWORK,
sort = UserTokensResponse.SortType.BALANCE, sort = UserTokensResponse.SortType.BALANCE,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = listOf(account), accounts = listOf(account),
unassignedTokens = listOf(token2), unassignedTokens = listOf(token2),
@ -178,6 +183,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 2, totalAccounts = 2,
totalArchivedAccounts = 0,
), ),
accounts = listOf(account1, account2), accounts = listOf(account1, account2),
unassignedTokens = listOf(token1, token2), unassignedTokens = listOf(token1, token2),
@ -217,6 +223,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
accounts = listOf(account), accounts = listOf(account),
unassignedTokens = emptyList(), unassignedTokens = emptyList(),
@ -248,6 +255,7 @@ class GetWalletAccountsResponseExtTest {
group = UserTokensResponse.GroupType.NONE, group = UserTokensResponse.GroupType.NONE,
sort = UserTokensResponse.SortType.MANUAL, sort = UserTokensResponse.SortType.MANUAL,
totalAccounts = 2, totalAccounts = 2,
totalArchivedAccounts = 0,
), ),
accounts = listOf(account), accounts = listOf(account),
unassignedTokens = listOf(token1, token2), unassignedTokens = listOf(token1, token2),

View file

@ -28,6 +28,7 @@ data class AccountList private constructor(
val userWalletId: UserWalletId, val userWalletId: UserWalletId,
val accounts: List<Account>, val accounts: List<Account>,
val totalAccounts: Int, val totalAccounts: Int,
val totalArchivedAccounts: Int,
val sortType: TokensSortType, val sortType: TokensSortType,
val groupType: TokensGroupType, val groupType: TokensGroupType,
) { ) {
@ -60,6 +61,7 @@ data class AccountList private constructor(
userWalletId = this.userWalletId, userWalletId = this.userWalletId,
accounts = accounts, accounts = accounts,
totalAccounts = this.totalAccounts + if (isNewAccount) 1 else 0, totalAccounts = this.totalAccounts + if (isNewAccount) 1 else 0,
totalArchivedAccounts = this.totalArchivedAccounts,
sortType = this.sortType, sortType = this.sortType,
groupType = this.groupType, groupType = this.groupType,
) )
@ -82,6 +84,7 @@ data class AccountList private constructor(
userWalletId = this.userWalletId, userWalletId = this.userWalletId,
accounts = accounts, accounts = accounts,
totalAccounts = this.totalAccounts - if (isExistingAccount) 1 else 0, totalAccounts = this.totalAccounts - if (isExistingAccount) 1 else 0,
totalArchivedAccounts = this.totalArchivedAccounts,
sortType = this.sortType, sortType = this.sortType,
groupType = this.groupType, groupType = this.groupType,
) )
@ -152,6 +155,7 @@ data class AccountList private constructor(
companion object { companion object {
const val MAX_ACCOUNTS_COUNT = 20 const val MAX_ACCOUNTS_COUNT = 20
const val MAX_ARCHIVED_ACCOUNTS_COUNT = 1000
private const val MAX_MAIN_ACCOUNTS_COUNT = 1 private const val MAX_MAIN_ACCOUNTS_COUNT = 1
/** /**
@ -166,6 +170,7 @@ data class AccountList private constructor(
userWalletId: UserWalletId, userWalletId: UserWalletId,
accounts: List<Account>, accounts: List<Account>,
totalAccounts: Int, totalAccounts: Int,
totalArchivedAccounts: Int,
sortType: TokensSortType = TokensSortType.NONE, sortType: TokensSortType = TokensSortType.NONE,
groupType: TokensGroupType = TokensGroupType.NONE, groupType: TokensGroupType = TokensGroupType.NONE,
): Either<Error, AccountList> = either { ): Either<Error, AccountList> = either {
@ -200,6 +205,7 @@ data class AccountList private constructor(
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = accounts, accounts = accounts,
totalAccounts = totalAccounts, totalAccounts = totalAccounts,
totalArchivedAccounts = totalArchivedAccounts,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,
) )
@ -225,6 +231,7 @@ data class AccountList private constructor(
), ),
), ),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,
) )

View file

@ -26,6 +26,7 @@ data class AccountStatusList(
val userWalletId: UserWalletId, val userWalletId: UserWalletId,
val accountStatuses: List<AccountStatus>, val accountStatuses: List<AccountStatus>,
val totalAccounts: Int, val totalAccounts: Int,
val totalArchivedAccounts: Int,
val totalFiatBalance: TotalFiatBalance, val totalFiatBalance: TotalFiatBalance,
val sortType: TokensSortType, val sortType: TokensSortType,
val groupType: TokensGroupType, val groupType: TokensGroupType,
@ -47,6 +48,7 @@ data class AccountStatusList(
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = accountStatuses.map(AccountStatus::account), accounts = accountStatuses.map(AccountStatus::account),
totalAccounts = totalAccounts, totalAccounts = totalAccounts,
totalArchivedAccounts = totalArchivedAccounts,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,
) )

View file

@ -55,10 +55,11 @@ class ApplyAccountListSortingUseCase(
val updatedAccountList = withError( val updatedAccountList = withError(
transform = { Error.DataOperationFailed("Unable to create AccountList: $it") }, transform = { Error.DataOperationFailed("Unable to create AccountList: $it") },
) { ) {
AccountList( AccountList.invoke(
userWalletId = accountList.userWalletId, userWalletId = accountList.userWalletId,
accounts = sortedAccounts, accounts = sortedAccounts,
totalAccounts = accountList.totalAccounts, totalAccounts = accountList.totalAccounts,
totalArchivedAccounts = accountList.totalArchivedAccounts,
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,
) )

View file

@ -87,6 +87,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = accounts, accounts = accounts,
totalAccounts = accounts.size, totalAccounts = accounts.size,
totalArchivedAccounts = 0,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,
) )
@ -96,6 +97,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = accounts, accounts = accounts,
totalAccounts = accounts.size, totalAccounts = accounts.size,
totalArchivedAccounts = 0,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,
) )
@ -110,6 +112,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = model.accounts, accounts = model.accounts,
totalAccounts = model.totalAccounts, totalAccounts = model.totalAccounts,
totalArchivedAccounts = 0,
) )
// Assert // Assert
@ -206,12 +209,14 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toAdd = newAccount, toAdd = newAccount,
expected = AccountList( expected = AccountList(
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount, newAccount), accounts = listOf(mainAccount, newAccount),
totalAccounts = 2, totalAccounts = 2,
totalArchivedAccounts = 0,
), ),
) )
}, },
@ -226,12 +231,14 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toAdd = newAccount, toAdd = newAccount,
expected = AccountList( expected = AccountList(
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(newAccount), accounts = listOf(newAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
) )
}, },
@ -252,6 +259,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toAdd = newAccount, toAdd = newAccount,
expected = AccountList.Error.MainAccountNotFound.left(), expected = AccountList.Error.MainAccountNotFound.left(),
@ -268,6 +276,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toAdd = newAccount, toAdd = newAccount,
expected = AccountList.Error.ExceedsMaxMainAccountsCount.left(), expected = AccountList.Error.ExceedsMaxMainAccountsCount.left(),
@ -284,6 +293,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toAdd = newAccount, toAdd = newAccount,
expected = AccountList.Error.DuplicateAccountNames.left(), expected = AccountList.Error.DuplicateAccountNames.left(),
@ -296,6 +306,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = createAccounts(count = 20), accounts = createAccounts(count = 20),
totalAccounts = 20, totalAccounts = 20,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toAdd = createAccount(derivationIndex = 21), toAdd = createAccount(derivationIndex = 21),
expected = AccountList.Error.ExceedsMaxAccountsCount.left(), expected = AccountList.Error.ExceedsMaxAccountsCount.left(),
@ -335,12 +346,14 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount, secondaryAccount), accounts = listOf(mainAccount, secondaryAccount),
totalAccounts = 2, totalAccounts = 2,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toRemove = secondaryAccount, toRemove = secondaryAccount,
expected = AccountList( expected = AccountList(
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
), ),
) )
}, },
@ -354,6 +367,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
) )
MinusTestModel( MinusTestModel(
@ -372,6 +386,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount), accounts = listOf(mainAccount),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toRemove = mainAccount, toRemove = mainAccount,
expected = AccountList.Error.EmptyAccountsList.left(), expected = AccountList.Error.EmptyAccountsList.left(),
@ -388,6 +403,7 @@ internal class AccountListTest {
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = listOf(mainAccount, secondaryAccount), accounts = listOf(mainAccount, secondaryAccount),
totalAccounts = 2, totalAccounts = 2,
totalArchivedAccounts = 0,
).getOrNull()!!, ).getOrNull()!!,
toRemove = mainAccount, toRemove = mainAccount,
expected = AccountList.Error.MainAccountNotFound.left(), expected = AccountList.Error.MainAccountNotFound.left(),

View file

@ -157,6 +157,7 @@ class ApplyAccountListSortingUseCaseTest {
userWalletId = accountList.userWalletId, userWalletId = accountList.userWalletId,
accounts = accountList.accounts.reversed(), accounts = accountList.accounts.reversed(),
totalAccounts = accountList.totalAccounts, totalAccounts = accountList.totalAccounts,
totalArchivedAccounts = accountList.totalArchivedAccounts,
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,
).getOrNull()!! ).getOrNull()!!

View file

@ -68,6 +68,7 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo
accountStatuses = accountStatuses.toList(), accountStatuses = accountStatuses.toList(),
totalAccounts = accountList.totalAccounts, totalAccounts = accountList.totalAccounts,
totalFiatBalance = TotalFiatBalanceCalculator.calculate(balances), totalFiatBalance = TotalFiatBalanceCalculator.calculate(balances),
totalArchivedAccounts = accountList.totalArchivedAccounts,
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,
) )
@ -194,6 +195,7 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo
} }
}, },
totalAccounts = accountList.totalAccounts, totalAccounts = accountList.totalAccounts,
totalArchivedAccounts = accountList.totalArchivedAccounts,
totalFiatBalance = TotalFiatBalance.Loading, totalFiatBalance = TotalFiatBalance.Loading,
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,

View file

@ -106,6 +106,7 @@ class ApplyTokenListSortingUseCaseV2(
userWalletId = accountList.userWalletId, userWalletId = accountList.userWalletId,
accounts = accountList.accounts.sortTokens(sortedTokensIdsByAccount, errors), accounts = accountList.accounts.sortTokens(sortedTokensIdsByAccount, errors),
totalAccounts = accountList.totalAccounts, totalAccounts = accountList.totalAccounts,
totalArchivedAccounts = accountList.totalArchivedAccounts,
sortType = if (isSortedByBalance) TokensSortType.BALANCE else TokensSortType.NONE, sortType = if (isSortedByBalance) TokensSortType.BALANCE else TokensSortType.NONE,
groupType = if (isGroupedByNetwork) TokensGroupType.NETWORK else TokensGroupType.NONE, groupType = if (isGroupedByNetwork) TokensGroupType.NETWORK else TokensGroupType.NONE,
).getOrElse { ).getOrElse {

View file

@ -90,6 +90,7 @@ class DefaultSingleAccountStatusListProducerTest {
), ),
), ),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = accountList.totalArchivedAccounts,
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL), totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,
@ -132,6 +133,7 @@ class DefaultSingleAccountStatusListProducerTest {
), ),
), ),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = accountList.totalArchivedAccounts,
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL), totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,
@ -153,6 +155,7 @@ class DefaultSingleAccountStatusListProducerTest {
), ),
), ),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = accountList.totalArchivedAccounts,
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL), totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
sortType = updatedAccountList.sortType, sortType = updatedAccountList.sortType,
groupType = updatedAccountList.groupType, groupType = updatedAccountList.groupType,
@ -192,6 +195,7 @@ class DefaultSingleAccountStatusListProducerTest {
), ),
), ),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = accountList.totalArchivedAccounts,
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL), totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,
@ -273,6 +277,7 @@ class DefaultSingleAccountStatusListProducerTest {
), ),
), ),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = accountList.totalArchivedAccounts,
totalFiatBalance = TotalFiatBalance.Loading, totalFiatBalance = TotalFiatBalance.Loading,
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,

View file

@ -348,6 +348,7 @@ internal class ApplyTokenListSortingUseCaseTest {
customAccount, // unchanged due to error customAccount, // unchanged due to error
), ),
totalAccounts = accountList.totalAccounts, totalAccounts = accountList.totalAccounts,
totalArchivedAccounts = accountList.totalArchivedAccounts,
sortType = TokensSortType.NONE, sortType = TokensSortType.NONE,
groupType = TokensGroupType.NONE, groupType = TokensGroupType.NONE,
) )

View file

@ -295,6 +295,7 @@ class ArchiveCryptoPortfolioUseCaseTest {
) )
}, },
totalAccounts = totalAccounts, totalAccounts = totalAccounts,
totalArchivedAccounts = totalArchivedAccounts,
totalFiatBalance = TotalFiatBalance.Loading, totalFiatBalance = TotalFiatBalance.Loading,
sortType = sortType, sortType = sortType,
groupType = groupType, groupType = groupType,

View file

@ -42,6 +42,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
userWalletId = userWalletId, userWalletId = userWalletId,
accountStatuses = emptyList(), accountStatuses = emptyList(),
totalAccounts = 0, totalAccounts = 0,
totalArchivedAccounts = 0,
totalFiatBalance = TotalFiatBalance.Failed, totalFiatBalance = TotalFiatBalance.Failed,
sortType = TokensSortType.NONE, sortType = TokensSortType.NONE,
groupType = TokensGroupType.NONE, groupType = TokensGroupType.NONE,
@ -205,6 +206,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
userWalletId = userWalletId, userWalletId = userWalletId,
accountStatuses = listOf(accountStatus), accountStatuses = listOf(accountStatus),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
totalFiatBalance = tokenList.totalFiatBalance, totalFiatBalance = tokenList.totalFiatBalance,
sortType = tokenList.sortedBy, sortType = tokenList.sortedBy,
groupType = groupType, groupType = groupType,

View file

@ -42,6 +42,7 @@ class ToggleTokenListSortingUseCaseV2Test {
userWalletId = userWalletId, userWalletId = userWalletId,
accountStatuses = emptyList(), accountStatuses = emptyList(),
totalAccounts = 0, totalAccounts = 0,
totalArchivedAccounts = 0,
totalFiatBalance = TotalFiatBalance.Failed, totalFiatBalance = TotalFiatBalance.Failed,
sortType = TokensSortType.NONE, sortType = TokensSortType.NONE,
groupType = TokensGroupType.NONE, groupType = TokensGroupType.NONE,
@ -145,6 +146,7 @@ class ToggleTokenListSortingUseCaseV2Test {
userWalletId = userWalletId, userWalletId = userWalletId,
accountStatuses = listOf(accountStatus), accountStatuses = listOf(accountStatus),
totalAccounts = 1, totalAccounts = 1,
totalArchivedAccounts = 0,
totalFiatBalance = tokenList.totalFiatBalance, totalFiatBalance = tokenList.totalFiatBalance,
sortType = tokenList.sortedBy, sortType = tokenList.sortedBy,
groupType = TokensGroupType.NONE, groupType = TokensGroupType.NONE,

View file

@ -13,11 +13,40 @@ internal data class AccountsUM(
) { ) {
data class Button( data class Button(
val title: String, val id: ID,
val title: String = createTitle(id),
val isInProgress: Boolean = false, val isInProgress: Boolean = false,
val isEnabled: Boolean = true, val isEnabled: Boolean = true,
val onClick: (title: String) -> Unit, val onClick: () -> Unit,
) ) {
enum class ID {
ShowAccountList,
FetchAccounts,
FillOutList,
FillOutArchivedList,
ArchiveAll,
SortByDerivationIndex,
ClearETag,
}
fun reset(): Button {
return copy(title = createTitle(id), isInProgress = false, isEnabled = true)
}
companion object {
private fun createTitle(id: ID): String = when (id) {
ID.ShowAccountList -> "Show the account list"
ID.FetchAccounts -> "Fetch accounts"
ID.FillOutList -> "Fill out the list (up to 20)"
ID.FillOutArchivedList -> "Fill out the archived list"
ID.ArchiveAll -> "Archive all"
ID.SortByDerivationIndex -> "Sort by derivation index"
ID.ClearETag -> "Clear ETag"
}
}
}
data class WalletSelector( data class WalletSelector(
val selected: UserWallet?, val selected: UserWallet?,

View file

@ -206,7 +206,7 @@ private fun LazyListScope.ManageAccountsButtons(buttons: ImmutableList<AccountsU
items(buttons) { button -> items(buttons) { button ->
PrimaryButton( PrimaryButton(
text = button.title, text = button.title,
onClick = { button.onClick(button.title) }, onClick = button.onClick,
modifier = Modifier modifier = Modifier
.padding(horizontal = 16.dp, vertical = 8.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
.fillMaxWidth(), .fillMaxWidth(),

View file

@ -60,7 +60,7 @@ internal class TesterAccountsViewModel @Inject constructor(
userWallets.firstOrNull()?.let(::onWalletSelect) userWallets.firstOrNull()?.let(::onWalletSelect)
userWallets.mapIndexed { index, userWallet -> userWallets.map { userWallet ->
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId = userWallet.walletId)) singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId = userWallet.walletId))
.distinctUntilChanged() .distinctUntilChanged()
.onEach { accountList -> .onEach { accountList ->
@ -102,12 +102,16 @@ internal class TesterAccountsViewModel @Inject constructor(
}, },
), ),
buttons = persistentListOf( buttons = persistentListOf(
AccountsUM.Button(title = "Show the account list") { updateAccountsList() }, AccountsUM.Button(id = AccountsUM.Button.ID.ShowAccountList, onClick = ::updateAccountsList),
AccountsUM.Button(title = "Fetch accounts", onClick = ::fetchAccounts), AccountsUM.Button(id = AccountsUM.Button.ID.FetchAccounts, onClick = ::fetchAccounts),
AccountsUM.Button(title = "Fill out the list (up to 20)", onClick = ::fillOutAccountList), AccountsUM.Button(id = AccountsUM.Button.ID.FillOutList, onClick = ::onFillOutClick),
AccountsUM.Button(title = "Archive all", onClick = ::archiveAllAccounts), AccountsUM.Button(
AccountsUM.Button(title = "Sort by derivation index", onClick = ::sortAccountsByIndex), id = AccountsUM.Button.ID.FillOutArchivedList,
AccountsUM.Button(title = "Clear ETag") { clearETag() }, onClick = ::fillOutArchivedAccountList,
),
AccountsUM.Button(id = AccountsUM.Button.ID.ArchiveAll, onClick = ::onArchiveAllClick),
AccountsUM.Button(id = AccountsUM.Button.ID.SortByDerivationIndex, onClick = ::sortAccountsByIndex),
AccountsUM.Button(id = AccountsUM.Button.ID.ClearETag) { clearETag() },
), ),
) )
} }
@ -137,19 +141,15 @@ internal class TesterAccountsViewModel @Inject constructor(
} }
} }
private fun fetchAccounts(title: String) { private fun fetchAccounts() {
viewModelScope.launch { val userWalletId = uiState.value.walletSelector.selected?.walletId ?: return
val userWalletId = uiState.value.walletSelector.selected?.walletId ?: return@launch
toggleButtonProgress(title = title, isInProgress = true)
withProgress(id = AccountsUM.Button.ID.FetchAccounts) {
withContext(dispatchers.default) { withContext(dispatchers.default) {
singleAccountListFetcher( singleAccountListFetcher(
params = SingleAccountListFetcher.Params(userWalletId = userWalletId), params = SingleAccountListFetcher.Params(userWalletId = userWalletId),
) )
} }
toggleButtonProgress(title = title, isInProgress = false)
} }
} }
@ -160,84 +160,113 @@ internal class TesterAccountsViewModel @Inject constructor(
} }
} }
private fun fillOutAccountList(title: String) { private fun onFillOutClick() {
val userWalletId = getUserWallet()?.walletId ?: return val userWalletId = getUserWallet()?.walletId ?: return
viewModelScope.launch { withProgress(id = AccountsUM.Button.ID.FillOutList) {
toggleButtonProgress(title = title, isInProgress = true) fillOutAccountList(userWalletId = userWalletId)
}
}
withContext(dispatchers.default) { private fun fillOutArchivedAccountList() {
var accountList = walletAccounts.value[userWalletId] ?: return@withContext val userWalletId = getUserWallet()?.walletId ?: return
val occupiedIndexes = accountList.accounts val accountList = walletAccounts.value[userWalletId] ?: return
.filterIsInstance<Account.CryptoPortfolio>() if (accountList.totalArchivedAccounts == AccountList.MAX_ARCHIVED_ACCOUNTS_COUNT) return
.map { it.derivationIndex.value }
.toSet()
var nextIndex = 0 val id = AccountsUM.Button.ID.FillOutArchivedList
@Suppress("LoopWithTooManyJumpStatements") // never mind for Tester Menu
while (accountList.canAddMoreAccounts) {
while (occupiedIndexes.contains(nextIndex)) {
nextIndex++
}
val derivationIndex = DerivationIndex(nextIndex).getOrNull() ?: break viewModelScope.launch(dispatchers.default) {
var currentTotalArchived = accountList.totalArchivedAccounts
val newAccount = Account.CryptoPortfolio.invoke( while (currentTotalArchived < AccountList.MAX_ARCHIVED_ACCOUNTS_COUNT) {
accountId = AccountId.forCryptoPortfolio(userWalletId, derivationIndex), updateButton(id) { button ->
name = "Account #$nextIndex", button.copy(
icon = CryptoPortfolioIcon.ofDefaultCustomAccount(), title = "In progress... ($currentTotalArchived/${AccountList.MAX_ARCHIVED_ACCOUNTS_COUNT})",
derivationIndex = nextIndex, isEnabled = false,
cryptoCurrencies = emptySet(),
) )
.getOrNull()
?: break
(accountList + newAccount)
.onRight { accountList = it }
.getOrNull()
?: break
nextIndex++
} }
accountsCRUDRepository.saveAccounts(accountList) fillOutAccountList(userWalletId = userWalletId)
archiveAll(userWalletId = userWalletId)
accountsCRUDRepository.getAccountListSync(userWalletId).onSome {
currentTotalArchived = it.totalArchivedAccounts
}
} }
toggleButtonProgress(title = title, isInProgress = false) updateButton(id = id, button = AccountsUM.Button::reset)
} }
} }
private fun archiveAllAccounts(title: String) { private suspend fun fillOutAccountList(userWalletId: UserWalletId) {
val userWalletId = getUserWallet()?.walletId ?: return withContext(dispatchers.default) {
val accountList = walletAccounts.value[userWalletId] ?: return var accountList = walletAccounts.value[userWalletId] ?: return@withContext
viewModelScope.launch { var nextIndex = accountList.totalAccounts
toggleButtonProgress(title = title, isInProgress = true) @Suppress("LoopWithTooManyJumpStatements") // never mind for Tester Menu
while (accountList.canAddMoreAccounts) {
val derivationIndex = DerivationIndex(nextIndex).getOrNull() ?: break
withContext(dispatchers.default) { val newAccount = Account.CryptoPortfolio.invoke(
val updatedAccountList = AccountList.invoke( accountId = AccountId.forCryptoPortfolio(userWalletId, derivationIndex),
userWalletId = accountList.userWalletId, name = "Account #$nextIndex",
accounts = listOf(accountList.mainAccount), icon = CryptoPortfolioIcon.ofDefaultCustomAccount(),
totalAccounts = accountList.totalAccounts, derivationIndex = nextIndex,
sortType = accountList.sortType, cryptoCurrencies = emptySet(),
groupType = accountList.groupType,
) )
.getOrElse { return@withContext } .getOrNull()
?: break
accountsCRUDRepository.saveAccounts(accountList = updatedAccountList) (accountList + newAccount)
.onRight { accountList = it }
.getOrNull()
?: break
nextIndex++
} }
toggleButtonProgress(title = title, isInProgress = false) accountsCRUDRepository.saveAccounts(accountList)
} }
} }
private fun sortAccountsByIndex(title: String) { private fun onArchiveAllClick() {
val userWalletId = getUserWallet()?.walletId ?: return
withProgress(id = AccountsUM.Button.ID.ArchiveAll) {
archiveAll(userWalletId = userWalletId)
}
}
private suspend fun archiveAll(userWalletId: UserWalletId) {
val accountList = walletAccounts.value[userWalletId] ?: return
val possibleToArchive = AccountList.MAX_ARCHIVED_ACCOUNTS_COUNT - accountList.totalArchivedAccounts
if (possibleToArchive == 0) return
withContext(dispatchers.default) {
val updatedAccountList = AccountList.invoke(
userWalletId = accountList.userWalletId,
accounts = if (possibleToArchive > AccountList.MAX_ACCOUNTS_COUNT - 1) {
listOf(accountList.mainAccount)
} else {
accountList.accounts.subList(fromIndex = 0, toIndex = accountList.accounts.size - possibleToArchive)
},
totalAccounts = accountList.totalAccounts,
totalArchivedAccounts = accountList.totalArchivedAccounts,
sortType = accountList.sortType,
groupType = accountList.groupType,
)
.getOrElse { return@withContext }
accountsCRUDRepository.saveAccounts(accountList = updatedAccountList)
}
}
private fun sortAccountsByIndex() {
val userWalletId = getUserWallet()?.walletId ?: return val userWalletId = getUserWallet()?.walletId ?: return
val accountList = walletAccounts.value[userWalletId] ?: return val accountList = walletAccounts.value[userWalletId] ?: return
viewModelScope.launch { withProgress(id = AccountsUM.Button.ID.SortByDerivationIndex) {
toggleButtonProgress(title = title, isInProgress = true)
withContext(dispatchers.default) { withContext(dispatchers.default) {
val sortedAccountList = AccountList.invoke( val sortedAccountList = AccountList.invoke(
userWalletId = accountList.userWalletId, userWalletId = accountList.userWalletId,
@ -245,6 +274,7 @@ internal class TesterAccountsViewModel @Inject constructor(
.filterIsInstance<Account.CryptoPortfolio>() .filterIsInstance<Account.CryptoPortfolio>()
.sortedBy { it.derivationIndex.value }, .sortedBy { it.derivationIndex.value },
totalAccounts = accountList.totalAccounts, totalAccounts = accountList.totalAccounts,
totalArchivedAccounts = accountList.totalArchivedAccounts,
sortType = accountList.sortType, sortType = accountList.sortType,
groupType = accountList.groupType, groupType = accountList.groupType,
) )
@ -252,8 +282,6 @@ internal class TesterAccountsViewModel @Inject constructor(
accountsCRUDRepository.saveAccounts(accountList = sortedAccountList) accountsCRUDRepository.saveAccounts(accountList = sortedAccountList)
} }
toggleButtonProgress(title = title, isInProgress = false)
} }
} }
@ -266,22 +294,30 @@ internal class TesterAccountsViewModel @Inject constructor(
?: persistentListOf() ?: persistentListOf()
} }
private fun toggleButtonProgress(title: String, isInProgress: Boolean) { private fun withProgress(id: AccountsUM.Button.ID, block: suspend () -> Unit) {
uiState.update { state -> viewModelScope.launch {
state.copy( toggleButtonProgress(id = id, isInProgress = true)
buttons = state.buttons.updateButton(title) { try {
it.copy(isInProgress = isInProgress) block()
}, } finally {
) toggleButtonProgress(id = id, isInProgress = false)
}
} }
} }
private fun ImmutableList<AccountsUM.Button>.updateButton( private fun toggleButtonProgress(id: AccountsUM.Button.ID, isInProgress: Boolean) {
title: String, updateButton(id) {
button: (AccountsUM.Button) -> AccountsUM.Button, it.copy(isInProgress = isInProgress)
): ImmutableList<AccountsUM.Button> { }
return this }
.map { if (it.title == title) button(it) else it }
.toImmutableList() private fun updateButton(id: AccountsUM.Button.ID, button: (AccountsUM.Button) -> AccountsUM.Button) {
uiState.update { state ->
state.copy(
buttons = state.buttons
.map { if (it.id == id) button(it) else it }
.toImmutableList(),
)
}
} }
} }

View file

@ -19,12 +19,14 @@ object MockAccounts {
fun createAccountList( fun createAccountList(
activeAccounts: Int, activeAccounts: Int,
totalAccounts: Int = activeAccounts, totalAccounts: Int = activeAccounts,
totalArchivedAccounts: Int = 0,
userWalletId: UserWalletId = this.userWalletId, userWalletId: UserWalletId = this.userWalletId,
): AccountList { ): AccountList {
return AccountList( return AccountList(
userWalletId = userWalletId, userWalletId = userWalletId,
accounts = createAccounts(count = activeAccounts, userWalletId = userWalletId), accounts = createAccounts(count = activeAccounts, userWalletId = userWalletId),
totalAccounts = totalAccounts, totalAccounts = totalAccounts,
totalArchivedAccounts = totalArchivedAccounts,
).getOrNull()!! ).getOrNull()!!
} }