From 6d9297f4f4fba959a7b91caa45c949822b939576 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 24 Jul 2026 00:19:11 -0700 Subject: [PATCH] Updated on 2026-08-14 --- .../TangemPaySelectPlanCompareContent.kt | 198 ++++++------------ 1 file changed, 65 insertions(+), 133 deletions(-) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/tiers/select/TangemPaySelectPlanCompareContent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/tiers/select/TangemPaySelectPlanCompareContent.kt index d0dbb2ecb1..ded49e781e 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/tiers/select/TangemPaySelectPlanCompareContent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/tiers/select/TangemPaySelectPlanCompareContent.kt @@ -2,22 +2,17 @@ package com.tangem.features.tangempay.tiers.select import android.content.res.Configuration import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text -import androidx.compose.runtime.* +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.platform.LocalDensity +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEachIndexed import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet @@ -26,6 +21,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetType import com.tangem.core.ui.ds2.button.Close import com.tangem.core.ui.ds2.button.TangemButton +import com.tangem.core.ui.ds2.row.* import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.resourceReference @@ -33,9 +29,7 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.features.tangempay.details.impl.R -import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -import kotlinx.coroutines.launch @Composable internal fun ComparePlansBottomSheet(compare: TangemPaySelectPlanUM.ComparePlans?) { @@ -46,7 +40,7 @@ internal fun ComparePlansBottomSheet(compare: TangemPaySelectPlanUM.ComparePlans content = TangemBottomSheetConfigContent.Empty, ), type = TangemBottomSheetType.Modal, - containerColor = TangemTheme.colors3.bg.secondary, + containerColor = TangemTheme.colors3.bg.primary, title = { Box( modifier = Modifier @@ -75,134 +69,75 @@ internal fun ComparePlansBottomSheet(compare: TangemPaySelectPlanUM.ComparePlans @Composable private fun ComparePlansContent(compare: TangemPaySelectPlanUM.ComparePlans) { - BoxWithConstraints(modifier = Modifier.fillMaxWidth()) { - val cardWidth = maxWidth - CARD_PEEK - val cardWidthPx = with(LocalDensity.current) { cardWidth.toPx() } - val scope = rememberCoroutineScope() - - val rowStates = remember(compare.plans.size) { List(compare.plans.size) { LazyListState() } } - val tabState = rememberLazyListState() - - rowStates.forEach { source -> - LaunchedEffect(source) { - snapshotFlow { source.firstVisibleItemIndex to source.firstVisibleItemScrollOffset } - .collect { (index, offset) -> - if (source.isScrollInProgress) { - rowStates.forEach { target -> if (target !== source) target.scrollToItem(index, offset) } - } - } - } - } - - val selectedIndex by remember(rowStates, cardWidthPx) { - derivedStateOf { - val primary = rowStates.firstOrNull() ?: return@derivedStateOf 0 - val extra = if (primary.firstVisibleItemScrollOffset > cardWidthPx / 2f) 1 else 0 - (primary.firstVisibleItemIndex + extra).coerceIn(0, compare.attributes.lastIndex.coerceAtLeast(0)) - } - } - - LaunchedEffect(selectedIndex) { tabState.animateScrollToItem(selectedIndex) } - - Column( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 16.dp), - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { - compare.plans.fastForEachIndexed { index, plan -> - PlanValuesSection(plan = plan, listState = rowStates[index], cardWidth = cardWidth) - } - AttributeTabs( - attributes = compare.attributes, - selectedIndex = selectedIndex, - listState = tabState, - onTabClick = { index -> scope.launch { rowStates.firstOrNull()?.animateScrollToItem(index) } }, + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 16.dp) + .padding(bottom = 16.dp), + verticalArrangement = Arrangement.spacedBy(24.dp), + ) { + compare.attributes.fastForEachIndexed { attributeIndex, attribute -> + CompareSection( + title = attribute, + plans = compare.plans, + attributeIndex = attributeIndex, ) } } } @Composable -private fun PlanValuesSection(plan: TangemPaySelectPlanUM.ComparePlans.Plan, listState: LazyListState, cardWidth: Dp) { +private fun CompareSection( + title: TextReference, + plans: List, + attributeIndex: Int, +) { Column(modifier = Modifier.fillMaxWidth()) { Text( - modifier = Modifier.padding(horizontal = 32.dp, vertical = 12.dp), - text = plan.name.resolveReference(), + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + text = title.resolveReference(), style = TangemTheme.typography3.subheading.medium, color = TangemTheme.colors3.text.secondary, ) - LazyRow( - state = listState, - modifier = Modifier.fillMaxWidth(), - contentPadding = PaddingValues(horizontal = 16.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), - flingBehavior = rememberSnapFlingBehavior(lazyListState = listState), + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(24.dp)) + .background(TangemTheme.colors3.bg.secondary), ) { - items(count = plan.values.size) { index -> - ValueCard(value = plan.values[index], width = cardWidth) + plans.fastForEachIndexed { planIndex, plan -> + CompareRow( + name = plan.name, + value = plan.values.getOrNull(attributeIndex) ?: stringReference(""), + divider = planIndex != plans.lastIndex, + ) } } } } @Composable -private fun ValueCard(value: TextReference, width: Dp) { - Box( - modifier = Modifier - .width(width) - .heightIn(112.dp) - .clip(RoundedCornerShape(24.dp)) - .background(TangemTheme.colors3.bg.tertiary) - .padding(16.dp), - ) { - Text( - text = value.resolveReference(), - style = TangemTheme.typography3.body.medium, - color = TangemTheme.colors3.text.primary, - ) - } +private fun CompareRow(name: TextReference, value: TextReference, divider: Boolean) { + TangemRow( + divider = divider, + contentLead = TangemRowContentLead.End, + verticalAlignment = TangemRowVerticalAlignment.Center, + titleSlot = { + Text( + text = name.resolveReference(), + style = TangemTheme.typography3.body.medium, + color = TangemTheme.colors3.text.secondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + }, + valueSlot = { + TangemRowText(text = value, role = TangemRowTextRole.Value) + }, + ) } -@Composable -private fun AttributeTabs( - attributes: ImmutableList, - selectedIndex: Int, - listState: LazyListState, - onTabClick: (Int) -> Unit, -) { - LazyRow( - state = listState, - modifier = Modifier.fillMaxWidth(), - contentPadding = PaddingValues(horizontal = 16.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp), - ) { - itemsIndexed(attributes) { index, title -> - AttributeTab(title = title, selected = index == selectedIndex, onClick = { onTabClick(index) }) - } - } -} - -@Composable -private fun AttributeTab(title: TextReference, selected: Boolean, onClick: () -> Unit) { - Box( - modifier = Modifier - .clip(RoundedCornerShape(100.dp)) - .background(if (selected) TangemTheme.colors3.bg.tertiary else TangemTheme.colors3.bg.secondary) - .clickable(onClick = onClick) - .padding(horizontal = 16.dp, vertical = 12.dp), - ) { - Text( - text = title.resolveReference(), - style = TangemTheme.typography3.body.medium, - color = if (selected) TangemTheme.colors3.text.primary else TangemTheme.colors3.text.secondary, - maxLines = 1, - ) - } -} - -private val CARD_PEEK = 72.dp - @Preview(showBackground = true, widthDp = 402) @Preview(showBackground = true, widthDp = 402, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -211,7 +146,7 @@ private fun ComparePlansContentPreview() { Column( modifier = Modifier .fillMaxWidth() - .background(TangemTheme.colors3.bg.secondary), + .background(TangemTheme.colors3.bg.primary), ) { ComparePlansContent(compare = previewCompare()) } @@ -220,34 +155,31 @@ private fun ComparePlansContentPreview() { private fun previewCompare() = TangemPaySelectPlanUM.ComparePlans( attributes = persistentListOf( - stringReference("Visa Programme"), + stringReference("Available cards"), + stringReference("Visa programme"), stringReference("Plan fee"), - stringReference("FX fee"), - stringReference("Daily spending limit"), - stringReference("Max cards issued"), - stringReference("Additional benefits"), + stringReference("FX fee (for non-USD purchases)"), + stringReference("Daily spending limit, per card"), ), plans = persistentListOf( TangemPaySelectPlanUM.ComparePlans.Plan( name = stringReference("Basic"), values = persistentListOf( + stringReference("Virtual, up to 3 cards"), stringReference("Platinum"), - stringReference("$0.00"), + stringReference("$0"), stringReference("1%"), - stringReference("$10.000"), - stringReference("3"), - stringReference("No"), + stringReference("$10,000"), ), ), TangemPaySelectPlanUM.ComparePlans.Plan( name = stringReference("Plus"), values = persistentListOf( + stringReference("Virtual, up to 5 cards"), stringReference("Signature"), stringReference("$29.99/month"), stringReference("1%"), - stringReference("$50.000"), - stringReference("5"), - stringReference("Benefit 1, Benefit 2, Benefit 3"), + stringReference("$50,000"), ), ), ),