From 9f1ae7fafb454715e8ef175167b1d7776907bbc2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 9 Jun 2025 14:04:03 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../core/ui/components/audits/AuditLabel.kt | 44 ++- .../core/ui/components/audits/AuditLabelUM.kt | 3 + .../tangem/core/ui/components/badge/Badge.kt | 74 ++++ .../ui/components/badge/entity/BadgeUM.kt | 15 + .../buttons/common/TangemButtonSize.kt | 16 + .../provider/ProviderChooseCrypto.kt | 323 ++++++++++++++++++ .../provider/entity/ProviderChooseUM.kt | 39 +++ .../tangem/core/ui/extensions/ModifierExt.kt | 58 +++- core/ui/src/main/res/drawable/ic_gas_24.xml | 9 + core/ui/src/main/res/drawable/ic_speed_24.xml | 10 + .../main/res/drawable/ic_star_outline_24.xml | 9 + .../ui/SelectPaymentMethodBottomSheet.kt | 33 +- .../providers/ui/SelectProviderBottomSheet.kt | 24 +- .../features/onramp/utils/ModifierExt.kt | 24 -- 14 files changed, 602 insertions(+), 79 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/badge/Badge.kt create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/badge/entity/BadgeUM.kt create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/provider/ProviderChooseCrypto.kt create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/provider/entity/ProviderChooseUM.kt create mode 100644 core/ui/src/main/res/drawable/ic_gas_24.xml create mode 100644 core/ui/src/main/res/drawable/ic_speed_24.xml create mode 100644 core/ui/src/main/res/drawable/ic_star_outline_24.xml delete mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/ModifierExt.kt diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt b/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt index eed177c971..e5293e07ab 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt @@ -2,6 +2,7 @@ package com.tangem.core.ui.components.audits import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -11,6 +12,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.compose.ui.unit.dp import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme @@ -30,41 +32,59 @@ import com.tangem.core.ui.res.TangemThemePreview fun AuditLabel(state: AuditLabelUM, modifier: Modifier = Modifier) { AuditLabelInternal( textReference = state.text, - textColor = getColorByType(state.type), - backgroundColor = getColorByType(state.type).copy(alpha = 0.1f), + type = state.type, modifier = modifier, ) } @Composable -private fun AuditLabelInternal( - textReference: TextReference, - textColor: Color, - backgroundColor: Color, - modifier: Modifier = Modifier, -) { +private fun AuditLabelInternal(textReference: TextReference, type: AuditLabelUM.Type, modifier: Modifier = Modifier) { Box( modifier = modifier.background( - color = backgroundColor, + color = getBackgroundColorByType(type), shape = TangemTheme.shapes.roundedCornersSmall2, ), ) { Text( text = textReference.resolveReference(), style = TangemTheme.typography.caption1, - color = textColor, - modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4), + color = getTextColorByType(type), + modifier = Modifier.padding(getPaddingByType(type)), ) } } @ReadOnlyComposable @Composable -private fun getColorByType(type: AuditLabelUM.Type): Color { +private fun getTextColorByType(type: AuditLabelUM.Type): Color { return when (type) { AuditLabelUM.Type.Prohibition -> TangemTheme.colors.text.warning AuditLabelUM.Type.Warning -> TangemTheme.colors.text.attention AuditLabelUM.Type.Permit -> TangemTheme.colors.text.accent + AuditLabelUM.Type.Info -> TangemTheme.colors.text.primary2 + } +} + +@ReadOnlyComposable +@Composable +private fun getBackgroundColorByType(type: AuditLabelUM.Type): Color { + return when (type) { + AuditLabelUM.Type.Prohibition -> TangemTheme.colors.text.warning.copy(alpha = 0.1f) + AuditLabelUM.Type.Warning -> TangemTheme.colors.text.attention.copy(alpha = 0.1f) + AuditLabelUM.Type.Permit -> TangemTheme.colors.text.accent.copy(alpha = 0.1f) + AuditLabelUM.Type.Info -> TangemTheme.colors.text.accent + } +} + +@ReadOnlyComposable +@Composable +private fun getPaddingByType(type: AuditLabelUM.Type): PaddingValues { + return when (type) { + AuditLabelUM.Type.Prohibition, + AuditLabelUM.Type.Warning, + AuditLabelUM.Type.Permit, + -> PaddingValues(horizontal = 4.dp) + AuditLabelUM.Type.Info -> PaddingValues(horizontal = 6.dp, vertical = 1.dp) } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabelUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabelUM.kt index 25059b9594..4b1ed19772 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabelUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabelUM.kt @@ -22,5 +22,8 @@ data class AuditLabelUM(val text: TextReference, val type: Type) { /** Blue. Like, "trusted" */ Permit, + + /** Blue with white text. Like, "best rate" */ + Info, } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/badge/Badge.kt b/core/ui/src/main/java/com/tangem/core/ui/components/badge/Badge.kt new file mode 100644 index 0000000000..282f4a0618 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/badge/Badge.kt @@ -0,0 +1,74 @@ +package com.tangem.core.ui.components.badge + +import android.content.res.Configuration +import androidx.annotation.DrawableRes +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.R +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.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview + +/** + * Badge component + * + * @param iconRes icon drawable resource + * @param text text reference + * @param modifier composable modifier + * + * @see Figma + */ +@Composable +fun Badge(@DrawableRes iconRes: Int, text: TextReference, modifier: Modifier = Modifier) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier + .border(1.dp, TangemTheme.colors.stroke.primary, RoundedCornerShape(4.dp)) + .padding(horizontal = 4.dp), + ) { + Icon( + painter = rememberVectorPainter( + ImageVector.vectorResource(iconRes), + ), + contentDescription = null, + tint = TangemTheme.colors.icon.informative, + modifier = Modifier.size(12.dp), + ) + Text( + text = text.resolveReference(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + ) + } +} + +// region Preview +@Composable +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun Badge_Preview() { + TangemThemePreview { + Badge( + iconRes = R.drawable.ic_star_mini_24, + text = stringReference("4.9"), + ) + } +} +// endregion \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/badge/entity/BadgeUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/badge/entity/BadgeUM.kt new file mode 100644 index 0000000000..ee6aa0bcdb --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/badge/entity/BadgeUM.kt @@ -0,0 +1,15 @@ +package com.tangem.core.ui.components.badge.entity + +import androidx.annotation.DrawableRes +import com.tangem.core.ui.extensions.TextReference + +/** + * Badge component UI model + * + * @param iconRes icon drawable resource + * @param text text reference + */ +data class BadgeUM( + val text: TextReference, + @DrawableRes val iconRes: Int, +) \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt index 961bca8869..46530d78b1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt @@ -16,6 +16,7 @@ enum class TangemButtonSize { RoundedAction, WideAction, TwoLines, + Small, } @Composable @@ -28,6 +29,7 @@ internal fun TangemButtonSize.toHeightDp(): Dp = when (this) { TangemButtonSize.RoundedAction, -> TangemTheme.dimens.size36 TangemButtonSize.WideAction -> TangemTheme.dimens.size40 + TangemButtonSize.Small -> 24.dp } @Composable @@ -40,6 +42,7 @@ internal fun TangemButtonSize.toShape(): Shape = when (this) { TangemButtonSize.Action -> TangemTheme.shapes.roundedCornersMedium TangemButtonSize.TwoLines -> TangemTheme.shapes.roundedCornersXMedium TangemButtonSize.RoundedAction -> TangemTheme.shapes.roundedCornersLarge + TangemButtonSize.Small -> TangemTheme.shapes.roundedCornersXMedium } @Composable @@ -48,6 +51,7 @@ internal fun TangemButtonSize.toIconPadding(): Dp = when (this) { TangemButtonSize.Default, TangemButtonSize.WideAction, TangemButtonSize.TwoLines, + TangemButtonSize.Small, -> TangemTheme.dimens.spacing4 TangemButtonSize.Text -> TangemTheme.dimens.spacing8 TangemButtonSize.Selector -> 0.dp @@ -100,11 +104,18 @@ internal fun TangemButtonSize.toContentPadding(icon: TangemButtonIconPosition): start = horizontalPadding.first, end = horizontalPadding.second, ) + TangemButtonSize.Small -> PaddingValues( + top = TangemTheme.dimens.spacing4, + bottom = TangemTheme.dimens.spacing4, + start = horizontalPadding.first, + end = horizontalPadding.second, + ) } } @Composable @ReadOnlyComposable +@Suppress("CyclomaticComplexMethod") internal fun TangemButtonSize.toHorizontalContentPadding(icon: TangemButtonIconPosition): Pair { return when (this) { TangemButtonSize.Default, @@ -124,5 +135,10 @@ internal fun TangemButtonSize.toHorizontalContentPadding(icon: TangemButtonIconP is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing24 is TangemButtonIconPosition.End -> TangemTheme.dimens.spacing24 to TangemTheme.dimens.spacing16 } + TangemButtonSize.Small -> when (icon) { + is TangemButtonIconPosition.None -> TangemTheme.dimens.spacing12 to TangemTheme.dimens.spacing12 + is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing8 to TangemTheme.dimens.spacing12 + is TangemButtonIconPosition.End -> TangemTheme.dimens.spacing12 to TangemTheme.dimens.spacing8 + } } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/provider/ProviderChooseCrypto.kt b/core/ui/src/main/java/com/tangem/core/ui/components/provider/ProviderChooseCrypto.kt new file mode 100644 index 0000000000..1083b56912 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/provider/ProviderChooseCrypto.kt @@ -0,0 +1,323 @@ +package com.tangem.core.ui.components.provider + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastForEach +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.constraintlayout.compose.Dimension +import androidx.constraintlayout.compose.Visibility +import coil.compose.SubcomposeAsyncImage +import coil.request.ImageRequest +import com.tangem.core.ui.R +import com.tangem.core.ui.components.audits.AuditLabel +import com.tangem.core.ui.components.audits.AuditLabelUM +import com.tangem.core.ui.components.badge.Badge +import com.tangem.core.ui.components.badge.entity.BadgeUM +import com.tangem.core.ui.components.provider.entity.ProviderChooseUM +import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.res.TangemColorPalette +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import kotlinx.collections.immutable.persistentListOf + +/** + * Provider Row - Choose Crypto component + * + * @param providerChooseUM component ui model + * @param onClick click listener + * @param modifier composable modifier + * + * @see Figma + */ +@Composable +@Suppress("DestructuringDeclarationWithTooManyEntries") +fun ProviderChooseCrypto(providerChooseUM: ProviderChooseUM, onClick: () -> Unit, modifier: Modifier = Modifier) { + ConstraintLayout( + modifier = modifier + .background(TangemTheme.colors.background.action) + .clip(RoundedCornerShape(14.dp)) + .selectedBorder(isSelected = providerChooseUM.isSelected) + .clickable(enabled = true, onClick = onClick) + .fillMaxWidth() + .padding(all = 12.dp), + ) { + val (iconRef, titleRef, badgeRef, infoRef, labelRef) = createRefs() + val titleEndRef = createStartBarrier(infoRef, labelRef) + + IconContent( + iconUrl = providerChooseUM.iconUrl, + modifier = Modifier + .constrainAs(iconRef) { + start.linkTo(parent.start) + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + }, + ) + TitleContent( + providerChooseUM = providerChooseUM, + modifier = Modifier.constrainAs(titleRef) { + start.linkTo(iconRef.end, 12.dp) + end.linkTo(titleEndRef, 4.dp) + top.linkTo(parent.top) + bottom.linkTo(badgeRef.top) + width = Dimension.fillToConstraints + }, + ) + BadgeContent( + providerChooseUM = providerChooseUM, + modifier = Modifier.constrainAs(badgeRef) { + start.linkTo(iconRef.end, 12.dp) + end.linkTo(labelRef.start, 4.dp) + top.linkTo(titleRef.bottom, 4.dp) + bottom.linkTo(parent.bottom) + width = Dimension.fillToConstraints + visibility = if (providerChooseUM.badgeList.isEmpty()) { + Visibility.Gone + } else { + Visibility.Visible + } + }, + ) + InfoContent( + text = providerChooseUM.infoText, + modifier = Modifier.constrainAs(infoRef) { + end.linkTo(parent.end) + top.linkTo(parent.top) + bottom.linkTo(labelRef.top, 4.dp) + }, + ) + LabelContent( + labelUM = providerChooseUM.labelUM, + modifier = Modifier.constrainAs(labelRef) { + end.linkTo(parent.end) + top.linkTo(infoRef.bottom) + bottom.linkTo(parent.bottom) + visibility = if (providerChooseUM.labelUM == null) { + Visibility.Gone + } else { + Visibility.Visible + } + }, + ) + } +} + +@Composable +private fun IconContent(iconUrl: String, modifier: Modifier = Modifier) { + SubcomposeAsyncImage( + modifier = modifier + .size(40.dp) + .clip(RoundedCornerShape(8.dp)) + .background(TangemColorPalette.Light1), + model = ImageRequest.Builder(context = LocalContext.current) + .data(iconUrl) + .crossfade(enable = true) + .allowHardware(false) + .build(), + contentDescription = null, + ) +} + +@Composable +private fun TitleContent(providerChooseUM: ProviderChooseUM, modifier: Modifier = Modifier) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier, + ) { + Text( + text = providerChooseUM.title.resolveReference(), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + ) + Text( + text = providerChooseUM.subtitle.resolveReference(), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + ) + } +} + +@Composable +private fun InfoContent(text: TextReference, modifier: Modifier = Modifier) { + Text( + text = text.resolveReference(), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = modifier, + ) +} + +@Composable +private fun BadgeContent(providerChooseUM: ProviderChooseUM, modifier: Modifier = Modifier) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier, + ) { + providerChooseUM.badgeList.fastForEach { badge -> + Badge( + iconRes = badge.iconRes, + text = badge.text, + ) + } + } +} + +@Composable +private fun LabelContent(labelUM: ProviderChooseUM.LabelUM?, modifier: Modifier = Modifier) { + Box( + modifier = modifier, + ) { + when (labelUM) { + is ProviderChooseUM.LabelUM.Info -> AuditLabel(labelUM.auditLabelUM) + is ProviderChooseUM.LabelUM.Text -> Text( + text = labelUM.text.resolveReference(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.warning, + ) + null -> Unit + } + } +} + +// region Preview +@Composable +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun ProviderChooseCrypto_Preview( + @PreviewParameter(ProviderChooseCryptoPreviewProvider::class) params: ProviderChooseUM, +) { + TangemThemePreview { + ProviderChooseCrypto( + providerChooseUM = params, + onClick = {}, + ) + } +} + +private class ProviderChooseCryptoPreviewProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + ProviderChooseUM( + title = stringReference("ChangeHero"), + subtitle = stringReference("CEX"), + infoText = stringReference("1 800,00 POL"), + iconUrl = "", + badgeList = persistentListOf( + BadgeUM( + text = stringReference("4.9"), + iconRes = R.drawable.ic_star_outline_24, + ), + BadgeUM( + text = stringReference("5 mins"), + iconRes = R.drawable.ic_speed_24, + ), + BadgeUM( + text = stringReference("$3.45"), + iconRes = R.drawable.ic_gas_24, + ), + ), + isSelected = true, + labelUM = ProviderChooseUM.LabelUM.Info( + auditLabelUM = AuditLabelUM( + text = resourceReference(R.string.express_provider_best_rate), + type = AuditLabelUM.Type.Info, + ), + ), + ), + ProviderChooseUM( + title = stringReference("Changelly"), + subtitle = stringReference("CEX"), + infoText = stringReference("1 799,12 POL"), + iconUrl = "", + badgeList = persistentListOf( + BadgeUM( + text = stringReference("4.9"), + iconRes = R.drawable.ic_star_outline_24, + ), + BadgeUM( + text = stringReference("5 mins"), + iconRes = R.drawable.ic_speed_24, + ), + BadgeUM( + text = stringReference("$3.45"), + iconRes = R.drawable.ic_gas_24, + ), + ), + isSelected = false, + labelUM = ProviderChooseUM.LabelUM.Text( + text = stringReference("–0.2%"), + ), + ), + ProviderChooseUM( + title = stringReference("Changelly"), + subtitle = stringReference("CEX"), + infoText = stringReference("1 799,12 POL"), + iconUrl = "", + badgeList = persistentListOf(), + isSelected = false, + labelUM = ProviderChooseUM.LabelUM.Text( + text = stringReference("–0.2%"), + ), + ), + ProviderChooseUM( + title = stringReference("Changelly"), + subtitle = stringReference("CEX"), + infoText = stringReference("1 POL"), + iconUrl = "", + badgeList = persistentListOf(), + isSelected = false, + labelUM = ProviderChooseUM.LabelUM.Text( + text = stringReference("–0.2%"), + ), + ), + ProviderChooseUM( + title = stringReference("Changelly"), + subtitle = stringReference("CEX"), + infoText = stringReference("1 POL"), + iconUrl = "", + badgeList = persistentListOf(), + isSelected = false, + labelUM = null, + ), + ProviderChooseUM( + title = stringReference("Changelly"), + subtitle = stringReference("CEX"), + infoText = stringReference("1 POL"), + iconUrl = "", + badgeList = persistentListOf( + BadgeUM( + text = stringReference("4.9"), + iconRes = R.drawable.ic_star_outline_24, + ), + BadgeUM( + text = stringReference("5 mins"), + iconRes = R.drawable.ic_speed_24, + ), + BadgeUM( + text = stringReference("$3.45"), + iconRes = R.drawable.ic_gas_24, + ), + ), + isSelected = false, + labelUM = null, + ), + ) +} +// endregion \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/provider/entity/ProviderChooseUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/provider/entity/ProviderChooseUM.kt new file mode 100644 index 0000000000..b3a9392c87 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/provider/entity/ProviderChooseUM.kt @@ -0,0 +1,39 @@ +package com.tangem.core.ui.components.provider.entity + +import androidx.compose.runtime.Immutable +import com.tangem.core.ui.components.audits.AuditLabelUM +import com.tangem.core.ui.components.badge.entity.BadgeUM +import com.tangem.core.ui.extensions.TextReference +import kotlinx.collections.immutable.ImmutableList + +/** + * Provider Row - Choose Crypto component UI Model + * + * @property title title text + * @property subtitle subtitle text + * @property infoText info text + * @property iconUrl icon url + * @property isSelected indicated whether component is selected (border outline) + * @property badgeList list of badge components + * @property labelUM label component (whether AuditLabel or text) + */ +data class ProviderChooseUM( + val title: TextReference, + val subtitle: TextReference, + val infoText: TextReference, + val iconUrl: String, + val isSelected: Boolean, + val badgeList: ImmutableList, + val labelUM: LabelUM?, +) { + @Immutable + sealed class LabelUM { + data class Info( + val auditLabelUM: AuditLabelUM, + ) : LabelUM() + + data class Text( + val text: TextReference, + ) : LabelUM() + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/ModifierExt.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/ModifierExt.kt index a014910b24..fc74ccf197 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/extensions/ModifierExt.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/ModifierExt.kt @@ -1,12 +1,21 @@ package com.tangem.core.ui.extensions import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.composed +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.utils.MultipleClickPreventer /** @@ -38,4 +47,51 @@ fun Modifier.conditional(condition: Boolean, modifier: Modifier.() -> Modifier): } else { this } -} \ No newline at end of file +} + +/** + * Conditionally applies a modifier based on a boolean condition. + */ +@Composable +fun Modifier.conditionalCompose( + condition: Boolean, + modifier: @Composable Modifier.() -> Modifier = { Modifier }, + otherModifier: @Composable Modifier.() -> Modifier = { this }, +): Modifier { + return if (condition) { + then(modifier(Modifier)) + } else { + otherModifier() + } +} + +/** + * Border with accent outline when selected + */ +@Composable +fun Modifier.selectedBorder( + isSelected: Boolean, + width: Dp = 2.5.dp, + color: Color = TangemTheme.colors.text.accent.copy(alpha = 0.1f), + radius: Dp = 16.dp, +) = conditionalCompose( + condition = isSelected, + modifier = { + border( + width = width, + color = color, + shape = RoundedCornerShape(radius), + ) + .padding(2.5.dp) + .border( + width = 1.dp, + color = TangemTheme.colors.text.accent, + shape = RoundedCornerShape(radius - 2.dp), + ) + .clip(RoundedCornerShape(radius - 2.dp)) + }, + otherModifier = { + padding(2.dp) + .clip(RoundedCornerShape(radius - 2.dp)) + }, +) \ No newline at end of file diff --git a/core/ui/src/main/res/drawable/ic_gas_24.xml b/core/ui/src/main/res/drawable/ic_gas_24.xml new file mode 100644 index 0000000000..278945f9fa --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_gas_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/ui/src/main/res/drawable/ic_speed_24.xml b/core/ui/src/main/res/drawable/ic_speed_24.xml new file mode 100644 index 0000000000..8e4390a831 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_speed_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/core/ui/src/main/res/drawable/ic_star_outline_24.xml b/core/ui/src/main/res/drawable/ic_star_outline_24.xml new file mode 100644 index 0000000000..116e8fdc03 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_star_outline_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt index 48ce4dfda8..fb80254c3c 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt @@ -14,11 +14,11 @@ import androidx.compose.ui.draw.clip import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.selectedBorder import com.tangem.core.ui.res.TangemTheme import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodUM import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodsBottomSheetConfig -import com.tangem.features.onramp.utils.selectedBorder import kotlinx.collections.immutable.ImmutableList @Composable @@ -59,27 +59,16 @@ private fun SelectPaymentMethodBottomSheetContent( val isSelected = remember(item, selectedMethodId) { item.id == selectedMethodId } - val itemModifier = if (isSelected) { - Modifier - .fillMaxWidth() - .selectedBorder() - .clickable(onClick = item.onSelect) - .padding( - start = TangemTheme.dimens.spacing12, - top = TangemTheme.dimens.spacing10, - bottom = TangemTheme.dimens.spacing10, - ) - } else { - Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(TangemTheme.dimens.radius16)) - .clickable(onClick = item.onSelect) - .padding( - start = TangemTheme.dimens.spacing12, - top = TangemTheme.dimens.spacing10, - bottom = TangemTheme.dimens.spacing10, - ) - } + val itemModifier = Modifier + .fillMaxWidth() + .selectedBorder(isSelected = isSelected) + .clip(RoundedCornerShape(TangemTheme.dimens.radius16)) + .clickable(onClick = item.onSelect) + .padding( + start = TangemTheme.dimens.spacing12, + top = TangemTheme.dimens.spacing10, + bottom = TangemTheme.dimens.spacing10, + ) PaymentMethodItem( modifier = itemModifier, paymentMethod = item, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt index 6f74ef7c95..59cb8cb0b0 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt @@ -26,13 +26,10 @@ import androidx.compose.ui.util.fastForEach import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.core.ui.components.RectangleShimmer -import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.core.ui.extensions.TextReference -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.components.bottomsheets.sheet.TangemBottomSheet +import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.domain.onramp.model.OnrampPaymentMethod @@ -41,7 +38,6 @@ import com.tangem.features.onramp.paymentmethod.ui.PaymentMethodIcon import com.tangem.features.onramp.providers.entity.ProviderListItemUM import com.tangem.features.onramp.providers.entity.SelectPaymentAndProviderUM import com.tangem.features.onramp.providers.model.previewData.SelectProviderPreviewData -import com.tangem.features.onramp.utils.selectedBorder @Composable internal fun SelectProviderBottomSheet(config: TangemBottomSheetConfig, content: @Composable () -> Unit) { @@ -151,13 +147,7 @@ private fun ProviderItem(state: ProviderListItemUM, modifier: Modifier = Modifie private fun AvailableProviderItem(state: ProviderListItemUM.Available.Content, modifier: Modifier = Modifier) { Row( modifier = modifier - .then( - if (state.isSelected) { - Modifier.selectedBorder() - } else { - Modifier.clip(RoundedCornerShape(16.dp)) - }, - ) + .selectedBorder(isSelected = state.isSelected) .clickable(onClick = state.onClick) .padding(all = TangemTheme.dimens.spacing12), verticalAlignment = Alignment.CenterVertically, @@ -227,13 +217,7 @@ private fun UnavailableProviderItem( ) { Row( modifier = modifier - .then( - if (isSelected) { - Modifier.selectedBorder() - } else { - Modifier.clip(RoundedCornerShape(16.dp)) - }, - ) + .selectedBorder(isSelected = isSelected) .padding(all = TangemTheme.dimens.spacing12), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/ModifierExt.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/ModifierExt.kt deleted file mode 100644 index 8e38b54575..0000000000 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/utils/ModifierExt.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.features.onramp.utils - -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.unit.dp -import com.tangem.core.ui.res.TangemTheme - -@Composable -internal fun Modifier.selectedBorder() = border( - width = 2.5.dp, - color = TangemTheme.colors.text.accent.copy(alpha = 0.1f), - shape = RoundedCornerShape(18.dp), -) - .padding(2.5.dp) - .border( - width = 1.dp, - color = TangemTheme.colors.text.accent, - shape = RoundedCornerShape(16.dp), - ) - .clip(RoundedCornerShape(16.dp)) \ No newline at end of file