diff --git a/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt index c3520a41cf..8d32208885 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt @@ -7,6 +7,7 @@ import com.tangem.domain.managetokens.repository.ManageTokensRepository import com.tangem.domain.staking.repositories.StakingRepository 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.walletmanager.WalletManagersFacade import dagger.Module import dagger.Provides @@ -67,6 +68,7 @@ internal object ManageTokensDomainModule { networksRepository: NetworksRepository, derivationsRepository: DerivationsRepository, stakingRepository: StakingRepository, + quotesRepository: QuotesRepository, ): SaveManagedTokensUseCase { return SaveManagedTokensUseCase( customTokensRepository = customTokensRepository, @@ -75,6 +77,7 @@ internal object ManageTokensDomainModule { networksRepository = networksRepository, derivationsRepository = derivationsRepository, stakingRepository = stakingRepository, + quotesRepository = quotesRepository, ) } diff --git a/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt index 4498836964..72b1e2451c 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt @@ -4,6 +4,7 @@ import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.domain.card.repository.DerivationsRepository import com.tangem.domain.markets.* import com.tangem.domain.markets.repositories.MarketsTokenRepository +import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository import com.tangem.domain.tokens.repository.QuotesRepository @@ -57,12 +58,16 @@ object MarketsDomainModule { marketsTokenRepository: MarketsTokenRepository, currenciesRepository: CurrenciesRepository, networksRepository: NetworksRepository, + stakingRepository: StakingRepository, + quotesRepository: QuotesRepository, ): SaveMarketTokensUseCase { return SaveMarketTokensUseCase( derivationsRepository = derivationsRepository, marketsTokenRepository = marketsTokenRepository, currenciesRepository = currenciesRepository, networksRepository = networksRepository, + stakingRepository = stakingRepository, + quotesRepository = quotesRepository, ) } diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index b719015a7a..73ecbf344e 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -27,10 +27,14 @@ internal object TokensDomainModule { fun provideAddCryptoCurrenciesUseCase( currenciesRepository: CurrenciesRepository, networksRepository: NetworksRepository, + stakingRepository: StakingRepository, + quotesRepository: QuotesRepository, ): AddCryptoCurrenciesUseCase { return AddCryptoCurrenciesUseCase( currenciesRepository = currenciesRepository, networksRepository = networksRepository, + stakingRepository = stakingRepository, + quotesRepository = quotesRepository, ) } diff --git a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt index 4143444b7b..1cec10d0c1 100644 --- a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt +++ b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt @@ -10,9 +10,11 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.Network 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.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWalletId +@Suppress("LongParameterList") class SaveManagedTokensUseCase( private val customTokensRepository: CustomTokensRepository, private val walletManagersFacade: WalletManagersFacade, @@ -20,6 +22,7 @@ class SaveManagedTokensUseCase( private val networksRepository: NetworksRepository, private val derivationsRepository: DerivationsRepository, private val stakingRepository: StakingRepository, + private val quotesRepository: QuotesRepository, ) { suspend operator fun invoke( @@ -54,6 +57,8 @@ class SaveManagedTokensUseCase( ) refreshUpdatedYieldBalances(userWalletId, existingCurrencies) + + refreshUpdatedQuotes(addingCurrencies) } private suspend fun removeCurrenciesFromWalletManager( @@ -105,6 +110,13 @@ class SaveManagedTokensUseCase( ) } + private suspend fun refreshUpdatedQuotes(addedCurrencies: List) { + quotesRepository.fetchQuotes( + currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId }, + refresh = true, + ) + } + /** * Determines if the [existingCurrencies] list contains a coin that corresponds * to the given [network]. diff --git a/domain/markets/build.gradle.kts b/domain/markets/build.gradle.kts index b3d59216c4..f5a22e3d18 100644 --- a/domain/markets/build.gradle.kts +++ b/domain/markets/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { api(projects.domain.models) api(projects.domain.legacy) api(projects.domain.wallets) + api(projects.domain.staking) implementation(projects.domain.tokens.models) implementation(projects.domain.tokens) diff --git a/domain/markets/src/main/java/com/tangem/domain/markets/SaveMarketTokensUseCase.kt b/domain/markets/src/main/java/com/tangem/domain/markets/SaveMarketTokensUseCase.kt index f5b43a9bee..352fb55d85 100644 --- a/domain/markets/src/main/java/com/tangem/domain/markets/SaveMarketTokensUseCase.kt +++ b/domain/markets/src/main/java/com/tangem/domain/markets/SaveMarketTokensUseCase.kt @@ -3,10 +3,12 @@ package com.tangem.domain.markets import arrow.core.Either import com.tangem.domain.card.repository.DerivationsRepository import com.tangem.domain.markets.repositories.MarketsTokenRepository +import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.Network 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 /** @@ -23,6 +25,8 @@ class SaveMarketTokensUseCase( private val marketsTokenRepository: MarketsTokenRepository, private val currenciesRepository: CurrenciesRepository, private val networksRepository: NetworksRepository, + private val stakingRepository: StakingRepository, + private val quotesRepository: QuotesRepository, ) { suspend operator fun invoke( @@ -60,11 +64,37 @@ class SaveMarketTokensUseCase( currenciesRepository.addCurrencies(userWalletId = userWalletId, currencies = addedCurrencies) - networksRepository.getNetworkStatusesSync( - userWalletId = userWalletId, - networks = addedCurrencies.map(CryptoCurrency::network).toSet(), - refresh = true, - ) + refreshUpdatedNetworks(userWalletId, addedCurrencies) + + refreshUpdatedYieldBalances(userWalletId, addedCurrencies) + + refreshUpdatedQuotes(addedCurrencies) } } + + private suspend fun refreshUpdatedNetworks(userWalletId: UserWalletId, addedCurrencies: List) { + networksRepository.getNetworkStatusesSync( + userWalletId = userWalletId, + networks = addedCurrencies.map(CryptoCurrency::network).toSet(), + refresh = true, + ) + } + + private suspend fun refreshUpdatedYieldBalances( + userWalletId: UserWalletId, + existingCurrencies: List, + ) { + stakingRepository.fetchMultiYieldBalance( + userWalletId = userWalletId, + cryptoCurrencies = existingCurrencies, + refresh = true, + ) + } + + private suspend fun refreshUpdatedQuotes(addedCurrencies: List) { + quotesRepository.fetchQuotes( + currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId }, + refresh = true, + ) + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt index 01223c61a3..370a29ee8e 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt @@ -5,10 +5,12 @@ import arrow.core.raise.Raise import arrow.core.raise.catch import arrow.core.raise.either import arrow.core.toNonEmptyListOrNull +import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.Network 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 /** @@ -21,6 +23,8 @@ import com.tangem.domain.wallets.models.UserWalletId class AddCryptoCurrenciesUseCase( private val currenciesRepository: CurrenciesRepository, private val networksRepository: NetworksRepository, + private val stakingRepository: StakingRepository, + private val quotesRepository: QuotesRepository, ) { /** @@ -105,6 +109,8 @@ class AddCryptoCurrenciesUseCase( val tokenToAdd = createTokenCurrency(userWalletId, contractAddress, networkId) addCurrencies(userWalletId, listOf(tokenToAdd)) refreshUpdatedNetworks(userWalletId, listOf(tokenToAdd), existingCurrencies) + refreshUpdatedYieldBalances(userWalletId, existingCurrencies) + refreshUpdatedQuotes(existingCurrencies) tokenToAdd } @@ -139,6 +145,24 @@ class AddCryptoCurrenciesUseCase( } } + private suspend fun refreshUpdatedYieldBalances( + userWalletId: UserWalletId, + existingCurrencies: List, + ) { + stakingRepository.fetchMultiYieldBalance( + userWalletId = userWalletId, + cryptoCurrencies = existingCurrencies, + refresh = true, + ) + } + + private suspend fun refreshUpdatedQuotes(addedCurrencies: List) { + quotesRepository.fetchQuotes( + currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId }, + refresh = true, + ) + } + private suspend fun Raise.createTokenCurrency( userWalletId: UserWalletId, contractAddress: String, diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt index 739ad63738..a14f37e601 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt @@ -7,6 +7,7 @@ import com.tangem.domain.core.lce.LceFlow import com.tangem.domain.core.lce.lce import com.tangem.domain.core.lce.lceFlow import com.tangem.domain.core.utils.EitherFlow +import com.tangem.domain.core.utils.lceContent import com.tangem.domain.core.utils.lceError import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.staking.model.stakekit.YieldBalanceList @@ -44,30 +45,49 @@ class CachedCurrenciesStatusesOperations( userWalletId: UserWalletId, currenciesFlow: EitherFlow>, ): LceFlow> = lceFlow { - currenciesFlow.flatMapLatest { maybeCurrencies -> - val isUpdating = MutableStateFlow(value = true) + val prevStatuses = MutableStateFlow(value = emptyList()) - val nonEmptyCurrencies = maybeCurrencies + val isUpdating = MutableStateFlow(value = true) + val isFetchingStarted = MutableStateFlow(value = false) + + val nonEmptyCurrencies = currenciesFlow.mapNotNull { it.getOrNull() }.firstOrNull()?.toNonEmptyListOrNull() + + if (nonEmptyCurrencies != null) { + launch { + isFetchingStarted.value = true + + val (networks, currenciesIds) = getIds(nonEmptyCurrencies) + fetchComponents(userWalletId, networks, currenciesIds, nonEmptyCurrencies) + } + .invokeOnCompletion { isUpdating.value = false } + } + + currenciesFlow.flatMapLatest { maybeCurrencies -> + val currencies = maybeCurrencies .getOrElse { return@flatMapLatest flowOf(it.lceError()) } .toNonEmptyListOrNull() - if (nonEmptyCurrencies.isNullOrEmpty()) { + if (currencies.isNullOrEmpty()) { + prevStatuses.value = emptyList() return@flatMapLatest flowOf(TokenListError.EmptyTokens.lceError()) } // This is only 'true' when the flow here is empty, such as during initial loading if (isLoading.get()) { val loadingCurrencies = createCurrenciesStatuses( - currencies = nonEmptyCurrencies, + currencies = currencies, maybeNetworkStatuses = null, maybeQuotes = null, maybeYieldBalances = null, isUpdating = true, ) + + loadingCurrencies.getOrNull()?.let { prevStatuses.value = it } + send(loadingCurrencies) } - val (networks, currenciesIds) = getIds(nonEmptyCurrencies) + val (networks, currenciesIds) = getIds(currencies) fun createCurrenciesStatuses( maybeQuotes: Either>?, @@ -75,26 +95,46 @@ class CachedCurrenciesStatusesOperations( maybeYieldBalances: Either?, isUpdating: Boolean, ) = createCurrenciesStatuses( - currencies = nonEmptyCurrencies, + currencies = currencies, maybeQuotes = maybeQuotes, maybeNetworkStatuses = maybeNetworkStatuses, maybeYieldBalances = maybeYieldBalances, isUpdating = isUpdating, ) - launch { fetchComponents(userWalletId, networks, currenciesIds, nonEmptyCurrencies) } - .invokeOnCompletion { isUpdating.value = false } + // removing token + val prevStatusesValue = prevStatuses.value + if (prevStatusesValue.size - currencies.size == 1) { + val removed = prevStatusesValue.map { it.currency } - currencies + + return@flatMapLatest flowOf( + prevStatusesValue.filter { it.currency !in removed }.lceContent(), + ) + } + + if (!isFetchingStarted.value) { + launch { + isFetchingStarted.value = true + + fetchComponents(userWalletId, networks, currenciesIds, currencies) + } + .invokeOnCompletion { isUpdating.value = false } + } combine( flow = getQuotes(currenciesIds), flow2 = getNetworksStatuses(userWalletId, networks), - flow3 = getYieldBalances(userWalletId, nonEmptyCurrencies), + flow3 = getYieldBalances(userWalletId, currencies), flow4 = isUpdating, transform = ::createCurrenciesStatuses, ) .distinctUntilChanged() } - .onEach(::send) + .onEach { statusesLce -> + statusesLce.getOrNull()?.let { prevStatuses.value = it } + + send(statusesLce) + } .launchIn(scope = this) } @@ -112,13 +152,7 @@ class CachedCurrenciesStatusesOperations( val rawCurrenciesIds = currenciesIds.mapNotNullTo(mutableSetOf()) { it.rawCurrencyId } quotesRepository.fetchQuotes(rawCurrenciesIds) }, - async { - if (currencies.size == 1) { - stakingRepository.fetchSingleYieldBalance(userWalletId, currencies.first()) - } else { - stakingRepository.fetchMultiYieldBalance(userWalletId, currencies) - } - }, + async { stakingRepository.fetchMultiYieldBalance(userWalletId, currencies) }, ) } .map { }