diff --git a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketListItemV2.kt b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketListItemV2.kt index df7eea3655..9f5a2c1e63 100644 --- a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketListItemV2.kt +++ b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketListItemV2.kt @@ -39,6 +39,7 @@ import com.tangem.core.ui.ds.image.TangemIconUM import com.tangem.core.ui.ds.row.TangemRowContainer import com.tangem.core.ui.ds.row.TangemRowLayoutId import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.LocalIsInDarkTheme import com.tangem.core.ui.res.LocalWindowSize import com.tangem.core.ui.res.TangemTheme @@ -47,6 +48,7 @@ import com.tangem.core.ui.test.MarketsTestTags import com.tangem.core.ui.test.TokenElementsTestTags import com.tangem.core.ui.windowsize.WindowSizeType import com.tangem.utils.StringsSigns.MINUS +import java.math.BigDecimal import kotlin.random.Random @Composable @@ -88,6 +90,8 @@ fun MarketListItemContentV2(model: MarketsListItemUM, modifier: Modifier = Modif .testTag(tag = TokenElementsTestTags.TOKEN_FIAT_AMOUNT), price = model.price.text, priceChangeType = model.price.changeType, + priceAnnotated = model.price.annotated, + priceValue = model.price.fiatPrice, ) TokenSubtitle( @@ -127,7 +131,7 @@ private fun TokenTitle(name: String, currencySymbol: String, modifier: Modifier .alignByBaseline(), text = name, color = TangemTheme.colors2.text.neutral.primary, - style = TangemTheme.typography2.bodySemibold16, + style = TangemTheme.typography2.bodyMedium16, maxLines = 1, overflow = TextOverflow.Ellipsis, ) @@ -323,12 +327,16 @@ private fun Preview(@PreviewParameter(MarketChartListItemPreviewDataProvider::cl price = MarketsListItemUM.Price( text = "0.${prices[0].first}023 $", changeType = prices[0].second, + fiatPrice = BigDecimal(123123), + annotated = stringReference("0.${prices[0].first}023 $"), ), ) state2 = state2.copy( price = MarketsListItemUM.Price( text = "0.${prices[1].first}023 $", changeType = prices[1].second, + fiatPrice = BigDecimal(123123), + annotated = stringReference("0.${prices[0].first}023 $"), ), ) }, diff --git a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketsListItemPriceAnnotated.kt b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketsListItemPriceAnnotated.kt new file mode 100644 index 0000000000..a972e8801d --- /dev/null +++ b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketsListItemPriceAnnotated.kt @@ -0,0 +1,22 @@ +package com.tangem.common.ui.markets + +import androidx.compose.ui.text.SpanStyle +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.formatStyled +import com.tangem.core.ui.format.bigdecimal.price +import com.tangem.core.ui.res.TangemTheme +import java.math.BigDecimal + +/** + * Fiat amount for markets list rows: integer part in primary style, fractional part (from locale separator) in secondary. + */ +fun BigDecimal.toMarketsListItemPriceAnnotated(appCurrencyCode: String, appCurrencySymbol: String): TextReference { + return formatStyled { + fiat( + fiatCurrencyCode = appCurrencyCode, + fiatCurrencySymbol = appCurrencySymbol, + spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) }, + ).price() + } +} \ No newline at end of file diff --git a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketsListItemV1.kt b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketsListItemV1.kt index bfa927d620..6d051b3cff 100644 --- a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketsListItemV1.kt +++ b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/MarketsListItemV1.kt @@ -29,12 +29,14 @@ import com.tangem.core.ui.components.marketprice.PriceChangeInPercent import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.LocalWindowSize import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.test.MarketsTestTags import com.tangem.core.ui.windowsize.WindowSizeType import com.tangem.utils.StringsSigns.MINUS +import java.math.BigDecimal import kotlin.random.Random @Composable @@ -85,6 +87,8 @@ private fun MarketsListItemContentV1(model: MarketsListItemUM, modifier: Modifie modifier = Modifier.alignByBaseline(), price = model.price.text, priceChangeType = model.price.changeType, + priceAnnotated = model.price.annotated, + priceValue = model.price.fiatPrice, ) } @@ -306,12 +310,16 @@ private fun Preview(@PreviewParameter(MarketChartListItemPreviewDataProvider::cl price = MarketsListItemUM.Price( text = "0.${prices[0].first}023 $", changeType = prices[0].second, + fiatPrice = BigDecimal(123123), + annotated = stringReference("0.${prices[0].first}023 $"), ), ) state2 = state2.copy( price = MarketsListItemUM.Price( text = "0.${prices[1].first}023 $", changeType = prices[1].second, + fiatPrice = BigDecimal(123123), + annotated = stringReference("0.${prices[0].first}023 $"), ), ) }, diff --git a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/models/MarketsListItemUM.kt b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/models/MarketsListItemUM.kt index 7659617208..9136b31345 100644 --- a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/models/MarketsListItemUM.kt +++ b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/models/MarketsListItemUM.kt @@ -6,6 +6,7 @@ import com.tangem.common.ui.charts.state.MarketChartRawData import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.models.currency.CryptoCurrency +import java.math.BigDecimal @Immutable data class MarketsListItemUM( @@ -40,7 +41,9 @@ data class MarketsListItemUM( @Immutable data class Price( val text: String, + val annotated: TextReference, val changeType: PriceChangeType? = null, + val fiatPrice: BigDecimal, ) @Suppress("NullableToStringCall") diff --git a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/preview/MarketChartListItemPreviewDataProvider.kt b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/preview/MarketChartListItemPreviewDataProvider.kt index 29cd1685ff..0956d1a6a0 100644 --- a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/preview/MarketChartListItemPreviewDataProvider.kt +++ b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/preview/MarketChartListItemPreviewDataProvider.kt @@ -7,6 +7,7 @@ import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.models.currency.CryptoCurrency import kotlinx.collections.immutable.persistentListOf +import java.math.BigDecimal @Suppress("MagicNumber") class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvider( @@ -18,7 +19,11 @@ class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvide iconUrl = "", ratingPosition = "1", marketCap = "$6.233 B", - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + fiatPrice = BigDecimal(123123), + annotated = stringReference("31 285.72$"), + ), trendPercentText = "12.43%", trendType = PriceChangeType.UP, chartData = MarketChartRawData( @@ -35,7 +40,11 @@ class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvide iconUrl = null, ratingPosition = "2", marketCap = "$6.233 B", - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + fiatPrice = BigDecimal(123123), + annotated = stringReference("31 285.72$"), + ), trendPercentText = "12.43%", trendType = PriceChangeType.NEUTRAL, chartData = null, @@ -50,7 +59,11 @@ class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvide iconUrl = null, ratingPosition = "10", marketCap = "$6.23348172384781234 B", - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + fiatPrice = BigDecimal(123123), + annotated = stringReference("31 285.72$"), + ), trendPercentText = "12.43%", trendType = PriceChangeType.DOWN, chartData = MarketChartRawData( @@ -67,7 +80,11 @@ class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvide iconUrl = null, ratingPosition = "10", marketCap = null, - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + fiatPrice = BigDecimal(123123), + annotated = stringReference("31 285.72$"), + ), trendPercentText = "12.43%", trendType = PriceChangeType.UP, chartData = MarketChartRawData( @@ -84,7 +101,11 @@ class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvide iconUrl = null, ratingPosition = null, marketCap = "$6.233 B", - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + fiatPrice = BigDecimal(123123), + annotated = stringReference("31 285.72$"), + ), trendPercentText = "12.43%", trendType = PriceChangeType.UP, chartData = MarketChartRawData( @@ -101,7 +122,11 @@ class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvide iconUrl = null, ratingPosition = null, marketCap = null, - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + fiatPrice = BigDecimal(123123), + annotated = stringReference("31 285.72$"), + ), trendPercentText = "12.43%", trendType = PriceChangeType.UP, chartData = MarketChartRawData( diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenPriceText.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenPriceText.kt index df80ddeae9..7ab071bfbd 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenPriceText.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenPriceText.kt @@ -6,25 +6,33 @@ import androidx.compose.animation.core.tween import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.withStyle import com.tangem.core.ui.components.marketprice.PriceChangeType +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveAnnotatedReference import com.tangem.core.ui.res.LocalRedesignEnabled import com.tangem.core.ui.res.TangemTheme +import java.math.BigDecimal /** * Text view for token price. * - * @param price Price of the token. + * @param price Plain price string (used by V1 and as fallback for V2 when [priceAnnotated] is null). + * @param priceAnnotated Optional styled price (locale-aware decimal separator + secondary fractional color). * @param priceChangeType Type of the price change. */ @Composable -fun TokenPriceText(price: String, modifier: Modifier = Modifier, priceChangeType: PriceChangeType? = null) { +fun TokenPriceText( + priceValue: BigDecimal, + price: String, + priceAnnotated: TextReference, + modifier: Modifier = Modifier, + priceChangeType: PriceChangeType? = null, +) { if (LocalRedesignEnabled.current) { TokenPriceTextV2( - price = price, + priceValue = priceValue, + priceAnnotated = priceAnnotated, modifier = modifier, priceChangeType = priceChangeType, ) @@ -76,16 +84,20 @@ private fun TokenPriceTextV1(price: String, modifier: Modifier = Modifier, price } @Composable -private fun TokenPriceTextV2(price: String, modifier: Modifier = Modifier, priceChangeType: PriceChangeType? = null) { +private fun TokenPriceTextV2( + priceValue: BigDecimal, + priceAnnotated: TextReference, + modifier: Modifier = Modifier, + priceChangeType: PriceChangeType? = null, +) { val growColor = TangemTheme.colors2.text.status.accent val fallColor = TangemTheme.colors2.text.status.warning val generalColor = TangemTheme.colors2.text.neutral.primary - val decimalColor = TangemTheme.colors2.text.neutral.secondary val color = remember(generalColor) { Animatable(generalColor) } var isAnimationSkipped by remember { mutableStateOf(false) } - LaunchedEffect(price) { + LaunchedEffect(priceValue) { if (!isAnimationSkipped) { isAnimationSkipped = true return@LaunchedEffect @@ -103,27 +115,9 @@ private fun TokenPriceTextV2(price: String, modifier: Modifier = Modifier, price } } - val annotatedText = remember(price) { - buildAnnotatedString { - val dotIndex = price.indexOf(".") - - if (dotIndex == -1) { - append(price) - } else { - append(price.take(dotIndex)) - - withStyle( - style = SpanStyle(color = decimalColor), - ) { - append(price.substring(dotIndex)) - } - } - } - } - Text( modifier = modifier, - text = annotatedText, + text = priceAnnotated.resolveAnnotatedReference(), color = color.value, maxLines = 1, style = TangemTheme.typography2.bodySemibold16, diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/markets/models/response/TokenMarketInfoResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/markets/models/response/TokenMarketInfoResponse.kt index 8472387cb9..21c7d87c86 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/markets/models/response/TokenMarketInfoResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/markets/models/response/TokenMarketInfoResponse.kt @@ -116,6 +116,8 @@ data class TokenMarketInfoResponse( val maxSupply: BigDecimal?, @Json(name = "fully_diluted_valuation") val fullyDilutedValuation: BigDecimal?, + @Json(name = "fully_diluted_valuation_change_24h") + val fullyDilutedValuationChange24H: BigDecimal?, ) @JsonClass(generateAdapter = true) diff --git a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt index a1f6549b2b..2c29aedd8b 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt @@ -172,6 +172,40 @@ fun BigDecimalFiatFormat.price(): BigDecimalFormat = BigDecimalFormat { value -> .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) } +/** + * Formats fiat price with precision calculated based on the value. + * Styled version — fractional part uses [spanStyleReference]. + * @see getFiatPriceAmountWithScale + */ +fun BigDecimalFiatFormatStyled.price() = price(spanStyleReference) + +private fun BigDecimalFiatFormatStyled.price(spanStyleReference: SpanStyleReference) = BigDecimalFormatStyled { value -> + val formatterCurrency = getJavaCurrencyByCode(fiatCurrencyCode) + + val (priceAmount, finalScale) = getFiatPriceAmountWithScale(value = value) + + val formatter = NumberFormat.getCurrencyInstance(locale).apply { + currency = formatterCurrency + maximumFractionDigits = finalScale + minimumFractionDigits = FIAT_MARKET_DEFAULT_DIGITS + roundingMode = RoundingMode.HALF_UP + } + + val decimalSeparator = (formatter as? DecimalFormat)?.decimalFormatSymbols?.decimalSeparator + val formattedAmount = formatter.format(priceAmount) + .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) + + val separatorIndex = decimalSeparator?.let { formattedAmount.indexOf(it) } ?: formattedAmount.length + + val wholePart = formattedAmount.take(separatorIndex) + val fractionalPart = formattedAmount.drop(separatorIndex) + + combinedReference( + stringReference(wholePart), + styledStringReference(fractionalPart, spanStyleReference), + ) +} + /** * Formats fiat amount with an exact number of fractional digits. */ diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemTypography2.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemTypography2.kt index 8404f3a578..38675546fd 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemTypography2.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemTypography2.kt @@ -198,6 +198,18 @@ class TangemTypography2 internal constructor( ), ) + val bodyMedium16: TextStyle = TextStyle( + fontFamily = fontFamily, + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + letterSpacing = TextUnit(value = -0.32f, type = TextUnitType.Sp), + lineHeight = TextUnit(value = 20f, type = TextUnitType.Sp), + lineHeightStyle = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Center, + trim = LineHeightStyle.Trim.None, + ), + ) + val bodyRegular15: TextStyle = TextStyle( fontFamily = fontFamily, fontSize = 15.sp, diff --git a/core/ui/src/main/res/drawable/ic_yield_mode_16.xml b/core/ui/src/main/res/drawable/ic_yield_mode_16.xml new file mode 100644 index 0000000000..91bfaf07df --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_yield_mode_16.xml @@ -0,0 +1,9 @@ + + + diff --git a/data/markets/src/main/java/com/tangem/data/markets/converters/TokenMarketInfoConverter.kt b/data/markets/src/main/java/com/tangem/data/markets/converters/TokenMarketInfoConverter.kt index 8a6cee1f3f..bbcfcb10ab 100644 --- a/data/markets/src/main/java/com/tangem/data/markets/converters/TokenMarketInfoConverter.kt +++ b/data/markets/src/main/java/com/tangem/data/markets/converters/TokenMarketInfoConverter.kt @@ -111,6 +111,7 @@ internal class TokenMarketInfoConverter( volume24h = volume24h, maxSupply = maxSupply, fullyDilutedValuation = fullyDilutedValuation, + fullyDilutedValuationChange24 = fullyDilutedValuationChange24H, ) } diff --git a/data/search/src/main/java/com/tangem/data/search/converter/SearchHistoryConverter.kt b/data/search/src/main/java/com/tangem/data/search/converter/SearchHistoryConverter.kt index 60bedf12bd..68ccb8eec8 100644 --- a/data/search/src/main/java/com/tangem/data/search/converter/SearchHistoryConverter.kt +++ b/data/search/src/main/java/com/tangem/data/search/converter/SearchHistoryConverter.kt @@ -5,7 +5,9 @@ import com.tangem.data.search.model.TextHintDTO import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.search.model.RecentSearchToken import com.tangem.domain.search.model.SearchTextHint +import com.tangem.domain.search.model.TokenPriceChangeDirection import com.tangem.utils.converter.Converter +import java.math.BigDecimal internal class TextHintDTOToSearchTextHintConverter : Converter { override fun convert(value: TextHintDTO): SearchTextHint { @@ -24,6 +26,15 @@ internal class RecentTokenDTOToRecentSearchTokenConverter : Converter TextReference.Res(R.string.common_staking) EarnType.YIELD -> TextReference.Res(R.string.common_yield_mode) }, + earnType = value.earnToken.type, onItemClick = { onItemClick(value) }, ) } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt index 3dea584bad..dda2c04ee8 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt @@ -5,6 +5,7 @@ import com.tangem.common.ui.charts.state.MarketChartRawData import com.tangem.common.ui.charts.state.converter.PriceAndTimePointValuesConverter import com.tangem.common.ui.charts.state.sorted import com.tangem.common.ui.markets.models.MarketsListItemUM +import com.tangem.common.ui.markets.toMarketsListItemPriceAnnotated import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList @@ -110,7 +111,12 @@ internal class MarketsTokenItemConverter( return MarketsListItemUM.Price( text = priceText, + annotated = tokenQuotesShort.currentPrice.toMarketsListItemPriceAnnotated( + appCurrencyCode = appCurrency.code, + appCurrencySymbol = appCurrency.symbol, + ), changeType = changeType, + fiatPrice = tokenQuotesShort.currentPrice, ) } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/MarketsTokenDetailsModel.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/MarketsTokenDetailsModel.kt index b92a688326..85cb23c471 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/MarketsTokenDetailsModel.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/MarketsTokenDetailsModel.kt @@ -230,6 +230,9 @@ internal class MarketsTokenDetailsModel @Inject constructor( fiatCurrencySymbol = currentAppCurrency.value.symbol, ).price() }, + priceAnnotated = params.token.tokenQuotes.currentPrice.toMarketsTokenDetailsPriceAnnotated( + currentAppCurrency.value, + ), dateTimeText = resourceReference(R.string.common_today), priceChangePercentText = params.token.tokenQuotes.h24Percent?.format { percent() }, priceChangeType = params.token.tokenQuotes.h24Percent.percentChangeType(), @@ -505,6 +508,9 @@ internal class MarketsTokenDetailsModel @Inject constructor( fiatCurrencyCode = currentAppCurrency.value.code, ).price() }, + priceAnnotated = newInfo.quotes.currentPrice.toMarketsTokenDetailsPriceAnnotated( + currentAppCurrency.value, + ), priceChangePercentText = newInfo.quotes.getFormattedPercentByInterval( interval = marketsTokenDetailsUM.selectedInterval, ), @@ -604,7 +610,8 @@ internal class MarketsTokenDetailsModel @Inject constructor( ) } ?: getDefaultDateTimeString(currentState.selectedInterval) - val priceText = (price ?: currentQuotes.value.currentPrice).format { + val amountForPrice = price ?: currentQuotes.value.currentPrice + val priceText = amountForPrice.format { fiat( fiatCurrencySymbol = currentAppCurrency.value.symbol, fiatCurrencyCode = currentAppCurrency.value.code, @@ -625,6 +632,7 @@ internal class MarketsTokenDetailsModel @Inject constructor( isMarkerSet = markerTimestamp != null, dateTimeText = dateTimeText, priceText = priceText, + priceAnnotated = amountForPrice.toMarketsTokenDetailsPriceAnnotated(currentAppCurrency.value), priceChangePercentText = percentText, priceChangeType = percent.percentChangeType(), ) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/converter/MetricsConverter.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/converter/MetricsConverter.kt index 3422433ee1..ffd70f6371 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/converter/MetricsConverter.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/converter/MetricsConverter.kt @@ -1,10 +1,7 @@ package com.tangem.features.feed.model.market.details.converter import androidx.compose.runtime.Stable -import com.tangem.core.ui.extensions.combinedReference -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.stringReference -import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.extensions.* import com.tangem.core.ui.format.bigdecimal.compact import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.fiat @@ -188,6 +185,7 @@ internal class MetricsConverter( formatArgs = wrappedList(formatted), ) }, + fullyDilutedValuationChange24 = fullyDilutedValuationChange24?.convertChange(), onInfoClick = { onInfoClick( InfoBottomSheetContent( @@ -280,6 +278,17 @@ internal class MetricsConverter( } } + private fun BigDecimal?.convertChange(): TextReference? { + if (this == null) return null + val amount = this.abs().formatAmount() + val value = when { + this > BigDecimal.ZERO -> StringsSigns.PLUS + amount + this < BigDecimal.ZERO -> StringsSigns.MINUS + amount + else -> amount + } + return value?.let(::stringReference) + } + @Suppress("MagicNumber") private fun getLiquidity(volume24h: BigDecimal?, marketCap: BigDecimal?): Float? { if (volume24h == null || marketCap == null || marketCap == BigDecimal.ZERO) return null diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/formatter/Formatters.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/formatter/Formatters.kt index 218580167e..409fcf4e92 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/formatter/Formatters.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/formatter/Formatters.kt @@ -1,10 +1,12 @@ package com.tangem.features.feed.model.market.details.formatter +import androidx.compose.ui.text.SpanStyle import com.tangem.common.ui.charts.state.MarketChartLook import com.tangem.core.ui.components.marketprice.PriceChangeType -import com.tangem.core.ui.format.bigdecimal.format -import com.tangem.core.ui.format.bigdecimal.getFiatPriceAmountWithScale -import com.tangem.core.ui.format.bigdecimal.percent +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.format.bigdecimal.* +import com.tangem.core.ui.res.TangemTheme +import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.markets.PriceChangeInterval import com.tangem.domain.markets.TokenQuotes import java.math.BigDecimal @@ -73,4 +75,14 @@ internal fun PriceChangeType.toChartType(): MarketChartLook.Type { PriceChangeType.DOWN -> MarketChartLook.Type.Falling PriceChangeType.NEUTRAL -> MarketChartLook.Type.Neutral } +} + +internal fun BigDecimal.toMarketsTokenDetailsPriceAnnotated(appCurrency: AppCurrency): TextReference { + return formatStyled { + fiat( + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.tertiary) }, + ).price() + } } \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/state/QuotesStateUpdater.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/state/QuotesStateUpdater.kt index 8ea1c11938..c646386959 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/state/QuotesStateUpdater.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/details/state/QuotesStateUpdater.kt @@ -66,6 +66,7 @@ internal class QuotesStateUpdater( fiatCurrencyCode = currentAppCurrency().code, ).price() }, + priceAnnotated = newQuotes.currentPrice.toMarketsTokenDetailsPriceAnnotated(currentAppCurrency()), priceChangePercentText = newQuotes.getFormattedPercentByInterval( interval = stateToUpdate.selectedInterval, ), diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/news/details/converter/RelatedTokenConverter.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/news/details/converter/RelatedTokenConverter.kt index 27c51c52e0..ef61cb6cc5 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/news/details/converter/RelatedTokenConverter.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/news/details/converter/RelatedTokenConverter.kt @@ -6,6 +6,7 @@ import com.tangem.common.ui.charts.state.MarketChartRawData import com.tangem.common.ui.charts.state.converter.PriceAndTimePointValuesConverter import com.tangem.common.ui.charts.state.sorted import com.tangem.common.ui.markets.models.MarketsListItemUM +import com.tangem.common.ui.markets.toMarketsListItemPriceAnnotated import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.format.bigdecimal.* import com.tangem.data.common.currency.getTokenIconUrlFromDefaultHost @@ -68,7 +69,12 @@ internal class RelatedTokenConverter(private val appCurrency: AppCurrency) : return MarketsListItemUM.Price( text = priceText, + annotated = tokenInfo.quotes.currentPrice.toMarketsListItemPriceAnnotated( + appCurrencyCode = appCurrency.code, + appCurrencySymbol = appCurrency.symbol, + ), changeType = null, + fiatPrice = tokenInfo.quotes.currentPrice, ) } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt index a21b032562..2273f437bb 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt @@ -5,19 +5,27 @@ import com.tangem.common.ui.markets.models.MarketsListItemUM import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer -import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.common.ui.charts.state.MarketChartData +import com.tangem.common.ui.charts.state.converter.PriceAndTimePointValuesConverter +import com.tangem.common.ui.charts.state.sorted import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase +import com.tangem.domain.markets.GetTokenPriceChartUseCase +import com.tangem.domain.markets.PriceChangeInterval import com.tangem.domain.models.account.AccountName -import com.tangem.domain.search.model.RecentSearchToken import com.tangem.domain.search.usecase.ClearSearchHistoryUseCase import com.tangem.domain.search.usecase.GetSearchResultsUseCase +import com.tangem.domain.search.usecase.SaveRecentSearchTokenUseCase import com.tangem.domain.search.usecase.SaveSearchQueryUseCase import com.tangem.features.feed.components.search.DefaultSearchComponent import com.tangem.features.feed.model.market.list.state.MarketsListUM import com.tangem.features.feed.model.market.list.state.SortByTypeUM import com.tangem.features.feed.model.market.list.statemanager.MarketsListBatchFlowManager +import com.tangem.features.feed.model.search.converter.MarketsListItemUMToRecentSearchTokenConverter +import com.tangem.features.feed.model.search.converter.MarketsListItemUMWithAppCurrency +import com.tangem.features.feed.model.search.converter.RecentSearchTokenToMarketsListItemUMConverter +import com.tangem.features.feed.model.search.converter.RecentSearchTokenWithAppCurrency import com.tangem.features.feed.model.search.state.SearchStateController import com.tangem.features.feed.model.search.state.transformers.* import com.tangem.features.feed.ui.search.state.* @@ -28,6 +36,9 @@ import com.tangem.utils.coroutines.saveIn import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch @@ -45,7 +56,9 @@ internal class SearchModel @Inject constructor( getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getSearchResultsUseCase: GetSearchResultsUseCase, private val saveSearchQueryUseCase: SaveSearchQueryUseCase, + private val saveRecentSearchTokenUseCase: SaveRecentSearchTokenUseCase, private val clearSearchHistoryUseCase: ClearSearchHistoryUseCase, + private val getTokenPriceChartUseCase: GetTokenPriceChartUseCase, private val stateController: SearchStateController, ) : Model() { @@ -64,6 +77,18 @@ internal class SearchModel @Inject constructor( initialValue = AppCurrency.Default, ) + private val marketsListItemToRecentSearchTokenConverter by lazy { + MarketsListItemUMToRecentSearchTokenConverter() + } + + private val recentSearchTokenToMarketsListItemConverter by lazy { + RecentSearchTokenToMarketsListItemUMConverter() + } + + private val priceAndTimePointValuesConverter by lazy { + PriceAndTimePointValuesConverter(shouldFormatAxis = false) + } + private val searchMarketsListManager by lazy { MarketsListBatchFlowManager( getMarketsTokenListFlowUseCase = getMarketsTokenListFlowUseCase, @@ -108,8 +133,15 @@ internal class SearchModel @Inject constructor( stateController.update(UpdateSearchBarQueryTransformer(text)) } - fun onResultMarketTokenClick() { + fun onResultMarketTokenClick(item: MarketsListItemUM) { modelScope.launch(dispatchers.default) { + val appCurrency = currentAppCurrency.value + val input = MarketsListItemUMWithAppCurrency( + item = item, + appCurrencyCode = appCurrency.code, + appCurrencySymbol = appCurrency.symbol, + ) + saveRecentSearchTokenUseCase(marketsListItemToRecentSearchTokenConverter.convert(input)) saveSearchQueryUseCase(stateController.value.searchBar.query) } } @@ -263,31 +295,43 @@ internal class SearchModel @Inject constructor( TextHintItemUM(text = hint.text) }.toImmutableList() + val appCurrency = currentAppCurrency.value val recentTokens = searchResult.recentTokens.map { token -> - token.toMarketsListItemUM() + recentSearchTokenToMarketsListItemConverter.convert( + RecentSearchTokenWithAppCurrency(token = token, appCurrency = appCurrency), + ) }.toImmutableList() stateController.update(UpdateHistoryTransformer(textHints, recentTokens)) + + loadRecentTokenCharts(recentTokens, appCurrency) } }.saveIn(searchResultsJob) } - private fun RecentSearchToken.toMarketsListItemUM(): MarketsListItemUM { - return MarketsListItemUM( - id = id, - name = name, - currencySymbol = symbol, - iconUrl = imageUrl, - ratingPosition = null, - marketCap = null, - price = MarketsListItemUM.Price(text = ""), - trendPercentText = "", - trendType = PriceChangeType.NEUTRAL, - chartData = null, - isUnder100kMarketCap = false, - stakingRate = null, - updateTimestamp = timestamp, - ) + private suspend fun loadRecentTokenCharts(tokens: ImmutableList, appCurrency: AppCurrency) { + coroutineScope { + tokens.map { token -> + async(dispatchers.io) { + val chart = getTokenPriceChartUseCase( + appCurrency = appCurrency, + interval = PriceChangeInterval.H24, + tokenId = token.id, + tokenSymbol = token.currencySymbol, + preview = true, + ).getOrElse { return@async } + + val chartData = priceAndTimePointValuesConverter.convert( + MarketChartData.Data( + y = chart.priceY.toImmutableList(), + x = chart.timeStamps.map { it.toBigDecimal() }.toImmutableList(), + ).sorted(), + ) + + stateController.update(UpdateRecentTokenChartTransformer(token.id, chartData)) + } + }.awaitAll() + } } private fun AccountName.toDisplayString(): String { diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/MarketsListItemUMToRecentSearchTokenConverter.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/MarketsListItemUMToRecentSearchTokenConverter.kt new file mode 100644 index 0000000000..cd17f16458 --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/MarketsListItemUMToRecentSearchTokenConverter.kt @@ -0,0 +1,41 @@ +package com.tangem.features.feed.model.search.converter + +import com.tangem.core.ui.components.marketprice.PriceChangeType +import com.tangem.core.ui.extensions.TextReference +import com.tangem.domain.search.model.RecentSearchToken +import com.tangem.domain.search.model.TokenPriceChangeDirection +import com.tangem.utils.converter.Converter + +internal class MarketsListItemUMToRecentSearchTokenConverter : + Converter { + + override fun convert(value: MarketsListItemUMWithAppCurrency): RecentSearchToken { + val item = value.item + val direction = when (item.trendType) { + PriceChangeType.UP -> TokenPriceChangeDirection.UP + PriceChangeType.DOWN -> TokenPriceChangeDirection.DOWN + PriceChangeType.NEUTRAL -> TokenPriceChangeDirection.NEUTRAL + } + val stakingText = when (val rate = item.stakingRate) { + is TextReference.Str -> rate.value + is TextReference.StyledStr -> rate.value + else -> null + } + return RecentSearchToken( + id = item.id, + name = item.name, + symbol = item.currencySymbol, + imageUrl = item.iconUrl, + timestamp = item.updateTimestamp ?: System.currentTimeMillis(), + appCurrencyCode = value.appCurrencyCode, + appCurrencySymbol = value.appCurrencySymbol, + price = item.price.fiatPrice, + priceChangePercent = item.trendPercentText, + priceChangeDirection = direction, + marketCap = item.marketCap, + ratingPosition = item.ratingPosition, + isUnder100kMarketCap = item.isUnder100kMarketCap, + stakingRateText = stakingText, + ) + } +} \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/MarketsListItemUMWithAppCurrency.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/MarketsListItemUMWithAppCurrency.kt new file mode 100644 index 0000000000..e2c566a31b --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/MarketsListItemUMWithAppCurrency.kt @@ -0,0 +1,9 @@ +package com.tangem.features.feed.model.search.converter + +import com.tangem.common.ui.markets.models.MarketsListItemUM + +internal data class MarketsListItemUMWithAppCurrency( + val item: MarketsListItemUM, + val appCurrencyCode: String, + val appCurrencySymbol: String, +) \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/RecentSearchTokenToMarketsListItemUMConverter.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/RecentSearchTokenToMarketsListItemUMConverter.kt new file mode 100644 index 0000000000..840613cb88 --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/RecentSearchTokenToMarketsListItemUMConverter.kt @@ -0,0 +1,55 @@ +package com.tangem.features.feed.model.search.converter + +import com.tangem.common.ui.markets.models.MarketsListItemUM +import com.tangem.common.ui.markets.toMarketsListItemPriceAnnotated +import com.tangem.core.ui.components.marketprice.PriceChangeType +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.core.ui.format.bigdecimal.price +import com.tangem.domain.search.model.TokenPriceChangeDirection +import com.tangem.utils.converter.Converter + +internal class RecentSearchTokenToMarketsListItemUMConverter : + Converter { + + override fun convert(value: RecentSearchTokenWithAppCurrency): MarketsListItemUM { + val token = value.token + val currencyCode = token.appCurrencyCode.ifEmpty { value.appCurrency.code } + val currencySymbol = token.appCurrencySymbol.ifEmpty { value.appCurrency.symbol } + val trendType = when (token.priceChangeDirection) { + TokenPriceChangeDirection.UP -> PriceChangeType.UP + TokenPriceChangeDirection.DOWN -> PriceChangeType.DOWN + TokenPriceChangeDirection.NEUTRAL -> PriceChangeType.NEUTRAL + } + val priceText = token.price.format { + fiat( + fiatCurrencyCode = currencyCode, + fiatCurrencySymbol = currencySymbol, + ).price() + } + return MarketsListItemUM( + id = token.id, + name = token.name, + currencySymbol = token.symbol, + iconUrl = token.imageUrl, + ratingPosition = token.ratingPosition, + marketCap = token.marketCap, + price = MarketsListItemUM.Price( + text = priceText, + annotated = token.price.toMarketsListItemPriceAnnotated( + appCurrencyCode = currencyCode, + appCurrencySymbol = currencySymbol, + ), + changeType = null, + fiatPrice = token.price, + ), + trendPercentText = token.priceChangePercent, + trendType = trendType, + chartData = null, + isUnder100kMarketCap = token.isUnder100kMarketCap, + stakingRate = token.stakingRateText?.let { TextReference.Str(it) }, + updateTimestamp = token.timestamp, + ) + } +} \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/RecentSearchTokenWithAppCurrency.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/RecentSearchTokenWithAppCurrency.kt new file mode 100644 index 0000000000..6c7939c071 --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/converter/RecentSearchTokenWithAppCurrency.kt @@ -0,0 +1,9 @@ +package com.tangem.features.feed.model.search.converter + +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.search.model.RecentSearchToken + +internal data class RecentSearchTokenWithAppCurrency( + val token: RecentSearchToken, + val appCurrency: AppCurrency, +) \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/transformers/UpdateRecentTokenChartTransformer.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/transformers/UpdateRecentTokenChartTransformer.kt new file mode 100644 index 0000000000..ffef6c8505 --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/transformers/UpdateRecentTokenChartTransformer.kt @@ -0,0 +1,30 @@ +package com.tangem.features.feed.model.search.state.transformers + +import com.tangem.common.ui.charts.state.MarketChartRawData +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.features.feed.ui.search.state.SearchContentUM +import com.tangem.features.feed.ui.search.state.SearchUM +import kotlinx.collections.immutable.toImmutableList + +internal class UpdateRecentTokenChartTransformer( + private val tokenId: CryptoCurrency.RawID, + private val chartData: MarketChartRawData, +) : SearchUMTransformer { + + override fun transform(prevState: SearchUM): SearchUM { + val content = prevState.content + if (content !is SearchContentUM.History) return prevState + + val updatedTokens = content.recentTokens.map { token -> + if (token.id == tokenId) { + token.copy(chartData = chartData) + } else { + token + } + }.toImmutableList() + + return prevState.copy( + content = content.copy(recentTokens = updatedTokens), + ) + } +} \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt index d3800af21f..ffdf82486b 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt @@ -24,6 +24,7 @@ import com.tangem.core.ui.components.list.InfiniteListHandler import com.tangem.core.ui.decorations.roundedShapeItemDecoration import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.* +import com.tangem.domain.models.earn.EarnType import com.tangem.features.feed.ui.earn.components.* import com.tangem.features.feed.ui.earn.state.* import com.tangem.features.feed.ui.feed.state.FeedListSearchBar @@ -641,7 +642,8 @@ private fun previewEarnListItemUM( shouldShowCustomBadge = false, ), earnValue = stringReference("APY 6.54%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnListItem.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnListItem.kt index 6e4e9799cb..66ead3805f 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnListItem.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnListItem.kt @@ -30,6 +30,7 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.* +import com.tangem.domain.models.earn.EarnType import com.tangem.features.feed.ui.earn.state.EarnListItemUM @Composable @@ -95,7 +96,7 @@ private fun EarnListItemV1(item: EarnListItemUM, modifier: Modifier = Modifier) ) SpacerH(2.dp) Text( - text = item.earnType.resolveReference(), + text = item.earnTypeTitle.resolveReference(), color = TangemTheme.colors.text.tertiary, style = TangemTheme.typography.caption2, maxLines = 1, @@ -147,6 +148,7 @@ private fun EarnListItemV2(item: EarnListItemUM, modifier: Modifier = Modifier) ModeBlock( modifier = Modifier.layoutId(layoutId = TangemRowLayoutId.END_BOTTOM), earnType = item.earnType, + earnTypeTitle = item.earnTypeTitle, ) }, ) @@ -200,19 +202,24 @@ private fun TokenTitle(name: String, symbol: String, modifier: Modifier = Modifi } @Composable -private fun ModeBlock(earnType: TextReference, modifier: Modifier = Modifier) { +private fun ModeBlock(earnType: EarnType, earnTypeTitle: TextReference, modifier: Modifier = Modifier) { Row( modifier = modifier, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(2.dp), ) { Icon( - imageVector = ImageVector.vectorResource(R.drawable.ic_staking_new_16), + imageVector = ImageVector.vectorResource( + id = when (earnType) { + EarnType.STAKING -> R.drawable.ic_staking_new_16 + EarnType.YIELD -> R.drawable.ic_yield_mode_16 + }, + ), tint = TangemTheme.colors2.markers.iconGray, contentDescription = null, ) Text( - text = earnType.resolveReference(), + text = earnTypeTitle.resolveReference(), style = TangemTheme.typography2.captionSemibold12, color = TangemTheme.colors2.text.neutral.tertiary, ) @@ -239,7 +246,8 @@ private fun EarnListItemPreviewV1() { shouldShowCustomBadge = false, ), earnValue = stringReference("APY 8.50%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ), ) @@ -257,7 +265,8 @@ private fun EarnListItemPreviewV1() { shouldShowCustomBadge = false, ), earnValue = stringReference("APY 8.50%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ), ) @@ -286,7 +295,8 @@ private fun EarnListItemPreviewV2() { shouldShowCustomBadge = false, ), earnValue = stringReference("APY 8.50%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ), ) @@ -305,7 +315,8 @@ private fun EarnListItemPreviewV2() { shouldShowCustomBadge = false, ), earnValue = stringReference("APY 8.50%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ), ) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/MostlyUsedCard.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/MostlyUsedCard.kt index b9c88ee004..1acfb25681 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/MostlyUsedCard.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/MostlyUsedCard.kt @@ -21,6 +21,7 @@ import com.tangem.core.ui.ds.image.TangemIconUM import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.* +import com.tangem.domain.models.earn.EarnType import com.tangem.features.feed.ui.earn.state.EarnListItemUM @Composable @@ -161,7 +162,8 @@ private fun EarnListItemPreviewV1() { shouldShowCustomBadge = false, ), earnValue = stringReference("APY 6.54%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ), onClick = {}, @@ -187,7 +189,8 @@ private fun EarnListItemPreviewV2() { shouldShowCustomBadge = false, ), earnValue = stringReference("APY 6.54%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ), onClick = {}, diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt index 72ba54139d..763954d13f 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt @@ -3,6 +3,7 @@ package com.tangem.features.feed.ui.earn.state import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.currency.icon.CurrencyIconState import com.tangem.core.ui.extensions.TextReference +import com.tangem.domain.models.earn.EarnType import kotlinx.collections.immutable.ImmutableList @Immutable @@ -32,6 +33,7 @@ internal data class EarnListItemUM( val tokenName: TextReference, val currencyIconState: CurrencyIconState, val earnValue: TextReference, - val earnType: TextReference, + val earnType: EarnType, + val earnTypeTitle: TextReference, val onItemClick: () -> Unit, ) \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/preview/FeedListPreviewDataProvider.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/preview/FeedListPreviewDataProvider.kt index 7f775602b2..e3a0a86a28 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/preview/FeedListPreviewDataProvider.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/preview/FeedListPreviewDataProvider.kt @@ -11,12 +11,14 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemColorPalette import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.earn.EarnType import com.tangem.features.feed.model.market.list.state.SortByTypeUM import com.tangem.features.feed.ui.earn.state.EarnListItemUM import com.tangem.features.feed.ui.earn.state.EarnListUM import com.tangem.features.feed.ui.feed.components.articles.ArticleConfigUM import com.tangem.features.feed.ui.feed.state.* import kotlinx.collections.immutable.* +import java.math.BigDecimal @Suppress("MagicNumber") internal object FeedListPreviewDataProvider { @@ -246,7 +248,11 @@ internal object FeedListPreviewDataProvider { iconUrl = null, ratingPosition = rating, marketCap = marketCap, - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + fiatPrice = BigDecimal(123123), + annotated = stringReference("31 285.72$"), + ), trendPercentText = percent, trendType = trendType, chartData = MarketChartRawData( @@ -273,7 +279,8 @@ internal object FeedListPreviewDataProvider { shouldShowCustomBadge = false, ), earnValue = stringReference("APY 6.54%"), - earnType = stringReference("Yield"), + earnTypeTitle = stringReference("Yield"), + earnType = EarnType.YIELD, onItemClick = {}, ) }.toPersistentList() diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt index 68076673c5..48b2e71786 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt @@ -37,6 +37,7 @@ import com.tangem.core.ui.ds.tabs.TangemSegmentedPicker import com.tangem.core.ui.event.EventEffect import com.tangem.core.ui.event.StateEvent import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveAnnotatedReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.res.LocalRedesignEnabled @@ -182,6 +183,7 @@ private fun Header(state: MarketsTokenDetailsUM, modifier: Modifier = Modifier) Column(modifier = Modifier.weight(1f)) { TokenPriceText( price = state.priceText, + priceAnnotated = state.priceAnnotated, triggerPriceChange = state.triggerPriceChange, ) Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4)) { @@ -212,6 +214,28 @@ private fun Header(state: MarketsTokenDetailsUM, modifier: Modifier = Modifier) @Composable private fun TokenPriceText( + price: String, + triggerPriceChange: StateEvent, + priceAnnotated: TextReference, + modifier: Modifier = Modifier, +) { + if (LocalRedesignEnabled.current) { + TokenPriceTextV2( + priceAnnotated = priceAnnotated, + triggerPriceChange = triggerPriceChange, + modifier = modifier, + ) + } else { + TokenPriceTextV1( + price = price, + triggerPriceChange = triggerPriceChange, + modifier = modifier, + ) + } +} + +@Composable +private fun TokenPriceTextV1( price: String, triggerPriceChange: StateEvent, modifier: Modifier = Modifier, @@ -244,6 +268,40 @@ private fun TokenPriceText( ) } +@Composable +private fun TokenPriceTextV2( + priceAnnotated: TextReference, + triggerPriceChange: StateEvent, + modifier: Modifier = Modifier, +) { + val growColor = TangemTheme.colors2.graphic.status.accent + val fallColor = TangemTheme.colors2.graphic.status.warning + val generalColor = TangemTheme.colors2.text.neutral.primary + + val color = remember(generalColor) { Animatable(generalColor) } + + EventEffect(triggerPriceChange) { priceChangeType -> + val nextColor = when (priceChangeType) { + PriceChangeType.UP, + -> growColor + PriceChangeType.DOWN -> fallColor + PriceChangeType.NEUTRAL -> return@EventEffect + } + + color.animateTo(nextColor, snap()) + color.animateTo(generalColor, tween(durationMillis = 500)) + } + + Text( + text = priceAnnotated.resolveAnnotatedReference(), + modifier = modifier, + color = color.value, + autoSize = TextAutoSize.StepBased(maxFontSize = TangemTheme.typography2.headingBold34.fontSize), + maxLines = 1, + style = TangemTheme.typography2.headingBold34, + ) +} + @Composable private fun IntervalSelector( trendInterval: PriceChangeInterval, diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt index d485b3bb18..966cf8e307 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt @@ -156,12 +156,42 @@ internal fun FDVCard(item: InfoPointUMV2.FullyDilutedValuation) { modifier = Modifier .heightIn(120.dp) .fillMaxWidth(), - title = { MetricValueText(value = item.value) }, + title = { + if (item.fullyDilutedValuationChange24 != null) { + Row { + MetricValueText(value = item.fullyDilutedValuationChange24) + Text( + modifier = Modifier.padding(TangemTheme.dimens2.x1), + text = stringResourceSafe(R.string.markets_token_details_trading_interval), + style = TangemTheme.typography2.captionSemibold11, + color = TangemTheme.colors2.text.neutral.primary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } else { + MetricValueText(value = item.value) + } + }, content = { - InformationTextBlock( - text = resourceReference(R.string.markets_token_details_fully_diluted_valuation), - onInfoClick = item.onInfoClick, - ) + Column { + if (item.fullyDilutedValuationChange24 != null) { + Text( + text = item.value?.resolveReference() + ?: stringResourceSafe(R.string.token_market_metrics_no_data), + style = TangemTheme.typography2.captionSemibold12, + color = TangemTheme.colors2.text.neutral.primary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + SpacerH(4.dp) + } + + InformationTextBlock( + text = resourceReference(R.string.markets_token_details_fully_diluted_valuation), + onInfoClick = item.onInfoClick, + ) + } }, ) } @@ -445,6 +475,7 @@ private fun MetricsCardsPreview() { FDVCard( item = InfoPointUMV2.FullyDilutedValuation( value = stringReference("$ 1.5 T"), + fullyDilutedValuationChange24 = stringReference("$ 2.44 M in total"), onInfoClick = {}, ), ) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/preview/MarketsTokenDetailsPreview.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/preview/MarketsTokenDetailsPreview.kt index ed7261d399..63b06d0833 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/preview/MarketsTokenDetailsPreview.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/preview/MarketsTokenDetailsPreview.kt @@ -50,6 +50,7 @@ internal object MarketsTokenDetailsPreview { onScroll = {}, ), onShareClick = {}, + priceAnnotated = stringReference("$0.00000000324"), ) val contentState = MarketsTokenDetailsUM( @@ -144,5 +145,6 @@ internal object MarketsTokenDetailsPreview { onScroll = {}, ), onShareClick = {}, + priceAnnotated = stringReference("$0.00000000324"), ) } \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MarketsTokenDetailsUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MarketsTokenDetailsUM.kt index 7da2ed065b..2cd7078d51 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MarketsTokenDetailsUM.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MarketsTokenDetailsUM.kt @@ -14,6 +14,7 @@ import java.math.BigDecimal internal data class MarketsTokenDetailsUM( val tokenName: String, val priceText: String, + val priceAnnotated: TextReference, val iconUrl: String?, val dateTimeText: TextReference, val priceChangePercentText: String?, diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MetricsUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MetricsUM.kt index 76db464700..396e1d12cd 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MetricsUM.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/state/MetricsUM.kt @@ -38,6 +38,7 @@ internal sealed interface InfoPointUMV2 { @Immutable data class FullyDilutedValuation( val value: TextReference?, + val fullyDilutedValuationChange24: TextReference?, val onInfoClick: () -> Unit, ) : InfoPointUMV2 diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt index b2da4c8e5f..287b580b15 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.tangem.common.ui.markets.MarketsListItem import com.tangem.common.ui.markets.MarketsListItemPlaceholder +import com.tangem.common.ui.markets.models.MarketsListItemUM import com.tangem.core.ui.R import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.components.SpacerW @@ -133,7 +134,10 @@ private fun LazyListScope.searchHistoryItems( } } -private fun LazyListScope.searchResultsItems(results: SearchContentUM.Results, onResultMarketTokenClick: () -> Unit) { +private fun LazyListScope.searchResultsItems( + results: SearchContentUM.Results, + onResultMarketTokenClick: (MarketsListItemUM) -> Unit, +) { if (results.userAssets.isNotEmpty()) { item(key = "header_portfolio") { SectionHeader(title = stringResourceSafe(R.string.markets_search_portfolio_header)) @@ -163,7 +167,7 @@ private fun LazyListScope.searchResultsItems(results: SearchContentUM.Results, o private fun LazyListScope.marketSearchResultItems( market: MarketSearchResultUM.Content, hasUserAssetsSection: Boolean, - onResultMarketTokenClick: () -> Unit, + onResultMarketTokenClick: (MarketsListItemUM) -> Unit, ) { if (hasUserAssetsSection) { item(key = "spacer_between_sections") { @@ -185,7 +189,7 @@ private fun LazyListScope.marketSearchResultItems( shape = RoundedCornerShape(TangemTheme.dimens2.x5), ), model = token, - onClick = onResultMarketTokenClick, + onClick = { onResultMarketTokenClick(token) }, ) } if (market.shouldShowUnder100kNotification) { diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt index b8f37312a4..bfb95e3819 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt @@ -25,6 +25,7 @@ import com.tangem.features.feed.ui.search.state.* import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +import java.math.BigDecimal /** Labeled UI state for [SearchContent] previews. */ internal data class SearchContentPreviewScenario( @@ -192,7 +193,11 @@ internal object SearchContentPreviewFixtures { iconUrl = null, ratingPosition = rating, marketCap = marketCap, - price = MarketsListItemUM.Price(text = priceText), + price = MarketsListItemUM.Price( + text = priceText, + annotated = stringReference(priceText), + fiatPrice = BigDecimal(123123), + ), trendPercentText = trendText, trendType = trend, chartData = chart, @@ -384,7 +389,7 @@ private val SearchContentPreviewCallbacks = SearchCallbacks( onLoadMore = {}, onClearHintsClick = {}, onTextHintClick = { _ -> }, - onResultMarketTokenClick = {}, + onResultMarketTokenClick = { _ -> }, ) /** All [SearchContentPreviewScenario] values for the Preview Parameter dropdown in Android Studio. */ diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt index e793512ce1..e5641b2bb8 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt @@ -1,8 +1,10 @@ package com.tangem.features.feed.ui.search.state +import com.tangem.common.ui.markets.models.MarketsListItemUM + internal data class SearchCallbacks( val onLoadMore: () -> Unit, val onClearHintsClick: () -> Unit, val onTextHintClick: (hint: String) -> Unit, - val onResultMarketTokenClick: () -> Unit, + val onResultMarketTokenClick: (MarketsListItemUM) -> Unit, ) \ No newline at end of file diff --git a/features/markets/impl/build.gradle.kts b/features/markets/impl/build.gradle.kts index bc76460d54..78f5e2b66c 100644 --- a/features/markets/impl/build.gradle.kts +++ b/features/markets/impl/build.gradle.kts @@ -81,6 +81,7 @@ dependencies { /* Common */ implementation(projects.common.ui) + implementation(projects.common.uiMarkets) implementation(projects.common.uiCharts) implementation(projects.common.routing) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt index 1cdaebeff0..e27a121ad5 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt @@ -6,6 +6,7 @@ import com.tangem.common.routing.AppRoute import com.tangem.common.ui.charts.state.MarketChartData import com.tangem.common.ui.charts.state.converter.PriceAndTimePointValuesConverter import com.tangem.common.ui.charts.state.sorted +import com.tangem.common.ui.markets.toMarketsListItemPriceAnnotated import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -62,6 +63,8 @@ internal class TokenMarketBlockModel @Inject constructor( TokenMarketBlockUM( currencySymbol = params.cryptoCurrency.symbol, currentPrice = null, + currentPriceValue = null, + priceAnnotated = null, h24Percent = null, priceChangeType = PriceChangeType.NEUTRAL, chartData = null, @@ -86,15 +89,21 @@ internal class TokenMarketBlockModel @Inject constructor( h24Percent = res.priceChange, ) + val appCurrency = currentAppCurrency.value state.value = state.value.copy( currentPrice = res.fiatRate.format { fiat( // TODO get currency from quotes use case [REDACTED_TASK_KEY] - fiatCurrencyCode = currentAppCurrency.value.code, + fiatCurrencyCode = appCurrency.code, // TODO get currency from quotes use case [REDACTED_TASK_KEY] - fiatCurrencySymbol = currentAppCurrency.value.symbol, + fiatCurrencySymbol = appCurrency.symbol, ).price() }, + currentPriceValue = res.fiatRate, + priceAnnotated = res.fiatRate.toMarketsListItemPriceAnnotated( + appCurrencyCode = appCurrency.code, + appCurrencySymbol = appCurrency.symbol, + ), h24Percent = res.priceChange.format { percent() }, priceChangeType = PriceChangeType.fromBigDecimal(res.priceChange), ) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlockLegacy.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlockLegacy.kt index 17d3314738..820fa36229 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlockLegacy.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlockLegacy.kt @@ -20,6 +20,8 @@ import com.tangem.core.ui.components.TextShimmer import com.tangem.core.ui.components.block.BlockCard import com.tangem.core.ui.components.marketprice.PriceChangeInPercent import com.tangem.core.ui.components.marketprice.PriceChangeType +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -27,6 +29,7 @@ import com.tangem.features.markets.impl.R import com.tangem.features.markets.token.block.impl.model.formatter.toChartType import com.tangem.features.markets.token.block.impl.ui.state.TokenMarketBlockUM import kotlinx.collections.immutable.toImmutableList +import java.math.BigDecimal import kotlin.random.Random @Composable @@ -47,6 +50,8 @@ internal fun TokenMarketBlockLegacy(state: TokenMarketBlockUM, modifier: Modifie modifier = Modifier.weight(1f), symbol = state.currencySymbol, priceText = state.currentPrice, + priceValue = state.currentPriceValue, + priceAnnotated = state.priceAnnotated, percentText = state.h24Percent, type = state.priceChangeType, ) @@ -61,11 +66,14 @@ internal fun TokenMarketBlockLegacy(state: TokenMarketBlockUM, modifier: Modifie ) } +@Suppress("LongParameterList") @OptIn(ExperimentalLayoutApi::class) @Composable private fun LeftSide( symbol: String, priceText: String?, + priceValue: BigDecimal?, + priceAnnotated: TextReference?, percentText: String?, type: PriceChangeType, modifier: Modifier = Modifier, @@ -88,6 +96,8 @@ private fun LeftSide( modifier = Modifier.alignByBaseline(), price = priceText, priceChangeType = type, + priceValue = priceValue ?: BigDecimal.ZERO, + priceAnnotated = priceAnnotated ?: TextReference.EMPTY, ) Row( horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), @@ -181,6 +191,8 @@ private fun Preview() { priceChangeType = PriceChangeType.UP, chartData = data, onClick = {}, + currentPriceValue = BigDecimal(1234), + priceAnnotated = stringReference("0,5$"), ) TangemThemePreview { diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/state/TokenMarketBlockUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/state/TokenMarketBlockUM.kt index 475c39e3f9..5ed0370ffb 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/state/TokenMarketBlockUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/state/TokenMarketBlockUM.kt @@ -2,10 +2,14 @@ package com.tangem.features.markets.token.block.impl.ui.state import com.tangem.common.ui.charts.state.MarketChartRawData import com.tangem.core.ui.components.marketprice.PriceChangeType +import com.tangem.core.ui.extensions.TextReference +import java.math.BigDecimal internal data class TokenMarketBlockUM( val currencySymbol: String, val currentPrice: String?, + val currentPriceValue: BigDecimal?, + val priceAnnotated: TextReference?, val h24Percent: String?, val priceChangeType: PriceChangeType, val chartData: MarketChartRawData?, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/market/converter/SwapMarketsTokenItemConverter.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/market/converter/SwapMarketsTokenItemConverter.kt index f76ce2af6d..98a4c621b3 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/market/converter/SwapMarketsTokenItemConverter.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/market/converter/SwapMarketsTokenItemConverter.kt @@ -5,6 +5,7 @@ import com.tangem.common.ui.charts.state.MarketChartRawData import com.tangem.common.ui.charts.state.converter.PriceAndTimePointValuesConverter import com.tangem.common.ui.charts.state.sorted import com.tangem.common.ui.markets.models.MarketsListItemUM +import com.tangem.common.ui.markets.toMarketsListItemPriceAnnotated import com.tangem.core.ui.R import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.extensions.resourceReference @@ -119,7 +120,12 @@ internal class SwapMarketsTokenItemConverter( return MarketsListItemUM.Price( text = priceText, + annotated = tokenQuotesShort.currentPrice.toMarketsListItemPriceAnnotated( + appCurrencyCode = appCurrency.code, + appCurrencySymbol = appCurrency.symbol, + ), changeType = changeType, + fiatPrice = tokenQuotesShort.currentPrice, ) } diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/models/market/converter/SwapMarketsTokenItemConverter.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/models/market/converter/SwapMarketsTokenItemConverter.kt index 31ea67416e..0e693eab2d 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/models/market/converter/SwapMarketsTokenItemConverter.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/models/market/converter/SwapMarketsTokenItemConverter.kt @@ -5,6 +5,7 @@ import com.tangem.common.ui.charts.state.MarketChartRawData import com.tangem.common.ui.charts.state.converter.PriceAndTimePointValuesConverter import com.tangem.common.ui.charts.state.sorted import com.tangem.common.ui.markets.models.MarketsListItemUM +import com.tangem.common.ui.markets.toMarketsListItemPriceAnnotated import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList @@ -119,7 +120,12 @@ internal class SwapMarketsTokenItemConverter( return MarketsListItemUM.Price( text = priceText, + annotated = tokenQuotesShort.currentPrice.toMarketsListItemPriceAnnotated( + appCurrencyCode = appCurrency.code, + appCurrencySymbol = appCurrency.symbol, + ), changeType = changeType, + fiatPrice = tokenQuotesShort.currentPrice, ) } diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/preview/SwapSelectTokenPreviewProvider.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/preview/SwapSelectTokenPreviewProvider.kt index f61c2e0da4..bb19ee30a7 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/preview/SwapSelectTokenPreviewProvider.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/preview/SwapSelectTokenPreviewProvider.kt @@ -19,6 +19,7 @@ import com.tangem.feature.swap.models.market.state.SwapMarketState import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toPersistentList +import java.math.BigDecimal internal object SwapSelectTokenPreviewProvider { @@ -205,7 +206,11 @@ internal object SwapSelectTokenPreviewProvider { iconUrl = iconUrl, ratingPosition = ratingPosition, marketCap = marketCap, - price = MarketsListItemUM.Price(text = "31 285.72$"), + price = MarketsListItemUM.Price( + text = "31 285.72$", + annotated = stringReference("31 285.72$"), + fiatPrice = BigDecimal("123123"), + ), trendPercentText = "12.43%", trendType = trendType, chartData = chartData,