From 0d8970b386f5e78f0c2b993a2a45af1007f6473a Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 8 May 2026 05:45:30 -0700 Subject: [PATCH] Updated on 2026-08-14 --- .../format/bigdecimal/BigDecimalFiatFormat.kt | 27 ++++++++++++++ .../bigdecimal/BigDecimalFiatFormatTest.kt | 36 +++++++++++++++++++ .../setup/TangemPayCardLimitSetupModel.kt | 10 +++--- .../tangempay/model/TangemPayCardPageModel.kt | 3 +- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt index 7629ed6986..af950e8bfe 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormat.kt @@ -242,6 +242,33 @@ fun BigDecimalFiatFormat.anyDecimals(decimals: Int): BigDecimalFormat = BigDecim .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) } +/** + * Formats fiat amount following the pattern: + * + * 123 -> $123 + * + * 123.1 -> $123.10 + * + * 123.10 -> $123.10 + * + * 123.456 -> $123.46 + */ +fun BigDecimalFiatFormat.optionalDecimals(): BigDecimalFormat = BigDecimalFormat { value -> + val formatterCurrency = getJavaCurrencyByCode(fiatCurrencyCode) + + val hasFraction = value.stripTrailingZeros().scale() > 0 + val defaultDigits = formatterCurrency.defaultFractionDigits + val formatter = NumberFormat.getCurrencyInstance(locale).apply { + currency = formatterCurrency + minimumFractionDigits = if (hasFraction) defaultDigits else 0 + maximumFractionDigits = defaultDigits + roundingMode = RoundingMode.HALF_UP + } + + formatter.format(value) + .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) +} + // == Helpers == private fun BigDecimal.isLessThanThreshold() = this > BigDecimal.ZERO && this < FIAT_FORMAT_THRESHOLD diff --git a/core/ui/src/test/kotlin/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormatTest.kt b/core/ui/src/test/kotlin/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormatTest.kt index fcc2eca898..a5133d16d0 100644 --- a/core/ui/src/test/kotlin/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormatTest.kt +++ b/core/ui/src/test/kotlin/com/tangem/core/ui/format/bigdecimal/BigDecimalFiatFormatTest.kt @@ -2,6 +2,9 @@ package com.tangem.core.ui.format.bigdecimal import com.google.common.truth.Truth import org.junit.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource import java.math.BigDecimal import java.util.Locale @@ -342,4 +345,37 @@ internal class BigDecimalFiatFormatTest { Truth.assertThat(formatted) .isEqualTo("-" + "0.50".addUsdSymbolLeft()) } + + @ParameterizedTest + @MethodSource("provideTestCasesForOptionalDecimals") + fun `GIVEN amount WHEN format with optionalDecimals THEN correct answer`( + amount: String, + answer: String, + ) { + val testValue = BigDecimal(amount) + + val formatted = testValue.format { + fiat( + fiatCurrencyCode = usdCurrencyCode, + fiatCurrencySymbol = usdSymbol, + locale = testLocale, + ).optionalDecimals() + } + + Truth.assertThat(formatted).isEqualTo(answer) + } + + private companion object { + @JvmStatic + fun provideTestCasesForOptionalDecimals() = listOf( + Arguments.of("123", "$123"), + Arguments.of("123.1", "$123.10"), + Arguments.of("123.10", "$123.10"), + Arguments.of("123.456", "$123.46"), + Arguments.of("0", "$0"), + Arguments.of("0.1", "$0.10"), + Arguments.of("0.12", "$0.12"), + Arguments.of("0.127", "$0.13"), + ) + } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt index ff13c3a2b7..cd273833c5 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt @@ -9,10 +9,10 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.WrappedList -import com.tangem.core.ui.format.bigdecimal.anyDecimals import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode +import com.tangem.core.ui.format.bigdecimal.optionalDecimals import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.models.StatusSource import com.tangem.domain.models.account.PaymentAccountStatusValue @@ -170,7 +170,7 @@ internal class TangemPayCardLimitSetupModel @Inject constructor( id = R.string.tangempay_card_limit_setup_amount_subtitle, formatArgs = WrappedList( listOf( - MIN_LIMIT.format { fiat(currency.currencyCode, currency.symbol).anyDecimals(0) }, + MIN_LIMIT.format { fiat(currency.currencyCode, currency.symbol).optionalDecimals() }, ), ), ) @@ -179,8 +179,8 @@ internal class TangemPayCardLimitSetupModel @Inject constructor( id = R.string.tangempay_daily_limit_hint, formatArgs = WrappedList( listOf( - MIN_LIMIT.format { fiat(currency.currencyCode, currency.symbol).anyDecimals(0) }, - maxLimit.format { fiat(currency.currencyCode, currency.symbol).anyDecimals(0) }, + MIN_LIMIT.format { fiat(currency.currencyCode, currency.symbol).optionalDecimals() }, + maxLimit.format { fiat(currency.currencyCode, currency.symbol).optionalDecimals() }, ), ), ) @@ -193,7 +193,7 @@ internal class TangemPayCardLimitSetupModel @Inject constructor( BigDecimal("10000"), BigDecimal("25000"), ).map { preset -> - val label = preset.format { fiat(currency.currencyCode, currency.symbol).anyDecimals(0) } + val label = preset.format { fiat(currency.currencyCode, currency.symbol).optionalDecimals() } TangemPayCardLimitSetupUM.LimitPresetUM( label = label, onClick = { onPresetClick(preset) }, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt index 14d8765c16..f5c7e0a5e5 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt @@ -17,6 +17,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode +import com.tangem.core.ui.format.bigdecimal.optionalDecimals import com.tangem.core.ui.message.SnackbarMessage import com.tangem.domain.models.StatusSource import com.tangem.domain.models.TokenReceiveConfig @@ -98,7 +99,7 @@ internal class TangemPayCardPageModel @Inject constructor( TangemPayDailyLimitBlockState.Content( limit = limit.amount.format { val symbol = getJavaCurrencyByCode(status.currencyCode).symbol - fiat(status.currencyCode, symbol) + fiat(status.currencyCode, symbol).optionalDecimals() }, onChangeClick = ::onClickLimitChange, )