Updated on 2026-08-14

This commit is contained in:
Tangem 2024-03-28 14:52:56 +05:00
commit dd2b494f85
6 changed files with 136 additions and 230 deletions

View file

@ -14,11 +14,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
@ -27,12 +27,14 @@ import com.tangem.core.ui.res.TangemTheme
fun SelectorRowItem(
@StringRes titleRes: Int,
@DrawableRes iconRes: Int,
onSelect: () -> Unit,
modifier: Modifier = Modifier,
preEllipsize: TextReference? = null,
postEllipsize: TextReference? = null,
paddingValues: PaddingValues = PaddingValues(TangemTheme.dimens.spacing12),
preDot: TextReference? = null,
postDot: TextReference? = null,
ellipsizeOffset: Int? = null,
isSelected: Boolean = false,
showDivider: Boolean = true,
onSelect: (() -> Unit)? = null,
) {
val iconTint by animateColorAsState(
targetValue = if (isSelected) {
@ -43,45 +45,39 @@ fun SelectorRowItem(
label = "Selector icon tint change",
)
val textStyle = if (isSelected) {
TangemTheme.typography.subtitle2
} else {
TangemTheme.typography.body2
}
Box(
modifier = modifier
.fillMaxWidth()
.clickable { onSelect() },
.then(
if (onSelect != null) {
Modifier.clickable { onSelect() }
} else {
Modifier
},
),
) {
Row(modifier = Modifier.fillMaxWidth()) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(paddingValues),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(iconRes),
tint = iconTint,
contentDescription = null,
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing12,
bottom = TangemTheme.dimens.spacing12,
),
)
Text(
text = stringResource(titleRes),
style = textStyle,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing8,
top = TangemTheme.dimens.spacing14,
bottom = TangemTheme.dimens.spacing14,
),
modifier = Modifier.padding(start = TangemTheme.dimens.spacing8),
)
if (preEllipsize != null && postEllipsize != null) {
if (preDot != null && postDot != null) {
SelectorValueContent(
amount = preEllipsize,
symbol = postEllipsize,
textStyle = textStyle,
preDot = preDot,
postDot = postDot,
ellipsizeOffset = ellipsizeOffset,
)
}
}
@ -99,33 +95,37 @@ fun SelectorRowItem(
}
@Composable
private fun RowScope.SelectorValueContent(amount: TextReference, symbol: TextReference, textStyle: TextStyle) {
Text(
text = amount.resolveReference(),
style = textStyle,
private fun RowScope.SelectorValueContent(
preDot: TextReference,
postDot: TextReference,
ellipsizeOffset: Int? = null,
) {
val ellipsis = if (ellipsizeOffset == null) {
TextEllipsis.End
} else {
TextEllipsis.OffsetEnd(ellipsizeOffset)
}
EllipsisText(
text = preDot.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.End,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
ellipsis = ellipsis,
modifier = Modifier
.weight(1f)
.padding(
start = TangemTheme.dimens.spacing4,
top = TangemTheme.dimens.spacing14,
bottom = TangemTheme.dimens.spacing14,
),
.padding(start = TangemTheme.dimens.spacing4),
)
Text(
text = symbol.resolveReference(),
style = textStyle,
text = "",
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.primary1,
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing1,
end = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing14,
bottom = TangemTheme.dimens.spacing14,
),
textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4),
)
Text(
text = postDot.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
}
@ -136,8 +136,9 @@ private fun SelectorRowItemPreview_Light() {
SelectorRowItem(
titleRes = R.string.common_fee_selector_option_slow,
iconRes = R.drawable.ic_tortoise_24,
preEllipsize = TextReference.Str("1000"),
postEllipsize = TextReference.Str("$"),
preDot = TextReference.Str("1000 ETH"),
postDot = TextReference.Str("1000 $"),
ellipsizeOffset = 4,
isSelected = true,
onSelect = { },
)
@ -151,8 +152,9 @@ private fun SelectorRowItemPreview_Dark() {
SelectorRowItem(
titleRes = R.string.common_fee_selector_option_slow,
iconRes = R.drawable.ic_tortoise_24,
preEllipsize = TextReference.Str("1000"),
postEllipsize = TextReference.Str("$"),
preDot = TextReference.Str("1000 ETH"),
postDot = TextReference.Str("1000 $"),
ellipsizeOffset = 4,
isSelected = true,
onSelect = { },
)

View file

@ -3,7 +3,6 @@ package com.tangem.features.send.impl.presentation.ui.fee
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Image
@ -16,7 +15,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
@ -33,11 +31,9 @@ import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.components.rows.SelectorRowItem
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.combinedReference
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.utils.BigDecimalFormatter
@ -267,55 +263,23 @@ private fun SendSpeedSelectorItem(
showDivider: Boolean = true,
showWarning: Boolean = false,
) {
val iconTint by animateColorAsState(
targetValue = if (isSelected) {
TangemTheme.colors.icon.accent
} else {
TangemTheme.colors.icon.informative
},
label = "Selector icon tint change",
)
val textStyle = if (isSelected) {
TangemTheme.typography.subtitle2
} else {
TangemTheme.typography.body2
}
Box(
modifier = modifier
.fillMaxWidth()
.clickable { onSelect() },
) {
Row(modifier = Modifier.fillMaxWidth()) {
SelectorTitleContent(
titleRes = titleRes,
iconRes = iconRes,
iconTint = iconTint,
textStyle = textStyle,
)
if (amount != null && symbolLength != null && fiatAmount != null) {
SelectorValueContent(
amount = amount,
fiatAmount = fiatAmount,
symbolLength = symbolLength,
textStyle = textStyle,
)
} else {
SpacerWMax()
}
WarningIcon(showWarning = showWarning)
}
if (showDivider) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(TangemTheme.dimens.size1)
.padding(horizontal = TangemTheme.dimens.spacing12)
.background(TangemTheme.colors.stroke.primary)
.align(Alignment.BottomCenter),
)
}
SelectorRowItem(
titleRes = titleRes,
iconRes = iconRes,
onSelect = onSelect,
modifier = modifier,
preDot = amount,
postDot = fiatAmount,
ellipsizeOffset = symbolLength,
isSelected = isSelected,
showDivider = showDivider,
)
WarningIcon(showWarning = showWarning)
}
}
@ -350,41 +314,6 @@ private fun SelectorTitleContent(
)
}
@Composable
private fun RowScope.SelectorValueContent(
amount: TextReference,
fiatAmount: TextReference,
symbolLength: Int,
textStyle: TextStyle,
) {
EllipsisText(
text = amount.resolveReference(),
style = textStyle,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.End,
ellipsis = TextEllipsis.OffsetEnd(symbolLength),
modifier = Modifier
.weight(1f)
.padding(
start = TangemTheme.dimens.spacing4,
top = TangemTheme.dimens.spacing14,
bottom = TangemTheme.dimens.spacing14,
),
)
Text(
text = "(${fiatAmount.resolveReference()})",
style = textStyle,
color = TangemTheme.colors.text.primary1,
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing4,
end = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing14,
bottom = TangemTheme.dimens.spacing14,
),
)
}
@Composable
private fun WarningIcon(showWarning: Boolean = false) {
AnimatedVisibility(
@ -393,15 +322,18 @@ private fun WarningIcon(showWarning: Boolean = false) {
enter = fadeIn(),
exit = fadeOut(),
) {
Image(
painter = painterResource(R.drawable.ic_alert_triangle_20),
contentDescription = null,
modifier = Modifier
.padding(
vertical = TangemTheme.dimens.spacing12,
horizontal = TangemTheme.dimens.spacing14,
),
)
Row {
SpacerWMax()
Image(
painter = painterResource(R.drawable.ic_alert_triangle_20),
contentDescription = null,
modifier = Modifier
.padding(
vertical = TangemTheme.dimens.spacing12,
horizontal = TangemTheme.dimens.spacing14,
),
)
}
}
}

View file

@ -3,23 +3,19 @@ package com.tangem.features.send.impl.presentation.ui.send
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
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.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.components.rows.SelectorRowItem
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.features.send.impl.R
@ -54,48 +50,24 @@ internal fun FeeBlock(feeState: SendStates.FeeState, isSuccess: Boolean, onClick
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action)
.clickable(enabled = !isSuccess) { onClick() }
.padding(
vertical = TangemTheme.dimens.spacing12,
horizontal = TangemTheme.dimens.spacing14,
),
.padding(TangemTheme.dimens.spacing12),
) {
Text(
text = stringResource(R.string.common_network_fee_title),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
)
Row(
SelectorRowItem(
titleRes = title,
iconRes = icon,
preDot = stringReference(feeCryptoValue),
postDot = stringReference(feeFiatValue),
ellipsizeOffset = fee.amount.currencySymbol.length,
isSelected = true,
showDivider = false,
paddingValues = PaddingValues(),
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(icon),
tint = TangemTheme.colors.icon.accent,
contentDescription = null,
)
Text(
text = stringResource(title),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
modifier = Modifier.padding(start = TangemTheme.dimens.spacing8),
)
EllipsisText(
text = feeCryptoValue,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.End,
ellipsis = TextEllipsis.OffsetEnd(fee.amount.currencySymbol.length),
modifier = Modifier
.weight(1f)
.padding(start = TangemTheme.dimens.spacing4),
)
Text(
text = "($feeFiatValue)",
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
modifier = Modifier.padding(start = TangemTheme.dimens.spacing4),
)
}
)
}
}

