diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt index c5fc3d7442..020cc01c45 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt @@ -14,12 +14,18 @@ object BigDecimalFormatter { private const val TEMP_CURRENCY_CODE = "USD" - fun formatCryptoAmount(cryptoAmount: BigDecimal?, cryptoCurrency: String, decimals: Int): String { + fun formatCryptoAmount( + cryptoAmount: BigDecimal?, + cryptoCurrency: String, + decimals: Int, + locale: Locale = Locale.getDefault(), + ): String { if (cryptoAmount == null) return EMPTY_BALANCE_SIGN - val formatter = NumberFormat.getNumberInstance().apply { + val formatter = NumberFormat.getNumberInstance(locale).apply { maximumFractionDigits = decimals.coerceAtMost(maximumValue = 8) minimumFractionDigits = 2 + isGroupingUsed = true roundingMode = RoundingMode.DOWN } @@ -32,8 +38,12 @@ object BigDecimalFormatter { } } - fun formatCryptoAmount(cryptoAmount: BigDecimal?, cryptoCurrency: CryptoCurrency): String { - return formatCryptoAmount(cryptoAmount, cryptoCurrency.symbol, cryptoCurrency.decimals) + fun formatCryptoAmount( + cryptoAmount: BigDecimal?, + cryptoCurrency: CryptoCurrency, + locale: Locale = Locale.getDefault(), + ): String { + return formatCryptoAmount(cryptoAmount, cryptoCurrency.symbol, cryptoCurrency.decimals, locale) } fun formatFiatAmount( diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt index 265631000e..56ca1cbc5b 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt @@ -1,7 +1,9 @@ package com.tangem.feature.swap.models.states +import androidx.compose.runtime.Immutable import com.tangem.core.ui.extensions.TextReference +@Immutable sealed class ProviderState { abstract val onProviderClick: ((String) -> Unit)? @@ -25,6 +27,7 @@ sealed class ProviderState { val subtitle: TextReference, val selectionType: SelectionType, val additionalBadge: AdditionalBadge, + val namePrefix: PrefixType, val percentLowerThenBest: PercentLowerThanBest = PercentLowerThanBest.Empty, override val onProviderClick: (String) -> Unit, ) : ProviderState() @@ -39,17 +42,25 @@ sealed class ProviderState { override val onProviderClick: ((String) -> Unit)? = null, ) : ProviderState() + @Immutable sealed class AdditionalBadge { object BestTrade : AdditionalBadge() object Empty : AdditionalBadge() object PermissionRequired : AdditionalBadge() } + @Immutable enum class SelectionType { NONE, CLICK, SELECT } + + @Immutable + enum class PrefixType { + NONE, PROVIDED_BY + } } +@Immutable sealed class PercentLowerThanBest { data class Value(val value: Float) : PercentLowerThanBest() object Empty : PercentLowerThanBest() diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt index 51757b8c16..2e04a4eef3 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt @@ -116,6 +116,7 @@ private fun ChooseProviderBottomSheet_Preview() { additionalBadge = ProviderState.AdditionalBadge.BestTrade, percentLowerThenBest = PercentLowerThanBest.Value(-1.0f), selectionType = ProviderState.SelectionType.SELECT, + namePrefix = ProviderState.PrefixType.NONE, onProviderClick = {}, ), ProviderState.Unavailable( diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt index eaddec7e0c..df12b50590 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt @@ -17,11 +17,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource 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.datasource.CollectionPreviewParameterProvider import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.core.ui.R import com.tangem.core.ui.components.RectangleShimmer -import com.tangem.core.ui.components.SpacerH24 import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme @@ -113,12 +114,14 @@ private fun ProviderContentState( modifier = Modifier.padding(start = TangemTheme.dimens.spacing12), ) { Row { - Text( - text = stringResource(id = R.string.express_by_provider), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.tertiary, - modifier = Modifier.padding(end = TangemTheme.dimens.spacing4), - ) + if (state.namePrefix == ProviderState.PrefixType.PROVIDED_BY) { + Text( + text = stringResource(id = R.string.express_by_provider), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier.padding(end = TangemTheme.dimens.spacing4), + ) + } AnimatedContent(targetState = state.name, label = "") { Text( text = it, @@ -391,75 +394,76 @@ private fun PermissionBadgeItem(modifier: Modifier = Modifier) { } } -@Preview +// region Preview +@Preview(showBackground = true, widthDp = 360) @Composable -private fun ProviderItem_Loading_Preview() { - Column { - TangemTheme(isDark = false) { - ProviderItemBlock(state = ProviderState.Loading()) - } - - SpacerH24() - - TangemTheme(isDark = true) { - ProviderItemBlock(state = ProviderState.Loading()) - } +private fun ProviderItemPreview_Light( + @PreviewParameter(ProviderItemParameterProvider::class) state: Pair, +) { + TangemTheme { + ProviderItem( + modifier = Modifier.background(TangemTheme.colors.background.action), + state = state.first, + isSelected = state.second, + ) } } -@Preview +@Preview(showBackground = true, widthDp = 360) @Composable -private fun ProviderItem_Content_Preview() { - val state = ProviderState.Content( - id = "1", - name = "1inch", - type = "DEX", - iconUrl = "", - subtitle = stringReference("1 000 000"), - additionalBadge = ProviderState.AdditionalBadge.PermissionRequired, - percentLowerThenBest = PercentLowerThanBest.Value(-1.0f), - selectionType = ProviderState.SelectionType.SELECT, - onProviderClick = {}, - ) - Column { - TangemTheme(isDark = false) { - ProviderItemBlock(state = state) - } - - SpacerH24() - - TangemTheme(isDark = true) { - ProviderItemBlock(state = state) - } +private fun ProviderItemPreview_Dark( + @PreviewParameter(ProviderItemParameterProvider::class) state: Pair, +) { + TangemTheme(isDark = true) { + ProviderItem( + modifier = Modifier.background(TangemTheme.colors.background.action), + state = state.first, + isSelected = state.second, + ) } } -@Preview -@Composable -private fun ProviderItem_Unavailable_Preview() { - val state = ProviderState.Unavailable( - id = "1", - name = "1inch", - type = "DEX", - iconUrl = "", - selectionType = ProviderState.SelectionType.SELECT, - alertText = stringReference("Unavailable"), - ) - Column { - TangemTheme(isDark = false) { - ProviderItemBlock(state = state) - } +private class ProviderItemParameterProvider : CollectionPreviewParameterProvider>( + collection = buildList { + val contentState = ProviderState.Content( + id = "1", + name = "1inch", + type = "DEX", + iconUrl = "", + subtitle = stringReference(value = "0,64554846 DAI ≈ 1 MATIC"), + additionalBadge = ProviderState.AdditionalBadge.Empty, + percentLowerThenBest = PercentLowerThanBest.Empty, + selectionType = ProviderState.SelectionType.SELECT, + namePrefix = ProviderState.PrefixType.PROVIDED_BY, + onProviderClick = {}, + ) + val contentState2 = contentState.copy( + subtitle = stringReference(value = "1 132,46 MATIC"), + additionalBadge = ProviderState.AdditionalBadge.PermissionRequired, + percentLowerThenBest = PercentLowerThanBest.Value(value = 5f), + ) + val unavailableState = ProviderState.Unavailable( + id = "1", + name = "1inch", + type = "DEX", + iconUrl = "", + alertText = stringReference(value = "Not available"), + selectionType = ProviderState.SelectionType.SELECT, + onProviderClick = {}, + ) + val loadingState = ProviderState.Loading() - SpacerH24() + add(contentState to true) + add(contentState to false) - TangemTheme(isDark = true) { - ProviderItemBlock(state = state) - } + add(contentState2 to true) + add(contentState2 to false) - SpacerH24() + add(unavailableState to true) + add(unavailableState to false) - TangemTheme(isDark = true) { - ProviderItem(state = state, isSelected = true) - } - } -} \ No newline at end of file + add(loadingState to true) + add(loadingState to false) + }, +) +// endregion Preview \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index d6a880f213..446b40e5ae 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -1229,6 +1229,7 @@ internal class StateBuilder( additionalBadge = badge, selectionType = selectionType, percentLowerThenBest = PercentLowerThanBest.Empty, + namePrefix = ProviderState.PrefixType.PROVIDED_BY, onProviderClick = onProviderClick, ) } @@ -1260,6 +1261,7 @@ internal class StateBuilder( percentLowerThenBest = pricesLowerBest[this.providerId]?.let { percent -> PercentLowerThanBest.Value(percent) } ?: PercentLowerThanBest.Value(0f), + namePrefix = ProviderState.PrefixType.NONE, onProviderClick = onProviderClick, ) } @@ -1294,6 +1296,11 @@ internal class StateBuilder( subtitle = alertText, additionalBadge = ProviderState.AdditionalBadge.Empty, percentLowerThenBest = PercentLowerThanBest.Empty, + namePrefix = if (selectionType != ProviderState.SelectionType.SELECT) { + ProviderState.PrefixType.PROVIDED_BY + } else { + ProviderState.PrefixType.NONE + }, onProviderClick = onProviderClick, ) } @@ -1319,7 +1326,7 @@ internal class StateBuilder( } private fun SwapAmount.getFormattedCryptoAmount(token: CryptoCurrency): String { - return "${this.formatToUIRepresentation()} ${token.symbol}" + return BigDecimalFormatter.formatCryptoAmount(value, token.symbol, token.decimals) } private fun BigDecimal.calculateRate(to: BigDecimal, decimals: Int): BigDecimal {