fiat amount string formatting and parsing and more WIP usages thereof

This commit is contained in:
julian 2023-06-16 13:42:37 -06:00
parent 7bcfc87f4d
commit f88d7f200c
4 changed files with 74 additions and 67 deletions

View file

@ -10,7 +10,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math';
import 'package:bip47/bip47.dart'; import 'package:bip47/bip47.dart';
import 'package:cw_core/monero_transaction_priority.dart'; import 'package:cw_core/monero_transaction_priority.dart';
@ -127,27 +126,13 @@ class _SendViewState extends ConsumerState<SendView> {
void _cryptoAmountChanged() async { void _cryptoAmountChanged() async {
if (!_cryptoAmountChangeLock) { if (!_cryptoAmountChangeLock) {
String cryptoAmount = cryptoAmountController.text; final cryptoAmount = ref.read(pAmountFormatter(coin)).tryParse(
if (cryptoAmount.isNotEmpty && cryptoAmountController.text,
cryptoAmount != "." && locale: ref.read(localeServiceChangeNotifierProvider).locale,
cryptoAmount != ",") { coin: coin,
if (cryptoAmount.startsWith("~")) { );
cryptoAmount = cryptoAmount.substring(1); if (cryptoAmount != null) {
} _amountToSend = cryptoAmount;
if (cryptoAmount.contains(" ")) {
cryptoAmount = cryptoAmount.split(" ").first;
}
// ensure we don't shift past minimum atomic value
final shift = min(ref.read(pAmountUnit(coin)).shift, coin.decimals);
_amountToSend = cryptoAmount.contains(",")
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
.shift(0 - shift)
.toAmount(fractionDigits: coin.decimals)
: Decimal.parse(cryptoAmount)
.shift(0 - shift)
.toAmount(fractionDigits: coin.decimals);
if (_cachedAmountToSend != null && if (_cachedAmountToSend != null &&
_cachedAmountToSend == _amountToSend) { _cachedAmountToSend == _amountToSend) {
return; return;
@ -1623,17 +1608,11 @@ class _SendViewState extends ConsumerState<SendView> {
: oldValue), : oldValue),
], ],
onChanged: (baseAmountString) { onChanged: (baseAmountString) {
if (baseAmountString.isNotEmpty && final baseAmount = Amount.tryParseFiatString(
baseAmountString != "." && baseAmountString,
baseAmountString != ",") { locale: locale,
final Amount baseAmount = );
baseAmountString.contains(",") if (baseAmount != null) {
? Decimal.parse(baseAmountString
.replaceFirst(",", "."))
.toAmount(fractionDigits: 2)
: Decimal.parse(baseAmountString)
.toAmount(fractionDigits: 2);
final Decimal _price = ref final Decimal _price = ref
.read(priceAnd24hChangeNotifierProvider) .read(priceAnd24hChangeNotifierProvider)
.getPrice(coin) .getPrice(coin)

View file

@ -218,16 +218,11 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
} }
void _onFiatAmountFieldChanged(String baseAmountString) { void _onFiatAmountFieldChanged(String baseAmountString) {
if (baseAmountString.isNotEmpty && final baseAmount = Amount.tryParseFiatString(
baseAmountString != "." && baseAmountString,
baseAmountString != ",") { locale: ref.read(localeServiceChangeNotifierProvider).locale,
final baseAmount = Amount.fromDecimal( );
baseAmountString.contains(",") if (baseAmount != null) {
? Decimal.parse(baseAmountString.replaceFirst(",", "."))
: Decimal.parse(baseAmountString),
fractionDigits: tokenContract.decimals,
);
final _price = ref final _price = ref
.read(priceAnd24hChangeNotifierProvider) .read(priceAnd24hChangeNotifierProvider)
.getTokenPrice(tokenContract.address) .getTokenPrice(tokenContract.address)
@ -272,22 +267,14 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
void _cryptoAmountChanged() async { void _cryptoAmountChanged() async {
if (!_cryptoAmountChangeLock) { if (!_cryptoAmountChangeLock) {
String cryptoAmount = cryptoAmountController.text; final cryptoAmount = ref.read(pAmountFormatter(coin)).tryParse(
if (cryptoAmount.isNotEmpty && cryptoAmountController.text,
cryptoAmount != "." && locale: ref.read(localeServiceChangeNotifierProvider).locale,
cryptoAmount != ",") { coin: coin,
if (cryptoAmount.startsWith("~")) { ethContract: tokenContract,
cryptoAmount = cryptoAmount.substring(1); );
} if (cryptoAmount != null) {
if (cryptoAmount.contains(" ")) { _amountToSend = cryptoAmount;
cryptoAmount = cryptoAmount.split(" ").first;
}
_amountToSend = Amount.fromDecimal(
cryptoAmount.contains(",")
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
: Decimal.parse(cryptoAmount),
fractionDigits: tokenContract.decimals);
if (_cachedAmountToSend != null && if (_cachedAmountToSend != null &&
_cachedAmountToSend == _amountToSend) { _cachedAmountToSend == _amountToSend) {
return; return;
@ -1185,7 +1172,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
ConnectionState.done && ConnectionState.done &&
snapshot.hasData) { snapshot.hasData) {
return Text( return Text(
"~${snapshot.data! as String}", "~${snapshot.data!}",
style: style:
STextStyles.itemSubtitle( STextStyles.itemSubtitle(
context), context),

View file

@ -32,6 +32,39 @@ class Amount {
: assert(fractionDigits >= 0), : assert(fractionDigits >= 0),
_value = amount.shift(fractionDigits).toBigInt(); _value = amount.shift(fractionDigits).toBigInt();
static Amount? tryParseFiatString(
String value, {
required String locale,
}) {
final parts = value.split(" ");
if (parts.first.isEmpty) {
return null;
}
String str = parts.first;
if (str.startsWith(RegExp(r'[+-]'))) {
str = str.substring(1);
}
if (str.isEmpty) {
return null;
}
// get number symbols for decimal place and group separator
final numberSymbols = numberFormatSymbols[locale] as NumberSymbols? ??
numberFormatSymbols[locale.substring(0, 2)] as NumberSymbols?;
final groupSeparator = numberSymbols?.GROUP_SEP ?? ",";
final decimalSeparator = numberSymbols?.DECIMAL_SEP ?? ".";
str = str.replaceAll(groupSeparator, "");
final decimalString = str.replaceFirst(decimalSeparator, ".");
return Decimal.tryParse(decimalString)?.toAmount(fractionDigits: 2);
}
// =========================================================================== // ===========================================================================
// ======= Instance properties =============================================== // ======= Instance properties ===============================================
@ -67,15 +100,23 @@ class Amount {
}) { }) {
final wholeNumber = decimal.truncate(); final wholeNumber = decimal.truncate();
final String separator = // get number symbols for decimal place and group separator
(numberFormatSymbols[locale] as NumberSymbols?)?.DECIMAL_SEP ?? final numberSymbols = numberFormatSymbols[locale] as NumberSymbols? ??
(numberFormatSymbols[locale.substring(0, 2)] as NumberSymbols?) numberFormatSymbols[locale.substring(0, 2)] as NumberSymbols?;
?.DECIMAL_SEP ??
"."; final String separator = numberSymbols?.DECIMAL_SEP ?? ".";
final fraction = decimal - wholeNumber; final fraction = decimal - wholeNumber;
return "${wholeNumber.toStringAsFixed(0)}$separator${fraction.toStringAsFixed(2).substring(2)}"; String wholeNumberString = wholeNumber.toStringAsFixed(0);
// insert group separator
final regex = RegExp(r'\B(?=(\d{3})+(?!\d))');
wholeNumberString = wholeNumberString.replaceAllMapped(
regex,
(m) => "${m.group(0)}${numberSymbols?.GROUP_SEP ?? ","}",
);
return "$wholeNumberString$separator${fraction.toStringAsFixed(2).substring(2)}";
} }
// String localizedStringAsFixed({ // String localizedStringAsFixed({
// required String locale, // required String locale,

View file

@ -64,7 +64,7 @@ class AmountFormatter {
); );
} }
Amount? amountFrom( Amount? tryParse(
String string, { String string, {
required String locale, required String locale,
required Coin coin, required Coin coin,