Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-02 07:32:06 +01:00
parent 96478230a0
commit 4acd7ce3b2
25 changed files with 1010 additions and 338 deletions

View file

@ -25,9 +25,7 @@ import com.tangem.features.feed.ui.earn.state.EarnListItemUM
@Composable
internal fun MostlyUsedCard(item: EarnListItemUM, onClick: () -> Unit, modifier: Modifier = Modifier) {
val isRedesignEnabled = LocalRedesignEnabled.current
if (isRedesignEnabled) {
if (LocalRedesignEnabled.current) {
MostlyUsedCardV2(
modifier = modifier,
item = item,

View file

@ -1,15 +1,96 @@
package com.tangem.features.feed.ui.feed.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onFirstVisible
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.HorizontalFadeWithBlur
import com.tangem.core.ui.components.block.TangemBlockCardColors
import com.tangem.core.ui.components.haze.hazeSourceTangem
import com.tangem.core.ui.extensions.conditionalCompose
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.feed.ui.feed.components.articles.ArticleCard
import com.tangem.features.feed.ui.feed.components.articles.ShowMoreArticlesCard
import com.tangem.features.feed.ui.feed.state.NewsSliderConfig
@Suppress("LongMethod")
@Composable
internal fun NewsSlider(newsSliderConfig: NewsSliderConfig) {
val background = LocalMainBottomSheetColor.current.value
val isRedesignEnabled = LocalRedesignEnabled.current
if (isRedesignEnabled) {
NewsSliderV2(newsSliderConfig)
} else {
NewsSliderV1(newsSliderConfig)
Box(
modifier = Modifier.fillMaxWidth(),
) {
LazyRow(
modifier = Modifier
.conditionalCompose(
condition = isRedesignEnabled,
modifier = {
hazeSourceTangem(-1f)
},
)
.background(color = background),
verticalAlignment = Alignment.CenterVertically,
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
state = rememberLazyListState(),
) {
itemsIndexed(
items = newsSliderConfig.content,
key = { index, _ -> index },
contentType = { _, _ -> "article" },
) { index, article ->
val articleModifier = if (index == FOURTH_ITEM_INDEX) {
Modifier.onFirstVisible(
minFractionVisible = 0.5f,
callback = newsSliderConfig.callbacks.onSliderScroll,
)
} else {
Modifier
}
ArticleCard(
articleConfigUM = article,
onArticleClick = { newsSliderConfig.callbacks.onArticleClick(article.id) },
modifier = articleModifier
.width(228.dp)
.heightIn(min = 172.dp)
.fillMaxHeight(),
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
)
}
if (newsSliderConfig.shouldShowSeeAllNewsItem) {
item(contentType = "show_more") {
ShowMoreArticlesCard(
modifier = Modifier
.width(228.dp)
.heightIn(min = 172.dp)
.onFirstVisible(
minFractionVisible = 0.5f,
callback = newsSliderConfig.callbacks.onSliderEndReached,
),
onClick = newsSliderConfig.callbacks.onOpenAllNews,
)
}
}
}
if (isRedesignEnabled) {
HorizontalFadeWithBlur(
modifier = Modifier
.align(Alignment.TopEnd)
.heightIn(min = 172.dp)
.fillMaxHeight()
.width(100.dp),
backgroundColor = background,
)
}
}
}

View file

@ -1,67 +0,0 @@
package com.tangem.features.feed.ui.feed.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onFirstVisible
import androidx.compose.ui.unit.dp
import com.tangem.features.feed.ui.feed.components.articles.ArticleCard
import com.tangem.features.feed.ui.feed.components.articles.ShowMoreArticlesCard
import com.tangem.core.ui.components.block.TangemBlockCardColors
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.feed.ui.feed.state.NewsSliderConfig
@Composable
internal fun NewsSliderV1(newsSliderConfig: NewsSliderConfig) {
LazyRow(
verticalAlignment = Alignment.CenterVertically,
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
state = rememberLazyListState(),
) {
itemsIndexed(
items = newsSliderConfig.content,
key = { index, _ -> index },
contentType = { _, _ -> "article" },
) { index, article ->
val articleModifier = if (index == FOURTH_ITEM_INDEX) {
Modifier.onFirstVisible(
minFractionVisible = 0.5f,
callback = newsSliderConfig.callbacks.onSliderScroll,
)
} else {
Modifier
}
ArticleCard(
articleConfigUM = article,
onArticleClick = { newsSliderConfig.callbacks.onArticleClick(article.id) },
modifier = articleModifier
.heightIn(min = 164.dp)
.width(216.dp),
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
)
}
if (newsSliderConfig.shouldShowSeeAllNewsItem) {
item(contentType = "show_more") {
ShowMoreArticlesCard(
modifier = Modifier
.width(216.dp)
.heightIn(min = 164.dp)
.onFirstVisible(
minFractionVisible = 0.5f,
callback = newsSliderConfig.callbacks.onSliderEndReached,
),
onClick = newsSliderConfig.callbacks.onOpenAllNews,
)
}
}
}
}

View file

@ -1,112 +0,0 @@
package com.tangem.features.feed.ui.feed.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.onFirstVisible
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import com.tangem.features.feed.ui.feed.components.articles.ArticleCard
import com.tangem.features.feed.ui.feed.components.articles.ShowMoreArticlesCard
import com.tangem.core.ui.extensions.conditional
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.feed.ui.feed.state.NewsSliderConfig
private val dividerSpacerWidth = 20.dp
@Suppress("MagicNumber", "LongMethod")
@Composable
internal fun NewsSliderV2(newsSliderConfig: NewsSliderConfig) {
val density = LocalDensity.current
val dividerWidthPx = with(density) { 1.dp.roundToPx() }
val spacerWidthPx = with(density) { dividerSpacerWidth.roundToPx() }
LazyRow(
verticalAlignment = Alignment.CenterVertically,
contentPadding = PaddingValues(horizontal = 16.dp),
state = rememberLazyListState(),
) {
itemsIndexed(
items = newsSliderConfig.content,
key = { index, _ -> index },
contentType = { _, _ -> "article" },
) { index, article ->
val articleModifier = Modifier.conditional(
condition = index == FOURTH_ITEM_INDEX,
modifier = {
onFirstVisible(
minFractionVisible = 0.5f,
callback = newsSliderConfig.callbacks.onSliderScroll,
)
},
)
val shouldShowDivider = newsSliderConfig.shouldShowSeeAllNewsItem ||
index < newsSliderConfig.content.size - 1
// have to use layout cause LazyRow has not fixed height and divider can not be measured
Layout(
modifier = Modifier,
content = {
ArticleCard(
articleConfigUM = article,
onArticleClick = { newsSliderConfig.callbacks.onArticleClick(article.id) },
modifier = articleModifier
.fillMaxHeight()
.width(220.dp),
)
Spacer(modifier = Modifier.width(dividerSpacerWidth))
Box(
modifier = Modifier
.width(1.dp)
.background(TangemTheme.colors2.border.neutral.secondary),
)
Spacer(modifier = Modifier.width(dividerSpacerWidth))
},
) { measurables, constraints ->
val cardPlaceable = measurables[0].measure(constraints)
val height = cardPlaceable.height
if (shouldShowDivider) {
val leftSpacer = measurables[1].measure(Constraints.fixed(spacerWidthPx, height))
val divider = measurables[2].measure(Constraints.fixed(dividerWidthPx, height))
val rightSpacer = measurables[3].measure(Constraints.fixed(spacerWidthPx, height))
val totalWidth = cardPlaceable.width + leftSpacer.width + divider.width + rightSpacer.width
layout(totalWidth, height) {
cardPlaceable.place(0, 0)
leftSpacer.place(cardPlaceable.width, 0)
divider.place(cardPlaceable.width + leftSpacer.width, 0)
rightSpacer.place(cardPlaceable.width + leftSpacer.width + divider.width, 0)
}
} else {
layout(cardPlaceable.width, height) {
cardPlaceable.place(0, 0)
}
}
}
}
if (newsSliderConfig.shouldShowSeeAllNewsItem) {
item(contentType = "show_more") {
ShowMoreArticlesCard(
modifier = Modifier
.fillMaxHeight()
.width(216.dp)
.onFirstVisible(
minFractionVisible = 0.5f,
callback = newsSliderConfig.callbacks.onSliderEndReached,
),
onClick = newsSliderConfig.callbacks.onOpenAllNews,
)
}
}
}
}

View file

@ -13,9 +13,7 @@ fun ArticleCard(
modifier: Modifier = Modifier,
colors: CardColors = TangemBlockCardColors,
) {
val isRedesignEnabled = LocalRedesignEnabled.current
if (isRedesignEnabled) {
if (LocalRedesignEnabled.current) {
ArticleCardV2(
articleConfigUM = articleConfigUM,
onArticleClick = onArticleClick,

View file

@ -122,6 +122,7 @@ internal fun ShowMoreArticlesCardV2(modifier: Modifier = Modifier, onClick: () -
.padding(vertical = 41.dp, horizontal = 16.dp),
) {
Image(
modifier = Modifier.size(40.dp),
imageVector = ImageVector.vectorResource(R.drawable.ic_show_more_news_48),
contentDescription = stringResourceSafe(R.string.common_show_more),
)
@ -134,6 +135,8 @@ internal fun ShowMoreArticlesCardV2(modifier: Modifier = Modifier, onClick: () -
color = TangemTheme.colors2.text.neutral.primary,
)
SpacerH(4.dp)
Text(
text = stringResourceSafe(R.string.news_stay_in_the_loop),
style = TangemTheme.typography2.captionSemibold12,
@ -150,17 +153,27 @@ private fun DefaultArticle(
) {
Column(
modifier = modifier
.background(TangemTheme.colors2.surface.level2)
.clickable { onArticleClick() }
.padding(vertical = 16.dp, horizontal = 10.dp),
.clip(RoundedCornerShape(20.dp))
.background(color = TangemTheme.colors2.surface.level3)
.clickable(onClick = onArticleClick)
.border(
width = 1.dp,
color = TangemTheme.colors2.border.neutral.primary,
shape = RoundedCornerShape(20.dp),
)
.padding(16.dp),
) {
Row(verticalAlignment = Alignment.CenterVertically) {
RatingInfo(rating = stringReference("${articleConfigUM.score}"))
RatingInfo(
rating = stringReference("${articleConfigUM.score}"),
isTrending = false,
)
}
SpacerH(8.dp)
Text(
modifier = Modifier.weight(1f),
text = articleConfigUM.title,
color = if (articleConfigUM.isViewed) {
TangemTheme.colors2.text.neutral.tertiary
@ -168,13 +181,13 @@ private fun DefaultArticle(
TangemTheme.colors2.text.neutral.primary
},
style = TangemTheme.typography2.bodyRegular16,
minLines = 3,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
)
SpacerH(8.dp)
Text(
modifier = Modifier.padding(vertical = 20.dp),
text = articleConfigUM.createdAt.resolveReference(),
style = TangemTheme.typography2.captionSemibold12,
color = TangemTheme.colors2.text.neutral.secondary,
@ -182,6 +195,8 @@ private fun DefaultArticle(
maxLines = 1,
)
SpacerH(8.dp)
Tags(tags = articleConfigUM.tags.toImmutableList())
}
}
@ -269,7 +284,7 @@ private fun DayAndRatingInfo(rating: TextReference, modifier: Modifier = Modifie
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
) {
RatingInfo(rating)
RatingInfo(rating = rating, isTrending = true)
SpacerW(8.dp)
@ -282,10 +297,14 @@ private fun DayAndRatingInfo(rating: TextReference, modifier: Modifier = Modifie
}
@Composable
private fun RatingInfo(rating: TextReference) {
private fun RatingInfo(rating: TextReference, isTrending: Boolean) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_wrapped_circle_star_16),
tint = TangemTheme.colors2.fill.status.attention,
tint = if (isTrending) {
TangemTheme.colors2.fill.status.attention
} else {
TangemTheme.colors2.markers.iconGray
},
contentDescription = null,
)
@ -293,7 +312,11 @@ private fun RatingInfo(rating: TextReference) {
Text(
text = rating.resolveReference(),
color = TangemTheme.colors2.text.status.attention,
color = if (isTrending) {
TangemTheme.colors2.text.status.attention
} else {
TangemTheme.colors2.text.neutral.secondary
},
style = TangemTheme.typography2.captionSemibold12,
)
}

View file

@ -1,18 +1,32 @@
package com.tangem.features.feed.ui.feed.components.articles
import android.content.res.Configuration
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
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.SpacerH
import com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.components.block.TangemBlockCardColors
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
@Composable
fun TrendingLoadingArticle(modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
TrendingLoadingArticleV2(modifier)
} else {
TrendingLoadingArticleV1(modifier)
}
}
@Composable
private fun TrendingLoadingArticleV1(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier,
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
@ -40,25 +54,167 @@ fun TrendingLoadingArticle(modifier: Modifier = Modifier) {
}
}
@Composable
private fun TrendingLoadingArticleV2(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier,
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors2.surface.level3),
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
) {
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
SpacerH(8.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(24.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(48.dp)
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
SpacerH(12.dp)
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
RectangleShimmer(
modifier = Modifier.size(width = 58.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier.size(width = 58.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier.size(width = 58.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
}
}
}
}
@Composable
fun DefaultLoadingArticle(modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
DefaultLoadingArticleV2(modifier)
} else {
DefaultLoadingArticleV1(modifier)
}
}
@Composable
private fun DefaultLoadingArticleV1(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier,
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
) {
Column(modifier = Modifier.padding(12.dp)) {
RectangleShimmer(modifier = Modifier.size(width = 110.dp, height = 16.dp), radius = 4.dp)
SpacerH(12.dp)
RectangleShimmer(modifier = Modifier.size(width = 142.dp, height = 18.dp), radius = 4.dp)
SpacerH(6.dp)
RectangleShimmer(modifier = Modifier.size(width = 176.dp, height = 18.dp), radius = 4.dp)
SpacerH(6.dp)
RectangleShimmer(modifier = Modifier.size(width = 120.dp, height = 18.dp), radius = 4.dp)
SpacerH(16.dp)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
) {
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
SpacerH(8.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(28.dp)
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
SpacerH(8.dp)
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
RectangleShimmer(modifier = Modifier.size(width = 72.dp, height = 24.dp), radius = 8.dp)
RectangleShimmer(modifier = Modifier.size(width = 72.dp, height = 24.dp), radius = 8.dp)
RectangleShimmer(
modifier = Modifier.size(width = 72.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier.size(width = 62.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier.size(width = 32.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
}
}
}
}
@Composable
private fun DefaultLoadingArticleV2(modifier: Modifier = Modifier) {
BlockCard(
modifier = modifier,
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors2.surface.level3),
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
) {
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
SpacerH(8.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(44.dp)
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
SpacerH(12.dp)
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
RectangleShimmer(
modifier = Modifier.size(width = 72.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier.size(width = 62.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier.size(width = 32.dp, height = 24.dp),
radius = TangemTheme.dimens2.x25,
)
}
}
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun TrendingLoadingArticlePreviewV1() {
TangemThemePreview {
TrendingLoadingArticle()
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun TrendingLoadingArticlePreviewV2() {
TangemThemePreviewRedesign {
TrendingLoadingArticle()
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun DefaultLoadingArticlePreviewV1() {
TangemThemePreview {
DefaultLoadingArticle()
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun DefaultLoadingArticlePreviewV2() {
TangemThemePreviewRedesign {
DefaultLoadingArticle()
}
}

View file

@ -8,8 +8,12 @@ import androidx.compose.ui.layout.SubcomposeMeasureScope
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.label.Label
import com.tangem.core.ui.components.label.entity.LabelLeadingContentUM
import com.tangem.core.ui.components.label.entity.LabelUM
import com.tangem.core.ui.ds.badge.*
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.utils.StringsSigns
import kotlinx.collections.immutable.ImmutableList
@ -31,7 +35,25 @@ internal fun Tags(tags: ImmutableList<LabelUM>, modifier: Modifier = Modifier) {
val tagPlaceables = subcompose(ContentSlot.Tags) {
tags.forEach { tag ->
Label(state = tag)
if (LocalRedesignEnabled.current) {
TangemBadge(
text = tag.text,
tangemIconUM = when (val content = tag.leadingContent) {
LabelLeadingContentUM.None -> null
is LabelLeadingContentUM.Token -> TangemIconUM.Url(content.iconUrl)
},
shape = TangemBadgeShape.Rounded,
size = TangemBadgeSize.X6,
type = TangemBadgeType.Tinted,
color = TangemBadgeColor.Gray,
iconPosition = when (tag.leadingContent) {
LabelLeadingContentUM.None -> TangemBadgeIconPosition.None
is LabelLeadingContentUM.Token -> TangemBadgeIconPosition.Start
},
)
} else {
Label(state = tag)
}
}
}.map { it.measure(constraints) }
@ -108,12 +130,22 @@ private fun SubcomposeMeasureScope.calculateLayoutInfo(
@Composable
private fun OverflowLabel(count: Int) {
Label(
state = LabelUM(
if (LocalRedesignEnabled.current) {
TangemBadge(
text = TextReference.Str("${StringsSigns.PLUS}$count"),
maxLines = 1,
),
)
shape = TangemBadgeShape.Rounded,
size = TangemBadgeSize.X6,
type = TangemBadgeType.Tinted,
color = TangemBadgeColor.Gray,
)
} else {
Label(
state = LabelUM(
text = TextReference.Str("${StringsSigns.PLUS}$count"),
maxLines = 1,
),
)
}
}
private fun calculateRowWidth(placeables: List<Placeable>, spacingPx: Int): Int {

View file

@ -1,23 +1,45 @@
package com.tangem.features.feed.ui.news.details.components
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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.SpacerH
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
@Composable
fun NewsDetailsPlaceholder(background: Color, modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
NewsDetailsPlaceholderV2(background, modifier)
} else {
NewsDetailsPlaceholderV1(background, modifier)
}
}
@Suppress("LongMethod")
@Composable
private fun NewsDetailsPlaceholderV1(background: Color, modifier: Modifier = Modifier) {
Column(
modifier = modifier.fillMaxSize().background(background).padding(16.dp),
modifier = modifier
.fillMaxSize()
.background(background)
.padding(16.dp),
) {
RectangleShimmer(modifier = Modifier.size(width = 112.dp, height = 20.dp))
SpacerH(8.dp)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(28.dp),
modifier = Modifier
.fillMaxWidth()
.height(28.dp),
)
SpacerH(4.dp)
RectangleShimmer(modifier = Modifier.size(height = 28.dp, width = 208.dp))
@ -29,29 +51,178 @@ fun NewsDetailsPlaceholder(background: Color, modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 30.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 30.dp),
)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 30.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 30.dp),
)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 24.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 24.dp),
)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 70.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 70.dp),
)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 30.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 30.dp),
)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 96.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 96.dp),
)
RectangleShimmer(
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 100.dp),
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 100.dp),
)
}
}
}
@Suppress("LongMethod")
@Composable
private fun NewsDetailsPlaceholderV2(background: Color, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxSize()
.background(background)
.padding(16.dp),
) {
Row(
modifier = Modifier.height(50.dp),
horizontalArrangement = Arrangement.spacedBy(30.dp),
) {
Column {
RectangleShimmer(
modifier = Modifier.size(width = 50.dp, height = 20.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(10.dp)
RectangleShimmer(
modifier = Modifier.size(width = 90.dp, height = 18.dp),
radius = TangemTheme.dimens2.x25,
)
}
VerticalDivider(color = TangemTheme.colors2.border.neutral.primary)
Column {
RectangleShimmer(
modifier = Modifier.size(width = 50.dp, height = 20.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(10.dp)
RectangleShimmer(
modifier = Modifier.size(width = 90.dp, height = 18.dp),
radius = TangemTheme.dimens2.x25,
)
}
}
SpacerH(36.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(40.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(12.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
.padding(end = 106.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(36.dp)
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
RectangleShimmer(
modifier = Modifier.size(width = 98.dp, height = 36.dp),
radius = TangemTheme.dimens2.x25,
)
RectangleShimmer(
modifier = Modifier.size(width = 98.dp, height = 36.dp),
radius = TangemTheme.dimens2.x25,
)
}
SpacerH(20.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 22.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(12.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 66.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(12.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 18.dp),
radius = TangemTheme.dimens2.x25,
)
SpacerH(12.dp)
RectangleShimmer(
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.padding(end = 46.dp),
radius = TangemTheme.dimens2.x25,
)
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun NewsDetailsPlaceholderPreviewV1() {
TangemThemePreview {
NewsDetailsPlaceholder(background = TangemTheme.colors.background.tertiary)
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun NewsDetailsPlaceholderPreviewV2() {
TangemThemePreviewRedesign {
NewsDetailsPlaceholder(background = TangemTheme.colors2.surface.level3)
}
}

View file

@ -0,0 +1,126 @@
package com.tangem.features.feed.ui.news.details.components
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerW
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
@Composable
internal fun QuickRecap(content: String, modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
QuickRecapV2(content, modifier)
} else {
QuickRecapV1(content, modifier)
}
}
@Composable
private fun QuickRecapV1(content: String, modifier: Modifier = Modifier) {
Box(
modifier = modifier.height(IntrinsicSize.Min),
) {
VerticalDivider(
modifier = Modifier
.fillMaxHeight()
.padding(start = 8.dp),
thickness = 2.dp,
color = TangemTheme.colors.stroke.primary,
)
Column(modifier = Modifier.padding(start = 20.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
painter = painterResource(id = R.drawable.ic_quick_recap_16),
contentDescription = null,
tint = TangemTheme.colors.icon.accent,
modifier = Modifier.size(20.dp),
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResourceSafe(R.string.news_quick_recap),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.accent,
)
}
Spacer(modifier = Modifier.height(12.dp))
Text(
text = content,
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
}
}
}
@Composable
private fun QuickRecapV2(content: String, modifier: Modifier = Modifier) {
Column(modifier = modifier.height(IntrinsicSize.Min)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Image(
imageVector = ImageVector.vectorResource(R.drawable.ic_stars_20),
contentDescription = null,
)
SpacerW(2.dp)
Text(
text = buildAnnotatedString {
withStyle(
SpanStyle().copy(
brush = Brush.linearGradient(
GRADIENT_START to Color(LINEAR_GRADIENT_FIRST_PART),
GRADIENT_END to Color(LINEAR_GRADIENT_SECOND_PART),
),
),
) {
append(stringResourceSafe(R.string.news_quick_recap))
}
},
style = TangemTheme.typography2.bodyRegular14,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
}
SpacerH(10.dp)
Box {
VerticalDivider(
modifier = Modifier.fillMaxHeight(),
thickness = 2.dp,
color = Color(QUICK_RECAP_DIVIDER_COLOR),
)
Text(
modifier = Modifier.padding(start = 16.dp),
text = content,
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
}
}
}
private const val QUICK_RECAP_DIVIDER_COLOR = 0xFFA99FFF
private const val LINEAR_GRADIENT_FIRST_PART = 0xFFA3A0FF
private const val LINEAR_GRADIENT_SECOND_PART = 0xFFF79DFF
private const val GRADIENT_START = 0f
private const val GRADIENT_END = 0.5f

View file

@ -17,8 +17,10 @@ import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.chip.Chip
import com.tangem.core.ui.components.chip.entity.ChipUM
import com.tangem.core.ui.components.label.entity.LabelUM
import com.tangem.core.ui.ds.tabs.TangemTab
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.feed.ui.news.list.components.NewsListLazyColumn
import com.tangem.features.feed.ui.news.list.state.NewsListState
@ -29,6 +31,7 @@ import kotlinx.collections.immutable.toImmutableSet
@Composable
internal fun NewsListContent(state: NewsListUM, modifier: Modifier = Modifier) {
val background = LocalMainBottomSheetColor.current.value
val isRedesignEnabled = LocalRedesignEnabled.current
val lazyListState = rememberLazyListState()
Column(
@ -44,7 +47,17 @@ internal fun NewsListContent(state: NewsListUM, modifier: Modifier = Modifier) {
items = state.filters,
key = { it.id },
) { filter ->
Chip(state = filter)
if (isRedesignEnabled) {
TangemTab(
text = filter.text,
isChecked = filter.isSelected,
onCheckedChange = {
filter.onClick()
},
)
} else {
Chip(state = filter)
}
}
}

View file

@ -112,7 +112,9 @@ private fun Content(
key = ArticleConfigUM::id,
) { article ->
ArticleCard(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.heightIn(min = 152.dp)
.fillMaxWidth(),
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
articleConfigUM = article,
onArticleClick = {