Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-16 14:26:00 +01:00
parent bcee90926c
commit ba1b0e1f84
9 changed files with 652 additions and 52 deletions

View file

@ -801,6 +801,10 @@
<string name="markets_token_details_holders">Holders</string>
<string name="markets_token_details_holders_description">The change in the number of token holders within a specific timeframe</string>
<string name="markets_token_details_holders_full">Holders</string>
<string name="markets_token_details_insight_day_timeline">D</string>
<string name="markets_token_details_insight_month_timeline">M</string>
<string name="markets_token_details_insight_week_timeline">W</string>
<string name="markets_token_details_insight_year_timeline">Y</string>
<string name="markets_token_details_insights">Insights</string>
<string name="markets_token_details_links">Links</string>
<string name="markets_token_details_liquidity">Liquidity</string>

View file

@ -40,7 +40,7 @@ inline fun <T : Any> InformationBlockContentScope.ListItems(
}
@Composable
inline fun <T : Any> InformationBlockContentScope.GridItems(
inline fun <T : Any> GridItems(
items: ImmutableList<T>,
modifier: Modifier = Modifier,
verticalAlignment: Alignment.Vertical = Alignment.Top,

View file

@ -1,24 +1,30 @@
package com.tangem.core.ui.components.items
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
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.TextShimmer
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.extensions.stringResourceSafe
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.res.TangemThemePreviewRedesign
import com.tangem.core.ui.utils.PreviewShimmerContainer
import com.tangem.utils.StringsSigns
@ -29,6 +35,32 @@ fun DescriptionItem(
onReadMoreClick: () -> Unit,
modifier: Modifier = Modifier,
textStyle: TextStyle = TangemTheme.typography.body2,
) {
if (LocalRedesignEnabled.current) {
DescriptionItemV2(
description = description,
hasFullDescription = hasFullDescription,
onReadMoreClick = onReadMoreClick,
modifier = modifier,
)
} else {
DescriptionItemV1(
description = description,
hasFullDescription = hasFullDescription,
onReadMoreClick = onReadMoreClick,
modifier = modifier,
textStyle = textStyle,
)
}
}
@Composable
private fun DescriptionItemV1(
description: TextReference,
hasFullDescription: Boolean,
onReadMoreClick: () -> Unit,
modifier: Modifier = Modifier,
textStyle: TextStyle = TangemTheme.typography.body2,
) {
if (hasFullDescription) {
val text = buildAnnotatedString {
@ -66,7 +98,58 @@ fun DescriptionItem(
}
@Composable
public fun DescriptionPlaceholder(modifier: Modifier = Modifier) {
private fun DescriptionItemV2(
description: TextReference,
hasFullDescription: Boolean,
onReadMoreClick: () -> Unit,
modifier: Modifier = Modifier,
) {
if (hasFullDescription) {
val text = buildAnnotatedString {
withStyle(SpanStyle(color = TangemTheme.colors2.text.neutral.tertiary)) {
append(description.resolveReference())
}
withStyle(SpanStyle(color = TangemTheme.colors2.text.neutral.primary)) {
append(
" " + stringResourceSafe(R.string.common_read_more).replace(
' ',
StringsSigns.NON_BREAKING_SPACE,
),
)
}
}
Text(
modifier = modifier
.clickable(
interactionSource = null,
indication = null,
onClick = onReadMoreClick,
),
text = text,
style = TangemTheme.typography2.bodyRegular15,
)
} else {
Text(
modifier = modifier,
text = description.resolveReference(),
style = TangemTheme.typography2.bodyRegular15,
color = TangemTheme.colors2.text.neutral.tertiary,
)
}
}
@Composable
fun DescriptionPlaceholder(modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
DescriptionPlaceholderV2(modifier)
} else {
DescriptionPlaceholderV1(modifier)
}
}
@Composable
private fun DescriptionPlaceholderV1(modifier: Modifier = Modifier) {
Column(
modifier = modifier,
) {
@ -88,9 +171,33 @@ public fun DescriptionPlaceholder(modifier: Modifier = Modifier) {
}
}
@Composable
private fun DescriptionPlaceholderV2(modifier: Modifier = Modifier) {
Column(
modifier = modifier.padding(horizontal = 6.dp),
verticalArrangement = Arrangement.spacedBy(6.dp),
) {
TextShimmer(
modifier = Modifier.fillMaxWidth(),
style = TangemTheme.typography2.bodyRegular15,
radius = TangemTheme.dimens2.x25,
)
TextShimmer(
modifier = Modifier.fillMaxWidth(),
style = TangemTheme.typography2.bodyRegular15,
radius = TangemTheme.dimens2.x25,
)
TextShimmer(
modifier = Modifier.fillMaxWidth(fraction = 0.8f),
style = TangemTheme.typography2.bodyRegular15,
radius = TangemTheme.dimens2.x25,
)
}
}
@Preview
@Composable
private fun ContentPreview() {
private fun ContentPreviewV1() {
TangemThemePreview {
DescriptionItem(
description = stringReference(
@ -105,15 +212,49 @@ private fun ContentPreview() {
@Preview
@Composable
private fun PreviewPlaceholder() {
private fun ContentPreviewV2() {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
TangemThemePreviewRedesign {
DescriptionItem(
description = stringReference(
"XRP (XRP) is a cryptocurrency launched in January 2009, where the first " +
"genesis block was mined on 9th January 2009",
),
hasFullDescription = true,
onReadMoreClick = {},
)
}
}
}
@Preview
@Composable
private fun PreviewPlaceholderV1() {
TangemThemePreview {
PreviewShimmerContainer(
actualContent = {
ContentPreview()
ContentPreviewV1()
},
shimmerContent = {
DescriptionPlaceholder()
},
)
}
}
@Preview
@Composable
private fun PreviewPlaceholderV2() {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
TangemThemePreviewRedesign {
PreviewShimmerContainer(
actualContent = {
ContentPreviewV2()
},
shimmerContent = {
DescriptionPlaceholder()
},
)
}
}
}

View file

@ -79,6 +79,7 @@ fun TangemSegmentedPicker(
hasSeparator: Boolean = false,
isFixed: Boolean = false,
isAltSurface: Boolean = false,
minSegmentWidth: Dp = Dp.Unspecified,
onClick: (TangemSegmentUM) -> Unit,
) {
if (items.isEmpty() || items.size == 1) return
@ -123,6 +124,7 @@ fun TangemSegmentedPicker(
item = item,
index = index,
isFixed = isFixed,
minSegmentWidth = minSegmentWidth,
selectedIndex = selectedIndex,
onClick = { onClick(item) },
modifier = Modifier
@ -176,9 +178,11 @@ private fun RowScope.Segment(
selectedIndex: MutableState<Int>,
onClick: () -> Unit,
modifier: Modifier = Modifier,
minSegmentWidth: Dp = Dp.Unspecified,
) {
Box(
modifier = modifier
.defaultMinSize(minWidth = minSegmentWidth)
.conditional(isFixed) {
weight(1f)
}

View file

@ -2,17 +2,11 @@ package com.tangem.features.feed.ui.market.detailed.components
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
@ -21,18 +15,30 @@ 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.RectangleShimmer
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
import com.tangem.core.ui.extensions.stringReference
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.res.TangemThemePreviewRedesign
import com.tangem.core.ui.utils.PreviewShimmerContainer
import com.tangem.features.feed.ui.market.detailed.state.InfoPointUM
@Composable
internal fun InfoPoint(infoPointUM: InfoPointUM, modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
InfoPointV2(infoPointUM, modifier)
} else {
InfoPointV1(infoPointUM, modifier)
}
}
@Composable
private fun InfoPointV1(infoPointUM: InfoPointUM, modifier: Modifier = Modifier) {
Column(
modifier = modifier.padding(vertical = TangemTheme.dimens.spacing8),
horizontalAlignment = Alignment.Start,
@ -81,8 +87,68 @@ internal fun InfoPoint(infoPointUM: InfoPointUM, modifier: Modifier = Modifier)
}
}
@Composable
private fun InfoPointV2(infoPointUM: InfoPointUM, modifier: Modifier = Modifier) {
Column(
modifier = modifier.padding(vertical = TangemTheme.dimens.spacing8),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
Row {
Text(
text = infoPointUM.value,
style = TangemTheme.typography2.headingSemibold20,
color = TangemTheme.colors2.text.neutral.primary,
)
if (infoPointUM.change != null) {
SpacerW4()
Icon(
modifier = Modifier
.size(TangemTheme.dimens2.x2)
.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.colors2.markers.iconGreen
InfoPointUM.ChangeType.DOWN -> TangemTheme.colors2.markers.iconRed
},
contentDescription = null,
)
}
}
if (infoPointUM.onInfoClick != null) {
InformationTextBlock(
text = infoPointUM.title,
onInfoClick = infoPointUM.onInfoClick,
informationTextBlockIconPosition = InformationTextBlockIconPosition.START,
)
} else {
Text(
text = infoPointUM.title.resolveReference(),
style = TangemTheme.typography2.captionSemibold12,
color = TangemTheme.colors2.text.neutral.tertiary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}
@Composable
internal fun InfoPointShimmer(modifier: Modifier = Modifier, withTooltip: Boolean = false) {
if (LocalRedesignEnabled.current) {
InfoPointShimmerV2(modifier)
} else {
InfoPointShimmerV1(modifier, withTooltip)
}
}
@Composable
private fun InfoPointShimmerV1(modifier: Modifier = Modifier, withTooltip: Boolean = false) {
Column(
modifier = modifier.padding(vertical = TangemTheme.dimens.spacing8),
horizontalAlignment = Alignment.Start,
@ -115,10 +181,34 @@ internal fun InfoPointShimmer(modifier: Modifier = Modifier, withTooltip: Boolea
}
}
@Composable
private fun InfoPointShimmerV2(modifier: Modifier = Modifier) {
Column(
modifier = modifier.padding(vertical = TangemTheme.dimens2.x6),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
) {
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(24.dp)
.padding(end = 10.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier
.width(68.dp)
.height(16.dp),
radius = TangemTheme.dimens2.x25,
)
}
}
@Preview
@Preview("Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun ContentPreview() {
private fun ContentPreviewV1() {
TangemThemePreview {
Column(
modifier = Modifier
@ -158,6 +248,53 @@ private fun ContentPreview() {
}
}
@Preview
@Preview("Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun ContentPreviewV2() {
CompositionLocalProvider(
LocalRedesignEnabled provides true,
) {
TangemThemePreviewRedesign {
Column(
modifier = Modifier
.width(150.dp)
.background(TangemTheme.colors.background.tertiary),
) {
InfoPoint(
infoPointUM = InfoPointUM(
title = stringReference("Market Cap"),
value = "$1,000,000,000",
),
)
InfoPoint(
infoPointUM = InfoPointUM(
title = stringReference("Market Cap"),
value = "$1,000,000,000",
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 = { },
),
)
}
}
}
}
@Preview
@Preview("Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
@ -186,7 +323,7 @@ private fun PreviewShimmer() {
}
},
actualContent = {
ContentPreview()
ContentPreviewV1()
},
)
}

View file

@ -1,37 +1,33 @@
package com.tangem.features.feed.ui.market.detailed.components
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SpacerW
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.ds.tabs.TangemSegmentUM
import com.tangem.core.ui.ds.tabs.TangemSegmentedPicker
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
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.res.TangemThemePreviewRedesign
import com.tangem.core.ui.utils.PreviewShimmerContainer
import com.tangem.domain.markets.PriceChangeInterval
import com.tangem.features.feed.impl.R
import com.tangem.features.feed.ui.components.TokenMarketInformationBlock
import com.tangem.features.feed.ui.market.detailed.getText
import com.tangem.features.feed.ui.market.detailed.state.InfoPointUM
import com.tangem.features.feed.ui.market.detailed.state.InsightsUM
@ -40,6 +36,15 @@ import kotlinx.collections.immutable.toImmutableList
@Composable
internal fun InsightsBlock(state: InsightsUM, modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
InsightsBlockV2(state, modifier)
} else {
InsightsBlockV1(state, modifier)
}
}
@Composable
private fun InsightsBlockV1(state: InsightsUM, modifier: Modifier = Modifier) {
var currentInterval by remember { mutableStateOf(PriceChangeInterval.H24) }
InformationBlock(
@ -104,8 +109,84 @@ internal fun InsightsBlock(state: InsightsUM, modifier: Modifier = Modifier) {
)
}
@Composable
private fun InsightsBlockV2(state: InsightsUM, modifier: Modifier = Modifier) {
val segmentItems = persistentListOf(
TangemSegmentUM(
id = PriceChangeInterval.H24.name,
title = resourceReference(R.string.markets_token_details_insight_day_timeline),
),
TangemSegmentUM(
id = PriceChangeInterval.WEEK.name,
title = resourceReference(R.string.markets_token_details_insight_week_timeline),
),
TangemSegmentUM(
id = PriceChangeInterval.MONTH.name,
title = resourceReference(R.string.markets_token_details_insight_month_timeline),
),
)
var currentInterval by remember { mutableStateOf(segmentItems.first()) }
TokenMarketInformationBlock(
modifier = modifier,
title = {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = stringResourceSafe(R.string.markets_token_details_insights),
style = TangemTheme.typography2.headingSemibold20,
color = TangemTheme.colors2.text.neutral.primary,
)
TangemSegmentedPicker(
items = segmentItems,
initialSelectedItem = segmentItems.first(),
hasSeparator = true,
isFixed = false,
isAltSurface = true,
minSegmentWidth = 48.dp,
onClick = { segment ->
currentInterval = segment
state.onIntervalChanged(PriceChangeInterval.valueOf(segment.id))
},
)
}
},
content = {
val infoPoints = when (currentInterval.id) {
PriceChangeInterval.H24.name -> state.h24Info
PriceChangeInterval.WEEK.name -> state.weekInfo
PriceChangeInterval.MONTH.name -> state.monthInfo
else -> state.h24Info
}
GridItems(
modifier = Modifier.padding(top = 24.dp),
items = infoPoints,
itemContent = { infoPointUM ->
InfoPoint(
modifier = Modifier.align(Alignment.CenterStart),
infoPointUM = infoPointUM,
)
},
)
},
)
}
@Composable
internal fun InsightsBlockPlaceholder(modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
InsightsBlockPlaceholderV2(modifier)
} else {
InsightsBlockPlaceholderV1(modifier)
}
}
@Composable
internal fun InsightsBlockPlaceholderV1(modifier: Modifier = Modifier) {
val subtitle2dp = with(LocalDensity.current) { TangemTheme.typography.subtitle2.lineHeight.toDp() }
val caption1dp = with(LocalDensity.current) { TangemTheme.typography.caption1.lineHeight.toDp() }
val headerHeight = maxOf(subtitle2dp, caption1dp) + TangemTheme.dimens.spacing4
@ -134,10 +215,47 @@ internal fun InsightsBlockPlaceholder(modifier: Modifier = Modifier) {
)
}
@Composable
internal fun InsightsBlockPlaceholderV2(modifier: Modifier = Modifier) {
TokenMarketInformationBlock(
modifier = modifier,
title = {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
RectangleShimmer(
modifier = Modifier
.height(24.dp)
.width(120.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerW(62.dp)
RectangleShimmer(
modifier = Modifier
.height(36.dp)
.weight(1f),
radius = TangemTheme.dimens2.x25,
)
}
},
content = {
GridItems(
items = List(size = 4) { it }.toImmutableList(),
horizontalArragement = Arrangement.spacedBy(10.dp),
itemContent = {
InfoPointShimmer(modifier = Modifier.fillMaxWidth())
},
)
},
)
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun ContentPreview() {
private fun ContentPreviewV1() {
TangemThemePreview {
InsightsBlock(
state = InsightsUM(
@ -205,11 +323,95 @@ private fun ContentPreview() {
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun PreviewPlaceholder() {
private fun ContentPreviewV2() {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
TangemThemePreviewRedesign {
InsightsBlock(
state = InsightsUM(
h24Info = persistentListOf(
InfoPointUM(
title = resourceReference(R.string.markets_token_details_experienced_buyers),
value = "1 000 000 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_buy_pressure),
value = "1 000 000 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_holders),
value = "1 000 000 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_liquidity),
value = "1 000 000 000",
),
),
weekInfo = persistentListOf(
InfoPointUM(
title = resourceReference(R.string.markets_token_details_experienced_buyers),
value = "1 000 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_buy_pressure),
value = "1 000 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_holders),
value = "1 000 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_liquidity),
value = "1 000 000",
),
),
monthInfo = persistentListOf(
InfoPointUM(
title = resourceReference(R.string.markets_token_details_experienced_buyers),
value = "1 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_buy_pressure),
value = "1 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_holders),
value = "1 000",
),
InfoPointUM(
title = resourceReference(R.string.markets_token_details_liquidity),
value = "1 000",
),
),
onInfoClick = {},
onIntervalChanged = {},
),
)
}
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun PreviewPlaceholderV1() {
TangemThemePreview {
PreviewShimmerContainer(
actualContent = { ContentPreview() },
actualContent = { ContentPreviewV1() },
shimmerContent = { InsightsBlockPlaceholder() },
)
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun PreviewPlaceholderV2() {
TangemThemePreviewRedesign {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
PreviewShimmerContainer(
actualContent = { ContentPreviewV2() },
shimmerContent = { InsightsBlockPlaceholder() },
)
}
}
}

View file

@ -156,17 +156,17 @@ internal fun ListedOnBlockPlaceholderV1(modifier: Modifier = Modifier) {
@Composable
internal fun ListedOnBlockPlaceholderV2(modifier: Modifier = Modifier) {
TokenMarketInformationBlock(
modifier = modifier,
modifier = modifier.fillMaxWidth(),
title = {
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
TextShimmer(
style = TangemTheme.typography2.headingSemibold20,
modifier = Modifier.fillMaxWidth(fraction = 0.5f),
modifier = Modifier.width(120.dp),
radius = TangemTheme.dimens2.x25,
)
TextShimmer(
style = TangemTheme.typography2.captionSemibold13,
modifier = Modifier.fillMaxWidth(fraction = 0.5f),
modifier = Modifier.width(66.dp),
radius = TangemTheme.dimens2.x25,
)
}

View file

@ -129,7 +129,7 @@ private fun SecurityScoreBlockPlaceholderV2(modifier: Modifier = Modifier) {
TangemRowContainer(modifier = modifier) {
TextShimmer(
modifier = Modifier
.width(74.dp)
.width(114.dp)
.layoutId(layoutId = TangemRowLayoutId.START_TOP),
style = TangemTheme.typography2.headingBold28,
radius = TangemTheme.dimens2.x25,
@ -137,7 +137,8 @@ private fun SecurityScoreBlockPlaceholderV2(modifier: Modifier = Modifier) {
TextShimmer(
modifier = Modifier
.width(96.dp)
.width(74.dp)
.padding(top = 8.dp)
.layoutId(layoutId = TangemRowLayoutId.START_BOTTOM),
style = TangemTheme.typography2.captionSemibold12,
radius = TangemTheme.dimens2.x25,
@ -145,7 +146,7 @@ private fun SecurityScoreBlockPlaceholderV2(modifier: Modifier = Modifier) {
TextShimmer(
modifier = Modifier
.width(120.dp)
.width(116.dp)
.layoutId(layoutId = TangemRowLayoutId.END_TOP),
style = TangemTheme.typography2.headingBold28,
radius = TangemTheme.dimens2.x25,
@ -153,7 +154,8 @@ private fun SecurityScoreBlockPlaceholderV2(modifier: Modifier = Modifier) {
TextShimmer(
modifier = Modifier
.width(72.dp)
.width(96.dp)
.padding(top = 8.dp)
.layoutId(layoutId = TangemRowLayoutId.END_BOTTOM),
style = TangemTheme.typography2.captionSemibold12,
radius = TangemTheme.dimens2.x25,

View file

@ -26,6 +26,26 @@ internal fun LazyListScope.tokenMarketDetailsBody(
state: MarketsTokenDetailsUM.Body,
portfolioBlock: @Composable ((Modifier) -> Unit)?,
relatedNews: RelatedNews,
) {
if (isRedesignEnabled) {
tokenMarketDetailsBodyV2(
state = state,
relatedNews = relatedNews,
)
} else {
tokenMarketDetailsBodyV1(
state = state,
portfolioBlock = portfolioBlock,
relatedNews = relatedNews,
)
}
}
@Suppress("CanBeNonNullable")
private fun LazyListScope.tokenMarketDetailsBodyV1(
state: MarketsTokenDetailsUM.Body,
portfolioBlock: @Composable ((Modifier) -> Unit)?,
relatedNews: RelatedNews,
) {
when (state) {
MarketsTokenDetailsUM.Body.Loading -> {
@ -41,7 +61,7 @@ internal fun LazyListScope.tokenMarketDetailsBody(
aboutCoinHeader()
loadingInfoBlocks(isRedesignEnabled)
loadingInfoBlocks(false)
}
is MarketsTokenDetailsUM.Body.Content -> {
if (state.description != null) {
@ -60,9 +80,35 @@ internal fun LazyListScope.tokenMarketDetailsBody(
aboutCoinHeader()
infoBlocksList(
infoBlocksListV1(state = state.infoBlocks)
}
is MarketsTokenDetailsUM.Body.Error -> {
error(state)
}
MarketsTokenDetailsUM.Body.Nothing -> {
// Do nothing
}
}
}
@Suppress("CanBeNonNullable")
private fun LazyListScope.tokenMarketDetailsBodyV2(state: MarketsTokenDetailsUM.Body, relatedNews: RelatedNews) {
when (state) {
MarketsTokenDetailsUM.Body.Loading -> {
item("description-loading") {
DescriptionPlaceholder(modifier = Modifier.blockPaddings())
}
loadingInfoBlocks(true)
}
is MarketsTokenDetailsUM.Body.Content -> {
if (state.description != null) {
description(state.description)
}
infoBlocksListV2(
state = state.infoBlocks,
isRedesignEnabled = isRedesignEnabled,
relatedNews = relatedNews,
)
}
is MarketsTokenDetailsUM.Body.Error -> {
@ -116,7 +162,7 @@ private fun LazyListScope.description(description: MarketsTokenDetailsUM.Descrip
}
}
internal fun LazyListScope.infoBlocksList(state: MarketsTokenDetailsUM.InformationBlocks, isRedesignEnabled: Boolean) {
internal fun LazyListScope.infoBlocksListV1(state: MarketsTokenDetailsUM.InformationBlocks) {
if (state.insights != null) {
item("insights") {
InsightsBlock(
@ -126,7 +172,7 @@ internal fun LazyListScope.infoBlocksList(state: MarketsTokenDetailsUM.Informati
}
}
if (state.securityScore != null && !isRedesignEnabled) {
if (state.securityScore != null) {
item("securityScore") {
SecurityScoreBlock(
modifier = Modifier.blockPaddings(),
@ -160,7 +206,47 @@ internal fun LazyListScope.infoBlocksList(state: MarketsTokenDetailsUM.Informati
)
}
if (state.securityScore != null && isRedesignEnabled) {
if (state.links != null) {
item("links") {
LinksBlock(
modifier = Modifier.blockPaddings(),
state = state.links,
)
}
}
}
internal fun LazyListScope.infoBlocksListV2(state: MarketsTokenDetailsUM.InformationBlocks, relatedNews: RelatedNews) {
if (state.metrics != null) {
item("metrics") {
MetricsBlock(
modifier = Modifier.blockPaddings(),
state = state.metrics,
)
}
}
if (state.insights != null) {
item("insights") {
InsightsBlock(
modifier = Modifier.blockPaddings(),
state = state.insights,
)
}
}
item(key = "listedOn") {
ListedOnBlock(
state = state.listedOn,
modifier = Modifier.blockPaddings(),
)
}
if (relatedNews.articles.isNotEmpty()) {
relatedNews(relatedNews)
}
if (state.securityScore != null) {
item("securityScore") {
SecurityScoreBlock(
modifier = Modifier.blockPaddings(),
@ -180,16 +266,22 @@ internal fun LazyListScope.infoBlocksList(state: MarketsTokenDetailsUM.Informati
}
private fun LazyListScope.loadingInfoBlocks(isRedesignEnabled: Boolean) {
if (isRedesignEnabled) {
loadingInfoBlocksV2()
} else {
loadingInfoBlocksV1()
}
}
private fun LazyListScope.loadingInfoBlocksV1() {
item("insights-loading") {
InsightsBlockPlaceholder(
modifier = Modifier.blockPaddings(),
)
}
if (!isRedesignEnabled) {
item("securityScore-loading") {
SecurityScoreBlockPlaceholder(modifier = Modifier.blockPaddings())
}
item("securityScore-loading") {
SecurityScoreBlockPlaceholder(modifier = Modifier.blockPaddings())
}
item("metrics-loading") {
@ -204,10 +296,28 @@ private fun LazyListScope.loadingInfoBlocks(isRedesignEnabled: Boolean) {
ListedOnBlockPlaceholder(modifier = Modifier.blockPaddings())
}
if (isRedesignEnabled) {
item("securityScore-loading") {
SecurityScoreBlockPlaceholder(modifier = Modifier.blockPaddings())
}
item("links-loading") {
LinksBlockPlaceholder(modifier = Modifier.blockPaddings())
}
}
private fun LazyListScope.loadingInfoBlocksV2() {
item("metrics-loading") {
MetricsBlockPlaceholder(modifier = Modifier.blockPaddings())
}
item("insights-loading") {
InsightsBlockPlaceholder(
modifier = Modifier.blockPaddings(),
)
}
item(key = "listedOn-loading") {
ListedOnBlockPlaceholder(modifier = Modifier.blockPaddings())
}
item("securityScore-loading") {
SecurityScoreBlockPlaceholder(modifier = Modifier.blockPaddings())
}
item("links-loading") {