Updated on 2026-08-14
This commit is contained in:
parent
4f7b1b791b
commit
4f23a66742
29 changed files with 740 additions and 128 deletions
|
|
@ -1,273 +0,0 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CardColors
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerHMax
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.block.TangemBlockCardColors
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableSet
|
||||
|
||||
@Composable
|
||||
fun ArticleCard(
|
||||
articleConfigUM: ArticleConfigUM,
|
||||
onArticleClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
colors: CardColors = TangemBlockCardColors,
|
||||
) {
|
||||
if (articleConfigUM.isTrending) {
|
||||
TrendingArticle(
|
||||
articleConfigUM = articleConfigUM,
|
||||
modifier = modifier,
|
||||
onArticleClick = onArticleClick,
|
||||
colors = colors,
|
||||
)
|
||||
} else {
|
||||
DefaultArticle(
|
||||
articleConfigUM = articleConfigUM,
|
||||
modifier = modifier,
|
||||
onArticleClick = onArticleClick,
|
||||
colors = colors,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrendingArticle(
|
||||
articleConfigUM: ArticleConfigUM,
|
||||
onArticleClick: () -> Unit,
|
||||
colors: CardColors,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(colors.containerColor)
|
||||
.clickable { onArticleClick() },
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
painter = painterResource(R.drawable.bg_trending_article),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 24.dp, horizontal = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.icon.accent.copy(alpha = 0.1f),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
)
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
text = stringResourceSafe(R.string.feed_trending_now),
|
||||
style = TangemTheme.typography.caption1,
|
||||
color = TangemTheme.colors.icon.accent,
|
||||
)
|
||||
|
||||
SpacerH(12.dp)
|
||||
|
||||
Text(
|
||||
text = articleConfigUM.title,
|
||||
color = if (articleConfigUM.isViewed) {
|
||||
TangemTheme.colors.text.tertiary
|
||||
} else {
|
||||
TangemTheme.colors.text.primary1
|
||||
},
|
||||
style = TangemTheme.typography.h3,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
SpacerH(8.dp)
|
||||
|
||||
ArticleInfo(
|
||||
score = articleConfigUM.score,
|
||||
createdAt = articleConfigUM.createdAt.resolveReference(),
|
||||
)
|
||||
|
||||
SpacerH(32.dp)
|
||||
|
||||
Tags(
|
||||
modifier = Modifier.padding(horizontal = 46.dp),
|
||||
tags = articleConfigUM.tags.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowMoreArticlesCard(modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(vertical = 31.dp, horizontal = 12.dp),
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_show_more_news_48),
|
||||
contentDescription = stringResourceSafe(R.string.common_show_more),
|
||||
)
|
||||
|
||||
SpacerH(16.dp)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.news_all_news),
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.news_stay_in_the_loop),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DefaultArticle(
|
||||
articleConfigUM: ArticleConfigUM,
|
||||
onArticleClick: () -> Unit,
|
||||
colors: CardColors,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(colors.containerColor)
|
||||
.clickable { onArticleClick() }
|
||||
.padding(12.dp),
|
||||
) {
|
||||
ArticleInfo(
|
||||
score = articleConfigUM.score,
|
||||
createdAt = articleConfigUM.createdAt.resolveReference(),
|
||||
)
|
||||
|
||||
SpacerH(8.dp)
|
||||
|
||||
Text(
|
||||
text = articleConfigUM.title,
|
||||
color = if (articleConfigUM.isViewed) {
|
||||
TangemTheme.colors.text.tertiary
|
||||
} else {
|
||||
TangemTheme.colors.text.primary1
|
||||
},
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
SpacerH(16.dp)
|
||||
|
||||
SpacerHMax()
|
||||
|
||||
Tags(tags = articleConfigUM.tags.toImmutableList())
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TagsPreview() {
|
||||
TangemThemePreview {
|
||||
Tags(
|
||||
tags = persistentListOf(
|
||||
LabelUM(TextReference.Str("Hype")),
|
||||
LabelUM(TextReference.Str("BTC")),
|
||||
LabelUM(TextReference.Str("Supply")),
|
||||
LabelUM(TextReference.Str("Demand")),
|
||||
LabelUM(TextReference.Str("Best rate")),
|
||||
LabelUM(TextReference.Str("Breaking news")),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360, backgroundColor = 0xFF000000)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun ArticleCardsPreview() {
|
||||
val tags = listOf(
|
||||
LabelUM(TextReference.Str("Hype")),
|
||||
LabelUM(TextReference.Str("BTC")),
|
||||
LabelUM(TextReference.Str("Supply")),
|
||||
LabelUM(TextReference.Str("Demand")),
|
||||
LabelUM(TextReference.Str("Breaking news")),
|
||||
).toImmutableSet()
|
||||
|
||||
val config = ArticleConfigUM(
|
||||
id = 1,
|
||||
title = "Bitcoin ETFs log 4th straight day of inflows (+\$550M)",
|
||||
score = 9.5f,
|
||||
createdAt = TextReference.Str("1h ago"),
|
||||
isTrending = true,
|
||||
tags = tags,
|
||||
isViewed = false,
|
||||
)
|
||||
|
||||
TangemThemePreview {
|
||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||
ArticleCard(
|
||||
articleConfigUM = config,
|
||||
onArticleClick = {},
|
||||
)
|
||||
|
||||
SpacerH(20.dp)
|
||||
|
||||
ArticleCard(
|
||||
articleConfigUM = config.copy(isViewed = true),
|
||||
onArticleClick = {},
|
||||
)
|
||||
|
||||
SpacerH(20.dp)
|
||||
|
||||
ArticleCard(
|
||||
articleConfigUM = config.copy(isTrending = false),
|
||||
onArticleClick = {},
|
||||
)
|
||||
|
||||
SpacerH(20.dp)
|
||||
|
||||
ArticleCard(
|
||||
articleConfigUM = config.copy(isTrending = false, isViewed = true),
|
||||
onArticleClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableSet
|
||||
|
||||
data class ArticleConfigUM(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val score: Float,
|
||||
val createdAt: TextReference,
|
||||
val isTrending: Boolean,
|
||||
val tags: ImmutableSet<LabelUM>,
|
||||
val isViewed: Boolean,
|
||||
)
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.label.Label
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun ArticleHeader(
|
||||
title: String,
|
||||
createdAt: String,
|
||||
score: Float,
|
||||
tags: ImmutableList<LabelUM>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
ArticleInfo(
|
||||
score = score,
|
||||
createdAt = createdAt,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Text(
|
||||
text = title,
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
||||
if (tags.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
tags.forEach { tag ->
|
||||
Label(
|
||||
state = tag,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun ArticleInfo(score: Float, createdAt: String, modifier: Modifier = Modifier) {
|
||||
val dotColor = TangemTheme.colors.text.secondary
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_start_circle_12),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = score.toString(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.size(4.dp)
|
||||
.drawWithCache {
|
||||
val radius = size.minDimension / 2f
|
||||
onDrawBehind {
|
||||
drawCircle(
|
||||
color = dotColor,
|
||||
radius = radius,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
Text(
|
||||
text = createdAt,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
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.TangemTheme
|
||||
|
||||
@Composable
|
||||
fun TrendingLoadingArticle(modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 24.dp, horizontal = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 96.dp, height = 24.dp), radius = 8.dp)
|
||||
SpacerH(12.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 285.dp, height = 18.dp), radius = 4.dp)
|
||||
SpacerH(6.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 190.dp, height = 18.dp), radius = 4.dp)
|
||||
SpacerH(14.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 110.dp, height = 18.dp), radius = 4.dp)
|
||||
SpacerH(32.dp)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 64.dp, height = 24.dp), radius = 8.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 64.dp, height = 24.dp), radius = 8.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 64.dp, height = 24.dp), radius = 8.dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DefaultLoadingArticle(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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.Placeable
|
||||
import androidx.compose.ui.layout.SubcomposeLayout
|
||||
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.LabelUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.utils.StringsSigns
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
private val TAG_SPACING = 4.dp
|
||||
|
||||
/**
|
||||
* A layout that displays a list of tags, automatically calculating how many can fit
|
||||
* in a single line. If not all tags fit, it shows an overflow indicator (e.g., "+N").
|
||||
*
|
||||
* @param tags The immutable list of [LabelUM] to display.
|
||||
* @param modifier The modifier to be applied to the layout.
|
||||
*/
|
||||
@Composable
|
||||
internal fun Tags(tags: ImmutableList<LabelUM>, modifier: Modifier = Modifier) {
|
||||
if (tags.isEmpty()) return
|
||||
|
||||
SubcomposeLayout(modifier = modifier) { constraints ->
|
||||
val spacingPx = TAG_SPACING.roundToPx()
|
||||
|
||||
val tagPlaceables = subcompose(ContentSlot.Tags) {
|
||||
tags.forEach { tag ->
|
||||
Label(state = tag)
|
||||
}
|
||||
}.map { it.measure(constraints) }
|
||||
|
||||
val layoutInfo = calculateLayoutInfo(
|
||||
maxWidth = constraints.maxWidth,
|
||||
spacingPx = spacingPx,
|
||||
tagPlaceables = tagPlaceables,
|
||||
)
|
||||
|
||||
val overflowPlaceable = layoutInfo.overflowCount.takeIf { it > 0 }?.let {
|
||||
subcompose(ContentSlot.Overflow) {
|
||||
OverflowLabel(count = it)
|
||||
}.first().measure(constraints)
|
||||
}
|
||||
|
||||
val visiblePlaceables = tagPlaceables.take(layoutInfo.visibleCount)
|
||||
val allVisibleItems = visiblePlaceables + listOfNotNull(overflowPlaceable)
|
||||
|
||||
val width = calculateRowWidth(
|
||||
placeables = allVisibleItems,
|
||||
spacingPx = spacingPx,
|
||||
).coerceIn(constraints.minWidth, constraints.maxWidth)
|
||||
|
||||
val height = allVisibleItems.maxOfOrNull { it.height } ?: 0
|
||||
|
||||
layout(width = width, height = height) {
|
||||
var xPosition = 0
|
||||
allVisibleItems.forEachIndexed { index, placeable ->
|
||||
if (index > 0) {
|
||||
xPosition += spacingPx
|
||||
}
|
||||
val yPosition = height - placeable.height
|
||||
placeable.placeRelative(xPosition, yPosition)
|
||||
xPosition += placeable.width
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates how many tags can be displayed and how many are overflowing.
|
||||
*/
|
||||
private fun SubcomposeMeasureScope.calculateLayoutInfo(
|
||||
maxWidth: Int,
|
||||
spacingPx: Int,
|
||||
tagPlaceables: List<Placeable>,
|
||||
): TagsLayoutInfo {
|
||||
val totalWidthWithoutOverflow = calculateRowWidth(tagPlaceables, spacingPx)
|
||||
|
||||
if (totalWidthWithoutOverflow <= maxWidth) {
|
||||
return TagsLayoutInfo(visibleCount = tagPlaceables.size, overflowCount = 0)
|
||||
}
|
||||
|
||||
for (count in tagPlaceables.indices.reversed()) {
|
||||
val visibleTags = tagPlaceables.take(count)
|
||||
val overflowCount = tagPlaceables.size - count
|
||||
|
||||
val tempOverflowPlaceable = subcompose("overflow_temp_$overflowCount") {
|
||||
OverflowLabel(count = overflowCount)
|
||||
}.first().measure(Constraints())
|
||||
|
||||
val widthWithOverflow = calculateRowWidth(
|
||||
placeables = visibleTags + tempOverflowPlaceable,
|
||||
spacingPx = spacingPx,
|
||||
)
|
||||
|
||||
if (widthWithOverflow <= maxWidth) {
|
||||
return TagsLayoutInfo(visibleCount = count, overflowCount = overflowCount)
|
||||
}
|
||||
}
|
||||
|
||||
return TagsLayoutInfo(visibleCount = 0, overflowCount = tagPlaceables.size)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OverflowLabel(count: Int) {
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("${StringsSigns.PLUS}$count"),
|
||||
maxLines = 1,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun calculateRowWidth(placeables: List<Placeable>, spacingPx: Int): Int {
|
||||
if (placeables.isEmpty()) return 0
|
||||
val tagsWidth = placeables.sumOf { it.width }
|
||||
val spacingWidth = spacingPx * (placeables.size - 1).coerceAtLeast(0)
|
||||
return tagsWidth + spacingWidth
|
||||
}
|
||||
|
||||
private data class TagsLayoutInfo(val visibleCount: Int, val overflowCount: Int)
|
||||
|
||||
private enum class ContentSlot { Tags, Overflow }
|
||||
Loading…
Add table
Add a link
Reference in a new issue