Updated on 2026-08-14
This commit is contained in:
parent
bcee90926c
commit
ba1b0e1f84
9 changed files with 652 additions and 52 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue