From 13f139afa8f045e62f4c5ac6d1cf678092967915 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 6 May 2026 10:35:39 +0200 Subject: [PATCH 1/3] Updated on 2026-08-14 --- .../format/bigdecimal/BigDecimalFiatFormat.kt | 2 +- .../bigdecimal/BigDecimalFiatFormatTest.kt | 48 +++++++++++++++++++ .../converter/MarketsTokenItemConverter.kt | 15 +++++- 3 files changed, 63 insertions(+), 2 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 2c29aedd8b..e8eb6add6d 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 @@ -232,7 +232,7 @@ private fun BigDecimal.isLessThanThreshold() = this > BigDecimal.ZERO && this < * Returns amount with correct scale */ fun getFiatPriceAmountWithScale(value: BigDecimal): Pair { - return if (value < BigDecimal.ONE) { + return if (value > BigDecimal.ZERO && value < BigDecimal.ONE) { val leadingZeroes = value.scale() - value.precision() val scale = leadingZeroes + FRACTIONAL_PART_LENGTH_AFTER_LEADING_ZEROES 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 d5c2cb310e..fcc2eca898 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 @@ -294,4 +294,52 @@ internal class BigDecimalFiatFormatTest { Truth.assertThat(formatted) .isEqualTo("0.00000000000000000000123".addUsdSymbolLeft()) } + + @Test + fun `price zero is formatted with default precision and does not crash`() { + val testValue = BigDecimal.ZERO + + val formatted = testValue.format { + fiat( + fiatCurrencyCode = usdCurrencyCode, + fiatCurrencySymbol = usdSymbol, + locale = testLocale, + ).price() + } + + Truth.assertThat(formatted) + .isEqualTo("0.00".addUsdSymbolLeft()) + } + + @Test + fun `price negative integer keeps sign and does not crash`() { + val testValue = BigDecimal("-500") + + val formatted = testValue.format { + fiat( + fiatCurrencyCode = usdCurrencyCode, + fiatCurrencySymbol = usdSymbol, + locale = testLocale, + ).price() + } + + Truth.assertThat(formatted) + .isEqualTo("-" + "500.00".addUsdSymbolLeft()) + } + + @Test + fun `price negative fractional keeps sign and does not crash`() { + val testValue = BigDecimal("-0.5") + + val formatted = testValue.format { + fiat( + fiatCurrencyCode = usdCurrencyCode, + fiatCurrencySymbol = usdSymbol, + locale = testLocale, + ).price() + } + + Truth.assertThat(formatted) + .isEqualTo("-" + "0.50".addUsdSymbolLeft()) + } } \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt index dda2c04ee8..f9373e37a1 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt @@ -15,6 +15,7 @@ import com.tangem.domain.markets.TokenMarket import com.tangem.features.feed.impl.R import com.tangem.features.feed.model.market.list.state.MarketsListUM import com.tangem.utils.converter.Converter +import com.tangem.utils.logging.TangemLogger import kotlinx.collections.immutable.toImmutableList import java.math.BigDecimal import java.math.RoundingMode @@ -92,7 +93,15 @@ internal class MarketsTokenItemConverter( private fun TokenMarket.getCurrentPrice(prev: TokenMarket? = null): MarketsListItemUM.Price { val prevPrice = prev?.tokenQuotesShort?.currentPrice - val priceText = tokenQuotesShort.currentPrice.format { + val currentPrice = tokenQuotesShort.currentPrice + if (currentPrice < BigDecimal.ZERO) { + TangemLogger.withTag(MARKETS_PRICE_LOG_TAG).w( + messageString = "Unexpected non-positive price for tokenId=$id, symbol=$symbol, " + + "currency=${appCurrency.code}, value=${currentPrice.toPlainString()}", + ) + } + + val priceText = currentPrice.format { fiat( fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol, @@ -162,4 +171,8 @@ internal class MarketsTokenItemConverter( return percent.format { percent() } } + + private companion object { + const val MARKETS_PRICE_LOG_TAG = "MarketsTokenItemConverter" + } } \ No newline at end of file From 80e694892d439935176a553fe08d26639735b345 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 6 May 2026 22:27:01 +0200 Subject: [PATCH 2/3] Updated on 2026-08-14 --- .../format/bigdecimal/BigDecimalFiatFormat.kt | 40 ++++++++++++++----- .../converter/MarketsTokenItemConverter.kt | 16 +------- 2 files changed, 30 insertions(+), 26 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 e8eb6add6d..7629ed6986 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 @@ -98,13 +98,22 @@ fun BigDecimalFiatFormatStyled.defaultAmount(spanStyleReference: SpanStyleRefere } val decimalSeparator = (formatter as? DecimalFormat)?.decimalFormatSymbols?.decimalSeparator - val formattedAmount = formatter.format(formattingAmount) - .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) + val currencySymbol = formatterCurrency.getSymbol(locale) + val rawFormatted = formatter.format(formattingAmount) - val separatorIndex = decimalSeparator?.let { formattedAmount.indexOf(it) } ?: formattedAmount.length + val separatorIndex = decimalSeparator?.let { rawFormatted.indexOf(it).takeIf { i -> i >= 0 } } + ?: rawFormatted.length - val wholePart = formattedAmount.take(separatorIndex) - val fractionalPart = formattedAmount.drop(separatorIndex) + val formattedAmount = rawFormatted.replace(currencySymbol, fiatCurrencySymbol) + val offset = fiatCurrencySymbol.length - currencySymbol.length + val adjustedIndex = if (rawFormatted.indexOf(currencySymbol) in 0 until separatorIndex) { + separatorIndex + offset + } else { + separatorIndex + } + + val wholePart = formattedAmount.take(adjustedIndex) + val fractionalPart = formattedAmount.drop(adjustedIndex) combinedReference( if (formattingAmount.isLessThanThreshold()) stringReference(CAN_BE_LOWER_SIGN) else TextReference.EMPTY, @@ -192,13 +201,22 @@ private fun BigDecimalFiatFormatStyled.price(spanStyleReference: SpanStyleRefere } val decimalSeparator = (formatter as? DecimalFormat)?.decimalFormatSymbols?.decimalSeparator - val formattedAmount = formatter.format(priceAmount) - .replace(formatterCurrency.getSymbol(locale), fiatCurrencySymbol) + val currencySymbol = formatterCurrency.getSymbol(locale) + val rawFormatted = formatter.format(priceAmount) - val separatorIndex = decimalSeparator?.let { formattedAmount.indexOf(it) } ?: formattedAmount.length + val separatorIndex = decimalSeparator?.let { rawFormatted.indexOf(it).takeIf { i -> i >= 0 } } + ?: rawFormatted.length - val wholePart = formattedAmount.take(separatorIndex) - val fractionalPart = formattedAmount.drop(separatorIndex) + val formattedAmount = rawFormatted.replace(currencySymbol, fiatCurrencySymbol) + val offset = fiatCurrencySymbol.length - currencySymbol.length + val adjustedIndex = if (rawFormatted.indexOf(currencySymbol) in 0 until separatorIndex) { + separatorIndex + offset + } else { + separatorIndex + } + + val wholePart = formattedAmount.take(adjustedIndex) + val fractionalPart = formattedAmount.drop(adjustedIndex) combinedReference( stringReference(wholePart), @@ -232,7 +250,7 @@ private fun BigDecimal.isLessThanThreshold() = this > BigDecimal.ZERO && this < * Returns amount with correct scale */ fun getFiatPriceAmountWithScale(value: BigDecimal): Pair { - return if (value > BigDecimal.ZERO && value < BigDecimal.ONE) { + return if (value < BigDecimal.ONE) { val leadingZeroes = value.scale() - value.precision() val scale = leadingZeroes + FRACTIONAL_PART_LENGTH_AFTER_LEADING_ZEROES diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt index f9373e37a1..2d25b64eb9 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/converter/MarketsTokenItemConverter.kt @@ -15,7 +15,6 @@ import com.tangem.domain.markets.TokenMarket import com.tangem.features.feed.impl.R import com.tangem.features.feed.model.market.list.state.MarketsListUM import com.tangem.utils.converter.Converter -import com.tangem.utils.logging.TangemLogger import kotlinx.collections.immutable.toImmutableList import java.math.BigDecimal import java.math.RoundingMode @@ -92,16 +91,7 @@ internal class MarketsTokenItemConverter( private fun TokenMarket.getCurrentPrice(prev: TokenMarket? = null): MarketsListItemUM.Price { val prevPrice = prev?.tokenQuotesShort?.currentPrice - - val currentPrice = tokenQuotesShort.currentPrice - if (currentPrice < BigDecimal.ZERO) { - TangemLogger.withTag(MARKETS_PRICE_LOG_TAG).w( - messageString = "Unexpected non-positive price for tokenId=$id, symbol=$symbol, " + - "currency=${appCurrency.code}, value=${currentPrice.toPlainString()}", - ) - } - - val priceText = currentPrice.format { + val priceText = tokenQuotesShort.currentPrice.format { fiat( fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol, @@ -171,8 +161,4 @@ internal class MarketsTokenItemConverter( return percent.format { percent() } } - - private companion object { - const val MARKETS_PRICE_LOG_TAG = "MarketsTokenItemConverter" - } } \ No newline at end of file From 31fbd0872e841031e371eea2078b4615532a1f20 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 7 May 2026 07:42:36 +0000 Subject: [PATCH 3/3] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 94aa5668ec..7179ef2644 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,9 +5,9 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.37-1494" +tangemBlockchainSdk = "releases-5.38-1503" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.37-603" +tangemCardSdk = "releases-5.38-615" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "tangem-master-21" #tangemVico = "0.0.1" # Keep it! - used for local builds ^