Updated on 2026-08-14

This commit is contained in:
Tangem 2024-05-29 15:51:45 +04:00
parent 8491f524b9
commit 3519edfbfd
6 changed files with 154 additions and 2 deletions

View file

@ -356,4 +356,18 @@ internal object TokensDomainModule {
networksRepository = networksRepository,
)
}
@Provides
@Singleton
fun provideGetWalletTotalBalanceUseCase(
currenciesRepository: CurrenciesRepository,
quotesRepository: QuotesRepository,
networksRepository: NetworksRepository,
): GetWalletTotalBalanceUseCase {
return GetWalletTotalBalanceUseCase(
currenciesRepository = currenciesRepository,
quotesRepository = quotesRepository,
networksRepository = networksRepository,
)
}
}

View file

@ -173,6 +173,23 @@ internal class DefaultCurrenciesRepository(
}
}
override fun getWalletCurrenciesUpdates(userWalletId: UserWalletId): LceFlow<Throwable, List<CryptoCurrency>> {
return lceFlow {
val userWallet = catch({ getUserWallet(userWalletId) }) {
raise(it)
}
if (userWallet.isMultiCurrency) {
getMultiCurrencyWalletCurrenciesUpdatesLce(userWalletId).collect(::send)
} else {
val currency = catch({ getSingleCurrencyWalletPrimaryCurrency(userWalletId) }) {
raise(it)
}
send(listOf(currency))
}
}
}
override suspend fun getSingleCurrencyWalletPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency {
return withContext(dispatchers.io) {
val userWallet = getUserWallet(userWalletId)

View file

@ -0,0 +1,82 @@
package com.tangem.domain.tokens
import arrow.core.raise.ensureNotNull
import arrow.core.toNonEmptyListOrNull
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.core.lce.lce
import com.tangem.domain.core.utils.lceLoading
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.tokens.operations.CurrenciesStatusesLceOperations
import com.tangem.domain.tokens.operations.TokenListFiatBalanceOperations
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.transform
class GetWalletTotalBalanceUseCase(
private val currenciesRepository: CurrenciesRepository,
private val quotesRepository: QuotesRepository,
private val networksRepository: NetworksRepository,
) {
suspend operator fun invoke(
userWallestIds: Collection<UserWalletId>,
): LceFlow<TokenListError, Map<UserWalletId, TotalFiatBalance>> {
val flows = userWallestIds.distinct()
.map { userWalletId ->
invoke(userWalletId).map { maybeBalance ->
userWalletId to maybeBalance
}
}
return combine(flows) { balances ->
lce {
balances.associate { (userWalletId, maybeBalance) ->
userWalletId to maybeBalance.bind()
}
}
}
}
suspend operator fun invoke(userWalletId: UserWalletId): LceFlow<TokenListError, TotalFiatBalance> {
val currenciesStatuses = getStatuses(userWalletId)
return currenciesStatuses.transform { maybeStatuses ->
val balance = createBalance(maybeStatuses)
emit(balance)
}
}
private fun createBalance(
maybeStatuses: Lce<TokenListError, List<CryptoCurrencyStatus>>,
): Lce<TokenListError, TotalFiatBalance> = lce {
val statuses = maybeStatuses.bind()
val operations = TokenListFiatBalanceOperations(
currencies = ensureNotNull(statuses.toNonEmptyListOrNull()) { lceLoading() },
isAnyTokenLoading = false,
)
operations.calculateFiatBalance()
}
private fun getStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
val operations = CurrenciesStatusesLceOperations(
currenciesRepository = currenciesRepository,
quotesRepository = quotesRepository,
networksRepository = networksRepository,
)
return operations.getCurrenciesStatuses(
userWalletId = userWalletId,
isSingleCurrencyWalletsAllowed = true,
)
}
}

View file

@ -21,8 +21,25 @@ internal class CurrenciesStatusesLceOperations(
private val networksRepository: NetworksRepository,
) {
fun getCurrenciesStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
return getMultiCurrencyWalletCurrencies(userWalletId).transform transform@{ maybeCurrencies ->
fun getCurrenciesStatuses(
userWalletId: UserWalletId,
isSingleCurrencyWalletsAllowed: Boolean = false,
): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
return transformToCurrenciesStatuses(
userWalletId = userWalletId,
flow = if (isSingleCurrencyWalletsAllowed) {
getWalletCurrenies(userWalletId)
} else {
getMultiCurrencyWalletCurrencies(userWalletId)
},
)
}
private fun transformToCurrenciesStatuses(
userWalletId: UserWalletId,
flow: LceFlow<TokenListError, List<CryptoCurrency>>,
): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
return flow.transform transform@{ maybeCurrencies ->
val nonEmptyCurrencies = maybeCurrencies.fold(
ifLoading = { maybeContent ->
emit(createLoadingCurrenciesStatuses(maybeContent))
@ -74,6 +91,13 @@ internal class CurrenciesStatusesLceOperations(
return statuses
}
private fun getWalletCurrenies(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrency>> {
return currenciesRepository.getWalletCurrenciesUpdates(userWalletId)
.map { maybeCurrencies ->
maybeCurrencies.mapError { TokenListError.DataError(it) }
}
}
private fun getMultiCurrencyWalletCurrencies(
userWalletId: UserWalletId,
): LceFlow<TokenListError, List<CryptoCurrency>> {

View file

@ -62,6 +62,17 @@ interface CurrenciesRepository {
*/
suspend fun removeCurrencies(userWalletId: UserWalletId, currencies: List<CryptoCurrency>)
/**
* Retrieves the list of cryptocurrencies within a user wallet.
*
* This method returns a list of cryptocurrencies associated with the user wallet regardless of whether
* it is a multi-currency or single-currency wallet.
*
* @param userWalletId The unique identifier of the user wallet.
* @return A list of [CryptoCurrency].
*/
fun getWalletCurrenciesUpdates(userWalletId: UserWalletId): LceFlow<Throwable, List<CryptoCurrency>>
/**
* Retrieves the primary cryptocurrency for a specific single-currency user wallet.
*

View file

@ -54,6 +54,10 @@ internal class MockCurrenciesRepository(
override suspend fun removeCurrencies(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) = Unit
override fun getWalletCurrenciesUpdates(userWalletId: UserWalletId): LceFlow<Throwable, List<CryptoCurrency>> {
return emptyFlow()
}
override suspend fun getMultiCurrencyWalletCurrenciesSync(
userWalletId: UserWalletId,
refresh: Boolean,