From 244f9bc61d684dca5bb5168cd5ee8e39e16171be Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 14 Aug 2024 12:52:27 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/common/ui/charts/MarketChart.kt | 10 +-- .../common/ui/charts/MarketChartMini.kt | 4 ++ .../common/ui/charts/state/MarketChartLook.kt | 1 + .../ui/charts/state/MarketChartState.kt | 1 + .../core/ui/utils/DateTimeFormatters.kt | 61 +++++++++++++++---- .../markets/DefaultMarketsEntryComponent.kt | 36 +++++------ .../impl/model/MarketsTokenDetailsModel.kt | 16 +++++ .../model/converters/InsightsConverter.kt | 22 +++++++ .../impl/model/formatter/Formatters.kt | 13 ++-- .../formatter/MarketsDateTimeFormatters.kt | 2 +- .../details/impl/ui/components/InfoPoint.kt | 60 ++++++++++++++++-- .../impl/ui/components/InsightsBlock.kt | 15 ++--- .../ui/components/MarketTokenDetailsChart.kt | 2 + .../details/impl/ui/state/InfoPointUM.kt | 7 ++- .../details/impl/ui/state/InsightsUM.kt | 1 + .../tokenlist/impl/model/MarketsListModel.kt | 1 + .../statemanager/MarketsListUMStateManager.kt | 22 ++++++- .../components/MarketsListItemPlaceholder.kt | 22 ++----- .../impl/ui/state/MarketsListItemUM.kt | 5 +- 19 files changed, 224 insertions(+), 77 deletions(-) diff --git a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChart.kt b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChart.kt index 2e850fd87d..cd14d8f8c8 100644 --- a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChart.kt +++ b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChart.kt @@ -314,6 +314,7 @@ private fun MarketChartPreview( TangemThemePreview { val growingColor = TangemTheme.colors.icon.accent val fallingColor = TangemTheme.colors.icon.warning + val neutralColor = TangemTheme.colors.icon.informative val chartState = rememberMarketChartState( dataProducer = dataProducer, @@ -324,6 +325,7 @@ private fun MarketChartPreview( when (it) { MarketChartLook.Type.Growing -> growingColor MarketChartLook.Type.Falling -> fallingColor + MarketChartLook.Type.Neutral -> neutralColor } }, ) @@ -382,10 +384,10 @@ private fun MarketChartPreview( dataProducer.runTransaction { updateLook { it.copy( - type = if (it.type == MarketChartLook.Type.Growing) { - MarketChartLook.Type.Falling - } else { - MarketChartLook.Type.Growing + type = when (it.type) { + MarketChartLook.Type.Growing -> MarketChartLook.Type.Falling + MarketChartLook.Type.Falling -> MarketChartLook.Type.Neutral + MarketChartLook.Type.Neutral -> MarketChartLook.Type.Growing }, ) } diff --git a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChartMini.kt b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChartMini.kt index 2a124ed8d2..2e62078f0f 100644 --- a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChartMini.kt +++ b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/MarketChartMini.kt @@ -36,6 +36,7 @@ fun MarketChartMini( type: MarketChartLook.Type = MarketChartLook.Type.Growing, growingColor: Color = TangemTheme.colors.icon.accent, fallingColor: Color = TangemTheme.colors.icon.warning, + neutralColor: Color = TangemTheme.colors.icon.informative, ) { val model = remember(rawData) { CartesianChartModel(LineCartesianLayerModel.build { series(rawData.y) }) @@ -44,6 +45,7 @@ fun MarketChartMini( val lineColor = when (type) { MarketChartLook.Type.Growing -> growingColor MarketChartLook.Type.Falling -> fallingColor + MarketChartLook.Type.Neutral -> neutralColor } val lineSpec = rememberLine( @@ -85,6 +87,8 @@ private fun Preview() { MarketChartMini(rawData = data, type = MarketChartLook.Type.Growing) SpacerH16() MarketChartMini(rawData = data, type = MarketChartLook.Type.Falling) + SpacerH16() + MarketChartMini(rawData = data, type = MarketChartLook.Type.Neutral) } } } diff --git a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartLook.kt b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartLook.kt index dc194c3b3b..72c608da53 100644 --- a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartLook.kt +++ b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartLook.kt @@ -24,5 +24,6 @@ data class MarketChartLook( enum class Type { Growing, Falling, + Neutral, } } \ No newline at end of file diff --git a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartState.kt b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartState.kt index 8db48deab6..e031fc1a27 100644 --- a/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartState.kt +++ b/common/ui-charts/src/main/kotlin/com/tangem/common/ui/charts/state/MarketChartState.kt @@ -24,6 +24,7 @@ fun rememberMarketChartState( when (it) { MarketChartLook.Type.Growing -> Color.Green MarketChartLook.Type.Falling -> Color.Red + MarketChartLook.Type.Neutral -> Color.Gray } } }, diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/DateTimeFormatters.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/DateTimeFormatters.kt index 20296aec51..4dd1e38fd1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/DateTimeFormatters.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/DateTimeFormatters.kt @@ -11,12 +11,21 @@ import java.util.Locale object DateTimeFormatters { /** - * Two SS means, SHORT style for date and time. - * If pattern contains "a", it means time is in 12 hour format. - * [Documentation](https://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html) + * Determine if the time is in 12-hour format ("10:00 PM") for the current locale. + */ + val is12HourFormat by lazy { + /** + * Two SS means, SHORT style for date and time. + * If pattern contains "a", it means time is in 12 hour format. + * [Documentation](https://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html) + */ + DateTimeFormat.patternForStyle("SS", Locale.getDefault()).contains("a") + } + + /** + * Example: "12:00 PM", "12:00" */ val timeFormatter: DateTimeFormatter by lazy { - val is12HourFormat = DateTimeFormat.patternForStyle("SS", Locale.getDefault()).contains("a") if (is12HourFormat) { DateTimeFormatterBuilder() .appendClockhourOfHalfday(1) @@ -36,6 +45,9 @@ object DateTimeFormatters { } } + /** + * Example: "1 Jun, 2020", "1 Jun, 2020" + */ val dateFormatter: DateTimeFormatter by lazy { DateTimeFormatterBuilder() .appendDayOfMonth(1) @@ -47,36 +59,61 @@ object DateTimeFormatters { .withLocale(Locale.getDefault()) } + /** + * Example: "31.06.2020", "06/31/2020" + */ val dateDDMMYYYY: DateTimeFormatter by lazy { - DateTimeFormatterBuilder() - .appendPattern("dd.MM.yyyy") - .toFormatter() - .withLocale(Locale.getDefault()) + getBestFormatterBySkeleton("dd.MM.yyyy") } /** - * In API version < 24, there may be some problems with getting the best date and time format pattern. + * Example: "Jun 31, 2020", "31 Jun, 2020" */ val dateMMMdd: DateTimeFormatter by lazy { - getBestFormatterBySkeleton("dd MMM") + getBestFormatterBySkeleton("MMM dd") } + /** + * Example: "2020" + */ val dateYYYY: DateTimeFormatter by lazy { getBestFormatterBySkeleton("yyyy") } + /** + * Example: "31.06.2020 12:00", "06/31/2020 12:00", "06/31/2020 12:00 PM" + */ val dateTimeFormatter: DateTimeFormatter by lazy { - DateTimeFormat.forPattern("dd.MM.yyyy HH:mm") + getBestFormatterBySkeleton("dd.MM.yyyy HH:mm") } fun formatDate(date: DateTime, formatter: DateTimeFormatter = dateFormatter): String { return formatter.print(date) } + /** + * Returns the best date and time format pattern for the given skeleton and the current locale. + * (In API version < 24, there may be some problems with getting the best date and time format pattern.) + * + * @param skeleton The skeleton is an alternative to the pattern. The difference is that the pattern rigidly + * defines the date/time format, while the skeleton specifies only the date/time components (year, month, day, etc.) + * So the order of the components and separators (space, comma, etc.) is not taken into account. + * @see [dateYYYY], [dateMMMdd], [dateDDMMYYYY], [dateTimeFormatter] + */ fun getBestFormatterBySkeleton(skeleton: String): DateTimeFormatter { + val skeletonWithLocale = skeleton.replaceHourLetters() + return DateTimeFormatterBuilder() - .appendPattern(DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton)) + .appendPattern(DateFormat.getBestDateTimePattern(Locale.getDefault(), skeletonWithLocale)) .toFormatter() .withLocale(Locale.getDefault()) } + + private fun String.replaceHourLetters(): String { + return if (is12HourFormat) { + this.replace('H', 'h').replace('k', 'K') + } else { + this.replace('h', 'H').replace('K', 'k') + } + } } \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/DefaultMarketsEntryComponent.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/DefaultMarketsEntryComponent.kt index 0078651a11..a166e55e22 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/DefaultMarketsEntryComponent.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/DefaultMarketsEntryComponent.kt @@ -87,8 +87,27 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor( } } + // order of LaunchedEffects is important here + val activeChild = stackState.value.active.configuration + LaunchedEffect(activeChild) { + when (activeChild) { + is MarketsEntryChildFactory.Child.TokenDetails -> { + backgroundColor.animateTo( + secondary, + animationSpec = tween(durationMillis = 500), + ) + } + MarketsEntryChildFactory.Child.TokenList -> { + backgroundColor.animateTo( + primary, + animationSpec = tween(durationMillis = 500), + ) + } + } + } + LaunchedEffect(bottomSheetState.value) { if (activeChild is MarketsEntryChildFactory.Child.TokenDetails) { when (bottomSheetState.value) { @@ -108,23 +127,6 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor( } } - LaunchedEffect(activeChild) { - when (activeChild) { - is MarketsEntryChildFactory.Child.TokenDetails -> { - backgroundColor.animateTo( - secondary, - animationSpec = tween(durationMillis = 500), - ) - } - MarketsEntryChildFactory.Child.TokenList -> { - backgroundColor.animateTo( - primary, - animationSpec = tween(durationMillis = 500), - ) - } - } - } - LaunchedEffect(primary, secondary) { if (backgroundColor.isRunning) return@LaunchedEffect diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt index 9f9d524a84..2a40b0c83e 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt @@ -291,6 +291,14 @@ internal class MarketsTokenDetailsModel @Inject constructor( ), ) } + + chartDataProducer.runTransaction { + updateLook { + it.copy( + type = getChartTypeByPercent(percent), + ) + } + } }, ifLeft = { state.update { @@ -347,6 +355,14 @@ internal class MarketsTokenDetailsModel @Inject constructor( dateTimeText = getDefaultDateTimeString(stateToUpdate.selectedInterval), ) } + + chartDataProducer.runTransaction { + updateLook { + it.copy( + type = getChartTypeByPercent(percent), + ) + } + } } private fun onSelectedIntervalChange(interval: PriceChangeInterval) { diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/InsightsConverter.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/InsightsConverter.kt index e90f915acd..9bbcff51d9 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/InsightsConverter.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/InsightsConverter.kt @@ -2,6 +2,7 @@ package com.tangem.features.markets.details.impl.model.converters import androidx.compose.runtime.Stable import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.markets.TokenMarketInfo @@ -43,6 +44,14 @@ internal class InsightsConverter( liquidityChange = liquidityChange?.month, buyPressureChange = buyPressureChange?.month, ), + onInfoClick = { + onInfoClick( + InfoBottomSheetContent( + title = resourceReference(R.string.markets_token_details_insights), + body = stringReference("//TODO"), + ), + ) + }, ) } } @@ -57,6 +66,7 @@ internal class InsightsConverter( InfoPointUM( title = resourceReference(R.string.markets_token_details_experienced_buyers), value = experiencedBuyerChange.convertChange(), + change = experiencedBuyerChange.changeType(), onInfoClick = { onInfoClick( InfoBottomSheetContent( @@ -69,6 +79,7 @@ internal class InsightsConverter( InfoPointUM( title = resourceReference(R.string.markets_token_details_buy_pressure), value = buyPressureChange.convertChange(isFiatValue = true), + change = buyPressureChange.changeType(), onInfoClick = { onInfoClick( InfoBottomSheetContent( @@ -81,6 +92,7 @@ internal class InsightsConverter( InfoPointUM( title = resourceReference(R.string.markets_token_details_holders), value = holdersChange.convertChange(), + change = holdersChange.changeType(), onInfoClick = { onInfoClick( InfoBottomSheetContent( @@ -93,6 +105,7 @@ internal class InsightsConverter( InfoPointUM( title = resourceReference(R.string.markets_token_details_liquidity), value = liquidityChange.convertChange(), + change = liquidityChange.changeType(), onInfoClick = { onInfoClick( InfoBottomSheetContent( @@ -105,6 +118,15 @@ internal class InsightsConverter( ) } + private fun BigDecimal?.changeType(): InfoPointUM.ChangeType? { + return when { + this == null -> null + this > BigDecimal.ZERO -> InfoPointUM.ChangeType.UP + this < BigDecimal.ZERO -> InfoPointUM.ChangeType.DOWN + else -> null + } + } + private fun BigDecimal?.convertChange(isFiatValue: Boolean = false): String { if (this == null) return StringsSigns.DASH_SIGN diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/Formatters.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/Formatters.kt index fd560e41d7..f164289fe6 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/Formatters.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/Formatters.kt @@ -83,16 +83,17 @@ internal fun PriceChangeType.toChartType(): MarketChartLook.Type { return when (this) { PriceChangeType.UP -> MarketChartLook.Type.Growing PriceChangeType.DOWN -> MarketChartLook.Type.Falling - PriceChangeType.NEUTRAL -> MarketChartLook.Type.Growing + PriceChangeType.NEUTRAL -> MarketChartLook.Type.Neutral } } +@Suppress("MagicNumber") internal fun getChartTypeByPercent(percent: BigDecimal?): MarketChartLook.Type { + val scaled = percent?.setScale(4, RoundingMode.HALF_UP) return when { - percent == null -> return MarketChartLook.Type.Growing - percent == BigDecimal.ZERO -> MarketChartLook.Type.Growing - percent > BigDecimal.ZERO -> MarketChartLook.Type.Growing - percent < BigDecimal.ZERO -> MarketChartLook.Type.Falling - else -> MarketChartLook.Type.Growing + scaled == null -> return MarketChartLook.Type.Neutral + scaled > BigDecimal.ZERO -> MarketChartLook.Type.Growing + scaled < BigDecimal.ZERO -> MarketChartLook.Type.Falling + else -> MarketChartLook.Type.Neutral } } \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/MarketsDateTimeFormatters.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/MarketsDateTimeFormatters.kt index e93456eb34..acc0ec44fa 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/MarketsDateTimeFormatters.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/formatter/MarketsDateTimeFormatters.kt @@ -18,7 +18,7 @@ internal object MarketsDateTimeFormatters { private const val WEEK_MILLIS = 7L * H24_MILLIS private val dateTimeMMMFormatter by lazy { - DateTimeFormatters.getBestFormatterBySkeleton("dd MMM hh:mm") + DateTimeFormatters.getBestFormatterBySkeleton("dd MMM Hm") } private val dateFormatter = DateTimeFormatters.dateDDMMYYYY diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InfoPoint.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InfoPoint.kt index 09d8317df5..3ca286968f 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InfoPoint.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InfoPoint.kt @@ -3,13 +3,18 @@ package com.tangem.features.markets.details.impl.ui.components import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.tangem.core.ui.R +import com.tangem.core.ui.components.SpacerW4 import com.tangem.core.ui.components.TextShimmer import com.tangem.core.ui.components.text.TooltipText import com.tangem.core.ui.extensions.resolveReference @@ -40,11 +45,32 @@ internal fun InfoPoint(infoPointUM: InfoPointUM, modifier: Modifier = Modifier) overflow = TextOverflow.Ellipsis, ) } - Text( - text = infoPointUM.value, - style = TangemTheme.typography.body1, - color = TangemTheme.colors.text.primary1, - ) + Row { + Text( + text = infoPointUM.value, + style = TangemTheme.typography.body1, + color = TangemTheme.colors.text.primary1, + ) + if (infoPointUM.change != null) { + SpacerW4() + Icon( + modifier = Modifier + .size(TangemTheme.dimens.size8) + .align(Alignment.CenterVertically), + imageVector = ImageVector.vectorResource( + id = when (infoPointUM.change) { + InfoPointUM.ChangeType.UP -> R.drawable.ic_arrow_up_8 + InfoPointUM.ChangeType.DOWN -> R.drawable.ic_arrow_down_8 + }, + ), + tint = when (infoPointUM.change) { + InfoPointUM.ChangeType.UP -> TangemTheme.colors.icon.accent + InfoPointUM.ChangeType.DOWN -> TangemTheme.colors.icon.warning + }, + contentDescription = null, + ) + } + } } } @@ -105,6 +131,22 @@ private fun ContentPreview() { onInfoClick = { }, ), ) + InfoPoint( + infoPointUM = InfoPointUM( + title = stringReference("Market Cap"), + value = "$1,000,000", + change = InfoPointUM.ChangeType.UP, + onInfoClick = { }, + ), + ) + InfoPoint( + infoPointUM = InfoPointUM( + title = stringReference("Market Cap"), + value = "$1,000,000", + change = InfoPointUM.ChangeType.DOWN, + onInfoClick = { }, + ), + ) } } } @@ -126,6 +168,14 @@ private fun PreviewShimmer() { modifier = Modifier.fillMaxWidth(), withTooltip = true, ) + InfoPointShimmer( + modifier = Modifier.fillMaxWidth(), + withTooltip = true, + ) + InfoPointShimmer( + modifier = Modifier.fillMaxWidth(), + withTooltip = true, + ) } }, actualContent = { diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InsightsBlock.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InsightsBlock.kt index 3cd88bc115..df5dab7cce 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InsightsBlock.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/InsightsBlock.kt @@ -7,13 +7,12 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.block.information.GridItems import com.tangem.core.ui.components.block.information.InformationBlock import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons +import com.tangem.core.ui.components.text.TooltipText import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.res.TangemTheme @@ -34,13 +33,10 @@ internal fun InsightsBlock(state: InsightsUM, modifier: Modifier = Modifier) { InformationBlock( modifier = modifier, title = { - Text( - modifier = Modifier, - text = stringResource(R.string.markets_token_details_insights), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.tertiary, - maxLines = 1, - overflow = TextOverflow.Ellipsis, + TooltipText( + text = resourceReference(R.string.markets_token_details_insights), + textStyle = TangemTheme.typography.subtitle2, + onInfoClick = state.onInfoClick, ) }, action = { @@ -180,6 +176,7 @@ private fun ContentPreview() { value = "1 000", ), ), + onInfoClick = {}, ), ) } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/MarketTokenDetailsChart.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/MarketTokenDetailsChart.kt index b19876af06..83bc41555e 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/MarketTokenDetailsChart.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/MarketTokenDetailsChart.kt @@ -22,6 +22,7 @@ import com.tangem.features.markets.tokenlist.impl.ui.components.UnableToLoadData internal fun MarketTokenDetailsChart(state: MarketsTokenDetailsUM.ChartState, modifier: Modifier = Modifier) { val growingColor = TangemTheme.colors.icon.accent val fallingColor = TangemTheme.colors.icon.warning + val neutralColor = TangemTheme.colors.icon.informative val chartState = rememberMarketChartState( dataProducer = state.dataProducer, @@ -29,6 +30,7 @@ internal fun MarketTokenDetailsChart(state: MarketsTokenDetailsUM.ChartState, mo when (it) { MarketChartLook.Type.Growing -> growingColor MarketChartLook.Type.Falling -> fallingColor + MarketChartLook.Type.Neutral -> neutralColor } }, onMarkerShown = state.onMarkerPointSelected, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InfoPointUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InfoPointUM.kt index 5ef1b1ad91..383db4e627 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InfoPointUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InfoPointUM.kt @@ -5,5 +5,10 @@ import com.tangem.core.ui.extensions.TextReference internal data class InfoPointUM( val title: TextReference, val value: String, + val change: ChangeType? = null, val onInfoClick: (() -> Unit)? = null, -) \ No newline at end of file +) { + enum class ChangeType { + UP, DOWN + } +} \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InsightsUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InsightsUM.kt index f7d33a8ddc..9156f9bf1b 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InsightsUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/state/InsightsUM.kt @@ -6,4 +6,5 @@ internal data class InsightsUM( val h24Info: ImmutableList, val weekInfo: ImmutableList, val monthInfo: ImmutableList, + val onInfoClick: () -> Unit, ) \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt index 167b03fd6c..b2d0ca1844 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt @@ -48,6 +48,7 @@ internal class MarketsListModel @Inject constructor( private val visibleItemIds = MutableStateFlow>(emptyList()) private val marketsListUMStateManager = MarketsListUMStateManager( + currentVisibleIds = Provider { visibleItemIds.value }, onLoadMoreUiItems = { activeListManager.loadMore() }, visibleItemsChanged = { visibleItemIds.value = it }, onRetryButtonClicked = { activeListManager.reload() }, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt index 806d5434cb..50170ce417 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt @@ -12,6 +12,7 @@ import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListItemUM import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListUM import com.tangem.features.markets.tokenlist.impl.ui.state.SortByTypeUM +import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -19,6 +20,7 @@ import kotlinx.coroutines.flow.* @Stable internal class MarketsListUMStateManager( + private val currentVisibleIds: Provider>, private val onLoadMoreUiItems: () -> Unit, private val visibleItemsChanged: (itemsKeys: List) -> Unit, private val onRetryButtonClicked: () -> Unit, @@ -129,9 +131,11 @@ internal class MarketsListUMStateManager( } } + val itemsWithFilteredPriceChange = items.filterPriceChangeByVisibility() + return currentState.copy( list = ListUM.Content( - items = items, + items = itemsWithFilteredPriceChange, loadMore = onLoadMoreUiItems, visibleIdsChanged = visibleItemsChanged, showUnder100kTokens = isInSearchState.not() || isNextPageInSearch, @@ -157,6 +161,22 @@ internal class MarketsListUMStateManager( ) } + // Show price change animation for visible items only + private fun ImmutableList.filterPriceChangeByVisibility(): ImmutableList { + val visibleItemIds = currentVisibleIds() + return map { + it.copy( + price = it.price.copy( + changeType = if (visibleItemIds.contains(it.id)) { + it.price.changeType + } else { + null + }, + ), + ) + }.toImmutableList() + } + private fun generalContentState(newItems: ImmutableList): ListUM.Content { return ListUM.Content( items = newItems, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListItemPlaceholder.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListItemPlaceholder.kt index fa7b373811..692b663cc8 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListItemPlaceholder.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListItemPlaceholder.kt @@ -34,11 +34,11 @@ fun MarketsListItemPlaceholder() { SpacerW12() Column(modifier = Modifier.weight(1f)) { - Row( + Box( modifier = Modifier .fillMaxWidth() .padding(vertical = TangemTheme.dimens.spacing4), - horizontalArrangement = Arrangement.SpaceBetween, + contentAlignment = Alignment.CenterStart, ) { RectangleShimmer( modifier = Modifier @@ -46,23 +46,15 @@ fun MarketsListItemPlaceholder() { .height(sp12), radius = TangemTheme.dimens.radius3, ) - SpacerW8() - RectangleShimmer( - modifier = Modifier - .width(TangemTheme.dimens.size70) - .height(sp12), - radius = TangemTheme.dimens.radius3, - ) } SpacerH(height = TangemTheme.dimens.spacing2) - Row( + Box( modifier = Modifier .fillMaxWidth() .padding(vertical = TangemTheme.dimens.spacing2), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Bottom, + contentAlignment = Alignment.CenterStart, ) { RectangleShimmer( modifier = Modifier @@ -70,12 +62,6 @@ fun MarketsListItemPlaceholder() { .height(sp12), radius = TangemTheme.dimens.radius3, ) - RectangleShimmer( - modifier = Modifier - .width(TangemTheme.dimens.size52) - .height(sp12), - radius = TangemTheme.dimens.radius3, - ) } } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt index 020dd5b37a..9f3821c9c5 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt @@ -20,10 +20,9 @@ data class MarketsListItemUM( val isUnder100kMarketCap: Boolean = false, ) { val chartType: MarketChartLook.Type = when (trendType) { - PriceChangeType.UP, - PriceChangeType.NEUTRAL, - -> MarketChartLook.Type.Growing + PriceChangeType.UP -> MarketChartLook.Type.Growing PriceChangeType.DOWN -> MarketChartLook.Type.Falling + PriceChangeType.NEUTRAL -> MarketChartLook.Type.Neutral } @Immutable