View file

@ -4,10 +4,11 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.Text
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.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
@ -30,7 +31,10 @@ import kotlinx.collections.immutable.toImmutableList
@Composable
fun ChooseFeeBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet(config) { content: ChooseFeeBottomSheetConfig ->
TangemBottomSheet(
config = config,
containerColor = TangemTheme.colors.background.tertiary,
) { content: ChooseFeeBottomSheetConfig ->
ChooseFeeBottomSheetContent(content = content)
}
}
@ -39,7 +43,7 @@ fun ChooseFeeBottomSheet(config: TangemBottomSheetConfig) {
private fun ChooseFeeBottomSheetContent(content: ChooseFeeBottomSheetConfig) {
Column(
modifier = Modifier
.background(TangemTheme.colors.background.primary)
.background(TangemTheme.colors.background.tertiary)
.padding(bottom = TangemTheme.dimens.spacing8),
) {
Text(
@ -53,6 +57,7 @@ private fun ChooseFeeBottomSheetContent(content: ChooseFeeBottomSheetConfig) {
Column(
modifier = Modifier
.padding(TangemTheme.dimens.spacing16)
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(
color = TangemTheme.colors.background.action,
shape = TangemTheme.shapes.roundedCornersXMedium,
@ -103,29 +108,36 @@ private fun FooterBlock(readMore: TextReference, readMoreUrl: String, onReadMore
@Composable
private fun FeeItemsBlock(content: ChooseFeeBottomSheetConfig) {
content.feeItems.forEach { feeItem ->
content.feeItems.forEachIndexed { index, feeItem ->
val isSelected = feeItem.feeType == content.selectedFee
val preEllipsizeText = feeItem.amountCrypto
val postEllipsizeText = "${feeItem.symbolCrypto} (${feeItem.amountFiatFormatted})"
val showDivider = content.feeItems.lastIndex != index
val symbol = "${feeItem.symbolCrypto}"
val preDotText = "${feeItem.amountCrypto}$symbol"
val postDot = feeItem.amountFiatFormatted
val ellipsizeOffset = symbol.length
when (feeItem.feeType) {
FeeType.NORMAL -> {
SelectorRowItem(
titleRes = R.string.common_fee_selector_option_market,
iconRes = R.drawable.ic_bird_24,
preEllipsize = TextReference.Str(preEllipsizeText),
postEllipsize = TextReference.Str(postEllipsizeText),
preDot = TextReference.Str(preDotText),
postDot = TextReference.Str(postDot),
ellipsizeOffset = ellipsizeOffset,
isSelected = isSelected,
onSelect = { content.onSelectFeeType(feeItem.feeType) },
showDivider = showDivider,
)
}
FeeType.PRIORITY -> {
SelectorRowItem(
titleRes = R.string.common_fee_selector_option_fast,
iconRes = R.drawable.ic_hare_24,
preEllipsize = TextReference.Str(preEllipsizeText),
postEllipsize = TextReference.Str(postEllipsizeText),
preDot = TextReference.Str(preDotText),
postDot = TextReference.Str(postDot),
ellipsizeOffset = ellipsizeOffset,
isSelected = isSelected,
onSelect = { content.onSelectFeeType(feeItem.feeType) },
showDivider = showDivider,
)
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.feature.swap.ui
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Icon
@ -30,7 +31,7 @@ import com.tangem.feature.swap.models.states.PercentDifference
import com.tangem.feature.swap.models.states.ProviderState
/**
* UI Item for swap provider wrapped in a [BaseContainer] with rounded corners
* UI Item for swap provider wrapped with rounded corners
*
* https://www.figma.com/file/Vs6SkVsFnUPsSCNwlnVf5U/Android-%E2%80%93-UI?type=design&node-id=7856-41909&mode=design&t=vo7dyElitnzSPSW3-4
*/
@ -43,12 +44,21 @@ private val GrayscaleColorFilter: ColorFilter
@Composable
fun ProviderItemBlock(state: ProviderState, modifier: Modifier = Modifier) {
if (state !is ProviderState.Empty) {
BaseContainer(modifier = modifier) {
ProviderItem(
state = state,
modifier = Modifier.align(Alignment.CenterStart),
)
}
ProviderItem(
state = state,
modifier = modifier
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
.background(
color = TangemTheme.colors.background.action,
shape = TangemTheme.shapes.roundedCornersXMedium,
)
.clickable(
enabled = state.onProviderClick != null,
onClick = { state.onProviderClick?.invoke(state.id) },
)
.fillMaxWidth()
.padding(vertical = TangemTheme.dimens.spacing12),
)
}
}
@ -80,6 +90,7 @@ fun ProviderItem(state: ProviderState, modifier: Modifier = Modifier, isSelected
}
}
@Deprecated("Replace with InputRowBestRate")
@Suppress("LongMethod")
@Composable
private fun ProviderContentState(
@ -326,22 +337,6 @@ private fun BoxScope.ProviderChevron(selectionType: ProviderState.SelectionType,
}
}
@Composable
private fun BaseContainer(modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit) {
Box(
modifier = modifier
.background(
color = TangemTheme.colors.background.action,
shape = TangemTheme.shapes.roundedCornersXMedium,
)
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
.fillMaxWidth()
.defaultMinSize(minHeight = TangemTheme.dimens.size68),
) {
content()
}
}
@Composable
private fun ErrorProviderIcon(modifier: Modifier = Modifier) {
Box(

View file

@ -62,14 +62,7 @@ internal fun SwapScreenContent(state: SwapStateHolder, modifier: Modifier = Modi
) {
MainInfo(state)
ProviderItemBlock(
state = state.providerState,
modifier = Modifier
.clickable(
enabled = state.providerState.onProviderClick != null,
onClick = { state.providerState.onProviderClick?.invoke(state.providerState.id) },
),
)
ProviderItemBlock(state = state.providerState)
FeeItemBlock(state = state.fee)