From 9ac2009c89488ec0da564ea41655dbfdd6cf83db Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 2 Apr 2024 21:07:38 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../AppBarWithBackButtonAndIconContent.kt | 13 +- .../ui/components/fields/AmountTextField.kt | 57 ++------ .../AmountVisualTransformation.kt | 58 ++++++-- .../inputrow/InputRowEnterAmount.kt | 8 +- .../inputrow/InputRowEnterInfoAmount.kt | 15 +- .../core/ui/utils/BigDecimalFormatter.kt | 24 ++++ .../impl/presentation/state/SendUiState.kt | 1 + .../state/amount/SendAmountStateConverter.kt | 1 + .../fee/custom/EthereumCustomFeeConverter.kt | 131 +++++++++++------- .../fields/SendAmountFieldChangeConverter.kt | 8 +- .../previewdata/AmountStatePreviewData.kt | 1 + .../presentation/ui/amount/AmountField.kt | 64 ++++++--- .../ui/amount/AmountFieldContainer.kt | 1 + .../impl/presentation/ui/send/AmountBlock.kt | 17 ++- 14 files changed, 250 insertions(+), 149 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt index 2bd0141ea1..09b6158abb 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButtonAndIconContent.kt @@ -1,10 +1,7 @@ package com.tangem.core.ui.components.appbar import androidx.annotation.DrawableRes -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.animateContentSize -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut +import androidx.compose.animation.* import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -66,8 +63,7 @@ fun AppBarWithBackButtonAndIconContent( ) Column( verticalArrangement = Arrangement.Center, - modifier = Modifier.weight(1f) - .animateContentSize(), + modifier = Modifier.weight(1f), ) { AnimatedVisibility( visible = !text.isNullOrBlank(), @@ -84,8 +80,8 @@ fun AppBarWithBackButtonAndIconContent( } AnimatedVisibility( visible = !subtitle.isNullOrBlank(), - enter = fadeIn(), - exit = fadeOut(), + enter = fadeIn().plus(expandVertically()), + exit = fadeOut().plus(shrinkVertically()), label = "Toolbar subtitle change", ) { Text( @@ -93,6 +89,7 @@ fun AppBarWithBackButtonAndIconContent( color = TangemTheme.colors.text.secondary, maxLines = 1, style = TangemTheme.typography.caption2, + modifier = Modifier.animateContentSize(), ) } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt b/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt index fb140e00d4..75836f873a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/fields/AmountTextField.kt @@ -2,12 +2,10 @@ package com.tangem.core.ui.components.fields import androidx.annotation.FloatRange import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.TopCenter @@ -21,6 +19,7 @@ import androidx.compose.ui.text.ParagraphIntrinsics import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.createFontFamilyResolver import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.tooling.preview.Preview @@ -33,20 +32,21 @@ import java.text.DecimalFormat /** * Simple text field for amount input. - * Validates and trims input text using [DecimalFormat]. Formats visual output using [AmountVisualTransformation]. - * Can display aligned placeholder and currency symbol [symbol]. + * Validates and trims input text using [DecimalFormat]. Formats visual output using [visualTransformation]. + * Can display aligned placeholder. * * @param value initial text * @param decimals number of decimal places * @param onValueChange callback * @param textStyle text and placeholder styles * @param modifier modifier - * @param symbol currency symbol * @param color text color - * @param placeholderAlignment alignment of placeholder - * @param showPlaceholder show placeholder + * @param visualTransformation text visual transformation * @param keyboardOptions keyboard options - * + * @param keyboardActions keyboard actions + * @param isEnabled is field editing enabled + * @param isAutoResize is text font auto resize + * @param reduceFactor font resize factor * @see [SimpleTextField] for standard text field */ @Composable @@ -56,10 +56,8 @@ fun AmountTextField( onValueChange: (String) -> Unit, textStyle: TextStyle, modifier: Modifier = Modifier, - symbol: String? = null, color: Color = TangemTheme.colors.text.primary1, - placeholderAlignment: Alignment = TopStart, - showPlaceholder: Boolean = true, + visualTransformation: VisualTransformation = AmountVisualTransformation(decimals), keyboardOptions: KeyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number, ), @@ -70,12 +68,6 @@ fun AmountTextField( reduceFactor: Double = 0.9, ) { val decimalFormat = rememberDecimalFormat() - val visualTransformation = remember { AmountVisualTransformation(decimals, symbol, decimalFormat) } - val placeholderTextAlign = if (placeholderAlignment == TopCenter) { - TextAlign.Center - } else { - TextAlign.Start - } BoxWithConstraints(modifier = modifier) { var fontSize = textStyle.fontSize if (isAutoResize) { @@ -96,6 +88,7 @@ fun AmountTextField( } } } + val textColor = if (value.isBlank()) TangemTheme.colors.text.disabled else color SimpleTextField( value = value, onValueChange = { newText -> @@ -108,31 +101,13 @@ fun AmountTextField( fontSize = fontSize, textDirection = TextDirection.ContentOrLtr, ), - color = color, + color = textColor, keyboardOptions = keyboardOptions, keyboardActions = keyboardActions, singleLine = true, readOnly = !isEnabled, - visualTransformation = AmountVisualTransformation(decimals, symbol, decimalFormat), + visualTransformation = visualTransformation, modifier = Modifier.background(TangemTheme.colors.background.action), - decorationBox = { innerTextField -> - Box { - if (value.isBlank() && showPlaceholder) { - var placeholder = decimalFormat.defaultFormat() - if (symbol != null) { - placeholder = placeholder.plus(" $symbol") - } - Text( - text = placeholder, - style = textStyle.copy(textDirection = TextDirection.ContentOrLtr), - color = TangemTheme.colors.text.disabled, - textAlign = placeholderTextAlign, - modifier = Modifier.align(placeholderAlignment), - ) - } - innerTextField() - } - }, ) } } @@ -153,9 +128,6 @@ private fun AmountTextFieldPreview( AmountTextField( value = text, decimals = amount.decimals, - symbol = amount.symbol, - placeholderAlignment = amount.placeholderAlignment, - showPlaceholder = amount.showPlaceholder, onValueChange = { text = it }, textStyle = TangemTheme.typography.h2.copy( color = TangemTheme.colors.text.primary1, @@ -169,28 +141,24 @@ private fun AmountTextFieldPreview( private class AmountTextFieldPreviewProvider : PreviewParameterProvider { override val values = sequenceOf( AmountTextFieldPreviewData( - symbol = "USD", value = "1000000,123123", decimals = 3, placeholderAlignment = TopStart, showPlaceholder = true, ), AmountTextFieldPreviewData( - symbol = null, value = "1000000.123123", decimals = 6, placeholderAlignment = TopStart, showPlaceholder = false, ), AmountTextFieldPreviewData( - symbol = "$", value = null, decimals = 2, showPlaceholder = true, placeholderAlignment = TopCenter, ), AmountTextFieldPreviewData( - symbol = null, value = null, decimals = 2, showPlaceholder = true, @@ -200,7 +168,6 @@ private class AmountTextFieldPreviewProvider : PreviewParameterProvider 0) { + transformedOffset.coerceIn(0, minOf(symbolOffset, formattedText.length)) + } else { + transformedOffset.coerceIn(0, formattedText.length) + } + return transformedOffset } override fun transformedToOriginal(offset: Int): Int { diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterAmount.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterAmount.kt index dd7c375e77..28c9082f90 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterAmount.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterAmount.kt @@ -17,10 +17,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import com.tangem.core.ui.components.fields.AmountTextField +import com.tangem.core.ui.components.fields.visualtransformations.AmountVisualTransformation import com.tangem.core.ui.components.inputrow.inner.DividerContainer import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.rememberDecimalFormat /** * Input row for entering amount. Manages correct amount format and validation @@ -76,7 +78,11 @@ fun InputRowEnterAmount( AmountTextField( value = text, decimals = decimals, - symbol = symbol, + visualTransformation = AmountVisualTransformation( + decimals = decimals, + symbol = symbol, + decimalFormat = rememberDecimalFormat(), + ), onValueChange = onValueChange, color = textColor, textStyle = TangemTheme.typography.body2, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt index 40276abe7a..00d4221e37 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowEnterInfoAmount.kt @@ -12,23 +12,28 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.tangem.core.ui.components.fields.AmountTextField +import com.tangem.core.ui.components.fields.visualtransformations.AmountVisualTransformation import com.tangem.core.ui.components.inputrow.inner.DividerContainer import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.rememberDecimalFormat /** * `Input Row Enter Info` for entering amount. Manages correct amount format and validation * @param title title reference * @param text primary text reference + * @param decimals amount text decimal count * @param onValueChange text change callback * @param modifier modifier + * @param symbol amount symbol + * @param info info text * @param titleColor title color * @param textColor text color - * @param isSingleLine text - * @param visualTransformation applied transformation to text + * @param infoColor info text color * @param keyboardOptions keyboard options for field + * @param keyboardActions keyboard actions for field * @param showDivider show divider * * @see [InputRowEnterInfo] @@ -71,7 +76,11 @@ fun InputRowEnterInfoAmount( AmountTextField( value = text, decimals = decimals, - symbol = symbol, + visualTransformation = AmountVisualTransformation( + decimals = decimals, + symbol = symbol, + decimalFormat = rememberDecimalFormat(), + ), onValueChange = onValueChange, color = textColor, textStyle = TangemTheme.typography.body2, 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 020cc01c45..3ca0b57adf 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 @@ -38,6 +38,30 @@ object BigDecimalFormatter { } } + fun formatCryptoAmountUncapped( + cryptoAmount: BigDecimal?, + cryptoSymbol: String, + decimals: Int, + locale: Locale = Locale.getDefault(), + ): String { + if (cryptoAmount == null) return EMPTY_BALANCE_SIGN + + val formatter = NumberFormat.getNumberInstance(locale).apply { + maximumFractionDigits = decimals + minimumFractionDigits = minOf(2, decimals) + isGroupingUsed = true + roundingMode = RoundingMode.DOWN + } + + return formatter.format(cryptoAmount).let { + if (cryptoSymbol.isEmpty()) { + it + } else { + it + "\u2009$cryptoSymbol" + } + } + } + fun formatCryptoAmount( cryptoAmount: BigDecimal?, cryptoCurrency: CryptoCurrency, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt index d16f511bbd..a4306da4f4 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt @@ -50,6 +50,7 @@ internal sealed class SendStates { val segmentedButtonConfig: PersistentList, val amountTextField: SendTextField.AmountField, val notifications: ImmutableList, + val appCurrencyCode: String, val isFeeLoading: Boolean, ) : SendStates() diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt index 9e393e8bae..d12d7d3c28 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt @@ -40,6 +40,7 @@ internal class SendAmountStateConverter( isPrimaryButtonEnabled = false, notifications = persistentListOf(), isFeeLoading = false, + appCurrencyCode = appCurrency.code, segmentedButtonConfig = if (status.value.fiatRate.isNullOrZero()) { persistentListOf() } else { diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt index 950dd0b135..11dfc8f056 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt @@ -50,7 +50,7 @@ internal class EthereumCustomFeeConverter( ), SendTextField.CustomFee( value = value.gasPrice.toString(), - decimals = ETHEREUM_GAS_DECIMALS, + decimals = GAS_DECIMALS, symbol = ETHEREUM_GAS_UNIT, title = resourceReference(R.string.send_gas_price), footer = resourceReference(R.string.send_gas_price_footer), @@ -64,7 +64,7 @@ internal class EthereumCustomFeeConverter( SendTextField.CustomFee( value = value.gasLimit.toString(), decimals = GAS_DECIMALS, - symbol = null, + symbol = "", title = resourceReference(R.string.send_gas_limit), footer = resourceReference(R.string.send_gas_limit_footer), onValueChange = { clickIntents.onCustomFeeValueChange(GAS_LIMIT, it) }, @@ -95,57 +95,10 @@ internal class EthereumCustomFeeConverter( ): ImmutableList { val mutableCustomValues = customValues.toMutableList() return mutableCustomValues.apply { - val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals) when (index) { - FEE_AMOUNT -> { - val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals) - val newFeeAmount = newFeeAmountDecimal.movePointRight(this[FEE_AMOUNT].decimals) - val newGasPrice = newFeeAmount.divide(gasLimit, GAS_DECIMALS, RoundingMode.HALF_UP) - set(GAS_PRICE, this[GAS_PRICE].copy(value = newGasPrice.parseBigDecimal(GAS_DECIMALS))) - set( - index, - this[index].copy( - value = value, - label = getFeeFormatted(newFeeAmountDecimal), - ), - ) - } - GAS_PRICE -> { - val newGasPrice = value.parseToBigDecimal(this[GAS_PRICE].decimals) - .movePointLeft(this[GAS_PRICE].decimals) - val newFeeAmount = gasLimit * newGasPrice - set( - FEE_AMOUNT, - this[FEE_AMOUNT].copy( - value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals), - label = getFeeFormatted(newFeeAmount), - ), - ) - set(index, this[index].copy(value = value)) - } - else -> { - val newGasLimit = value.parseToBigDecimal(this[GAS_LIMIT].decimals) - val gasPrice = this[GAS_PRICE].value.parseToBigDecimal(this[GAS_PRICE].decimals) - .movePointLeft(this[FEE_AMOUNT].decimals) - val newFeeAmount = newGasLimit * gasPrice - set( - FEE_AMOUNT, - this[FEE_AMOUNT].copy( - value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals), - label = getFeeFormatted(newFeeAmount), - ), - ) - set( - index, - this[index].copy( - value = value, - keyboardOptions = KeyboardOptions( - imeAction = if (!checkExceedBalance(newFeeAmount)) ImeAction.None else ImeAction.Done, - keyboardType = KeyboardType.Number, - ), - ), - ) - } + FEE_AMOUNT -> setOnAmountChange(value, index) + GAS_PRICE -> setOnGasPriceChange(value, index) + else -> setOnGasLimitChange(value, index) } }.toImmutableList() } @@ -170,9 +123,81 @@ internal class EthereumCustomFeeConverter( return feeAmount == null || feeAmount.isZero() || feeAmount > currencyCryptoAmount } + private fun MutableList.setEmpty(index: Int) { + set(index, this[index].copy(value = "")) + } + + private fun MutableList.setOnAmountChange(value: String, index: Int) { + val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals) + if (value.isBlank()) { + setEmpty(FEE_AMOUNT) + setEmpty(GAS_PRICE) + } else { + val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals) + val newFeeAmount = newFeeAmountDecimal.movePointRight(this[FEE_AMOUNT].decimals) + val newGasPrice = newFeeAmount.divide(gasLimit, GAS_DECIMALS, RoundingMode.HALF_UP) + set(GAS_PRICE, this[GAS_PRICE].copy(value = newGasPrice.parseBigDecimal(GAS_DECIMALS))) + set( + index, + this[index].copy( + value = value, + label = getFeeFormatted(newFeeAmountDecimal), + ), + ) + } + } + + private fun MutableList.setOnGasPriceChange(value: String, index: Int) { + val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals) + if (value.isBlank()) { + setEmpty(FEE_AMOUNT) + setEmpty(GAS_PRICE) + } else { + val newGasPrice = value.parseToBigDecimal(this[GAS_PRICE].decimals) + .movePointLeft(this[GAS_PRICE].decimals) + val newFeeAmount = (gasLimit * newGasPrice).movePointLeft(this[FEE_AMOUNT].decimals) + set( + FEE_AMOUNT, + this[FEE_AMOUNT].copy( + value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals), + label = getFeeFormatted(newFeeAmount), + ), + ) + set(index, this[index].copy(value = value)) + } + } + + private fun MutableList.setOnGasLimitChange(value: String, index: Int) { + if (value.isBlank()) { + setEmpty(FEE_AMOUNT) + setEmpty(GAS_LIMIT) + } else { + val newGasLimit = value.parseToBigDecimal(this[GAS_LIMIT].decimals) + val gasPrice = this[GAS_PRICE].value.parseToBigDecimal(this[GAS_PRICE].decimals) + .movePointLeft(this[FEE_AMOUNT].decimals) + val newFeeAmount = newGasLimit * gasPrice + set( + FEE_AMOUNT, + this[FEE_AMOUNT].copy( + value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals), + label = getFeeFormatted(newFeeAmount), + ), + ) + set( + index, + this[index].copy( + value = value, + keyboardOptions = KeyboardOptions( + imeAction = if (!checkExceedBalance(newFeeAmount)) ImeAction.None else ImeAction.Done, + keyboardType = KeyboardType.Number, + ), + ), + ) + } + } + companion object { private const val ETHEREUM_GAS_UNIT = "GWEI" - private const val ETHEREUM_GAS_DECIMALS = 18 private const val FEE_AMOUNT = 0 private const val GAS_PRICE = 1 private const val GAS_LIMIT = 2 diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt index cd6254be4f..273e457783 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fields/SendAmountFieldChangeConverter.kt @@ -75,12 +75,16 @@ internal class SendAmountFieldChangeConverter( } private fun SendUiState.emptyState(): SendUiState { + if (amountState == null) return this + val amountTextField = amountState.amountTextField return copy( - amountState = amountState?.copy( + amountState = amountState.copy( isPrimaryButtonEnabled = false, - amountTextField = amountState.amountTextField.copy( + amountTextField = amountTextField.copy( value = "", fiatValue = "", + cryptoAmount = amountTextField.cryptoAmount.copy(value = BigDecimal.ZERO), + fiatAmount = amountTextField.fiatAmount.copy(value = BigDecimal.ZERO), isError = false, ), ), diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt index 43d0d75572..75e5ce97f4 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt @@ -24,6 +24,7 @@ internal object AmountStatePreviewData { segmentedButtonConfig = persistentListOf(), notifications = persistentListOf(), isFeeLoading = false, + appCurrencyCode = "usd", amountTextField = SendTextField.AmountField( value = "123.123123123123123123", onValueChange = {}, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt index 4c45622e33..5aa3ec82ac 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountField.kt @@ -3,42 +3,49 @@ package com.tangem.features.send.impl.presentation.ui.amount import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeightIn import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment.Companion.BottomCenter -import androidx.compose.ui.Alignment.Companion.TopCenter import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDirection import com.tangem.core.ui.components.fields.AmountTextField +import com.tangem.core.ui.components.fields.visualtransformations.AmountVisualTransformation import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.core.ui.utils.defaultFormat import com.tangem.core.ui.utils.rememberDecimalFormat import com.tangem.features.send.impl.presentation.state.fields.SendTextField +import kotlinx.coroutines.job @Composable -internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolean) { +internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolean, appCurrencyCode: String) { val decimalFormat = rememberDecimalFormat() - val (primaryValue, secondaryValue) = if (sendField.isFiatValue) { - sendField.fiatValue to sendField.value + val isFiatValue = sendField.isFiatValue + val currencyCode = if (isFiatValue) appCurrencyCode else null + val (primaryAmount, primaryValue) = if (isFiatValue) { + sendField.fiatAmount to sendField.fiatValue } else { - sendField.value to sendField.fiatValue + sendField.cryptoAmount to sendField.value } - - val (primaryAmount, secondaryAmount) = if (sendField.isFiatValue) { - sendField.fiatAmount to sendField.cryptoAmount - } else { - sendField.cryptoAmount to sendField.fiatAmount - } - + val requester = remember { FocusRequester() } AmountTextField( value = primaryValue, decimals = primaryAmount.decimals, - symbol = primaryAmount.currencySymbol, + visualTransformation = AmountVisualTransformation( + decimals = primaryAmount.decimals, + symbol = primaryAmount.currencySymbol, + currencyCode = currencyCode, + decimalFormat = decimalFormat, + ), onValueChange = sendField.onValueChange, keyboardOptions = sendField.keyboardOptions, keyboardActions = sendField.keyboardActions, @@ -48,8 +55,8 @@ internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolea ), isEnabled = isEnabled, isAutoResize = true, - placeholderAlignment = TopCenter, modifier = Modifier + .focusRequester(requester) .padding( top = TangemTheme.dimens.spacing24, start = TangemTheme.dimens.spacing12, @@ -57,7 +64,18 @@ internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolea ) .requiredHeightIn(min = TangemTheme.dimens.size32), ) + LaunchedEffect(key1 = Unit) { + this.coroutineContext.job.invokeOnCompletion { + requester.requestFocus() + } + } + AmountSecondary(sendField, appCurrencyCode) +} + +@Composable +private fun AmountSecondary(sendField: SendTextField.AmountField, appCurrencyCode: String) { + val secondaryAmount = if (sendField.isFiatValue) sendField.cryptoAmount else sendField.fiatAmount Box( modifier = Modifier .padding( @@ -66,10 +84,18 @@ internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolea end = TangemTheme.dimens.spacing12, ), ) { - val text = if (sendField.isFiatUnavailable) { - BigDecimalFormatter.EMPTY_BALANCE_SIGN + val text = if (sendField.isFiatValue) { + BigDecimalFormatter.formatCryptoAmount( + cryptoAmount = secondaryAmount.value, + cryptoCurrency = secondaryAmount.currencySymbol, + decimals = secondaryAmount.decimals, + ) } else { - "${secondaryValue.ifEmpty { decimalFormat.defaultFormat() }} ${secondaryAmount.currencySymbol}" + BigDecimalFormatter.formatFiatAmount( + fiatAmount = secondaryAmount.value, + fiatCurrencySymbol = secondaryAmount.currencySymbol, + fiatCurrencyCode = appCurrencyCode, + ) } Text( text = text, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountFieldContainer.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountFieldContainer.kt index 5cf940b41b..d9926e3f54 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountFieldContainer.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountFieldContainer.kt @@ -63,6 +63,7 @@ internal fun LazyListScope.amountField( AmountField( sendField = amountState.amountTextField, isEnabled = !amountState.isFeeLoading, + appCurrencyCode = amountState.appCurrencyCode, ) } } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt index 26c0380dd5..528cdfea00 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/AmountBlock.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.tangem.core.ui.components.ResizableText import com.tangem.core.ui.components.currency.tokenicon.TokenIcon import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.previewdata.AmountStatePreviewData @@ -29,8 +30,16 @@ internal fun AmountBlock( ) { val amount = amountState.amountTextField - val cryptoAmount = getAmountWithSymbol(amount.value, amount.cryptoAmount.currencySymbol) - val fiatAmount = getAmountWithSymbol(amount.fiatValue, amount.fiatAmount.currencySymbol) + val cryptoAmount = BigDecimalFormatter.formatCryptoAmount( + cryptoAmount = amount.cryptoAmount.value, + cryptoCurrency = amount.cryptoAmount.currencySymbol, + decimals = amount.cryptoAmount.decimals, + ) + val fiatAmount = BigDecimalFormatter.formatFiatAmount( + fiatAmount = amount.fiatAmount.value, + fiatCurrencySymbol = amount.fiatAmount.currencySymbol, + fiatCurrencyCode = amountState.appCurrencyCode, + ) val backgroundColor = if (isEditingDisabled) { TangemTheme.colors.button.disabled } else { @@ -77,10 +86,6 @@ internal fun AmountBlock( } } -private fun getAmountWithSymbol(amount: String, symbol: String): String { - return "$amount $symbol" -} - // region Preview @Preview @Composable