Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-26 08:54:52 +03:00
parent bbb3c9d6bb
commit 60ba581540
6 changed files with 106 additions and 22 deletions

View file

@ -24,20 +24,14 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisGuidelineComponent
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLabelComponent
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberCustomStartAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.*
import com.patrykandpatrick.vico.compose.cartesian.rememberCartesianChart
import com.patrykandpatrick.vico.compose.cartesian.rememberVicoScrollState
import com.patrykandpatrick.vico.compose.cartesian.rememberVicoZoomState
import com.patrykandpatrick.vico.compose.common.of
import com.patrykandpatrick.vico.core.cartesian.HorizontalLayout
import com.patrykandpatrick.vico.core.cartesian.Zoom
import com.patrykandpatrick.vico.core.cartesian.axis.AxisPosition
import com.patrykandpatrick.vico.core.cartesian.axis.BaseAxis
import com.patrykandpatrick.vico.core.cartesian.axis.HorizontalAxis
import com.patrykandpatrick.vico.core.cartesian.axis.VerticalAxis
import com.patrykandpatrick.vico.core.cartesian.axis.*
import com.patrykandpatrick.vico.core.cartesian.data.AxisValueOverrider
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarker
@ -54,6 +48,7 @@ import com.tangem.common.ui.charts.state.*
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.res.LocalHapticManager
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.DateTimeFormatters
@ -98,14 +93,26 @@ fun MarketChart(
val marker = rememberTangemChartMarker(color = state.chartColor)
val chart = rememberCartesianChart(
layer,
startAxis = rememberMarketChartStartAxis(state.yValueFormatter),
bottomAxis = rememberMarketChartBottomAxis(state.xValueFormatter),
horizontalLayout = HorizontalLayout.FullWidth(),
markerVisibilityListener = rememberMarketVisibilityListener(canvasWidth, state),
marker = marker,
)
val chart = if (state.isMinMaxLook) {
rememberCartesianChart(
layer,
startAxis = rememberMarketChartStartMinMaxAxis(state.yValueFormatter),
endAxis = rememberMarketChartEndAxis(),
bottomAxis = rememberMarketChartBottomAxis(state.xValueFormatter),
horizontalLayout = HorizontalLayout.FullWidth(),
markerVisibilityListener = rememberMarketVisibilityListener(canvasWidth, state),
marker = marker,
)
} else {
rememberCartesianChart(
layer,
startAxis = rememberMarketChartStartAxis(state.yValueFormatter),
bottomAxis = rememberMarketChartBottomAxis(state.xValueFormatter),
horizontalLayout = HorizontalLayout.FullWidth(),
markerVisibilityListener = rememberMarketVisibilityListener(canvasWidth, state),
marker = marker,
)
}
// we need to calculate what the overall height should be in order to get the correct height of the graph
val bottomAxisHeight = with(LocalDensity.current) {
@ -180,6 +187,62 @@ private fun rememberMarketVisibilityListener(
}
}
@Composable
private fun rememberMarketChartEndAxis(): VerticalAxis<AxisPosition.Vertical.End> {
return rememberEndAxis(
line = null,
tick = null,
guideline = rememberChartAxisGuidelineComponent(
color = TangemTheme.colors.icon.inactive.copy(alpha = 0.12f),
isWithPadding = false,
),
label = null,
horizontalLabelPosition = VerticalAxis.HorizontalLabelPosition.Inside,
verticalLabelPosition = VerticalAxis.VerticalLabelPosition.Center,
itemPlacer = MidVerticalAxisItemPlacer(false),
valueFormatter = CartesianValueFormatter.yPercent(),
)
}
@Composable
private fun rememberMarketChartStartMinMaxAxis(
yValueFormatter: CartesianValueFormatter,
): VerticalAxis<AxisPosition.Vertical.Start> {
val textStyle = TangemTheme.typography.caption2
val resolver = LocalFontFamilyResolver.current
val typeface by remember(resolver, textStyle) {
resolver.resolveAsTypeface(
fontFamily = textStyle.fontFamily,
fontWeight = textStyle.fontWeight ?: FontWeight.Normal,
fontStyle = textStyle.fontStyle ?: FontStyle.Normal,
fontSynthesis = textStyle.fontSynthesis ?: FontSynthesis.All,
)
}
return rememberMinMaxStartAxis(
line = null,
tick = null,
guideline = null,
labelGuideline = rememberChartAxisGuidelineComponent(
color = TangemTheme.colors.icon.inactive.copy(alpha = 0.12f),
),
label = rememberAxisLabelComponent(
color = TangemTheme.colors.text.tertiary,
background = null,
padding = Dimensions.of(
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
),
textSize = TangemTheme.typography.caption2.fontSize,
typeface = typeface,
),
horizontalLabelPosition = VerticalAxis.HorizontalLabelPosition.Inside,
verticalLabelPosition = VerticalAxis.VerticalLabelPosition.Center,
itemPlacer = VerticalAxis.ItemPlacer.count({ 2 }, false),
valueFormatter = yValueFormatter,
)
}
@Composable
private fun rememberMarketChartStartAxis(
yValueFormatter: CartesianValueFormatter,
@ -253,13 +316,27 @@ private fun rememberMarketChartBottomAxis(
}
@Composable
private fun rememberChartAxisGuidelineComponent(color: Color): LineComponent {
private fun rememberChartAxisGuidelineComponent(color: Color, isWithPadding: Boolean = true): LineComponent {
val isRedesign = LocalRedesignEnabled.current
val startPadding = if (isRedesign) {
TangemTheme.dimens2.x2_5
} else {
TangemTheme.dimens.spacing4
}
val endPadding = if (isRedesign) {
TangemTheme.dimens2.x2
} else {
TangemTheme.dimens.spacing4
}
return rememberAxisGuidelineComponent(
color = color,
shape = Shape.Rectangle,
margins = Dimensions(
startDp = TangemTheme.dimens.spacing4.value,
endDp = TangemTheme.dimens.spacing4.value,
startDp = if (isWithPadding) startPadding.value else 0f,
endDp = if (isWithPadding) endPadding.value else 0f,
topDp = 0f,
bottomDp = 0f,
),

View file

@ -6,9 +6,10 @@ import com.tangem.common.ui.charts.state.formatter.AxisLabelFormatter
/**
* This class represents the look and feel of a Market Chart.
* It includes properties for type, marker highlight, animation on data change, animate data appearance,
* and formatters for x and y axis.
* and formatters for x and y-axis.
*
* @property type The type of the chart, can be either Growing or Falling.
* @property isMinMaxLook A boolean indicating whether the chart should contain markers for minimum and maximum values.
* @property shouldMarkerHighlightRightSide A boolean indicating whether the marker highlights the right side of the chart.
* @property xAxisFormatter A formatter for the x-axis labels.
* @property yAxisFormatter A formatter for the y-axis labels.
@ -16,6 +17,7 @@ import com.tangem.common.ui.charts.state.formatter.AxisLabelFormatter
@Immutable
data class MarketChartLook(
val type: Type = Type.Growing,
val isMinMaxLook: Boolean = true,
val shouldMarkerHighlightRightSide: Boolean = true,
val xAxisFormatter: AxisLabelFormatter = AxisLabelFormatter { it.toString() },
val yAxisFormatter: AxisLabelFormatter = AxisLabelFormatter { it.toString() },

View file

@ -51,7 +51,6 @@ fun rememberMarketChartState(
* @property lookState The look state of the Market Chart.
* @property colorMapper A function that maps a MarketChartLook.Type to a Color.
* @property markerCallback A callback function that is called when the marker is shown, hidden, or updated.
* @property isDrawingAnimationInProgress A boolean indicating whether the drawing animation is in progress.
*/
@Stable
class MarketChartState internal constructor(
@ -70,6 +69,10 @@ class MarketChartState internal constructor(
lookState.value.shouldMarkerHighlightRightSide
}
internal val isMinMaxLook by derivedStateOf {
lookState.value.isMinMaxLook
}
internal val xValueFormatter = CartesianValueFormatter { value, _, _ ->
val formatter = dataProducer.lookState.value.xAxisFormatter

View file

@ -31,6 +31,7 @@ fun TangemThemeRedesign(content: @Composable () -> Unit) {
LocalTangemColors provides themeColors,
LocalTangemColors2 provides if (LocalIsInDarkTheme.current) darkThemeColors2() else lightThemeColors2(),
LocalTangemTypography2 provides TangemTypography2(InterFamily),
LocalTangemTypography provides TangemTypography(InterFamily),
LocalRootBackgroundColor provides remember(rootBackgroundColor) { mutableStateOf(rootBackgroundColor) },
) {
CompositionLocalProvider(

View file

@ -189,6 +189,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
marketChartLook.copy(
type = percentChangeType.toChartType(),
isMinMaxLook = designFeatureToggles.isRedesignEnabled,
xAxisFormatter = MarketsDateTimeFormatters.getChartXFormatterByInterval(PriceChangeInterval.H24),
yAxisFormatter = { value ->
value.format {

View file

@ -9,7 +9,7 @@ tangemBlockchainSdk = "develop-1455"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-598"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
tangemVico = "2.0.0-alpha.25-tangem12"
tangemVico = "tangem-master-21"
#tangemVico = "0.0.1" # Keep it! - used for local builds ^
tangemHotSdk = "develop-549"
#tangemHotSdk = "0.0.1" # Keep it! - used for local builds ^