From 6373b5a8a3ec2f6b41c2c5773b7e32072d291323 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 18 Jul 2025 15:27:34 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../kotlin/com/tangem/domain/core/lce/Lce.kt | 6 +++ .../tokens/GetWalletTotalBalanceUseCase.kt | 41 ++++++++++++++++++- .../wallet/child/wallet/model/WalletModel.kt | 6 ++- .../wallet/utils/DefaultUserWalletsFetcher.kt | 30 +++++++------- 4 files changed, 65 insertions(+), 18 deletions(-) diff --git a/domain/core/src/main/kotlin/com/tangem/domain/core/lce/Lce.kt b/domain/core/src/main/kotlin/com/tangem/domain/core/lce/Lce.kt index 2fef58e761..1eba8138a8 100644 --- a/domain/core/src/main/kotlin/com/tangem/domain/core/lce/Lce.kt +++ b/domain/core/src/main/kotlin/com/tangem/domain/core/lce/Lce.kt @@ -152,4 +152,10 @@ sealed class Lce { return this } + + fun onContent(action: (content: C) -> Unit): Lce { + if (this is Content) action(this.content) + + return this + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt index 8b6ba7ade2..5a9373451d 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt @@ -6,6 +6,7 @@ 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.lceContent import com.tangem.domain.core.utils.lceLoading import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -13,14 +14,17 @@ import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.tokens.operations.BaseCurrenciesStatusesOperations import com.tangem.domain.tokens.operations.TokenListFiatBalanceOperations import com.tangem.domain.wallets.models.UserWalletId -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.* import timber.log.Timber +import java.util.concurrent.ConcurrentHashMap class GetWalletTotalBalanceUseCase( private val currenciesStatusesOperations: BaseCurrenciesStatusesOperations, ) { + private val walletBalanceCache = ConcurrentHashMap() + operator fun invoke( userTallestIds: Collection, ): LceFlow> { @@ -52,8 +56,41 @@ class GetWalletTotalBalanceUseCase( } } + @OptIn(ExperimentalCoroutinesApi::class) operator fun invoke(userWalletId: UserWalletId): LceFlow { return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId).map(::createBalance) + .distinctUntilChanged() + .onStart { + val cachedBalance = walletBalanceCache[userWalletId] + + if (cachedBalance != null) { + emit(cachedBalance.lceContent()) + } + } + .mapLatest { lceBalance -> + val cachedBalance = walletBalanceCache[userWalletId] + + if (cachedBalance == null) { + lceBalance.onContent { content -> + if (content is TotalFiatBalance.Loaded) { + walletBalanceCache.put(userWalletId, content) + } + } + + lceBalance + } else { + val content = lceBalance.getOrNull(isPartialContentAccepted = false) + + if (content is TotalFiatBalance.Loaded && content != cachedBalance) { + walletBalanceCache.put(userWalletId, content) + + lceBalance + } else { + cachedBalance.lceContent() + } + } + } + .distinctUntilChanged() } private fun createBalance( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 327c2b8470..532589982d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -374,8 +374,10 @@ internal class WalletModel @Inject constructor( val otherWallets = action.wallets.minus(action.selectedWallet) - otherWallets.onEach { userWallet -> - modelScope.launch { walletContentFetcher(userWalletId = userWallet.walletId) } + if (tokensFeatureToggles.isWalletBalanceFetcherEnabled) { + otherWallets.onEach { userWallet -> + modelScope.launch { walletContentFetcher(userWalletId = userWallet.walletId) } + } } if (action.wallets.size > 1 && isWalletsScrollPreviewEnabled()) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletsFetcher.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletsFetcher.kt index ace0bd4279..110de91860 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletsFetcher.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletsFetcher.kt @@ -13,7 +13,6 @@ import com.tangem.domain.balancehiding.BalanceHidingSettings import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.lce.lce -import com.tangem.domain.core.utils.getOrElse import com.tangem.domain.core.utils.toLce import com.tangem.domain.models.ArtworkModel import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase @@ -27,6 +26,7 @@ import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.feature.wallet.impl.R import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.operations.attestation.ArtworkSize +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -45,6 +45,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor( @Assisted private val messageSender: UiMessageSender, @Assisted private val onlyMultiCurrency: Boolean, private val getCardImageUseCase: GetCardImageUseCase, + dispatchers: CoroutineDispatcherProvider, ) : UserWalletsFetcher { private var loadedArtworks: HashMap = hashMapOf() @@ -53,7 +54,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor( @OptIn(ExperimentalCoroutinesApi::class) override val userWallets: Flow> = walletsFlow.transformLatest { wallets -> - val uiModels = UserWalletItemUMConverter(onClick = { onWalletClick(it) }).convertList(wallets) + val uiModels = UserWalletItemUMConverter(onClick = onWalletClick).convertList(wallets) .toImmutableList() emit(uiModels) @@ -64,25 +65,26 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor( flow3 = getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)).distinctUntilChanged(), flow4 = loadArtworks(wallets), ) { maybeAppCurrency, balanceHidingSettings, maybeBalances, artworks -> - val models = createUiModels( + createUiModels( wallets = wallets, maybeAppCurrency = maybeAppCurrency, maybeBalances = maybeBalances, balanceHidingSettings = balanceHidingSettings, artworks = artworks, - ).getOrElse( - ifLoading = { return@combine }, - ifError = { - val message = resourceReference(R.string.common_unknown_error) - messageSender.send(SnackbarMessage(message)) - - return@combine - }, ) - - emit(models) - }.collect() + } + .collectLatest { lceItems: Lce> -> + when (lceItems) { + is Lce.Content> -> emit(lceItems.content) + is Lce.Error -> { + val message = resourceReference(R.string.common_unknown_error) + messageSender.send(SnackbarMessage(message)) + } + is Lce.Loading<*> -> Unit + } + } } + .flowOn(dispatchers.default) private fun loadArtworks(wallets: List): Flow> { return flow {