mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
CW-1017: Monero minor enhancements (#2347)
* feat: add max decimal handling for crypto amounts and test coverage * fix: correct decimal point handling in `withMaxDecimals` and update related test * fix: ensure amount formatting aligns with selected currency decimals in ReceivePage * fix: ensure amount controller syncs with ViewModel in AddressPage and ReceivePage * feat: add support for currency decimals and streamline amount handling logic * fix: ensure crypto and fiat amounts sync correctly in Send ViewModel
This commit is contained in:
@@ -1 +1,17 @@
|
||||
double cryptoAmountToDouble({required num amount, required num divider}) => amount / divider;
|
||||
double cryptoAmountToDouble({required num amount, required num divider}) => amount / divider;
|
||||
|
||||
extension MaxDecimals on String {
|
||||
String withMaxDecimals(int maxDecimals) {
|
||||
var parts = split(".");
|
||||
|
||||
if (parts.length > 2) {
|
||||
parts = [parts.first, parts.sublist(1, parts.length).join("")];
|
||||
}
|
||||
|
||||
if (parts.length == 2 && parts[1].length > maxDecimals) {
|
||||
parts[1] = parts[1].substring(0, maxDecimals);
|
||||
}
|
||||
|
||||
return parts.join(".");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ abstract class Currency {
|
||||
String? get tag;
|
||||
String? get fullName;
|
||||
String? get iconPath;
|
||||
}
|
||||
int get decimals;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
|
||||
void main() {
|
||||
group('String.withMaxDecimals', () {
|
||||
test('should return the original string when it has fewer decimal places than the max', () {
|
||||
final input = '123.45';
|
||||
final result = input.withMaxDecimals(3);
|
||||
|
||||
expect(result, equals(input));
|
||||
});
|
||||
|
||||
test('should truncate decimal places when the string has more than the max', () {
|
||||
final input = '123.4567';
|
||||
final result = input.withMaxDecimals(2);
|
||||
|
||||
expect(result, equals('123.45'));
|
||||
});
|
||||
|
||||
test('should handle strings with no decimal places', () {
|
||||
final input = '123';
|
||||
final result = input.withMaxDecimals(2);
|
||||
|
||||
expect(result, equals(input));
|
||||
});
|
||||
|
||||
test('should handle strings with multiple decimal points', () {
|
||||
final input = '123.45.67';
|
||||
final result = input.withMaxDecimals(4);
|
||||
|
||||
expect(result, equals('123.4567'));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -2,10 +2,16 @@ import 'package:cw_core/currency.dart';
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class FiatCurrency extends EnumerableItem<String> with Serializable<String> implements Currency {
|
||||
const FiatCurrency({required String symbol, required this.countryCode, required this.fullName}) : super(title: symbol, raw: symbol);
|
||||
const FiatCurrency({
|
||||
required String symbol,
|
||||
required this.countryCode,
|
||||
required this.fullName,
|
||||
this.decimals = 2,
|
||||
}) : super(title: symbol, raw: symbol);
|
||||
|
||||
final String countryCode;
|
||||
final String fullName;
|
||||
final int decimals;
|
||||
|
||||
static List<FiatCurrency> get all => _all.values.toList();
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/share_util.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
@@ -34,9 +33,7 @@ class AddressPage extends BasePage {
|
||||
_amountController = TextEditingController() {
|
||||
_amountController.addListener(() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
addressListViewModel.changeAmount(
|
||||
_amountController.text,
|
||||
);
|
||||
addressListViewModel.changeAmount(_amountController.text);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -79,7 +76,7 @@ class AddressPage extends BasePage {
|
||||
label: !isMobileView ? S.of(context).close : S.of(context).seed_alert_back,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
|
||||
overlayColor: WidgetStateColor.resolveWith((states) => Colors.transparent),
|
||||
),
|
||||
onPressed: () => onClose(context),
|
||||
child: !isMobileView ? _closeButton : _backButton,
|
||||
|
||||
@@ -225,6 +225,7 @@ class ExchangeCardState<T extends Currency> extends State<ExchangeCard<T>> {
|
||||
ValueKey('${_cardInstanceName}_currency_amount_textfield_widget_key'),
|
||||
imageArrow: widget.imageArrow,
|
||||
selectedCurrency: _selectedCurrency.toString(),
|
||||
selectedCurrencyDecimals: _selectedCurrency.decimals,
|
||||
amountFocusNode: widget.amountFocusNode,
|
||||
amountController: amountController,
|
||||
onTapPicker: () => _presentPicker(context),
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class CurrencyAmountTextField extends StatelessWidget {
|
||||
const CurrencyAmountTextField({
|
||||
required this.selectedCurrency,
|
||||
required this.selectedCurrencyDecimals,
|
||||
required this.amountFocusNode,
|
||||
required this.amountController,
|
||||
required this.isAmountEditable,
|
||||
@@ -42,6 +44,7 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
final Key? currencyAmountTextFieldWidgetKey;
|
||||
final Widget? imageArrow;
|
||||
final String selectedCurrency;
|
||||
final int selectedCurrencyDecimals;
|
||||
final String? tag;
|
||||
final String? hintText;
|
||||
final Color? tagBackgroundColor;
|
||||
@@ -197,6 +200,8 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
validator: isAmountEditable ? currencyValueValidator : null,
|
||||
onChanged: (value) => amountController.text =
|
||||
value.replaceAll(',', '.').withMaxDecimals(selectedCurrencyDecimals),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -211,6 +211,8 @@ class QRWidget extends StatelessWidget {
|
||||
hasUnderlineBorder: true,
|
||||
borderWidth: 0.0,
|
||||
selectedCurrency: _currencyName,
|
||||
selectedCurrencyDecimals:
|
||||
addressListViewModel.selectedCurrency.decimals,
|
||||
amountFocusNode: amountTextFieldFocusNode,
|
||||
amountController: amountController,
|
||||
padding: EdgeInsets.only(top: 20, left: _width / 4),
|
||||
|
||||
@@ -247,6 +247,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
currencyAmountTextFieldWidgetKey:
|
||||
ValueKey('send_page_crypto_currency_amount_textfield_widget_key'),
|
||||
selectedCurrency: sendViewModel.selectedCryptoCurrency.title,
|
||||
selectedCurrencyDecimals: sendViewModel.selectedCryptoCurrency.decimals,
|
||||
amountFocusNode: widget.cryptoAmountFocus,
|
||||
amountController: cryptoAmountController,
|
||||
isAmountEditable: true,
|
||||
@@ -308,6 +309,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
currencyAmountTextFieldWidgetKey:
|
||||
ValueKey('send_page_fiat_currency_amount_textfield_widget_key'),
|
||||
selectedCurrency: sendViewModel.fiat.title,
|
||||
selectedCurrencyDecimals: sendViewModel.fiat.decimals,
|
||||
amountFocusNode: widget.fiatAmountFocus,
|
||||
amountController: fiatAmountController,
|
||||
hintText: '0.00',
|
||||
|
||||
@@ -122,6 +122,7 @@ class SendTemplateCard extends StatelessWidget {
|
||||
hasUnderlineBorder: true,
|
||||
borderWidth: 0.0,
|
||||
selectedCurrency: template.selectedCurrency.title,
|
||||
selectedCurrencyDecimals: template.selectedCurrency.decimals,
|
||||
amountFocusNode: _cryptoAmountFocus,
|
||||
amountController: _cryptoAmountController,
|
||||
isSelected: template.isCryptoSelected,
|
||||
@@ -148,6 +149,7 @@ class SendTemplateCard extends StatelessWidget {
|
||||
hasUnderlineBorder: true,
|
||||
borderWidth: 0.0,
|
||||
selectedCurrency: sendTemplateViewModel.fiatCurrency,
|
||||
selectedCurrencyDecimals: sendTemplateViewModel.fiatCurrencyDecimals,
|
||||
amountFocusNode: _fiatAmountFocus,
|
||||
amountController: _fiatAmountController,
|
||||
isSelected: !template.isCryptoSelected,
|
||||
|
||||
@@ -250,7 +250,7 @@ abstract class OutputBase with Store {
|
||||
sendAll = false;
|
||||
}
|
||||
|
||||
cryptoAmount = amount.replaceAll(',', '.');
|
||||
cryptoAmount = amount;
|
||||
_updateFiatAmount();
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ abstract class SendTemplateViewModelBase with Store {
|
||||
@computed
|
||||
String get fiatCurrency => _settingsStore.fiatCurrency.title;
|
||||
|
||||
@computed
|
||||
int get fiatCurrencyDecimals => _settingsStore.fiatCurrency.decimals;
|
||||
|
||||
@computed
|
||||
ObservableList<Template> get templates => _sendTemplateStore.templates;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user