Updated on 2026-08-14
This commit is contained in:
parent
e6bb75a1fd
commit
47f5ac82df
8 changed files with 34 additions and 194 deletions
|
|
@ -67,17 +67,6 @@ internal object TokensDomainModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetCardTokensListUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
): GetNodlTokenListUseCase {
|
||||
return GetNodlTokenListUseCase(currenciesRepository, quotesRepository, networksRepository, stakingRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideRemoveCurrencyUseCase(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.plus
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
|
@ -207,8 +206,9 @@ internal class DefaultCurrenciesRepository(
|
|||
if (userWallet.isMultiCurrency) {
|
||||
getMultiCurrencyWalletCurrenciesUpdates(userWalletId).collect(::send)
|
||||
} else {
|
||||
val currency = getSingleCurrencyWalletPrimaryCurrency(userWalletId)
|
||||
send(listOf(currency))
|
||||
val currencies = getSingleCurrencyWalletWithCardCurrencies(userWalletId)
|
||||
|
||||
send(currencies)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -349,26 +349,34 @@ internal class DefaultCurrenciesRepository(
|
|||
|
||||
override fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean> {
|
||||
return channelFlow {
|
||||
ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true)
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
|
||||
launch(dispatchers.io) {
|
||||
if (userWallet.isMultiCurrency) {
|
||||
getSavedUserTokensResponse(userWalletId)
|
||||
.map { it.group == UserTokensResponse.GroupType.NETWORK }
|
||||
.collect(::send)
|
||||
.map { response -> response.group == UserTokensResponse.GroupType.NETWORK }
|
||||
.distinctUntilChanged()
|
||||
.onEach { isGrouped -> send(isGrouped) }
|
||||
.launchIn(scope = this + dispatchers.io)
|
||||
} else {
|
||||
send(element = false)
|
||||
}
|
||||
}.cancellable()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean> {
|
||||
return channelFlow {
|
||||
ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true)
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
|
||||
launch(dispatchers.io) {
|
||||
if (userWallet.isMultiCurrency) {
|
||||
getSavedUserTokensResponse(userWalletId)
|
||||
.map { it.sort == UserTokensResponse.SortType.BALANCE }
|
||||
.collect(::send)
|
||||
.map { response -> response.sort == UserTokensResponse.SortType.BALANCE }
|
||||
.distinctUntilChanged()
|
||||
.onEach { isSorted -> send(isSorted) }
|
||||
.launchIn(scope = this + dispatchers.io)
|
||||
} else {
|
||||
send(element = false)
|
||||
}
|
||||
}.cancellable()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isSendBlockedByPendingTransactions(
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.left
|
||||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToTokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.TokenListOperations
|
||||
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.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
|
||||
/**
|
||||
* Use case for getting a list of tokens for NODL card
|
||||
*
|
||||
* @property currenciesRepository currencies repository
|
||||
* @property quotesRepository quotes repository
|
||||
* @property networksRepository networks repository
|
||||
* @property stakingRepository staking repository
|
||||
*/
|
||||
class GetNodlTokenListUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
operator fun invoke(userWalletId: UserWalletId): EitherFlow<TokenListError, TokenList> {
|
||||
return getTokensStatuses(userWalletId).transformLatest { maybeTokens ->
|
||||
maybeTokens.fold(
|
||||
ifLeft = { error ->
|
||||
emit(error.left())
|
||||
},
|
||||
ifRight = { tokens ->
|
||||
emitAll(createTokenList(userWalletId, tokens))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTokensStatuses(userWalletId: UserWalletId): EitherFlow<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWalletId,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
return operations.getCardCurrenciesStatusesFlow()
|
||||
.map { maybeCurrenciesStatuses ->
|
||||
maybeCurrenciesStatuses.mapLeft(CurrenciesStatusesOperations.Error::mapToTokenListError)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTokenList(
|
||||
userWalletId: UserWalletId,
|
||||
tokens: List<CryptoCurrencyStatus>,
|
||||
): EitherFlow<TokenListError, TokenList> {
|
||||
val operations = TokenListOperations(
|
||||
userWalletId = userWalletId,
|
||||
tokens = tokens,
|
||||
currenciesRepository = currenciesRepository,
|
||||
)
|
||||
|
||||
return operations.getTokenListForSingleCurrencyFlow().map { maybeTokenList ->
|
||||
maybeTokenList.mapLeft(TokenListOperations.Error::mapToTokenListError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -120,50 +120,6 @@ internal class CurrenciesStatusesOperations(
|
|||
return createCurrencyStatus(currency, quotes, networkStatus, yieldBalances)
|
||||
}
|
||||
|
||||
fun getCardCurrenciesStatusesFlow(): Flow<Either<Error, List<CryptoCurrencyStatus>>> {
|
||||
return flow {
|
||||
val nonEmptyCurrencies = recover(
|
||||
block = { getCurrenciesFromCard(userWalletId) },
|
||||
recover = {
|
||||
emit(it.left())
|
||||
return@flow
|
||||
},
|
||||
).toNonEmptyListOrNull()
|
||||
|
||||
if (nonEmptyCurrencies == null) {
|
||||
val emptyCurrenciesStatuses = emptyList<CryptoCurrencyStatus>()
|
||||
|
||||
emit(emptyCurrenciesStatuses.right())
|
||||
return@flow
|
||||
}
|
||||
|
||||
val maybeLoadingCurrenciesStatuses = createCurrenciesStatuses(
|
||||
currencies = nonEmptyCurrencies,
|
||||
maybeNetworkStatuses = null,
|
||||
maybeQuotes = null,
|
||||
maybeYieldBalances = null,
|
||||
)
|
||||
|
||||
emit(maybeLoadingCurrenciesStatuses)
|
||||
|
||||
val (networks, currenciesIds) = getIds(nonEmptyCurrencies)
|
||||
|
||||
val currenciesFlow = combine(
|
||||
getQuotes(currenciesIds),
|
||||
getNetworksStatuses(networks),
|
||||
) { maybeQuotes, maybeNetworksStatuses ->
|
||||
createCurrenciesStatuses(
|
||||
currencies = nonEmptyCurrencies,
|
||||
maybeQuotes = maybeQuotes,
|
||||
maybeNetworkStatuses = maybeNetworksStatuses,
|
||||
maybeYieldBalances = null,
|
||||
)
|
||||
}
|
||||
|
||||
emitAll(currenciesFlow)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusFlow(currencyId: CryptoCurrency.ID): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getMultiCurrencyWalletCurrency(currencyId) },
|
||||
|
|
@ -377,12 +333,6 @@ internal class CurrenciesStatusesOperations(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getCurrenciesFromCard(userWalletId: UserWalletId): List<CryptoCurrency> {
|
||||
return catch({ currenciesRepository.getSingleCurrencyWalletWithCardCurrencies(userWalletId) }) {
|
||||
raise(Error.DataError(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getQuotes(tokensIds: NonEmptySet<CryptoCurrency.ID>): Flow<Either<Error, Set<Quote>>> {
|
||||
return quotesRepository.getQuotesUpdates(tokensIds)
|
||||
.map<Set<Quote>, Either<Error, Set<Quote>>> { quotes ->
|
||||
|
|
|
|||
|
|
@ -29,16 +29,6 @@ internal class TokenListOperations(
|
|||
}
|
||||
}
|
||||
|
||||
fun getTokenListForSingleCurrencyFlow(): Flow<Either<Error, TokenList>> {
|
||||
return flow {
|
||||
emit(
|
||||
either {
|
||||
createTokenList()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Raise<Error>.createTokenList(isGrouped: Boolean, isSortedByBalance: Boolean): TokenList {
|
||||
val nonEmptyCurrencies = tokens.toNonEmptyListOrNull() ?: return TokenList.Empty
|
||||
|
||||
|
|
@ -54,22 +44,6 @@ internal class TokenListOperations(
|
|||
)
|
||||
}
|
||||
|
||||
private fun Raise<Error>.createTokenList(): TokenList {
|
||||
val nonEmptyCurrencies = tokens.toNonEmptyListOrNull()
|
||||
?: return TokenList.Empty
|
||||
|
||||
val isAnyTokenLoading = nonEmptyCurrencies.any { it.value is CryptoCurrencyStatus.Loading }
|
||||
val fiatBalanceOperations = TokenListFiatBalanceOperations(nonEmptyCurrencies, isAnyTokenLoading)
|
||||
|
||||
return createTokenList(
|
||||
currencies = nonEmptyCurrencies,
|
||||
fiatBalance = fiatBalanceOperations.calculateFiatBalance(),
|
||||
isAnyTokenLoading = isAnyTokenLoading,
|
||||
isGrouped = false,
|
||||
isSortedByBalance = false,
|
||||
)
|
||||
}
|
||||
|
||||
private fun Raise<Error>.createTokenList(
|
||||
currencies: NonEmptyList<CryptoCurrencyStatus>,
|
||||
fiatBalance: TotalFiatBalance,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
||||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.tokens.GetNodlTokenListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
|
||||
|
|
@ -23,7 +23,7 @@ internal class SingleWalletWithTokenContentLoader(
|
|||
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
|
||||
private val walletWithFundsChecker: WalletWithFundsChecker,
|
||||
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
|
||||
private val getNodlTokenListUseCase: GetNodlTokenListUseCase,
|
||||
private val tokenListStore: MultiWalletTokenListStore,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) : WalletContentLoader(id = userWallet.walletId) {
|
||||
|
|
@ -36,7 +36,7 @@ internal class SingleWalletWithTokenContentLoader(
|
|||
clickIntents = clickIntents,
|
||||
tokenListAnalyticsSender = tokenListAnalyticsSender,
|
||||
walletWithFundsChecker = walletWithFundsChecker,
|
||||
getNodlTokenListUseCase = getNodlTokenListUseCase,
|
||||
tokenListStore = tokenListStore,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
||||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.tokens.GetNodlTokenListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
|
||||
|
|
@ -19,7 +19,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
|
|||
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
private val walletWithFundsChecker: WalletWithFundsChecker,
|
||||
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
|
||||
private val getNodlTokenListUseCase: GetNodlTokenListUseCase,
|
||||
private val tokenListStore: MultiWalletTokenListStore,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
|
||||
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
|
|
@ -33,7 +33,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
|
|||
tokenListAnalyticsSender = tokenListAnalyticsSender,
|
||||
walletWithFundsChecker = walletWithFundsChecker,
|
||||
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
|
||||
getNodlTokenListUseCase = getNodlTokenListUseCase,
|
||||
tokenListStore = tokenListStore,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
|
|
|
|||
|
|
@ -2,23 +2,21 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers
|
|||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.utils.toLce
|
||||
import com.tangem.domain.tokens.GetNodlTokenListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class SingleWalletWithTokenListSubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val getNodlTokenListUseCase: GetNodlTokenListUseCase,
|
||||
private val tokenListStore: MultiWalletTokenListStore,
|
||||
stateHolder: WalletStateController,
|
||||
clickIntents: WalletClickIntents,
|
||||
tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
|
|
@ -35,9 +33,9 @@ internal class SingleWalletWithTokenListSubscriber(
|
|||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
) {
|
||||
|
||||
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> =
|
||||
getNodlTokenListUseCase(
|
||||
userWallet.walletId,
|
||||
)
|
||||
.map { it.toLce() }
|
||||
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
|
||||
tokenListStore.addIfNot(userWallet.walletId, coroutineScope)
|
||||
|
||||
return tokenListStore.getOrThrow(userWallet.walletId)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue