Updated on 2026-08-14
This commit is contained in:
commit
d54f8452b6
6 changed files with 511 additions and 5 deletions
|
|
@ -1,19 +1,24 @@
|
|||
// TODO: [REDACTED_JIRA]
|
||||
@file:Suppress("unused", "unused_parameter")
|
||||
|
||||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.recover
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.tokens.error.TokensError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.model.TokenStatus
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.tokens.repository.TokensRepository
|
||||
import com.tangem.domain.tokens.utils.TokenListFiatBalanceOperations
|
||||
import com.tangem.domain.tokens.utils.TokenListOperations
|
||||
import com.tangem.domain.tokens.utils.TokensStatusesOperations
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.flatMapConcat
|
||||
|
||||
class GetTokenListUseCase(
|
||||
private val tokensRepository: TokensRepository,
|
||||
|
|
@ -23,6 +28,66 @@ class GetTokenListUseCase(
|
|||
) {
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId, refresh: Boolean = true): Flow<Either<TokensError, TokenList>> {
|
||||
return flowOf(TokensError.EmptyTokens.left())
|
||||
return channelFlow {
|
||||
recover(
|
||||
block = {
|
||||
getTokenList(userWalletId, refresh).collect { list ->
|
||||
send(list.right())
|
||||
}
|
||||
},
|
||||
recover = { error ->
|
||||
send(error.left())
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
private fun Raise<TokensError>.getTokenList(userWalletId: UserWalletId, refresh: Boolean): Flow<TokenList> {
|
||||
return getTokensStatuses(userWalletId, refresh).flatMapConcat { tokens ->
|
||||
createTokenList(userWalletId, tokens)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Raise<TokensError>.getTokensStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean,
|
||||
): Flow<Set<TokenStatus>> {
|
||||
val operations = TokensStatusesOperations(
|
||||
tokensRepository,
|
||||
quotesRepository,
|
||||
networksRepository,
|
||||
userWalletId,
|
||||
refresh,
|
||||
dispatchers,
|
||||
raise = this,
|
||||
)
|
||||
|
||||
return operations.getTokensStatusesFlow()
|
||||
}
|
||||
|
||||
private suspend fun Raise<TokensError>.createTokenList(
|
||||
userWalletId: UserWalletId,
|
||||
tokens: Set<TokenStatus>,
|
||||
): Flow<TokenList> {
|
||||
val isAnyTokenLoading = tokens.any { it.value is TokenStatus.Loading }
|
||||
val operations = TokenListOperations(
|
||||
tokensRepository,
|
||||
networksRepository,
|
||||
userWalletId,
|
||||
calculateFiatBalance(tokens, isAnyTokenLoading),
|
||||
isAnyTokenLoading,
|
||||
dispatchers,
|
||||
raise = this,
|
||||
)
|
||||
|
||||
return operations.getTokenListFlow(tokens)
|
||||
}
|
||||
|
||||
private suspend fun calculateFiatBalance(
|
||||
tokens: Set<TokenStatus>,
|
||||
isAnyTokenLoading: Boolean,
|
||||
): TokenList.FiatBalance {
|
||||
val operations = TokenListFiatBalanceOperations(tokens, isAnyTokenLoading, dispatchers)
|
||||
|
||||
return operations.calculateFiatBalance()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,21 @@
|
|||
package com.tangem.domain.tokens.error
|
||||
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.Token
|
||||
|
||||
sealed class TokensError {
|
||||
|
||||
object EmptyTokens : TokensError()
|
||||
|
||||
object EmptyQuotes : TokensError()
|
||||
|
||||
object EmptyNetworks : TokensError()
|
||||
|
||||
object EmptyNetworkStatues : TokensError()
|
||||
|
||||
data class TokenAmountNotFound(val tokenId: Token.ID) : TokensError()
|
||||
|
||||
data class TokenFiatAmountLessThenZero(val tokenId: Token.ID) : TokensError()
|
||||
|
||||
data class NetworkNotFound(val networkId: Network.ID) : TokensError()
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package com.tangem.domain.tokens.utils
|
||||
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.model.TokenStatus
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class TokenListFiatBalanceOperations(
|
||||
private val tokens: Set<TokenStatus>,
|
||||
private val isAnyTokenLoading: Boolean,
|
||||
private val dispatcher: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
suspend fun calculateFiatBalance(): TokenList.FiatBalance {
|
||||
return withContext(dispatcher.single) {
|
||||
var fiatBalance: TokenList.FiatBalance = TokenList.FiatBalance.Loading
|
||||
if (tokens.isEmpty() || isAnyTokenLoading) return@withContext fiatBalance
|
||||
|
||||
for (token in tokens) {
|
||||
when (val status = token.value) {
|
||||
is TokenStatus.Loading -> {
|
||||
fiatBalance = TokenList.FiatBalance.Loading
|
||||
break
|
||||
}
|
||||
is TokenStatus.MissedDerivation,
|
||||
is TokenStatus.Unreachable,
|
||||
-> {
|
||||
fiatBalance = TokenList.FiatBalance.Failed
|
||||
break
|
||||
}
|
||||
is TokenStatus.NoAccount -> {
|
||||
fiatBalance = recalculateBalanceForNoAccountStatus(fiatBalance)
|
||||
}
|
||||
is TokenStatus.Loaded -> {
|
||||
fiatBalance = recalculateBalance(status, fiatBalance)
|
||||
}
|
||||
is TokenStatus.Custom -> {
|
||||
fiatBalance = recalculateBalance(status, fiatBalance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fiatBalance
|
||||
}
|
||||
}
|
||||
private fun recalculateBalanceForNoAccountStatus(currentBalance: TokenList.FiatBalance): TokenList.FiatBalance {
|
||||
return with(currentBalance) {
|
||||
(this as? TokenList.FiatBalance.Loaded)?.copy(
|
||||
isAllAmountsSummarized = false,
|
||||
) ?: TokenList.FiatBalance.Loaded(
|
||||
amount = BigDecimal.ZERO,
|
||||
isAllAmountsSummarized = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun recalculateBalance(
|
||||
status: TokenStatus.Loaded,
|
||||
currentBalance: TokenList.FiatBalance,
|
||||
): TokenList.FiatBalance {
|
||||
return with(currentBalance) {
|
||||
(this as? TokenList.FiatBalance.Loaded)?.copy(
|
||||
amount = this.amount + status.fiatAmount,
|
||||
) ?: TokenList.FiatBalance.Loaded(
|
||||
amount = status.fiatAmount,
|
||||
isAllAmountsSummarized = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun recalculateBalance(
|
||||
status: TokenStatus.Custom,
|
||||
currentBalance: TokenList.FiatBalance,
|
||||
): TokenList.FiatBalance {
|
||||
return with(currentBalance) {
|
||||
val isTokenAmountCanBeSummarized = status.fiatAmount != null
|
||||
|
||||
(this as? TokenList.FiatBalance.Loaded)?.copy(
|
||||
amount = this.amount + (status.fiatAmount ?: BigDecimal.ZERO),
|
||||
isAllAmountsSummarized = isTokenAmountCanBeSummarized,
|
||||
) ?: TokenList.FiatBalance.Loaded(
|
||||
amount = status.fiatAmount ?: BigDecimal.ZERO,
|
||||
isAllAmountsSummarized = isTokenAmountCanBeSummarized,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package com.tangem.domain.tokens.utils
|
||||
|
||||
import arrow.core.NonEmptySet
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.ensureNotNull
|
||||
import arrow.core.toNonEmptySetOrNull
|
||||
import com.tangem.domain.tokens.error.TokensError
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.model.TokenStatus
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.TokensRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenListOperations(
|
||||
private val tokensRepository: TokensRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val userWalletId: UserWalletId,
|
||||
private val totalFiatBalance: TokenList.FiatBalance,
|
||||
private val isAnyTokenLoading: Boolean,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
raise: Raise<TokensError>,
|
||||
) : Raise<TokensError> by raise {
|
||||
|
||||
fun getTokenListFlow(tokens: Set<TokenStatus>): Flow<TokenList> {
|
||||
return combine(getIsGrouped(), getIsSortedByBalance()) { isGrouped, isSortedByBalance ->
|
||||
createTokenList(tokens, isGrouped, isSortedByBalance)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createTokenList(
|
||||
tokens: Set<TokenStatus>,
|
||||
isGrouped: Boolean,
|
||||
isSortedByBalance: Boolean,
|
||||
): TokenList = withContext(dispatchers.single) {
|
||||
val tokensNes = tokens.toNonEmptySetOrNull()
|
||||
|
||||
when {
|
||||
tokensNes == null -> TokenList.NotInitialized
|
||||
isGrouped -> {
|
||||
val networks = getNetworks(tokensNes)
|
||||
|
||||
createGroupedTokenList(tokensNes, networks, isSortedByBalance)
|
||||
}
|
||||
else -> createUngroupedTokenList(tokensNes, isSortedByBalance)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createUngroupedTokenList(
|
||||
tokens: NonEmptySet<TokenStatus>,
|
||||
isSortedByBalance: Boolean,
|
||||
): TokenList.Ungrouped {
|
||||
return TokenList.Ungrouped(
|
||||
sortedBy = getSortType(isSortedByBalance),
|
||||
totalFiatBalance = totalFiatBalance,
|
||||
tokens = if (isSortedByBalance) sortTokensByBalance(tokens) else tokens,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createGroupedTokenList(
|
||||
tokens: NonEmptySet<TokenStatus>,
|
||||
networks: NonEmptySet<Network>,
|
||||
isSortedByBalance: Boolean,
|
||||
): TokenList.GroupedByNetwork {
|
||||
return TokenList.GroupedByNetwork(
|
||||
sortedBy = getSortType(isSortedByBalance),
|
||||
totalFiatBalance = totalFiatBalance,
|
||||
groups = if (isSortedByBalance) groupAndSortTokens(tokens, networks) else groupTokens(tokens, networks),
|
||||
)
|
||||
}
|
||||
|
||||
private fun groupAndSortTokens(
|
||||
tokens: NonEmptySet<TokenStatus>,
|
||||
networks: NonEmptySet<Network>,
|
||||
): NonEmptySet<NetworkGroup> {
|
||||
val groupsWithSortedTokens = groupTokens(tokens, networks)
|
||||
.map { group ->
|
||||
group.copy(tokens = sortTokensByBalance(group.tokens))
|
||||
}
|
||||
val sortedGroups = if (isAnyTokenLoading) {
|
||||
groupsWithSortedTokens
|
||||
} else {
|
||||
sortGroupsByBalance(groupsWithSortedTokens)
|
||||
}
|
||||
|
||||
return sortedGroups
|
||||
}
|
||||
|
||||
private fun sortTokensByBalance(tokens: NonEmptySet<TokenStatus>): NonEmptySet<TokenStatus> {
|
||||
val sortedTokens = if (isAnyTokenLoading) {
|
||||
tokens
|
||||
} else {
|
||||
tokens
|
||||
.sortedByDescending { it.value.fiatAmount ?: BigDecimal.ZERO }
|
||||
.toNonEmptySetOrNull()
|
||||
}
|
||||
|
||||
return sortedTokens!!
|
||||
}
|
||||
|
||||
private fun groupTokens(
|
||||
tokens: NonEmptySet<TokenStatus>,
|
||||
networks: NonEmptySet<Network>,
|
||||
): NonEmptySet<NetworkGroup> {
|
||||
val groups = tokens
|
||||
.groupBy { it.networkId }
|
||||
.map { (networkId, tokens) ->
|
||||
val network = ensureNotNull(networks.firstOrNull { it.id == networkId }) {
|
||||
TokensError.NetworkNotFound(networkId)
|
||||
}
|
||||
|
||||
NetworkGroup(
|
||||
networkId = network.id,
|
||||
name = network.name,
|
||||
tokens = tokens.toNonEmptySetOrNull()!!,
|
||||
)
|
||||
}
|
||||
.toNonEmptySetOrNull()
|
||||
|
||||
return groups!!
|
||||
}
|
||||
|
||||
private suspend fun getNetworks(tokens: NonEmptySet<TokenStatus>): NonEmptySet<Network> {
|
||||
return withContext(dispatchers.io) {
|
||||
val networks = networksRepository.getNetworks(tokens.map { it.networkId }).bind()
|
||||
ensureNotNull(networks.toNonEmptySetOrNull()) { TokensError.EmptyNetworks }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIsGrouped(): Flow<Boolean> {
|
||||
return tokensRepository.isTokensGrouped(userWalletId)
|
||||
.map { it.bind() }
|
||||
.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private fun getIsSortedByBalance(): Flow<Boolean> {
|
||||
return tokensRepository.isTokensSortedByBalance(userWalletId)
|
||||
.map { it.bind() }
|
||||
.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private fun sortGroupsByBalance(groupsWithSortedTokens: NonEmptySet<NetworkGroup>): NonEmptySet<NetworkGroup> {
|
||||
return groupsWithSortedTokens
|
||||
.sortedByDescending { group ->
|
||||
group.tokens.sumOf { it.value.fiatAmount ?: BigDecimal.ZERO }
|
||||
}
|
||||
.toNonEmptySetOrNull()!!
|
||||
}
|
||||
|
||||
private fun getSortType(isSortedByBalance: Boolean) =
|
||||
if (isSortedByBalance) TokenList.SortType.BALANCE else TokenList.SortType.NONE
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package com.tangem.domain.tokens.utils
|
||||
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.ensure
|
||||
import arrow.core.raise.ensureNotNull
|
||||
import com.tangem.domain.tokens.error.TokensError
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.Token
|
||||
import com.tangem.domain.tokens.model.TokenStatus
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class TokenStatusOperations(
|
||||
private val token: Token,
|
||||
private val quote: Quote?,
|
||||
private val networkStatus: NetworkStatus?,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
raise: Raise<TokensError>,
|
||||
) : Raise<TokensError> by raise {
|
||||
|
||||
suspend fun createTokenStatus(): TokenStatus = withContext(dispatchers.single) {
|
||||
TokenStatus(
|
||||
id = token.id,
|
||||
networkId = token.networkId,
|
||||
name = token.name,
|
||||
symbol = token.symbol,
|
||||
isCoin = token.isCoin,
|
||||
value = createStatus(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createStatus(): TokenStatus.Status {
|
||||
return when (val status = networkStatus?.value) {
|
||||
null -> TokenStatus.Loading
|
||||
is NetworkStatus.MissedDerivation -> TokenStatus.MissedDerivation
|
||||
is NetworkStatus.Unreachable -> TokenStatus.Unreachable
|
||||
is NetworkStatus.NoAccount -> TokenStatus.NoAccount
|
||||
is NetworkStatus.TransactionInProgress,
|
||||
is NetworkStatus.Verified,
|
||||
-> createStatus(
|
||||
amount = getTokenAmount(),
|
||||
hasTransactionsInProgress = status is NetworkStatus.TransactionInProgress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStatus(amount: BigDecimal, hasTransactionsInProgress: Boolean): TokenStatus.Status {
|
||||
return when {
|
||||
token.isCustom -> TokenStatus.Custom(
|
||||
amount = amount,
|
||||
fiatAmount = calculateFiatAmountOrNull(amount, quote?.fiatRate),
|
||||
priceChange = quote?.priceChange,
|
||||
hasTransactionsInProgress = hasTransactionsInProgress,
|
||||
)
|
||||
quote == null -> TokenStatus.Loading
|
||||
else -> TokenStatus.Loaded(
|
||||
amount = amount,
|
||||
fiatAmount = calculateFiatAmount(amount, quote.fiatRate),
|
||||
priceChange = quote.priceChange,
|
||||
hasTransactionsInProgress = hasTransactionsInProgress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTokenAmount(): BigDecimal {
|
||||
val amount = networkStatus?.value?.amounts?.get(token.id)
|
||||
return ensureNotNull(amount) { TokensError.TokenAmountNotFound(token.id) }
|
||||
}
|
||||
|
||||
private fun calculateFiatAmountOrNull(amount: BigDecimal, fiatRate: BigDecimal?): BigDecimal? {
|
||||
if (fiatRate == null) return null
|
||||
|
||||
return calculateFiatAmount(amount, fiatRate)
|
||||
}
|
||||
|
||||
private fun calculateFiatAmount(amount: BigDecimal, fiatRate: BigDecimal): BigDecimal {
|
||||
val fiatAmount = amount * fiatRate
|
||||
ensure(condition = fiatAmount >= BigDecimal.ZERO) { TokensError.TokenFiatAmountLessThenZero(token.id) }
|
||||
|
||||
return fiatAmount
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.tangem.domain.tokens.utils
|
||||
|
||||
import arrow.core.NonEmptySet
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.toNonEmptySetOrNull
|
||||
import com.tangem.domain.tokens.error.TokensError
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.tokens.repository.TokensRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokensStatusesOperations(
|
||||
private val tokensRepository: TokensRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val userWalletId: UserWalletId,
|
||||
private val refresh: Boolean,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
raise: Raise<TokensError>,
|
||||
) : Raise<TokensError> by raise {
|
||||
|
||||
fun getTokensStatusesFlow(): Flow<Set<TokenStatus>> {
|
||||
return getTokens().flatMapConcat {
|
||||
val tokens = it.toNonEmptySetOrNull()
|
||||
|
||||
if (tokens == null) {
|
||||
flowOf(emptySet())
|
||||
} else {
|
||||
val tokensIds = tokens.map { token -> token.id }
|
||||
val groupedTokens = groupTokens(tokens)
|
||||
|
||||
combine(getQuotes(tokensIds), getNetworksStatues(groupedTokens)) { quotes, networksStatuses ->
|
||||
createTokensStatuses(tokens, quotes, networksStatuses)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createTokensStatuses(
|
||||
tokens: Set<Token>,
|
||||
quotes: Set<Quote>,
|
||||
networkStatuses: Set<NetworkStatus>,
|
||||
): Set<TokenStatus> = withContext(dispatchers.single) {
|
||||
tokens.map { token ->
|
||||
val quote = quotes.firstOrNull { it.tokenId == token.id }
|
||||
val networkStatus = networkStatuses.firstOrNull { it.networkId == token.networkId }
|
||||
|
||||
createStatus(token, quote, networkStatus)
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
private suspend fun createStatus(token: Token, quote: Quote?, networkStatus: NetworkStatus?): TokenStatus {
|
||||
val operations = TokenStatusOperations(token, quote, networkStatus, dispatchers, raise = this)
|
||||
return operations.createTokenStatus()
|
||||
}
|
||||
|
||||
private fun getTokens(): Flow<Set<Token>> {
|
||||
return tokensRepository.getTokens(userWalletId, refresh)
|
||||
.onEmpty { raise(TokensError.EmptyTokens) }
|
||||
.map { it.bind() }
|
||||
.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private fun getQuotes(tokensIds: NonEmptySet<Token.ID>): Flow<Set<Quote>> {
|
||||
return quotesRepository.getQuotes(tokensIds, refresh)
|
||||
.onEmpty { raise(TokensError.EmptyQuotes) }
|
||||
.map { it.bind() }
|
||||
.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private fun getNetworksStatues(groupedTokens: Map<Network.ID, NonEmptySet<Token.ID>>): Flow<Set<NetworkStatus>> {
|
||||
return networksRepository.getNetworkStatuses(userWalletId, groupedTokens, refresh)
|
||||
.onEmpty { raise(TokensError.EmptyNetworkStatues) }
|
||||
.map { it.bind() }
|
||||
.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private suspend fun groupTokens(tokens: NonEmptySet<Token>): Map<Network.ID, NonEmptySet<Token.ID>> =
|
||||
withContext(dispatchers.single) {
|
||||
tokens
|
||||
.groupBy { it.networkId }
|
||||
.mapValues { (_, tokens) ->
|
||||
tokens.toNonEmptySetOrNull()
|
||||
?.map { it.id }
|
||||
?: raise(TokensError.EmptyTokens)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue