Updated on 2026-08-14

This commit is contained in:
Tangem 2024-04-17 14:23:29 +05:00
commit a136c0bfdf
2 changed files with 36 additions and 2 deletions

View file

@ -11,6 +11,8 @@ import java.util.Locale
private const val TEXT_CHUNK_THOUSAND = 3 private const val TEXT_CHUNK_THOUSAND = 3
private const val POINT_SEPARATOR = '.' private const val POINT_SEPARATOR = '.'
private const val COMMA_SEPARATOR = ','
const val DECIMAL_SEPARATOR_LIMIT = 1
@Composable @Composable
fun rememberDecimalFormat(): DecimalFormat { fun rememberDecimalFormat(): DecimalFormat {
@ -152,6 +154,37 @@ fun BigDecimal.parseBigDecimal(decimals: Int, roundingMode: RoundingMode = Round
} }
} }
/**
* Universal amount string parser to [BigDecimal]
* Able to parse values with only ONE separator, assuming separator is COMMA.
* Otherwise returns null.
*/
fun String.parseBigDecimalOrNull() = runCatching {
// Filtering value containing more than one either grouping or decimal separator.
// We assume there will be only decimal separator, otherwise parsing will fail.
if (count { !it.isDigit() } > DECIMAL_SEPARATOR_LIMIT) return null
// An attempt to parse value with POINT decimal separator
val parsed = this.toBigDecimalOrNull()
if (parsed == null) {
// If parsing with POINT separator fails trying to parse with COMMA separator
val decimalFormatSymbol = DecimalFormatSymbols().apply {
decimalSeparator = COMMA_SEPARATOR
}
val decimalFormat = DecimalFormat().apply {
decimalFormatSymbols = decimalFormatSymbol
isParseBigDecimal = true
}
// Return either number or null if fails
decimalFormat.parse(this) as? BigDecimal
} else {
// If parsing with POINT separator succeeds return number
parsed
}
}.getOrNull()
private fun Int.getWithIntegerDecimals(before: String, separator: Char, after: String): String = if (this == 0) { private fun Int.getWithIntegerDecimals(before: String, separator: Char, after: String): String = if (this == 0) {
before before
} else { } else {

View file

@ -1,6 +1,7 @@
package com.tangem.data.qrscanning.repository package com.tangem.data.qrscanning.repository
import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Blockchain
import com.tangem.core.ui.utils.parseBigDecimalOrNull
import com.tangem.domain.qrscanning.models.QrResult import com.tangem.domain.qrscanning.models.QrResult
import com.tangem.domain.qrscanning.models.SourceType import com.tangem.domain.qrscanning.models.SourceType
import com.tangem.domain.qrscanning.repository.QrScanningEventsRepository import com.tangem.domain.qrscanning.repository.QrScanningEventsRepository
@ -44,7 +45,7 @@ internal class DefaultQrScanningEventsRepository : QrScanningEventsRepository {
when (it.key) { when (it.key) {
Parameter.Amount -> { Parameter.Amount -> {
// According to BIP-0021, the value is specified in decimals. No conversion needed // According to BIP-0021, the value is specified in decimals. No conversion needed
result.amount = it.value.toBigDecimalOrNull() result.amount = it.value.parseBigDecimalOrNull()
} }
Parameter.Message, Parameter.Message,
Parameter.Memo, Parameter.Memo,
@ -70,7 +71,7 @@ internal class DefaultQrScanningEventsRepository : QrScanningEventsRepository {
-> { -> {
// Extra convert parses scientific notation to decimal // Extra convert parses scientific notation to decimal
// This is necessary to be able comparing BigDecimal values // This is necessary to be able comparing BigDecimal values
result.amount = it.value.toBigDecimalOrNull() result.amount = it.value.parseBigDecimalOrNull()
?.toPlainString()?.toBigDecimalOrNull() ?.toPlainString()?.toBigDecimalOrNull()
?.divide(BigDecimal.TEN.pow(cryptoCurrency.decimals)) ?.divide(BigDecimal.TEN.pow(cryptoCurrency.decimals))
} }