Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-18 15:27:34 +04:00
parent 3bd0f8d01a
commit 6373b5a8a3
4 changed files with 65 additions and 18 deletions

View file

@ -152,4 +152,10 @@ sealed class Lce<out E : Any, out C : Any> {
return this
}
fun onContent(action: (content: C) -> Unit): Lce<E, C> {
if (this is Content) action(this.content)
return this
}
}

View file

@ -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<UserWalletId, TotalFiatBalance.Loaded>()
operator fun invoke(
userTallestIds: Collection<UserWalletId>,
): LceFlow<TokenListError, Map<UserWalletId, TotalFiatBalance>> {
@ -52,8 +56,41 @@ class GetWalletTotalBalanceUseCase(
}
}
@OptIn(ExperimentalCoroutinesApi::class)
operator fun invoke(userWalletId: UserWalletId): LceFlow<TokenListError, TotalFiatBalance> {
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(

View file

@ -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()) {

View file

@ -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<UserWalletId, ArtworkModel> = hashMapOf()
@ -53,7 +54,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
@OptIn(ExperimentalCoroutinesApi::class)
override val userWallets: Flow<ImmutableList<UserWalletItemUM>> = 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<Error, ImmutableList<UserWalletItemUM>> ->
when (lceItems) {
is Lce.Content<ImmutableList<UserWalletItemUM>> -> emit(lceItems.content)
is Lce.Error<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<UserWallet>): Flow<HashMap<UserWalletId, ArtworkModel>> {
return flow {