Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new formatter to block too many decimals #5

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 81 additions & 3 deletions lib/numeric_formatter.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'package:flutter/services.dart';
import 'dart:math';

import 'package:flutter/material.dart' show TextField;
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';

import 'dart:math';

///
/// An implementation of [NumberInputFormatter] automatically inserts thousands
/// separators to numeric input. For example, a input of `1234` should be
Expand Down Expand Up @@ -166,3 +166,81 @@ abstract class NumberInputFormatter extends TextInputFormatter {
TextEditingValue _formatValue(
TextEditingValue oldValue, TextEditingValue newValue);
}

/// Formatter that restricts the number of digits before and after a decimal point
class DecimalFormatter extends TextInputFormatter {
final int decimalCount;
final int numberCount;
final bool allowNegatives;
static final NumberFormat _formatter = NumberFormat.decimalPattern();
final NumberFormat formatter;

DecimalFormatter(
{this.decimalCount = 3,
this.numberCount = 7,
this.formatter,
this.allowNegatives = true})
: super();

@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
final _decimalSeparator = (formatter ?? _formatter).symbols.DECIMAL_SEP;

/// Blank string is allowed
if (newValue.text == "") {
return newValue;
}
if (newValue.text.contains("-") && !allowNegatives) {
return oldValue;
}

try {
/// Check if the number is parseable. This throws out anything that would make it invalid i.e. alpha characters.
final isNotANumber = double.tryParse(newValue.text).isNaN;
if (isNotANumber) {
return oldValue;
}
} catch (e) {
return oldValue;
}

/// Check how many decimal characters are in the string. If more than 2, kick it out.
final segments = newValue.text.split(_decimalSeparator);
final numberOfDecimal = segments.length;
if (numberOfDecimal > 2) {
return oldValue;
} else {
/// If we have a decimal
if (segments.length == 2) {
/// Check that both the number count and decimal pass
if (isDecimalPass(segments[1]) && isNumberPass(segments[0])) {
return newValue;
}
return oldValue;
} else {
/// If we don't have a decimal, just check that the number passes
if (isNumberPass(segments[0])) {
return newValue;
}
return oldValue;
}
}
}

/// checks string against decimal count
isDecimalPass(String text) {
if (text.length > decimalCount) {
return false;
}
return true;
}

/// checks string against number count
isNumberPass(String text) {
if (text.length > numberCount) {
return false;
}
return true;
}
}
29 changes: 28 additions & 1 deletion test/pattern_input_formatter_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:intl/intl.dart';

import 'package:pattern_formatter/pattern_formatter.dart';

void main() {
Expand All @@ -17,6 +16,9 @@ _numericFormatterSmokeTest() {
formatter: NumberFormat.decimalPattern('en_US'), allowFraction: true);
final CreditCardFormatter creditCardFormatter = CreditCardFormatter();

final DecimalFormatter decimalFormatterTwoDigits =
DecimalFormatter(decimalCount: 2);

test('numeric filter smoke test', () {
final newValue1 = thousandsFormatter.formatEditUpdate(
TextEditingValue(
Expand All @@ -36,11 +38,36 @@ _numericFormatterSmokeTest() {
TextEditingValue(
text: '12a', selection: TextSelection.collapsed(offset: 3)));

final twoDigitTestCharCheck = decimalFormatterTwoDigits.formatEditUpdate(
TextEditingValue(
text: '12', selection: TextSelection.collapsed(offset: 2)),
TextEditingValue(
text: '12a', selection: TextSelection.collapsed(offset: 3)));

final twoDigitTestCheck = decimalFormatterTwoDigits.formatEditUpdate(
TextEditingValue(
text: '12', selection: TextSelection.collapsed(offset: 2)),
TextEditingValue(
text: '12.1', selection: TextSelection.collapsed(offset: 3)));

final twoDigitTestTooManyDecimalsCheck =
decimalFormatterTwoDigits.formatEditUpdate(
TextEditingValue(
text: '12', selection: TextSelection.collapsed(offset: 2)),
TextEditingValue(
text: '12.133', selection: TextSelection.collapsed(offset: 3)));

expect(newValue1.text, equals('12'));

expect(newValue2.text, equals('12'));

expect(newValue3.text, equals('12'));

expect(twoDigitTestCharCheck.text, equals('12'));

expect(twoDigitTestCheck.text, equals('12.1'));

expect(twoDigitTestTooManyDecimalsCheck.text, equals('12'));
});

test('thousands grouping smoke test', () {
Expand Down