Updated on 2026-08-14
This commit is contained in:
commit
3c6fbf0b26
14 changed files with 602 additions and 79 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <a href="https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=3467-2362&t=SnNQ4qhxwj2mhhra-4">Figma</a>
|
||||
*/
|
||||
@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
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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<Dp, Dp> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <a href="https://www.figma.com/design/JJuqr3gX9IC4WBv3C95uqj/Android--Copy-?node-id=3467-2643&t=Tg0OOJTQK9H4KBWL-4">Figma</a>
|
||||
*/
|
||||
@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<ProviderChooseUM> {
|
||||
override val values: Sequence<ProviderChooseUM>
|
||||
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
|
||||
|
|
@ -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<BadgeUM>,
|
||||
val labelUM: LabelUM?,
|
||||
) {
|
||||
@Immutable
|
||||
sealed class LabelUM {
|
||||
data class Info(
|
||||
val auditLabelUM: AuditLabelUM,
|
||||
) : LabelUM()
|
||||
|
||||
data class Text(
|
||||
val text: TextReference,
|
||||
) : LabelUM()
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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))
|
||||
},
|
||||
)
|
||||
9
core/ui/src/main/res/drawable/ic_gas_24.xml
Normal file
9
core/ui/src/main/res/drawable/ic_gas_24.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19.77,7.23L19.78,7.22L16.06,3.5L15,4.56L17.11,6.67C16.17,7.03 15.5,7.93 15.5,9C15.5,10.38 16.62,11.5 18,11.5C18.36,11.5 18.69,11.42 19,11.29V18.5C19,19.05 18.55,19.5 18,19.5C17.45,19.5 17,19.05 17,18.5V14C17,12.9 16.1,12 15,12H14V5C14,3.9 13.1,3 12,3H6C4.9,3 4,3.9 4,5V21H14V13.5H15.5V18.5C15.5,19.88 16.62,21 18,21C19.38,21 20.5,19.88 20.5,18.5V9C20.5,8.31 20.22,7.68 19.77,7.23ZM12,13.5V19H6V12H12V13.5ZM12,10H6V5H12V10ZM18,10C17.45,10 17,9.55 17,9C17,8.45 17.45,8 18,8C18.55,8 19,8.45 19,9C19,9.55 18.55,10 18,10Z"
|
||||
android:fillColor="#1E1E1E"/>
|
||||
</vector>
|
||||
10
core/ui/src/main/res/drawable/ic_speed_24.xml
Normal file
10
core/ui/src/main/res/drawable/ic_speed_24.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19.15,10.42L20.38,8.57L20.39,8.56C21.393,10.106 21.948,11.9 21.996,13.742C22.044,15.584 21.581,17.404 20.66,19C20.484,19.305 20.23,19.558 19.924,19.734C19.619,19.91 19.272,20.001 18.92,20H5.07C4.721,19.998 4.379,19.904 4.077,19.729C3.775,19.554 3.524,19.302 3.35,19C2.24,17.057 1.813,14.799 2.138,12.585C2.463,10.371 3.522,8.33 5.143,6.789C6.765,5.248 8.857,4.295 11.085,4.083C13.312,3.871 15.547,4.412 17.43,5.62L15.58,6.85C14.042,6.081 12.297,5.827 10.604,6.128C8.91,6.428 7.359,7.266 6.179,8.517C5,9.769 4.255,11.367 4.055,13.075C3.855,14.783 4.211,16.51 5.07,18H18.93C19.591,16.853 19.957,15.561 19.995,14.238C20.034,12.915 19.743,11.603 19.15,10.42ZM11.239,15.844C10.996,15.743 10.776,15.596 10.59,15.41C10.404,15.224 10.257,15.004 10.156,14.761C10.055,14.518 10.003,14.258 10.003,13.995C10.003,13.732 10.055,13.472 10.156,13.229C10.257,12.986 10.404,12.766 10.59,12.58L19.08,6.92L13.42,15.41C13.234,15.596 13.014,15.743 12.771,15.844C12.528,15.945 12.268,15.997 12.005,15.997C11.742,15.997 11.482,15.945 11.239,15.844Z"
|
||||
android:fillColor="#1E1E1E"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/ic_star_outline_24.xml
Normal file
9
core/ui/src/main/res/drawable/ic_star_outline_24.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M22,9.24L14.81,8.62L12,2L9.19,8.63L2,9.24L7.46,13.97L5.82,21L12,17.27L18.18,21L16.55,13.97L22,9.24ZM12,15.4L8.24,17.67L9.24,13.39L5.92,10.51L10.3,10.13L12,6.1L13.71,10.14L18.09,10.52L14.77,13.4L15.77,17.68L12,15.4Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
Loading…
Add table
Add a link
Reference in a new issue