diff --git a/cw_core/lib/crypto_amount_format.dart b/cw_core/lib/crypto_amount_format.dart index a5c06e485..1be927c2a 100644 --- a/cw_core/lib/crypto_amount_format.dart +++ b/cw_core/lib/crypto_amount_format.dart @@ -1 +1,17 @@ -double cryptoAmountToDouble({required num amount, required num divider}) => amount / divider; \ No newline at end of file +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("."); + } +} diff --git a/cw_core/lib/currency.dart b/cw_core/lib/currency.dart index 4f67c4e28..f43455a3e 100644 --- a/cw_core/lib/currency.dart +++ b/cw_core/lib/currency.dart @@ -3,4 +3,5 @@ abstract class Currency { String? get tag; String? get fullName; String? get iconPath; -} \ No newline at end of file + int get decimals; +} diff --git a/cw_core/test/crypto_amount_format.dart b/cw_core/test/crypto_amount_format.dart new file mode 100644 index 000000000..0a66f3d73 --- /dev/null +++ b/cw_core/test/crypto_amount_format.dart @@ -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')); + }); + }); +} diff --git a/lib/entities/fiat_currency.dart b/lib/entities/fiat_currency.dart index 402c928b9..55eef1afe 100644 --- a/lib/entities/fiat_currency.dart +++ b/lib/entities/fiat_currency.dart @@ -2,10 +2,16 @@ import 'package:cw_core/currency.dart'; import 'package:cw_core/enumerable_item.dart'; class FiatCurrency extends EnumerableItem with Serializable 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 get all => _all.values.toList(); diff --git a/lib/src/screens/dashboard/pages/address_page.dart b/lib/src/screens/dashboard/pages/address_page.dart index ba399e82b..aa860a57f 100644 --- a/lib/src/screens/dashboard/pages/address_page.dart +++ b/lib/src/screens/dashboard/pages/address_page.dart @@ -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, diff --git a/lib/src/screens/exchange/widgets/exchange_card.dart b/lib/src/screens/exchange/widgets/exchange_card.dart index 94dd3c928..12b4748b7 100644 --- a/lib/src/screens/exchange/widgets/exchange_card.dart +++ b/lib/src/screens/exchange/widgets/exchange_card.dart @@ -225,6 +225,7 @@ class ExchangeCardState extends State> { ValueKey('${_cardInstanceName}_currency_amount_textfield_widget_key'), imageArrow: widget.imageArrow, selectedCurrency: _selectedCurrency.toString(), + selectedCurrencyDecimals: _selectedCurrency.decimals, amountFocusNode: widget.amountFocusNode, amountController: amountController, onTapPicker: () => _presentPicker(context), diff --git a/lib/src/screens/receive/widgets/currency_input_field.dart b/lib/src/screens/receive/widgets/currency_input_field.dart index c487753d9..83c5f9836 100644 --- a/lib/src/screens/receive/widgets/currency_input_field.dart +++ b/lib/src/screens/receive/widgets/currency_input_field.dart @@ -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), ), ), ), diff --git a/lib/src/screens/receive/widgets/qr_widget.dart b/lib/src/screens/receive/widgets/qr_widget.dart index a4591e092..267bcf13d 100644 --- a/lib/src/screens/receive/widgets/qr_widget.dart +++ b/lib/src/screens/receive/widgets/qr_widget.dart @@ -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), diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index a0c0a9473..c07654394 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -247,6 +247,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin with AutomaticKeepAliveClientMixin _settingsStore.fiatCurrency.title; + @computed + int get fiatCurrencyDecimals => _settingsStore.fiatCurrency.decimals; + @computed ObservableList