diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index 671e32f204..c2100bf9dd 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -12,6 +12,7 @@ import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.percent import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.StatusSource import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.utils.StringsSigns.DASH_SIGN @@ -40,7 +41,7 @@ class TokenItemStateConverter( createSubtitleState(it, appCurrency) }, private val subtitle2StateProvider: (CryptoCurrencyStatus) -> TokenItemState.Subtitle2State? = { - createSubtitle2State(currencyStatus = it) + createSubtitle2State(status = it) }, private val fiatAmountStateProvider: (CryptoCurrencyStatus) -> TokenItemState.FiatAmountState? = { createFiatAmountState(status = it, appCurrency = appCurrency) @@ -147,7 +148,7 @@ class TokenItemStateConverter( return totalAmount.format { crypto(currency) } } - fun CryptoCurrencyStatus.getStakedBalance() = + private fun CryptoCurrencyStatus.getStakedBalance() = (value.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance().orZero() private fun createTitleState(currencyStatus: CryptoCurrencyStatus): TokenItemState.TitleState { @@ -190,15 +191,16 @@ class TokenItemStateConverter( } } - private fun createSubtitle2State(currencyStatus: CryptoCurrencyStatus): TokenItemState.Subtitle2State? { - return when (currencyStatus.value) { + private fun createSubtitle2State(status: CryptoCurrencyStatus): TokenItemState.Subtitle2State? { + return when (status.value) { is CryptoCurrencyStatus.Loaded, is CryptoCurrencyStatus.Custom, is CryptoCurrencyStatus.NoQuote, is CryptoCurrencyStatus.NoAccount, -> { TokenItemState.Subtitle2State.TextContent( - text = currencyStatus.getFormattedCryptoAmount(includeStaking = true), + text = status.getFormattedCryptoAmount(includeStaking = true), + isFlickering = status.value.isFlickering(), ) } is CryptoCurrencyStatus.Loading, @@ -221,6 +223,7 @@ class TokenItemStateConverter( -> { TokenItemState.FiatAmountState.Content( text = status.getFormattedFiatAmount(appCurrency = appCurrency, includeStaking = true), + isFlickering = status.value.isFlickering(), icons = buildList { if (!status.getStakedBalance().isZero()) { TokenItemState.FiatAmountState.Content.IconUM( @@ -228,6 +231,12 @@ class TokenItemStateConverter( useAccentColor = true, ).let(::add) } + if (status.value.getStatusSource() == StatusSource.ONLY_CACHE) { + TokenItemState.FiatAmountState.Content.IconUM( + iconRes = R.drawable.ic_error_sync_24, + useAccentColor = false, + ).let(::add) + } }.toImmutableList(), ) } @@ -248,6 +257,7 @@ class TokenItemStateConverter( price = fiatRate.getFormattedCryptoPrice(appCurrency), priceChangePercent = priceChange.format { percent() }, type = priceChange.getPriceChangeType(), + isFlickering = value.isFlickering(), ) } else { TokenItemState.SubtitleState.Unknown @@ -263,5 +273,15 @@ class TokenItemStateConverter( private fun BigDecimal.getPriceChangeType(): PriceChangeType { return PriceChangeConverter.fromBigDecimal(value = this) } + + private fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = getStatusSource() == StatusSource.CACHE + + private fun CryptoCurrencyStatus.Value.getStatusSource(): StatusSource? { + return when (this) { + is CryptoCurrencyStatus.Loaded -> source + is CryptoCurrencyStatus.NoAccount -> source + else -> null + } + } } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt index 2d5126dd66..f3e3d06f65 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt @@ -10,10 +10,9 @@ import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.NetworkStatus import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.extensions.addOrReplace -import com.tangem.utils.extensions.replaceBy +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.* -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.launch private typealias NetworkStatusesByWalletId = Map> @@ -22,8 +21,6 @@ internal class DefaultNetworksStatusesStore( private val persistenceDataStore: DataStore, ) : NetworksStatusesStore { - private val mutex = Mutex() - override fun get(key: UserWalletId): Flow> { return runtimeDataStore.get(provideStringKey(key)) } @@ -42,11 +39,20 @@ internal class DefaultNetworksStatusesStore( if (cachedStatuses.isNotEmpty()) { send(cachedStatuses) + + /** + * Required for storing cache data. + * This will help to recognize networks that are still uploaded. + * + * @see mergeStatuses + */ + storeAll(key = key, values = cachedStatuses) } runtimeDataStore.get(provideStringKey(key)) .onEach { runtimeStatuses -> val mergedStatuses = mergeStatuses( + networks = networks, cachedStatuses = cachedStatuses, runtimeStatuses = runtimeStatuses, ) @@ -57,36 +63,20 @@ internal class DefaultNetworksStatusesStore( } override suspend fun getSyncOrNull(key: UserWalletId): Set? { - return runtimeDataStore.getSyncOrNull(provideStringKey(key)) + return runtimeDataStore.getSyncOrNull(key = provideStringKey(key)) } override suspend fun store(key: UserWalletId, value: NetworkStatus) { - mutex.withLock { - val newValues = getSyncOrNull(key) - ?.addOrReplace(value) { it.network == value.network } - ?: setOf(value) - - runtimeDataStore.store(provideStringKey(key), newValues) - storeNetworkStatusInPersistence(key, value) - } + storeAll(key = key, values = setOf(value)) } - override suspend fun storeAll(key: UserWalletId, values: Collection) { - mutex.withLock { - val currentValues = getSyncOrNull(key) ?: emptySet() - val updatedValues = currentValues.toMutableSet() + override suspend fun storeAll(key: UserWalletId, values: Set) { + coroutineScope { + val updatedValues = getSyncOrNull(key).orEmpty() + .addOrReplace(items = values) { prev, new -> prev.network == new.network } - values.forEach { newValue -> - val isReplaced = updatedValues.replaceBy(newValue) { - it.network == newValue.network - } - - if (!isReplaced) { - updatedValues.add(newValue) - } - } - - runtimeDataStore.store(provideStringKey(key), updatedValues) + launch { runtimeDataStore.store(key = provideStringKey(key), value = updatedValues) } + launch { storeNetworkStatusInPersistence(userWalletId = key, statuses = updatedValues) } } } @@ -96,19 +86,24 @@ internal class DefaultNetworksStatusesStore( * If a status with the same network is in both sets, the status from [runtimeStatuses] is used. */ private fun mergeStatuses( + networks: Set, cachedStatuses: Set, runtimeStatuses: Set, ): Set { - return runtimeStatuses - .map { runtime -> - runtime.takeIf { it.value !is NetworkStatus.Unreachable } - ?: getCachedStatusIfPossible(cachedStatuses = cachedStatuses, runtime = runtime) + return networks.mapNotNullTo(hashSetOf()) { network -> + val runtimeStatus = runtimeStatuses.firstOrNull { it.network == network } + + if (runtimeStatus == null || runtimeStatus.value is NetworkStatus.Unreachable) { + getCachedStatusIfPossible(cachedStatuses = cachedStatuses, network = network) + ?: runtimeStatus + } else { + runtimeStatus } - .toSet() + } } - private fun getCachedStatusIfPossible(cachedStatuses: Set, runtime: NetworkStatus): NetworkStatus { - val cached = cachedStatuses.firstOrNull { it.network == runtime.network } ?: return runtime + private fun getCachedStatusIfPossible(cachedStatuses: Set, network: Network): NetworkStatus? { + val cached = cachedStatuses.firstOrNull { it.network == network } ?: return null val updatedCachedStatus = when (val status = cached.value) { is NetworkStatus.NoAccount -> status.copy(source = StatusSource.ONLY_CACHE) @@ -122,22 +117,17 @@ internal class DefaultNetworksStatusesStore( return if (updatedCachedStatus != null) { cached.copy(value = updatedCachedStatus) } else { - runtime + null } } - private suspend fun storeNetworkStatusInPersistence(userWalletId: UserWalletId, networkStatus: NetworkStatus) { - val network = networkStatus.network - + private suspend fun storeNetworkStatusInPersistence(userWalletId: UserWalletId, statuses: Set) { // Converter will return null if the network status is not supported - val newStatus = NetworkStatusDataModelConverter.convert(value = networkStatus) ?: return + val newStatuses = NetworkStatusDataModelConverter.convertSet(input = statuses).filterNotNull().toSet() persistenceDataStore.updateData { storedStatuses -> - val userWalletStatuses = storedStatuses[userWalletId.stringValue].orEmpty() - val updatedStatuses = userWalletStatuses.addOrReplace(item = newStatus) { it.networkId == network.id } - storedStatuses.toMutableMap().apply { - this[userWalletId.stringValue] = updatedStatuses + this[userWalletId.stringValue] = newStatuses } } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt index 6b191e150d..81838f97aa 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt @@ -15,5 +15,5 @@ interface NetworksStatusesStore { suspend fun store(key: UserWalletId, value: NetworkStatus) - suspend fun storeAll(key: UserWalletId, values: Collection) + suspend fun storeAll(key: UserWalletId, values: Set) } \ No newline at end of file diff --git a/core/utils/src/main/java/com/tangem/utils/extensions/Set.kt b/core/utils/src/main/java/com/tangem/utils/extensions/Set.kt index f5c0cf1eb7..f15a1a5f30 100644 --- a/core/utils/src/main/java/com/tangem/utils/extensions/Set.kt +++ b/core/utils/src/main/java/com/tangem/utils/extensions/Set.kt @@ -36,4 +36,16 @@ inline fun Set.addOrReplace(item: T, predicate: (T) -> Boolean): Set { } return mutableList +} + +inline fun Set.addOrReplace(items: Set, predicate: (T, T) -> Boolean): Set { + val updatedValues = this.toMutableSet() + + items.forEach { newValue -> + val isReplaced = updatedValues.replaceBy(item = newValue, predicate = { predicate(it, newValue) }) + + if (!isReplaced) updatedValues.add(newValue) + } + + return updatedValues } \ No newline at end of file diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt index 716ae1da27..0760786a7d 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt @@ -129,7 +129,7 @@ internal class DefaultNetworksRepository( } if (statusesToRefresh != null) { - networksStatusesStore.storeAll(key = userWalletId, values = statusesToRefresh) + networksStatusesStore.storeAll(key = userWalletId, values = statusesToRefresh.toSet()) } } diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt index e03676a2dc..8c7ce6b8bf 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext +import timber.log.Timber internal class DefaultQuotesRepository( private val tangemTechApi: TangemTechApi, @@ -115,25 +116,26 @@ internal class DefaultQuotesRepository( val replacementIdsResult = quotesUnsupportedCurrenciesAdapter.replaceUnsupportedCurrencies( rawCurrenciesIds.map { it.value }.toSet(), ) - val response = safeApiCallWithTimeout( + + safeApiCallWithTimeout( call = { val coinIds = replacementIdsResult.idsForRequest.joinToString(separator = ",") - tangemTechApi.getQuotes(appCurrencyId, coinIds).bind() + val response = tangemTechApi.getQuotes(appCurrencyId, coinIds).bind() + + val updatedResponse = quotesUnsupportedCurrenciesAdapter.getResponseWithUnsupportedCurrencies( + response = response, + filteredIds = replacementIdsResult.idsFiltered, + ) + + quotesStore.store(updatedResponse) }, onError = { error -> + Timber.e(error) + cacheRegistry.invalidate(rawCurrenciesIds.map { getQuoteCacheKey(it) }) quotesStore.storeEmptyQuotes(currenciesIds = rawCurrenciesIds) - - throw error }, ) - - val updatedResponse = quotesUnsupportedCurrenciesAdapter.getResponseWithUnsupportedCurrencies( - response, - replacementIdsResult.idsFiltered, - ) - - quotesStore.store(updatedResponse) } private suspend fun filterExpiredCurrenciesIds( diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/TotalFiatBalance.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/TotalFiatBalance.kt index 98deb39ace..5cb26044a2 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/TotalFiatBalance.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/TotalFiatBalance.kt @@ -1,5 +1,6 @@ package com.tangem.domain.tokens.model +import com.tangem.domain.models.StatusSource import java.math.BigDecimal /** @@ -27,5 +28,6 @@ sealed class TotalFiatBalance { data class Loaded( val amount: BigDecimal, val isAllAmountsSummarized: Boolean, + val source: StatusSource, ) : TotalFiatBalance() } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/TokenList.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/TokenList.kt index 2bd9431825..3814c64c01 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/TokenList.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/TokenList.kt @@ -1,5 +1,6 @@ package com.tangem.domain.tokens.model +import com.tangem.domain.models.StatusSource import java.math.BigDecimal /** @@ -47,6 +48,7 @@ sealed class TokenList { override val totalFiatBalance: TotalFiatBalance = TotalFiatBalance.Loaded( amount = BigDecimal.ZERO, isAllAmountsSummarized = true, + source = StatusSource.ACTUAL, ) } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt index 41f42b4ccd..d8cea3866c 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt @@ -1,6 +1,7 @@ package com.tangem.domain.tokens.operations import arrow.core.NonEmptyList +import com.tangem.domain.models.StatusSource import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.TotalFiatBalance @@ -34,14 +35,14 @@ internal class TokenListFiatBalanceOperations( is CryptoCurrencyStatus.NoAmount, -> { if (BlockchainUtils.isIncludeToBalanceOnError(token.currency.network.id.value)) { - fiatBalance = recalculateNoAccountBalance(fiatBalance) + fiatBalance = recalculateNoAccountBalance(status, fiatBalance) } else { fiatBalance = TotalFiatBalance.Failed break } } is CryptoCurrencyStatus.NoAccount -> { - fiatBalance = recalculateNoAccountBalance(fiatBalance) + fiatBalance = recalculateNoAccountBalance(status, fiatBalance) } is CryptoCurrencyStatus.Loaded -> { fiatBalance = recalculateBalance(status, fiatBalance) @@ -55,11 +56,15 @@ internal class TokenListFiatBalanceOperations( return fiatBalance } - private fun recalculateNoAccountBalance(currentBalance: TotalFiatBalance): TotalFiatBalance { + private fun recalculateNoAccountBalance( + status: CryptoCurrencyStatus.Value, + currentBalance: TotalFiatBalance, + ): TotalFiatBalance { return (currentBalance as? TotalFiatBalance.Loaded)?.copy(isAllAmountsSummarized = false) ?: TotalFiatBalance.Loaded( amount = BigDecimal.ZERO, isAllAmountsSummarized = false, + source = (status as? CryptoCurrencyStatus.NoAccount)?.source ?: StatusSource.ACTUAL, ) } @@ -77,6 +82,7 @@ internal class TokenListFiatBalanceOperations( ) ?: TotalFiatBalance.Loaded( amount = status.fiatAmount + fiatStakingBalance, isAllAmountsSummarized = true, + source = status.source, ) } } @@ -95,6 +101,7 @@ internal class TokenListFiatBalanceOperations( ) ?: TotalFiatBalance.Loaded( amount = status.fiatAmount.orZero() + fiatYieldBalance, isAllAmountsSummarized = isTokenAmountCanBeSummarized, + source = StatusSource.ACTUAL, ) } } diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt index 3f15752baf..a9a32bc442 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt @@ -2,6 +2,7 @@ package com.tangem.domain.tokens.mock import arrow.core.NonEmptyList import arrow.core.toNonEmptyListOrNull +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.mock.MockNetworksGroups.failedNetworksGroups import com.tangem.domain.tokens.mock.MockNetworksGroups.loadedNetworksGroups import com.tangem.domain.tokens.mock.MockNetworksGroups.sortedNetworksGroups @@ -79,6 +80,7 @@ internal object MockTokenLists { totalFiatBalance = TotalFiatBalance.Loaded( amount = tokens.sumOf { it.value.fiatAmount ?: BigDecimal.ZERO }, isAllAmountsSummarized = true, + source = StatusSource.ACTUAL, ), ) } @@ -95,6 +97,7 @@ internal object MockTokenLists { .flatMap { it.currencies as NonEmptyList } .sumOf { it.value.fiatAmount ?: BigDecimal.ZERO }, isAllAmountsSummarized = true, + source = StatusSource.ACTUAL, ), ) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index 91ac3d6a00..1c1e455117 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -12,6 +12,7 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.* import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.StatusSource import com.tangem.domain.staking.model.StakingAvailability import com.tangem.domain.staking.model.StakingEntryInfo import com.tangem.domain.staking.model.stakekit.RewardBlockType @@ -121,7 +122,7 @@ internal class TokenDetailsLoadedBalanceConverter( onBalanceSelect = clickIntents::onBalanceSelect, selectedBalanceType = currentState.selectedBalanceType, isBalanceSelectorEnabled = isBalanceSelectorEnabled, - isBalanceFlickering = false, // TODO: Implement in [REDACTED_JIRA] + isBalanceFlickering = status.value.isFlickering(), ) is CryptoCurrencyStatus.Loading -> TokenDetailsBalanceBlockState.Loading( actionButtons = currentState.actionButtons, @@ -344,4 +345,14 @@ internal class TokenDetailsLoadedBalanceConverter( RewardBlockType.RewardUnavailable -> TextReference.EMPTY } } + + private fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = getStatusSource() == StatusSource.CACHE + + private fun CryptoCurrencyStatus.Value.getStatusSource(): StatusSource? { + return when (this) { + is CryptoCurrencyStatus.Loaded -> source + is CryptoCurrencyStatus.NoAccount -> source + else -> null + } + } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt index 97bbb348fb..9fcfe012b5 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt @@ -4,8 +4,8 @@ import arrow.core.Either import arrow.core.getOrElse import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.format.bigdecimal.crypto +import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format -import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.domain.common.util.getCardsCount import com.tangem.domain.visa.model.VisaCurrency import com.tangem.domain.wallets.models.UserWallet @@ -78,17 +78,20 @@ internal class SetBalancesAndLimitsTransformer( }, cardCount = userWallet.getCardsCount(), isZeroBalance = visaCurrency.balances.available.isZero(), - isBalanceFlickering = false, // TODO: Implement in [REDACTED_JIRA] + isBalanceFlickering = false, ) } } private fun createAdditionalInfo(visaCurrency: VisaCurrency): WalletAdditionalInfo { - val fiatAmount = BigDecimalFormatter.formatFiatAmount( - fiatAmount = visaCurrency.fiatRate?.let { visaCurrency.balances.available.multiply(it) }, - fiatCurrencyCode = visaCurrency.fiatCurrency.code, - fiatCurrencySymbol = visaCurrency.fiatCurrency.symbol, - ) + val fiatAmount = visaCurrency.fiatRate?.let { visaCurrency.balances.available.multiply(it) } + .format { + fiat( + fiatCurrencyCode = visaCurrency.fiatCurrency.code, + fiatCurrencySymbol = visaCurrency.fiatCurrency.symbol, + ) + } + val infoContent = stringReference( value = buildString { append(fiatAmount) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt index 3705598bcd..46073ee11f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt @@ -1,6 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers -import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.common.util.getCardsCount import com.tangem.domain.tokens.error.TokenListError @@ -62,14 +63,12 @@ internal class SetTokenListErrorTransformer( imageResId = imageResId, onRenameClick = onRenameClick, onDeleteClick = onDeleteClick, - balance = BigDecimalFormatter.formatFiatAmount( - fiatAmount = BigDecimal.ZERO, - fiatCurrencyCode = appCurrency.code, - fiatCurrencySymbol = appCurrency.symbol, - ), + balance = BigDecimal.ZERO.format { + fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol) + }, cardCount = selectedWallet.getCardsCount(), isZeroBalance = true, - isBalanceFlickering = false, // TODO: Implement in [REDACTED_JIRA] + isBalanceFlickering = false, ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt index 2fdbb17338..ba2ce3318c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt @@ -1,8 +1,10 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter -import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.common.util.getCardsCount +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory @@ -54,14 +56,12 @@ internal class MultiWalletCardStateConverter( imageResId = imageResId, onRenameClick = onRenameClick, onDeleteClick = onDeleteClick, - balance = BigDecimalFormatter.formatFiatAmount( - fiatAmount = fiatBalance.amount, - fiatCurrencyCode = appCurrency.code, - fiatCurrencySymbol = appCurrency.symbol, - ), + balance = fiatBalance.amount.format { + fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol) + }, isZeroBalance = fiatBalance.amount.isZero(), cardCount = selectedWallet.getCardsCount(), - isBalanceFlickering = false, // TODO: Implement in [REDACTED_JIRA] + isBalanceFlickering = fiatBalance.source == StatusSource.CACHE, ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt index 83dd7c2422..6f850012d0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt @@ -1,12 +1,15 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter -import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.common.util.getCardsCount +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState +import com.tangem.utils.StringsSigns.DASH_SIGN import com.tangem.utils.converter.Converter import com.tangem.utils.extensions.isZero @@ -65,17 +68,15 @@ internal class SingleWalletCardStateConverter( balance = formatFiatAmount(status = status, appCurrency = appCurrency), cardCount = selectedWallet.getCardsCount(), isZeroBalance = status.fiatAmount?.isZero(), - isBalanceFlickering = false, // TODO: Implement in [REDACTED_JIRA] + isBalanceFlickering = (status as? CryptoCurrencyStatus.Loaded)?.source == StatusSource.CACHE, ) } private fun formatFiatAmount(status: CryptoCurrencyStatus.Value, appCurrency: AppCurrency): String { - val fiatAmount = status.fiatAmount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN + val fiatAmount = status.fiatAmount ?: return DASH_SIGN - return BigDecimalFormatter.formatFiatAmount( - fiatAmount = fiatAmount, - fiatCurrencyCode = appCurrency.code, - fiatCurrencySymbol = appCurrency.symbol, - ) + return fiatAmount.format { + fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol) + } } } \ No newline at end of file