From e386c3655704c7090bc4961ff00ad2b6597b8781 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 12 Aug 2024 20:36:12 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../ui/amountScreen/utils/FormatterUtils.kt | 18 ------- .../core/ui/utils/BigDecimalFormatter.kt | 52 +++++++++++++++++-- .../presentation/ui/SendNavigationButtons.kt | 34 +++++++----- .../ui/fee/SendSpeedSelectorItem.kt | 11 +++- .../impl/presentation/ui/send/FeeBlock.kt | 13 +++-- .../presentation/ui/block/StakingFeeBlock.kt | 17 ++++-- 6 files changed, 99 insertions(+), 46 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/utils/FormatterUtils.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/utils/FormatterUtils.kt index 67c6ed8cc9..c578193df0 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/utils/FormatterUtils.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/utils/FormatterUtils.kt @@ -1,30 +1,12 @@ package com.tangem.common.ui.amountScreen.utils -import com.tangem.blockchain.common.Amount import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.combinedReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.core.ui.utils.BigDecimalFormatter.EMPTY_BALANCE_SIGN import com.tangem.domain.appcurrency.model.AppCurrency import java.math.BigDecimal -private const val CRYPTO_FEE_DECIMALS = 6 - -fun getCryptoReference(amount: Amount?, isFeeApproximate: Boolean): TextReference? { - if (amount == null) return null - return combinedReference( - if (isFeeApproximate) stringReference("${BigDecimalFormatter.CAN_BE_LOWER_SIGN} ") else TextReference.EMPTY, - stringReference( - BigDecimalFormatter.formatCryptoAmount( - cryptoAmount = amount.value, - cryptoCurrency = amount.currencySymbol, - decimals = amount.decimals.coerceAtMost(CRYPTO_FEE_DECIMALS), - ), - ), - ) -} - fun getFiatReference(value: BigDecimal?, rate: BigDecimal?, appCurrency: AppCurrency): TextReference? { if (value == null || rate == null) return null val formattedFiat = getFiatString(value = value, rate = rate, appCurrency = appCurrency) 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 d1d4cf9c8c..b0c1a83fed 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 @@ -13,15 +13,18 @@ import java.text.NumberFormat import java.util.Currency import java.util.Locale +@Suppress("LargeClass") object BigDecimalFormatter { const val EMPTY_BALANCE_SIGN = DASH_SIGN - const val CAN_BE_LOWER_SIGN = LOWER_SIGN + private const val CAN_BE_LOWER_SIGN = LOWER_SIGN private val FORMAT_THRESHOLD = BigDecimal("0.01") private const val TEMP_CURRENCY_CODE = "USD" private val FIAT_FORMAT_THRESHOLD = BigDecimal("0.01") + private val CRYPTO_FEE_FORMAT_THRESHOLD = BigDecimal("0.000001") + private const val FIAT_MARKET_DEFAULT_DIGITS = 2 private const val FIAT_MARKET_EXTENDED_DIGITS = 6 @@ -112,6 +115,45 @@ object BigDecimalFormatter { } } + fun formatCryptoFeeAmount( + cryptoAmount: BigDecimal?, + cryptoCurrency: String, + decimals: Int, + canBeLower: Boolean = false, + locale: Locale = Locale.getDefault(), + ): String { + if (cryptoAmount == null) return EMPTY_BALANCE_SIGN + + val formatter = NumberFormat.getNumberInstance(locale).apply { + maximumFractionDigits = decimals.coerceAtMost(maximumValue = 6) + minimumFractionDigits = 2 + isGroupingUsed = true + roundingMode = RoundingMode.HALF_UP + } + + val amountFormatted = if (cryptoAmount.checkCryptoThreshold()) { + buildString { + append(CAN_BE_LOWER_SIGN) + append( + formatter.format(CRYPTO_FEE_FORMAT_THRESHOLD), + ) + } + } else { + buildString { + if (canBeLower) { + append(CAN_BE_LOWER_SIGN) + } + append(formatter.format(cryptoAmount)) + } + } + + return if (cryptoCurrency.isEmpty()) { + amountFormatted + } else { + amountFormatted + "\u2009$cryptoCurrency" + } + } + fun formatCryptoAmount( cryptoAmount: BigDecimal?, cryptoCurrency: CryptoCurrency, @@ -137,7 +179,7 @@ object BigDecimalFormatter { roundingMode = RoundingMode.HALF_UP } - return if (fiatAmount.isLessThanThreshold()) { + return if (fiatAmount.checkFiatThreshold()) { buildString { append(CAN_BE_LOWER_SIGN) append( @@ -160,7 +202,7 @@ object BigDecimalFormatter { if (fiatAmount == null) return EMPTY_BALANCE_SIGN val formatterCurrency = getCurrency(fiatCurrencyCode) - val digits = if (fiatAmount.isLessThanThreshold()) { + val digits = if (fiatAmount.checkFiatThreshold()) { FIAT_MARKET_EXTENDED_DIGITS } else { FIAT_MARKET_DEFAULT_DIGITS @@ -358,7 +400,9 @@ object BigDecimalFormatter { } } - private fun BigDecimal.isLessThanThreshold() = this > BigDecimal.ZERO && this < FIAT_FORMAT_THRESHOLD + private fun BigDecimal.checkFiatThreshold() = this > BigDecimal.ZERO && this < FIAT_FORMAT_THRESHOLD + + private fun BigDecimal.checkCryptoThreshold() = this > BigDecimal.ZERO && this < CRYPTO_FEE_FORMAT_THRESHOLD @Suppress("MagicNumber") fun getProperFiatPriceDecimals(price: BigDecimal): Int { diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt index 3e676181c9..18d8413082 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt @@ -22,7 +22,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.ui.SendDoneButtons -import com.tangem.common.ui.amountScreen.utils.getCryptoReference import com.tangem.common.ui.amountScreen.utils.getFiatString import com.tangem.core.ui.R import com.tangem.core.ui.components.Keyboard @@ -34,6 +33,7 @@ import com.tangem.core.ui.components.keyboardAsState import com.tangem.core.ui.extensions.* 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.SendUiCurrentScreen import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.state.SendUiStateType @@ -186,16 +186,6 @@ private fun SendingText( fiatCurrencySymbol = feeState.appCurrency.symbol, fiatCurrencyCode = feeState.appCurrency.code, ) - val feeValue = if (feeState.isFeeConvertibleToFiat) { - getFiatString( - value = feeState.fee?.amount?.value, - rate = feeState.rate, - appCurrency = feeState.appCurrency, - ) - } else { - getCryptoReference(feeState.fee?.amount, feeState.isFeeApproximate)?.resolveReference().orEmpty() - } - val textResource = remember(uiState) { resourceReference( id = if (feeState.isFeeConvertibleToFiat) { @@ -203,7 +193,7 @@ private fun SendingText( } else { R.string.send_summary_transaction_description_no_fiat_fee }, - formatArgs = wrappedList(sendingValue, feeValue), + formatArgs = wrappedList(sendingValue, feeState.getFiatValue()), ) } Text( @@ -219,6 +209,22 @@ private fun SendingText( } } +private fun SendStates.FeeState.getFiatValue() = if (isFeeConvertibleToFiat) { + getFiatString( + value = fee?.amount?.value, + rate = rate, + appCurrency = appCurrency, + ) +} else { + val amount = fee?.amount + BigDecimalFormatter.formatCryptoFeeAmount( + cryptoAmount = amount?.value, + cryptoCurrency = amount?.currencySymbol.orEmpty(), + decimals = amount?.decimals ?: 0, + canBeLower = isFeeApproximate, + ) +} + private fun getButtonData( uiState: SendUiState, currentState: SendUiCurrentScreen, @@ -245,11 +251,11 @@ private fun getButtonData( private fun isButtonEnabled(currentState: SendUiCurrentScreen, uiState: SendUiState): Boolean { return when (currentState.type) { - SendUiStateType.Amount -> uiState.amountState?.isPrimaryButtonEnabled + SendUiStateType.Amount -> uiState.amountState.isPrimaryButtonEnabled SendUiStateType.Recipient -> uiState.recipientState?.isPrimaryButtonEnabled SendUiStateType.Fee -> uiState.feeState?.isPrimaryButtonEnabled SendUiStateType.Send -> uiState.sendState?.isPrimaryButtonEnabled - SendUiStateType.EditAmount -> uiState.editAmountState?.isPrimaryButtonEnabled + SendUiStateType.EditAmount -> uiState.editAmountState.isPrimaryButtonEnabled SendUiStateType.EditRecipient -> uiState.editRecipientState?.isPrimaryButtonEnabled SendUiStateType.EditFee -> uiState.editFeeState?.isPrimaryButtonEnabled else -> true diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt index f7aacce75a..712f915547 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt @@ -11,11 +11,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.transaction.TransactionFee -import com.tangem.common.ui.amountScreen.utils.getCryptoReference import com.tangem.common.ui.amountScreen.utils.getFiatReference import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.SpacerWMax 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.core.ui.utils.parseToBigDecimal @@ -52,7 +52,14 @@ internal fun SendSpeedSelectorItem( iconRes = iconRes, onSelect = onSelect, modifier = modifier, - preDot = getCryptoReference(amount, state.isFeeApproximate), + preDot = stringReference( + BigDecimalFormatter.formatCryptoFeeAmount( + cryptoAmount = amount?.value, + cryptoCurrency = amount?.currencySymbol.orEmpty(), + decimals = amount?.decimals ?: 0, + canBeLower = state.isFeeApproximate, + ), + ), postDot = if (state.isFeeConvertibleToFiat) { getFiatReference(amount?.value, state.rate, state.appCurrency) } else { diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt index c43df695b9..b396811b81 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt @@ -14,12 +14,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.tangem.common.ui.amountScreen.utils.getCryptoReference import com.tangem.common.ui.amountScreen.utils.getFiatReference import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.rows.SelectorRowItem -import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.SendStates @@ -61,7 +61,14 @@ internal fun FeeBlock(feeState: SendStates.FeeState, isClickDisabled: Boolean, o SelectorRowItem( titleRes = title, iconRes = icon, - preDot = getCryptoReference(feeAmount, feeState.isFeeApproximate), + preDot = stringReference( + BigDecimalFormatter.formatCryptoFeeAmount( + cryptoAmount = feeAmount?.value, + cryptoCurrency = feeAmount?.currencySymbol.orEmpty(), + decimals = feeAmount?.decimals ?: 0, + canBeLower = feeState.isFeeApproximate, + ), + ), postDot = if (feeState.isFeeConvertibleToFiat) { getFiatReference(feeAmount?.value, feeState.rate, feeState.appCurrency) } else { diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/StakingFeeBlock.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/StakingFeeBlock.kt index c552ca2fbc..196b47b156 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/StakingFeeBlock.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/StakingFeeBlock.kt @@ -16,14 +16,14 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.transaction.Fee +import com.tangem.common.ui.R +import com.tangem.common.ui.amountScreen.utils.getFiatReference import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.rows.SelectorRowItem -import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.common.ui.R -import com.tangem.common.ui.amountScreen.utils.getCryptoReference -import com.tangem.common.ui.amountScreen.utils.getFiatReference import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.features.staking.impl.presentation.state.FeeState import java.math.BigDecimal @@ -53,7 +53,14 @@ internal fun StakingFeeBlock(feeState: FeeState) { SelectorRowItem( titleRes = title, iconRes = icon, - preDot = getCryptoReference(feeAmount, feeState.isFeeApproximate), + preDot = stringReference( + BigDecimalFormatter.formatCryptoFeeAmount( + cryptoAmount = feeAmount?.value, + cryptoCurrency = feeAmount?.currencySymbol.orEmpty(), + decimals = feeAmount?.decimals ?: 0, + canBeLower = feeState.isFeeApproximate, + ), + ), postDot = if (feeState.isFeeConvertibleToFiat) { getFiatReference(feeAmount?.value, feeState.rate, feeState.appCurrency) } else {