Updated on 2026-08-14
This commit is contained in:
parent
eab83c7675
commit
9ce639e080
21 changed files with 110 additions and 113 deletions
|
|
@ -37,7 +37,7 @@ internal class DefaultCurrenciesRepository(
|
|||
|
||||
override suspend fun saveTokens(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: Set<CryptoCurrency>,
|
||||
currencies: List<CryptoCurrency>,
|
||||
isGroupedByNetwork: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
) = withContext(dispatchers.io) {
|
||||
|
|
@ -64,7 +64,7 @@ internal class DefaultCurrenciesRepository(
|
|||
override fun getMultiCurrencyWalletCurrencies(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean,
|
||||
): Flow<Set<CryptoCurrency>> = channelFlow {
|
||||
): Flow<List<CryptoCurrency>> = channelFlow {
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true)
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ internal class DefaultCurrenciesRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<Set<CryptoCurrency>> {
|
||||
private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<List<CryptoCurrency>> {
|
||||
return userTokensStore.get(userWallet.walletId).map { storedTokens ->
|
||||
responseCurrenciesFactory.createCurrencies(
|
||||
response = storedTokens,
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ internal class DefaultNetworksRepository(
|
|||
val result = walletManagersFacade.update(
|
||||
userWalletId = userWalletId,
|
||||
networkId = networkId,
|
||||
extraTokens = currencies.filterIsInstanceTo(hashSetOf()),
|
||||
extraTokens = currencies.filterIsInstance<CryptoCurrency.Token>().toSet(),
|
||||
)
|
||||
val networkStatus = networkStatusFactory.createNetworkStatus(
|
||||
networkId = networkId,
|
||||
|
|
@ -103,7 +103,7 @@ internal class DefaultNetworksRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getCurrencies(userWalletId: UserWalletId): Set<CryptoCurrency> {
|
||||
private suspend fun getCurrencies(userWalletId: UserWalletId): List<CryptoCurrency> {
|
||||
val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||
"Unable to find user wallet with provided ID: $userWalletId"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.blockchain.common.Token as SdkToken
|
|||
|
||||
internal class CardCurrenciesFactory(private val demoConfig: DemoConfig) {
|
||||
|
||||
fun createDefaultCoinsForMultiCurrencyCard(card: CardDTO): Set<CryptoCurrency.Coin> {
|
||||
fun createDefaultCoinsForMultiCurrencyCard(card: CardDTO): List<CryptoCurrency.Coin> {
|
||||
var blockchains = if (demoConfig.isDemoCardId(card.cardId)) {
|
||||
demoConfig.demoBlockchains
|
||||
} else {
|
||||
|
|
@ -23,7 +23,7 @@ internal class CardCurrenciesFactory(private val demoConfig: DemoConfig) {
|
|||
blockchains = blockchains.mapNotNull { it.getTestnetVersion() }
|
||||
}
|
||||
|
||||
return blockchains.mapNotNull { createCoin(it, card) }.toSet()
|
||||
return blockchains.mapNotNull { createCoin(it, card) }
|
||||
}
|
||||
|
||||
fun createPrimaryCurrencyForSingleCurrencyCard(scanResponse: ScanResponse): CryptoCurrency {
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ internal class ResponseCurrenciesFactory(private val demoConfig: DemoConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
fun createCurrencies(response: UserTokensResponse, card: CardDTO): Set<CryptoCurrency> {
|
||||
return response.tokens.mapNotNull { createCurrency(it, card) }.toSet()
|
||||
fun createCurrencies(response: UserTokensResponse, card: CardDTO): List<CryptoCurrency> {
|
||||
return response.tokens.mapNotNull { createCurrency(it, card) }
|
||||
}
|
||||
|
||||
private fun createCurrency(responseToken: UserTokensResponse.Token, card: CardDTO): CryptoCurrency? {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
|||
internal class UserTokensResponseFactory {
|
||||
|
||||
fun createUserTokensResponse(
|
||||
currencies: Set<CryptoCurrency>,
|
||||
currencies: List<CryptoCurrency>,
|
||||
isGroupedByNetwork: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
): UserTokensResponse {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import arrow.core.raise.Raise
|
|||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.ensureNotNull
|
||||
import arrow.core.toNonEmptyListOrNull
|
||||
import arrow.core.toNonEmptySetOrNull
|
||||
import com.tangem.domain.tokens.error.TokenListSortingError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -22,7 +23,7 @@ class ApplyTokenListSortingUseCase(
|
|||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
sortedTokensIds: Set<Pair<Network.ID, CryptoCurrency.ID>>,
|
||||
sortedTokensIds: List<Pair<Network.ID, CryptoCurrency.ID>>,
|
||||
isGroupedByNetwork: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
): Either<TokenListSortingError, Unit> {
|
||||
|
|
@ -39,16 +40,16 @@ class ApplyTokenListSortingUseCase(
|
|||
}
|
||||
|
||||
private suspend fun Raise<TokenListSortingError>.sortTokens(
|
||||
sortedTokensIds: Set<Pair<Network.ID, CryptoCurrency.ID>>,
|
||||
unsortedTokens: Set<CryptoCurrency>,
|
||||
): Set<CryptoCurrency> = withContext(dispatchers.default) {
|
||||
sortedTokensIds: List<Pair<Network.ID, CryptoCurrency.ID>>,
|
||||
unsortedTokens: List<CryptoCurrency>,
|
||||
): List<CryptoCurrency> = withContext(dispatchers.default) {
|
||||
val nonEmptySortedTokensIds = ensureNotNull(sortedTokensIds.toNonEmptySetOrNull()) {
|
||||
TokenListSortingError.TokenListIsEmpty
|
||||
}
|
||||
|
||||
val sortedTokens = sortedMapOf<Int, CryptoCurrency>()
|
||||
|
||||
unsortedTokens.forEach { token ->
|
||||
unsortedTokens.distinct().forEach { token ->
|
||||
val index = nonEmptySortedTokensIds.indexOfFirst { (networkId, tokenId) ->
|
||||
networkId == token.networkId && tokenId == token.id
|
||||
}
|
||||
|
|
@ -60,12 +61,12 @@ class ApplyTokenListSortingUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
ensureNotNull(sortedTokens.values.toNonEmptySetOrNull()) {
|
||||
ensureNotNull(sortedTokens.values.toNonEmptyListOrNull()) {
|
||||
TokenListSortingError.TokenListIsEmpty
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<TokenListSortingError>.getCurrencies(userWalletId: UserWalletId): Set<CryptoCurrency> {
|
||||
private suspend fun Raise<TokenListSortingError>.getCurrencies(userWalletId: UserWalletId): List<CryptoCurrency> {
|
||||
val tokens = catch(
|
||||
block = {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrencies(userWalletId, refresh = false).firstOrNull()
|
||||
|
|
@ -73,14 +74,14 @@ class ApplyTokenListSortingUseCase(
|
|||
catch = { raise(TokenListSortingError.DataError(it)) },
|
||||
)
|
||||
|
||||
return ensureNotNull(tokens?.toNonEmptySetOrNull()) {
|
||||
return ensureNotNull(tokens?.toNonEmptyListOrNull()) {
|
||||
TokenListSortingError.TokenListIsEmpty
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<TokenListSortingError>.applySorting(
|
||||
userWalletId: UserWalletId,
|
||||
tokens: Set<CryptoCurrency>,
|
||||
tokens: List<CryptoCurrency>,
|
||||
isGrouped: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
) = withContext(dispatchers.io) {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class GetTokenListUseCase(
|
|||
private fun getTokensStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean,
|
||||
): Flow<Either<TokenListError, Set<CryptoCurrencyStatus>>> {
|
||||
): Flow<Either<TokenListError, List<CryptoCurrencyStatus>>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWalletId,
|
||||
refresh = refresh,
|
||||
|
|
@ -58,7 +58,7 @@ class GetTokenListUseCase(
|
|||
|
||||
private fun createTokenList(
|
||||
userWalletId: UserWalletId,
|
||||
tokens: Set<CryptoCurrencyStatus>,
|
||||
tokens: List<CryptoCurrencyStatus>,
|
||||
): Flow<Either<TokenListError, TokenList>> {
|
||||
val operations = TokenListOperations(
|
||||
userWalletId = userWalletId,
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import com.tangem.domain.tokens.models.Network
|
|||
* This class encapsulates a collection of cryptocurrency statuses, all of which are part of the same blockchain network.
|
||||
*
|
||||
* @property network The blockchain network associated with the group.
|
||||
* @property currencies A set of cryptocurrency statuses that belong to the network.
|
||||
* @property currencies A list of cryptocurrency statuses that belong to the network.
|
||||
*/
|
||||
data class NetworkGroup(
|
||||
val network: Network,
|
||||
val currencies: Set<CryptoCurrencyStatus>,
|
||||
val currencies: List<CryptoCurrencyStatus>,
|
||||
)
|
||||
|
|
@ -18,12 +18,12 @@ sealed class TokenList {
|
|||
/**
|
||||
* Represents tokens that are grouped by their network.
|
||||
*
|
||||
* @property groups A set of network groups containing tokens.
|
||||
* @property groups A list of network groups containing tokens.
|
||||
* @property totalFiatBalance The total fiat balance across all groups.
|
||||
* @property sortedBy The criteria used for sorting the tokens within the groups.
|
||||
*/
|
||||
data class GroupedByNetwork(
|
||||
val groups: Set<NetworkGroup>,
|
||||
val groups: List<NetworkGroup>,
|
||||
override val totalFiatBalance: FiatBalance,
|
||||
override val sortedBy: SortType,
|
||||
) : TokenList()
|
||||
|
|
@ -31,12 +31,12 @@ sealed class TokenList {
|
|||
/**
|
||||
* Represents tokens that are not grouped by any specific criteria.
|
||||
*
|
||||
* @property currencies A set of cryptocurrency statuses.
|
||||
* @property currencies A list of cryptocurrency statuses.
|
||||
* @property totalFiatBalance The total fiat balance across all currencies.
|
||||
* @property sortedBy The criteria used for sorting the currencies.
|
||||
*/
|
||||
data class Ungrouped(
|
||||
val currencies: Set<CryptoCurrencyStatus>,
|
||||
val currencies: List<CryptoCurrencyStatus>,
|
||||
override val totalFiatBalance: FiatBalance,
|
||||
override val sortedBy: SortType,
|
||||
) : TokenList()
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ internal class CurrenciesStatusesOperations(
|
|||
)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun getCurrenciesStatusesFlow(): Flow<Either<Error, Set<CryptoCurrencyStatus>>> {
|
||||
fun getCurrenciesStatusesFlow(): Flow<Either<Error, List<CryptoCurrencyStatus>>> {
|
||||
return getMultiCurrencyWalletCurrencies().flatMapMerge flatMap@{ maybeCurrencies ->
|
||||
val nonEmptyCurrencies = maybeCurrencies.fold(
|
||||
ifLeft = { error ->
|
||||
return@flatMap flowOf(error.left())
|
||||
},
|
||||
ifRight = { it.toNonEmptySetOrNull() },
|
||||
) ?: return@flatMap flowOf(emptySet<CryptoCurrencyStatus>().right())
|
||||
ifRight = { it.toNonEmptyListOrNull() },
|
||||
) ?: return@flatMap flowOf(emptyList<CryptoCurrencyStatus>().right())
|
||||
|
||||
val (networksIds, currenciesIds) = getIds(nonEmptyCurrencies)
|
||||
|
||||
|
|
@ -96,11 +96,11 @@ internal class CurrenciesStatusesOperations(
|
|||
}
|
||||
|
||||
private fun createCurrenciesStatuses(
|
||||
currencies: NonEmptySet<CryptoCurrency>,
|
||||
currencies: NonEmptyList<CryptoCurrency>,
|
||||
quotes: Set<Quote>,
|
||||
networkStatuses: Set<NetworkStatus>,
|
||||
): Set<CryptoCurrencyStatus> {
|
||||
return currencies.mapTo(hashSetOf()) { token ->
|
||||
): List<CryptoCurrencyStatus> {
|
||||
return currencies.map { token ->
|
||||
val quote = quotes.firstOrNull { it.currencyId == token.id }
|
||||
val networkStatus = networkStatuses.firstOrNull { it.networkId == token.networkId }
|
||||
|
||||
|
|
@ -122,9 +122,9 @@ internal class CurrenciesStatusesOperations(
|
|||
return currencyStatusOperations.createTokenStatus()
|
||||
}
|
||||
|
||||
private fun getMultiCurrencyWalletCurrencies(): Flow<Either<Error, Set<CryptoCurrency>>> {
|
||||
private fun getMultiCurrencyWalletCurrencies(): Flow<Either<Error, List<CryptoCurrency>>> {
|
||||
return currenciesRepository.getMultiCurrencyWalletCurrencies(userWalletId, refresh)
|
||||
.map<Set<CryptoCurrency>, Either<Error, Set<CryptoCurrency>>> { it.right() }
|
||||
.map<List<CryptoCurrency>, Either<Error, List<CryptoCurrency>>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyCurrencies.left()) }
|
||||
}
|
||||
|
|
@ -157,7 +157,7 @@ internal class CurrenciesStatusesOperations(
|
|||
}
|
||||
|
||||
private fun getIds(
|
||||
currencies: NonEmptySet<CryptoCurrency>,
|
||||
currencies: NonEmptyList<CryptoCurrency>,
|
||||
): Pair<NonEmptySet<Network.ID>, NonEmptySet<CryptoCurrency.ID>> {
|
||||
val currencyIdToNetworkId = currencies.associate { currency ->
|
||||
currency.id to currency.networkId
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.domain.tokens.operations
|
||||
|
||||
import arrow.core.NonEmptySet
|
||||
import arrow.core.NonEmptyList
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class TokenListFiatBalanceOperations(
|
||||
private val currencies: NonEmptySet<CryptoCurrencyStatus>,
|
||||
private val currencies: NonEmptyList<CryptoCurrencyStatus>,
|
||||
private val isAnyTokenLoading: Boolean,
|
||||
) {
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ internal class TokenListOperations(
|
|||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val userWalletId: UserWalletId,
|
||||
private val tokens: Set<CryptoCurrencyStatus>,
|
||||
private val tokens: List<CryptoCurrencyStatus>,
|
||||
) {
|
||||
|
||||
constructor(
|
||||
userWalletId: UserWalletId,
|
||||
tokens: Set<CryptoCurrencyStatus>,
|
||||
tokens: List<CryptoCurrencyStatus>,
|
||||
useCase: GetTokenListUseCase,
|
||||
) : this(
|
||||
currenciesRepository = useCase.currenciesRepository,
|
||||
|
|
@ -42,14 +42,14 @@ internal class TokenListOperations(
|
|||
}
|
||||
|
||||
private fun Raise<Error>.createTokenList(isGrouped: Boolean, isSortedByBalance: Boolean): TokenList {
|
||||
val tokensNes = tokens.toNonEmptySetOrNull()
|
||||
val nonEmptyCurrencies = tokens.toNonEmptyListOrNull()
|
||||
?: return TokenList.NotInitialized
|
||||
|
||||
val isAnyTokenLoading = tokensNes.any { it.value is CryptoCurrencyStatus.Loading }
|
||||
val fiatBalanceOperations = TokenListFiatBalanceOperations(tokensNes, isAnyTokenLoading)
|
||||
val isAnyTokenLoading = nonEmptyCurrencies.any { it.value is CryptoCurrencyStatus.Loading }
|
||||
val fiatBalanceOperations = TokenListFiatBalanceOperations(nonEmptyCurrencies, isAnyTokenLoading)
|
||||
|
||||
return createTokenList(
|
||||
tokens = tokensNes,
|
||||
currencies = nonEmptyCurrencies,
|
||||
fiatBalance = fiatBalanceOperations.calculateFiatBalance(),
|
||||
isAnyTokenLoading = isAnyTokenLoading,
|
||||
isGrouped = isGrouped,
|
||||
|
|
@ -58,23 +58,23 @@ internal class TokenListOperations(
|
|||
}
|
||||
|
||||
private fun Raise<Error>.createTokenList(
|
||||
tokens: NonEmptySet<CryptoCurrencyStatus>,
|
||||
currencies: NonEmptyList<CryptoCurrencyStatus>,
|
||||
fiatBalance: TokenList.FiatBalance,
|
||||
isAnyTokenLoading: Boolean,
|
||||
isGrouped: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
): TokenList {
|
||||
val sortingOperations = TokenListSortingOperations(
|
||||
currencies = tokens,
|
||||
currencies = currencies,
|
||||
isAnyTokenLoading = isAnyTokenLoading,
|
||||
sortByBalance = isSortedByBalance,
|
||||
)
|
||||
|
||||
return createTokenList(tokens, sortingOperations, fiatBalance, isGrouped)
|
||||
return createTokenList(currencies, sortingOperations, fiatBalance, isGrouped)
|
||||
}
|
||||
|
||||
private fun Raise<Error>.createTokenList(
|
||||
tokens: NonEmptySet<CryptoCurrencyStatus>,
|
||||
tokens: NonEmptyList<CryptoCurrencyStatus>,
|
||||
sortingOperations: TokenListSortingOperations,
|
||||
fiatBalance: TokenList.FiatBalance,
|
||||
isGrouped: Boolean,
|
||||
|
|
@ -92,7 +92,7 @@ internal class TokenListOperations(
|
|||
}
|
||||
}
|
||||
|
||||
private fun Raise<Error>.getNetworks(tokensNes: NonEmptySet<CryptoCurrencyStatus>): Set<Network> {
|
||||
private fun Raise<Error>.getNetworks(tokensNes: NonEmptyList<CryptoCurrencyStatus>): Set<Network> {
|
||||
val networksIds = tokensNes.map { it.currency.networkId }.toNonEmptySet()
|
||||
|
||||
return catch(
|
||||
|
|
@ -131,7 +131,7 @@ internal class TokenListOperations(
|
|||
)
|
||||
|
||||
private fun createUnsortedUngroupedTokenList(
|
||||
tokens: Set<CryptoCurrencyStatus>,
|
||||
tokens: List<CryptoCurrencyStatus>,
|
||||
fiatBalance: TokenList.FiatBalance,
|
||||
): TokenList.Ungrouped {
|
||||
return TokenList.Ungrouped(
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package com.tangem.domain.tokens.operations
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.NonEmptySet
|
||||
import arrow.core.*
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.ensure
|
||||
import arrow.core.raise.ensureNotNull
|
||||
import arrow.core.toNonEmptySetOrNull
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
|
|
@ -14,7 +12,7 @@ import com.tangem.domain.tokens.models.Network
|
|||
import java.math.BigDecimal
|
||||
|
||||
internal class TokenListSortingOperations(
|
||||
private val currencies: Set<CryptoCurrencyStatus>,
|
||||
private val currencies: List<CryptoCurrencyStatus>,
|
||||
private val isAnyTokenLoading: Boolean,
|
||||
private val sortByBalance: Boolean,
|
||||
) {
|
||||
|
|
@ -25,15 +23,15 @@ internal class TokenListSortingOperations(
|
|||
isAnyTokenLoading: Boolean = tokenList.totalFiatBalance is TokenList.FiatBalance.Loading,
|
||||
) : this(
|
||||
currencies = when (tokenList) {
|
||||
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap { it.currencies }.toSet()
|
||||
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap { it.currencies }
|
||||
is TokenList.Ungrouped -> tokenList.currencies
|
||||
is TokenList.NotInitialized -> emptySet()
|
||||
is TokenList.NotInitialized -> emptyList()
|
||||
},
|
||||
isAnyTokenLoading = isAnyTokenLoading,
|
||||
sortByBalance = sortByBalance,
|
||||
)
|
||||
|
||||
fun getGroupedTokens(networks: Set<Network>): Either<Error, NonEmptySet<NetworkGroup>> = either {
|
||||
fun getGroupedTokens(networks: Set<Network>): Either<Error, NonEmptyList<NetworkGroup>> = either {
|
||||
ensure(currencies.isNotEmpty()) { Error.EmptyTokens }
|
||||
val networksNes = ensureNotNull(networks.toNonEmptySetOrNull()) {
|
||||
Error.EmptyNetworks
|
||||
|
|
@ -46,17 +44,17 @@ internal class TokenListSortingOperations(
|
|||
}
|
||||
}
|
||||
|
||||
fun getTokens(): Either<Error, NonEmptySet<CryptoCurrencyStatus>> = either {
|
||||
val tokensNes = ensureNotNull(currencies.toNonEmptySetOrNull()) {
|
||||
fun getTokens(): Either<Error, NonEmptyList<CryptoCurrencyStatus>> = either {
|
||||
val nonEmptyCurrencies = ensureNotNull(currencies.toNonEmptyListOrNull()) {
|
||||
Error.EmptyTokens
|
||||
}
|
||||
|
||||
if (sortByBalance) sortTokensByBalance(tokensNes) else tokensNes
|
||||
if (sortByBalance) sortTokensByBalance(nonEmptyCurrencies) else nonEmptyCurrencies
|
||||
}
|
||||
|
||||
fun getSortType(): TokenList.SortType = if (sortByBalance) TokenList.SortType.BALANCE else TokenList.SortType.NONE
|
||||
|
||||
private fun Raise<Error>.groupTokens(networks: NonEmptySet<Network>): NonEmptySet<NetworkGroup> {
|
||||
private fun Raise<Error>.groupTokens(networks: NonEmptySet<Network>): NonEmptyList<NetworkGroup> {
|
||||
val groupedTokens = currencies
|
||||
.groupBy { it.currency.networkId }
|
||||
.map { (networkId, tokens) ->
|
||||
|
|
@ -66,22 +64,21 @@ internal class TokenListSortingOperations(
|
|||
|
||||
NetworkGroup(
|
||||
network = network,
|
||||
currencies = ensureNotNull(tokens.toNonEmptySetOrNull()) { Error.EmptyTokens },
|
||||
currencies = ensureNotNull(tokens.toNonEmptyListOrNull()) { Error.EmptyTokens },
|
||||
)
|
||||
}
|
||||
.toNonEmptySetOrNull()
|
||||
.toNonEmptyListOrNull()
|
||||
|
||||
return ensureNotNull(groupedTokens) { Error.EmptyTokens }
|
||||
}
|
||||
|
||||
private fun Raise<Error>.groupAndSortTokensByBalance(networks: NonEmptySet<Network>): NonEmptySet<NetworkGroup> {
|
||||
private fun Raise<Error>.groupAndSortTokensByBalance(networks: NonEmptySet<Network>): NonEmptyList<NetworkGroup> {
|
||||
val groupsWithSortedTokens = groupTokens(networks)
|
||||
.map { group ->
|
||||
val tokens = group.currencies as? NonEmptySet<CryptoCurrencyStatus>
|
||||
val tokens = group.currencies as? NonEmptyList<CryptoCurrencyStatus>
|
||||
?: error("Tokens can not be empty here")
|
||||
group.copy(currencies = sortTokensByBalance(tokens))
|
||||
}
|
||||
.toNonEmptySet()
|
||||
|
||||
return if (isAnyTokenLoading) {
|
||||
groupsWithSortedTokens
|
||||
|
|
@ -90,22 +87,22 @@ internal class TokenListSortingOperations(
|
|||
}
|
||||
}
|
||||
|
||||
private fun sortTokensByBalance(tokens: NonEmptySet<CryptoCurrencyStatus>): NonEmptySet<CryptoCurrencyStatus> {
|
||||
private fun sortTokensByBalance(tokens: NonEmptyList<CryptoCurrencyStatus>): NonEmptyList<CryptoCurrencyStatus> {
|
||||
return if (isAnyTokenLoading) {
|
||||
tokens
|
||||
} else {
|
||||
tokens.sortedByDescending { it.value.fiatAmount ?: BigDecimal.ZERO }
|
||||
.toNonEmptySetOrNull()
|
||||
.toNonEmptyListOrNull()
|
||||
?: error("Tokens can not be empty here")
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortGroupsByBalance(groupsWithSortedTokens: NonEmptySet<NetworkGroup>): NonEmptySet<NetworkGroup> {
|
||||
private fun sortGroupsByBalance(groupsWithSortedTokens: NonEmptyList<NetworkGroup>): NonEmptyList<NetworkGroup> {
|
||||
return groupsWithSortedTokens
|
||||
.sortedByDescending { group ->
|
||||
group.currencies.sumOf { it.value.fiatAmount ?: BigDecimal.ZERO }
|
||||
}
|
||||
.toNonEmptySetOrNull()
|
||||
.toNonEmptyListOrNull()
|
||||
?: error("Tokens can not be empty here")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import kotlinx.coroutines.flow.Flow
|
|||
interface CurrenciesRepository {
|
||||
|
||||
/**
|
||||
* Saves the given set of cryptocurrencies, along with the preferences for grouping and sorting, for a specific
|
||||
* Saves the given list of cryptocurrencies, along with the preferences for grouping and sorting, for a specific
|
||||
* multi-currency user wallet.
|
||||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param currencies The set of cryptocurrencies to be saved.
|
||||
* @param currencies The list of cryptocurrencies to be saved.
|
||||
* @param isGroupedByNetwork A boolean flag indicating whether the tokens should be grouped by network.
|
||||
* @param isSortedByBalance A boolean flag indicating whether the tokens should be sorted by balance.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
|
|
@ -22,7 +22,7 @@ interface CurrenciesRepository {
|
|||
*/
|
||||
suspend fun saveTokens(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: Set<CryptoCurrency>,
|
||||
currencies: List<CryptoCurrency>,
|
||||
isGroupedByNetwork: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
)
|
||||
|
|
@ -38,7 +38,7 @@ interface CurrenciesRepository {
|
|||
suspend fun getSingleCurrencyWalletPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency
|
||||
|
||||
/**
|
||||
* Retrieves the set of cryptocurrencies within a multi-currency wallet.
|
||||
* Retrieves the list of cryptocurrencies within a multi-currency wallet.
|
||||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param refresh A boolean flag indicating whether the data should be refreshed.
|
||||
|
|
@ -46,7 +46,7 @@ interface CurrenciesRepository {
|
|||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
fun getMultiCurrencyWalletCurrencies(userWalletId: UserWalletId, refresh: Boolean): Flow<Set<CryptoCurrency>>
|
||||
fun getMultiCurrencyWalletCurrencies(userWalletId: UserWalletId, refresh: Boolean): Flow<List<CryptoCurrency>>
|
||||
|
||||
/**
|
||||
* Retrieves the cryptocurrency for a specific multi-currency user wallet.
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
// When
|
||||
val result = useCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = emptySet(),
|
||||
sortedTokensIds = emptyList(),
|
||||
isGroupedByNetwork = false,
|
||||
isSortedByBalance = false,
|
||||
)
|
||||
|
|
@ -54,7 +54,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
// When
|
||||
val result = useCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = MockTokens.tokens.map { it.networkId to it.id }.toSet(),
|
||||
sortedTokensIds = MockTokens.tokens.map { it.networkId to it.id },
|
||||
isGroupedByNetwork = false,
|
||||
isSortedByBalance = false,
|
||||
)
|
||||
|
|
@ -76,7 +76,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
// When
|
||||
useCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id }.toSet(),
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id },
|
||||
isGroupedByNetwork = expectedIsGrouped,
|
||||
isSortedByBalance = expectedIsSorted,
|
||||
)
|
||||
|
|
@ -100,7 +100,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
// When
|
||||
useCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id }.toSet(),
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id },
|
||||
isGroupedByNetwork = expectedIsGrouped,
|
||||
isSortedByBalance = expectedIsSorted,
|
||||
)
|
||||
|
|
@ -124,7 +124,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
// When
|
||||
useCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id }.toSet(),
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id },
|
||||
isGroupedByNetwork = expectedIsGrouped,
|
||||
isSortedByBalance = expectedIsSorted,
|
||||
)
|
||||
|
|
@ -148,7 +148,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
// When
|
||||
useCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id }.toSet(),
|
||||
sortedTokensIds = expectedTokens.map { it.networkId to it.id },
|
||||
isGroupedByNetwork = expectedIsGrouped,
|
||||
isSortedByBalance = expectedIsSorted,
|
||||
)
|
||||
|
|
@ -170,7 +170,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
// When
|
||||
val result = useCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = getSortedTokens().drop(n = 3).map { it.networkId to it.id }.toSet(),
|
||||
sortedTokensIds = getSortedTokens().drop(n = 3).map { it.networkId to it.id },
|
||||
isGroupedByNetwork = false,
|
||||
isSortedByBalance = false,
|
||||
)
|
||||
|
|
@ -181,7 +181,6 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
|
||||
private fun getSortedTokens() = MockTokens.tokens
|
||||
.sortedBy { Random.nextInt(0, MockTokens.tokens.size) }
|
||||
.toSet()
|
||||
|
||||
private fun getUseCase(tokensRepository: MockCurrenciesRepository = getTokensRepository()) =
|
||||
ApplyTokenListSortingUseCase(
|
||||
|
|
@ -191,7 +190,7 @@ internal class ApplyTokenListSortingUseCaseTest {
|
|||
|
||||
private fun getTokensRepository(
|
||||
sortTokensResult: Either<DataError, Unit> = Unit.right(),
|
||||
tokens: Flow<Either<DataError, Set<CryptoCurrency>>> = flowOf(MockTokens.tokens.right()),
|
||||
tokens: Flow<Either<DataError, List<CryptoCurrency>>> = flowOf(MockTokens.tokens.right()),
|
||||
): MockCurrenciesRepository {
|
||||
return MockCurrenciesRepository(sortTokensResult, MockTokens.token1.right(), tokens, emptyFlow(), emptyFlow())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ internal class GetTokenListUseCaseTest {
|
|||
fun `when tokens is empty then not initialized token list should be received`() = runTest {
|
||||
val expectedResult = MockTokenLists.notInitializedTokenList.right()
|
||||
|
||||
val useCase = getUseCase(tokens = flowOf(emptySet<CryptoCurrency>().right()))
|
||||
val useCase = getUseCase(tokens = flowOf(emptyList<CryptoCurrency>().right()))
|
||||
|
||||
// When
|
||||
val result = useCase(userWalletId).first()
|
||||
|
|
@ -319,7 +319,7 @@ internal class GetTokenListUseCaseTest {
|
|||
}
|
||||
|
||||
private fun getUseCase(
|
||||
tokens: Flow<Either<DataError, Set<CryptoCurrency>>> = flowOf(MockTokens.tokens.right()),
|
||||
tokens: Flow<Either<DataError, List<CryptoCurrency>>> = flowOf(MockTokens.tokens.right()),
|
||||
quotes: Flow<Either<DataError, Set<Quote>>> = flowOf(MockQuotes.quotes.right()),
|
||||
networks: Either<DataError, Set<Network>> = MockNetworks.networks.right(),
|
||||
statuses: Flow<Either<DataError, Set<NetworkStatus>>> = flowOf(MockNetworks.errorNetworksStatuses.right()),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.domain.tokens.mock
|
||||
|
||||
import arrow.core.nonEmptySetOf
|
||||
import arrow.core.toNonEmptySetOrNull
|
||||
import arrow.core.nonEmptyListOf
|
||||
import arrow.core.toNonEmptyListOrNull
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
|
|
@ -11,42 +11,42 @@ internal object MockNetworksGroups {
|
|||
network = MockNetworks.network1,
|
||||
currencies = MockTokensStates.failedTokenStates
|
||||
.filter { it.currency.networkId == MockNetworks.network1.id }
|
||||
.toNonEmptySetOrNull()!!,
|
||||
.toNonEmptyListOrNull()!!,
|
||||
)
|
||||
|
||||
val networkGroup2 = NetworkGroup(
|
||||
network = MockNetworks.network2,
|
||||
currencies = MockTokensStates.failedTokenStates
|
||||
.filter { it.currency.networkId == MockNetworks.network2.id }
|
||||
.toNonEmptySetOrNull()!!,
|
||||
.toNonEmptyListOrNull()!!,
|
||||
)
|
||||
|
||||
val networkGroup3 = NetworkGroup(
|
||||
network = MockNetworks.network3,
|
||||
currencies = MockTokensStates.failedTokenStates
|
||||
.filter { it.currency.networkId == MockNetworks.network3.id }
|
||||
.toNonEmptySetOrNull()!!,
|
||||
.toNonEmptyListOrNull()!!,
|
||||
)
|
||||
|
||||
val failedNetworksGroups = nonEmptySetOf(networkGroup1, networkGroup2, networkGroup3)
|
||||
val failedNetworksGroups = nonEmptyListOf(networkGroup1, networkGroup2, networkGroup3)
|
||||
|
||||
val loadedNetworksGroups = failedNetworksGroups.map { group ->
|
||||
group.copy(
|
||||
currencies = MockTokensStates.loadedTokensStates
|
||||
.filter { it.currency.networkId == group.network.id }
|
||||
.toNonEmptySetOrNull()!!,
|
||||
.toNonEmptyListOrNull()!!,
|
||||
)
|
||||
}.toNonEmptySet()
|
||||
}
|
||||
|
||||
val sortedNetworksGroups = loadedNetworksGroups.map { group ->
|
||||
group.copy(
|
||||
currencies = group.currencies
|
||||
.sortedByDescending { it.value.fiatAmount }
|
||||
.toNonEmptySetOrNull()!!,
|
||||
.toNonEmptyListOrNull()!!,
|
||||
)
|
||||
}
|
||||
.sortedByDescending { group ->
|
||||
group.currencies.sumOf { it.value.fiatAmount!! }
|
||||
}
|
||||
.toNonEmptySetOrNull()!!
|
||||
.toNonEmptyListOrNull()!!
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.domain.tokens.mock
|
||||
|
||||
import arrow.core.NonEmptySet
|
||||
import arrow.core.toNonEmptySetOrNull
|
||||
import arrow.core.NonEmptyList
|
||||
import arrow.core.toNonEmptyListOrNull
|
||||
import com.tangem.domain.tokens.mock.MockNetworksGroups.failedNetworksGroups
|
||||
import com.tangem.domain.tokens.mock.MockNetworksGroups.loadedNetworksGroups
|
||||
import com.tangem.domain.tokens.mock.MockNetworksGroups.sortedNetworksGroups
|
||||
|
|
@ -18,13 +18,13 @@ internal object MockTokenLists {
|
|||
val notInitializedTokenList = TokenList.NotInitialized
|
||||
|
||||
val emptyGroupedTokenList = TokenList.GroupedByNetwork(
|
||||
groups = emptySet(),
|
||||
groups = emptyList(),
|
||||
totalFiatBalance = TokenList.FiatBalance.Failed,
|
||||
sortedBy = TokenList.SortType.NONE,
|
||||
)
|
||||
|
||||
val emptyUngroupedTokenList = TokenList.Ungrouped(
|
||||
currencies = emptySet(),
|
||||
currencies = emptyList(),
|
||||
totalFiatBalance = TokenList.FiatBalance.Failed,
|
||||
sortedBy = TokenList.SortType.NONE,
|
||||
)
|
||||
|
|
@ -43,7 +43,7 @@ internal object MockTokenLists {
|
|||
|
||||
val loadingUngroupedTokenList = with(failedUngroupedTokenList) {
|
||||
copy(
|
||||
currencies = currencies.map { it.copy(value = CryptoCurrencyStatus.Loading) }.toNonEmptySetOrNull()!!,
|
||||
currencies = currencies.map { it.copy(value = CryptoCurrencyStatus.Loading) }.toNonEmptyListOrNull()!!,
|
||||
totalFiatBalance = TokenList.FiatBalance.Loading,
|
||||
)
|
||||
}
|
||||
|
|
@ -55,9 +55,9 @@ internal object MockTokenLists {
|
|||
group.copy(
|
||||
currencies = group.currencies
|
||||
.map { it.copy(value = CryptoCurrencyStatus.Loading) }
|
||||
.toNonEmptySetOrNull()!!,
|
||||
.toNonEmptyListOrNull()!!,
|
||||
)
|
||||
}.toNonEmptySetOrNull()!!,
|
||||
}.toNonEmptyListOrNull()!!,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ internal object MockTokenLists {
|
|||
sortedBy = TokenList.SortType.NONE,
|
||||
totalFiatBalance = TokenList.FiatBalance.Loaded(
|
||||
amount = groups
|
||||
.flatMap { it.currencies as NonEmptySet<CryptoCurrencyStatus> }
|
||||
.flatMap { it.currencies as NonEmptyList<CryptoCurrencyStatus> }
|
||||
.sumOf { it.value.fiatAmount ?: BigDecimal.ZERO },
|
||||
isAllAmountsSummarized = true,
|
||||
),
|
||||
|
|
@ -95,7 +95,7 @@ internal object MockTokenLists {
|
|||
get() {
|
||||
val tokens = MockTokensStates.loadedTokensStates
|
||||
.sortedByDescending { it.value.fiatAmount }
|
||||
.toNonEmptySetOrNull()!!
|
||||
.toNonEmptyListOrNull()!!
|
||||
|
||||
return unsortedUngroupedTokenList.copy(
|
||||
currencies = tokens,
|
||||
|
|
|
|||
|
|
@ -119,5 +119,5 @@ internal object MockTokens {
|
|||
derivationPath = null,
|
||||
)
|
||||
|
||||
val tokens = setOf(token1, token2, token3, token4, token5, token6, token7, token8, token9, token10)
|
||||
val tokens = listOf(token1, token2, token3, token4, token5, token6, token7, token8, token9, token10)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.domain.tokens.mock
|
||||
|
||||
import arrow.core.nonEmptySetOf
|
||||
import arrow.core.nonEmptyListOf
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ internal object MockTokensStates {
|
|||
value = CryptoCurrencyStatus.NoAccount,
|
||||
)
|
||||
|
||||
val failedTokenStates = nonEmptySetOf(
|
||||
val failedTokenStates = nonEmptyListOf(
|
||||
tokenState1,
|
||||
tokenState2,
|
||||
tokenState3,
|
||||
|
|
@ -86,5 +86,5 @@ internal object MockTokensStates {
|
|||
hasTransactionsInProgress = false,
|
||||
),
|
||||
)
|
||||
}.toNonEmptySet()
|
||||
}
|
||||
}
|
||||
|
|
@ -11,12 +11,12 @@ import kotlinx.coroutines.flow.map
|
|||
internal class MockCurrenciesRepository(
|
||||
private val sortTokensResult: Either<DataError, Unit>,
|
||||
private val token: Either<DataError, CryptoCurrency>,
|
||||
private val tokens: Flow<Either<DataError, Set<CryptoCurrency>>>,
|
||||
private val tokens: Flow<Either<DataError, List<CryptoCurrency>>>,
|
||||
private val isGrouped: Flow<Either<DataError, Boolean>>,
|
||||
private val isSortedByBalance: Flow<Either<DataError, Boolean>>,
|
||||
) : CurrenciesRepository {
|
||||
|
||||
var tokensIdsAfterSortingApply: Set<CryptoCurrency>? = null
|
||||
var tokensIdsAfterSortingApply: List<CryptoCurrency>? = null
|
||||
private set
|
||||
|
||||
var isTokensGroupedAfterSortingApply: Boolean? = null
|
||||
|
|
@ -27,7 +27,7 @@ internal class MockCurrenciesRepository(
|
|||
|
||||
override suspend fun saveTokens(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: Set<CryptoCurrency>,
|
||||
currencies: List<CryptoCurrency>,
|
||||
isGroupedByNetwork: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
) {
|
||||
|
|
@ -45,7 +45,7 @@ internal class MockCurrenciesRepository(
|
|||
override fun getMultiCurrencyWalletCurrencies(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean,
|
||||
): Flow<Set<CryptoCurrency>> {
|
||||
): Flow<List<CryptoCurrency>> {
|
||||
return tokens.map { it.getOrElse { e -> throw e } }
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue