From 8bcf8b555b84002ec9b654dae39adaa2f7a46bd2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 1 Nov 2024 15:26:06 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../ui/tokens/TokenItemStateConverter.kt | 71 +++++++++++++------ .../CryptoCurrencyToIconStateConverter.kt | 10 ++- .../token/internal/TokenFiatAmount.kt | 33 ++++++--- .../components/token/internal/TokenPrice.kt | 14 ++-- .../components/token/internal/TokenTitle.kt | 16 +++-- .../components/token/state/TokenItemState.kt | 10 ++- 6 files changed, 106 insertions(+), 48 deletions(-) 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 913b07dd84..ae4993d6ce 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 @@ -1,5 +1,6 @@ package com.tangem.common.ui.tokens +import com.tangem.core.ui.components.currency.icon.CurrencyIconState import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.components.marketprice.utils.PriceChangeConverter @@ -28,16 +29,20 @@ import java.math.BigDecimal */ class TokenItemStateConverter( private val appCurrency: AppCurrency, + private val iconStateProvider: (CryptoCurrencyStatus) -> CurrencyIconState = { + CryptoCurrencyToIconStateConverter().convert(it) + }, private val titleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.TitleState = Companion::createTitleState, private val subtitleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.SubtitleState? = { createSubtitleState(it, appCurrency) }, + private val fiatAmountStateProvider: (CryptoCurrencyStatus) -> TokenItemState.FiatAmountState? = { + createFiatAmountState(it, appCurrency) + }, private val onItemClick: (CryptoCurrencyStatus) -> Unit, private val onItemLongClick: ((CryptoCurrencyStatus) -> Unit)? = null, ) : Converter { - private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter) - override fun convert(value: CryptoCurrencyStatus): TokenItemState { return when (value.value) { is CryptoCurrencyStatus.Loading -> value.mapToLoadingState() @@ -56,7 +61,7 @@ class TokenItemStateConverter( private fun CryptoCurrencyStatus.mapToLoadingState(): TokenItemState.Loading { return TokenItemState.Loading( id = currency.id.value, - iconState = iconStateConverter.convert(value = this), + iconState = iconStateProvider(this), titleState = titleStateProvider(this) as TokenItemState.TitleState.Content, subtitleState = requireNotNull(subtitleStateProvider(this)), ) @@ -65,13 +70,10 @@ class TokenItemStateConverter( private fun CryptoCurrencyStatus.mapToTokenItemState(): TokenItemState.Content { return TokenItemState.Content( id = currency.id.value, - iconState = iconStateConverter.convert(value = this), + iconState = iconStateProvider(this), titleState = titleStateProvider(this), subtitleState = requireNotNull(subtitleStateProvider(this)), - fiatAmountState = TokenItemState.FiatAmountState.Content( - text = getFormattedFiatAmount(), - hasStaked = !getStakedBalance().isZero(), - ), + fiatAmountState = requireNotNull(fiatAmountStateProvider(this)), subtitle2State = TokenItemState.Subtitle2State.TextContent(text = getFormattedAmount()), onItemClick = { onItemClick(this) }, onItemLongClick = onItemLongClick?.let { @@ -86,20 +88,10 @@ class TokenItemStateConverter( return amount.format { crypto(currency) } } - private fun CryptoCurrencyStatus.getFormattedFiatAmount(): String { - val fiatYieldBalance = value.fiatRate?.times(getStakedBalance()).orZero() - val fiatAmount = value.fiatAmount?.plus(fiatYieldBalance) ?: return DASH_SIGN - - return BigDecimalFormatter.formatFiatAmount(fiatAmount, appCurrency.code, appCurrency.symbol) - } - - private fun CryptoCurrencyStatus.getStakedBalance() = - (value.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance().orZero() - private fun CryptoCurrencyStatus.mapToUnreachableTokenItemState(): TokenItemState.Unreachable { return TokenItemState.Unreachable( id = currency.id.value, - iconState = iconStateConverter.convert(value = this), + iconState = iconStateProvider(this), titleState = titleStateProvider(this), subtitleState = subtitleStateProvider(this), onItemClick = { onItemClick(this) }, @@ -112,7 +104,7 @@ class TokenItemStateConverter( private fun CryptoCurrencyStatus.mapToNoAddressTokenItemState(): TokenItemState.NoAddress { return TokenItemState.NoAddress( id = currency.id.value, - iconState = iconStateConverter.convert(this), + iconState = iconStateProvider(this), titleState = titleStateProvider(this), subtitleState = subtitleStateProvider(this), onItemLongClick = onItemLongClick?.let { @@ -121,9 +113,9 @@ class TokenItemStateConverter( ) } - private companion object { + companion object { - fun createTitleState(currencyStatus: CryptoCurrencyStatus): TokenItemState.TitleState { + private fun createTitleState(currencyStatus: CryptoCurrencyStatus): TokenItemState.TitleState { return when (val value = currencyStatus.value) { is CryptoCurrencyStatus.Loading, is CryptoCurrencyStatus.MissedDerivation, @@ -145,7 +137,7 @@ class TokenItemStateConverter( } } - fun createSubtitleState( + private fun createSubtitleState( currencyStatus: CryptoCurrencyStatus, appCurrency: AppCurrency, ): TokenItemState.SubtitleState? { @@ -163,6 +155,29 @@ class TokenItemStateConverter( } } + private fun createFiatAmountState( + status: CryptoCurrencyStatus, + appCurrency: AppCurrency, + ): TokenItemState.FiatAmountState? { + return when (status.value) { + is CryptoCurrencyStatus.Loaded, + is CryptoCurrencyStatus.Custom, + is CryptoCurrencyStatus.NoQuote, + is CryptoCurrencyStatus.NoAccount, + -> { + TokenItemState.FiatAmountState.Content( + text = status.getFormattedFiatAmount(appCurrency), + hasStaked = !status.getStakedBalance().isZero(), + ) + } + is CryptoCurrencyStatus.Unreachable, + is CryptoCurrencyStatus.NoAmount, + is CryptoCurrencyStatus.MissedDerivation, + is CryptoCurrencyStatus.Loading, + -> null + } + } + private fun CryptoCurrencyStatus.getCryptoPriceState(appCurrency: AppCurrency): TokenItemState.SubtitleState { val fiatRate = value.fiatRate val priceChange = value.priceChange @@ -189,5 +204,15 @@ class TokenItemStateConverter( private fun BigDecimal.getPriceChangeType(): PriceChangeType { return PriceChangeConverter.fromBigDecimal(value = this) } + + fun CryptoCurrencyStatus.getFormattedFiatAmount(appCurrency: AppCurrency): String { + val fiatYieldBalance = value.fiatRate?.times(getStakedBalance()).orZero() + val fiatAmount = value.fiatAmount?.plus(fiatYieldBalance) ?: return DASH_SIGN + + return BigDecimalFormatter.formatFiatAmount(fiatAmount, appCurrency.code, appCurrency.symbol) + } + + private fun CryptoCurrencyStatus.getStakedBalance() = + (value.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance().orZero() } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/currency/icon/converter/CryptoCurrencyToIconStateConverter.kt b/core/ui/src/main/java/com/tangem/core/ui/components/currency/icon/converter/CryptoCurrencyToIconStateConverter.kt index c331fc8a1d..6c221c5b10 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/currency/icon/converter/CryptoCurrencyToIconStateConverter.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/currency/icon/converter/CryptoCurrencyToIconStateConverter.kt @@ -10,8 +10,12 @@ import com.tangem.utils.converter.Converter /** * Converts [CryptoCurrencyStatus] to [CurrencyIconState] + * + * @property isAvailable flag that indicates if the currency is available (affects on icon's grayscale) */ -class CryptoCurrencyToIconStateConverter : Converter { +class CryptoCurrencyToIconStateConverter( + private val isAvailable: Boolean = true, +) : Converter { override fun convert(value: CryptoCurrencyStatus): CurrencyIconState { return when (val currency = value.currency) { @@ -57,7 +61,7 @@ class CryptoCurrencyToIconStateConverter : Converter { - FiatAmountText( + ContentFiatAmount( text = state.text.orMaskWithStars(isBalanceHidden), hasStaked = state.hasStaked, modifier = modifier, ) } + is TokenItemState.FiatAmountState.TextContent -> { + FiatAmountText( + text = state.text.orMaskWithStars(isBalanceHidden), + modifier = modifier, + isAvailable = state.isAvailable, + ) + } is TokenFiatAmountState.Loading -> { RectangleShimmer(modifier = modifier.placeholderSize(), radius = TangemTheme.dimens.radius4) } @@ -41,7 +49,7 @@ internal fun TokenFiatAmount(state: TokenFiatAmountState?, isBalanceHidden: Bool } @Composable -private fun FiatAmountText(text: String, hasStaked: Boolean, modifier: Modifier = Modifier) { +private fun ContentFiatAmount(text: String, hasStaked: Boolean, modifier: Modifier = Modifier) { Row( modifier = modifier, verticalAlignment = Alignment.CenterVertically, @@ -58,16 +66,23 @@ private fun FiatAmountText(text: String, hasStaked: Boolean, modifier: Modifier .size(TangemTheme.dimens.size12), ) } - Text( - text = text, - color = TangemTheme.colors.text.primary1, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - style = TangemTheme.typography.body2, - ) + + FiatAmountText(text = text) } } +@Composable +private fun FiatAmountText(text: String, modifier: Modifier = Modifier, isAvailable: Boolean = true) { + Text( + text = text, + modifier = modifier, + color = if (isAvailable) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.tertiary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + style = TangemTheme.typography.body2, + ) +} + private fun Modifier.placeholderSize(): Modifier = composed { return@composed this .padding(vertical = TangemTheme.dimens.spacing4) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenPrice.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenPrice.kt index aacba7c8b7..f2986b6e11 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenPrice.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenPrice.kt @@ -37,8 +37,12 @@ internal fun TokenPrice(state: TokenPriceState?, modifier: Modifier = Modifier) priceChangePercent = state.priceChangePercent, ) } - is TokenPriceState.TextContent -> PriceText(text = state.value, modifier = modifier) - is TokenPriceState.Unknown -> PriceText(text = DASH_SIGN, modifier = modifier) + is TokenPriceState.TextContent -> { + PriceText(text = state.value, modifier = modifier, isAvailable = state.isAvailable) + } + is TokenPriceState.Unknown -> { + PriceText(text = DASH_SIGN, modifier = modifier) + } is TokenPriceState.Loading -> { RectangleShimmer(modifier = modifier.placeholderSize(), radius = TangemTheme.dimens.radius4) } @@ -71,11 +75,11 @@ private fun PriceBlock( } @Composable -private fun PriceText(text: String, modifier: Modifier = Modifier) { +private fun PriceText(text: String, modifier: Modifier = Modifier, isAvailable: Boolean = true) { AnimatedContent(targetState = text, label = "Update the price text", modifier = modifier) { animatedText -> Text( text = animatedText, - color = TangemTheme.colors.text.tertiary, + color = if (isAvailable) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.tertiary, maxLines = 1, overflow = TextOverflow.Ellipsis, style = TangemTheme.typography.caption2, @@ -154,7 +158,7 @@ private class TokenPriceChangeStateProvider : CollectionPreviewParameterProvider priceChangePercent = "2.5%", type = PriceChangeType.NEUTRAL, ), - TokenPriceState.TextContent(value = "Subtitle"), + TokenPriceState.TextContent(value = "Subtitle", isAvailable = true), TokenPriceState.Unknown, TokenPriceState.Loading, TokenPriceState.Locked, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt index 706120f20e..9bf3412f33 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt @@ -22,7 +22,7 @@ import com.tangem.core.ui.components.token.state.TokenItemState.TitleState as To internal fun TokenTitle(state: TokenTitleState?, modifier: Modifier = Modifier) { when (state) { is TokenTitleState.Content -> { - ContentTitle(name = state.text, hasPending = state.hasPending, modifier = modifier) + ContentTitle(state = state, modifier = modifier) } is TokenTitleState.Loading -> { RectangleShimmer(modifier = modifier.placeholderSize(), radius = TangemTheme.dimens.radius4) @@ -35,7 +35,7 @@ internal fun TokenTitle(state: TokenTitleState?, modifier: Modifier = Modifier) } @Composable -private fun ContentTitle(name: String, hasPending: Boolean, modifier: Modifier = Modifier) { +private fun ContentTitle(state: TokenTitleState.Content, modifier: Modifier = Modifier) { Row( modifier = modifier, horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing6), @@ -45,21 +45,25 @@ private fun ContentTitle(name: String, hasPending: Boolean, modifier: Modifier = * If currency name has a long width, then it will completely displace the image. * So we need to use [weight] to avoid displacement. */ - CurrencyNameText(name = name, modifier = Modifier.weight(weight = 1f, fill = false)) + CurrencyNameText( + name = state.text, + isAvailable = state.isAvailable, + modifier = Modifier.weight(weight = 1f, fill = false), + ) PendingTransactionImage( - hasPending = hasPending, + hasPending = state.hasPending, modifier = Modifier.align(alignment = Alignment.CenterVertically), ) } } @Composable -private fun CurrencyNameText(name: String, modifier: Modifier = Modifier) { +private fun CurrencyNameText(name: String, isAvailable: Boolean, modifier: Modifier = Modifier) { Text( text = name, modifier = modifier, - color = TangemTheme.colors.text.primary1, + color = if (isAvailable) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.tertiary, overflow = TextOverflow.Ellipsis, maxLines = 1, style = TangemTheme.typography.subtitle2, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt index 528978ea61..c33e5c8caa 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt @@ -160,7 +160,11 @@ sealed class TokenItemState { @Immutable sealed class TitleState { - data class Content(val text: String, val hasPending: Boolean = false) : TitleState() + data class Content( + val text: String, + val hasPending: Boolean = false, + val isAvailable: Boolean = true, + ) : TitleState() data object Loading : TitleState() @@ -176,7 +180,7 @@ sealed class TokenItemState { val type: PriceChangeType, ) : SubtitleState() - data class TextContent(val value: String) : SubtitleState() + data class TextContent(val value: String, val isAvailable: Boolean = true) : SubtitleState() data object Unknown : SubtitleState() @@ -192,6 +196,8 @@ sealed class TokenItemState { val hasStaked: Boolean = false, ) : FiatAmountState() + data class TextContent(val text: String, val isAvailable: Boolean = true) : FiatAmountState() + data object Loading : FiatAmountState() data object Locked : FiatAmountState()