diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt index 7db27cf7f4..b5a21b53f7 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt @@ -11,6 +11,8 @@ import java.util.Locale private const val TEXT_CHUNK_THOUSAND = 3 private const val POINT_SEPARATOR = '.' +private const val COMMA_SEPARATOR = ',' +const val DECIMAL_SEPARATOR_LIMIT = 1 @Composable 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) { before } else { diff --git a/data/qr-scanning/src/main/java/com/tangem/data/qrscanning/repository/DefaultQrScanningEventsRepository.kt b/data/qr-scanning/src/main/java/com/tangem/data/qrscanning/repository/DefaultQrScanningEventsRepository.kt index 994539366b..cce12822c5 100644 --- a/data/qr-scanning/src/main/java/com/tangem/data/qrscanning/repository/DefaultQrScanningEventsRepository.kt +++ b/data/qr-scanning/src/main/java/com/tangem/data/qrscanning/repository/DefaultQrScanningEventsRepository.kt @@ -1,6 +1,7 @@ package com.tangem.data.qrscanning.repository 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.SourceType import com.tangem.domain.qrscanning.repository.QrScanningEventsRepository @@ -44,7 +45,7 @@ internal class DefaultQrScanningEventsRepository : QrScanningEventsRepository { when (it.key) { Parameter.Amount -> { // 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.Memo, @@ -70,7 +71,7 @@ internal class DefaultQrScanningEventsRepository : QrScanningEventsRepository { -> { // Extra convert parses scientific notation to decimal // This is necessary to be able comparing BigDecimal values - result.amount = it.value.toBigDecimalOrNull() + result.amount = it.value.parseBigDecimalOrNull() ?.toPlainString()?.toBigDecimalOrNull() ?.divide(BigDecimal.TEN.pow(cryptoCurrency.decimals)) }