caseyryan / flutter_multi_formatter

A set of formatters for text and input fields. Not only it can format a phone number but also automatically detect a country dial code and the name of the country. It also can apply formatting for currencies e.g. you need to convert 100000 into a USD currency value representation. Add MoneyInputFormatter and you can get it e.g. like: $100,000.00 right on the fly or whatever you need. Just see the example of usage
https://pub.dev/packages/flutter_multi_formatter
Other
307 stars 75 forks source link

CurrencyInputFormatter - Incorrect cursor position when typing 0 with a leading symbol #134

Open nizioleque opened 1 year ago

nizioleque commented 1 year ago

I am using the CurrencyInputFormatter with a leading symbol (let's say EUR).

When I enter a non-zero digit the cursor is positioned correctly next to the period (which is correct an expected behavior) - example: in an empty field I input 1. The result is EUR1|.00 where | is the cursor position.

But when I enter 0, the cursor is not positioned correctly - example: in an empty field I input 0. The result is E|UR0.00.

I would appreciate a fix for this issue :)

nizioleque commented 1 year ago

Here is my temporary walkaround for this issue:

I add two formatters before and after the CurrencyInputFormatter - the first one detects this issue, changes the 0 to a 1, then CurrencyInputFormatter sets the cursor position correctly, then the second one changes the 1 back to a 0. A List is used to pass the boolean by reference.

In the widget:

List<bool> shouldReplace = [false];

// ...

TextFormField(
  inputFormatters: [
    FixZeroBeforeInputFormatter(shouldReplace),
    CurrencyInputFormatter(leadingSymbol: 'EUR'),
    FixZeroAfterInputFormatter(shouldReplace)
  ],
)

and here are the formatters:

class FixZeroBeforeInputFormatter extends TextInputFormatter {
  FixZeroBeforeInputFormatter(this.shouldReplace);

  List<bool> shouldReplace;

  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    if (newValue.text == '0') {
      shouldReplace[0] = true;
      return newValue.copyWith(text: '1');
    }

    return newValue;
  }
}

class FixZeroAfterInputFormatter extends TextInputFormatter {
  FixZeroAfterInputFormatter(this.shouldReplace);

  List<bool> shouldReplace;

  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    bool tmpShouldReplace = shouldReplace[0];
    shouldReplace[0] = false;

    if (tmpShouldReplace) {
      String newText = newValue.text.replaceFirst('1', '0');
      return newValue.copyWith(text: newText);
    }

    return newValue;
  }
}