Skip to content

Commit ae40340

Browse files
authored
feat: set inputFormatters for IntField
Closes #43
1 parent 783ab3a commit ae40340

File tree

4 files changed

+163
-46
lines changed

4 files changed

+163
-46
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ and this project adheres to [Dart Package Versioning](https://dart.dev/tools/pub
1212
- HexField, a text form field for entering hexadecimal digits —
1313
[41](https://github.com/dartoos-dev/well_formed/issues/41).
1414

15+
### Changed
16+
17+
- The IntField constructor sets the inputFormatters to allow only digits and
18+
the plus '+' or minus '-' signs.
19+
- IntField.pos constructor sets the inputFormatters to only allow digits and
20+
the plus '+' sign.
21+
- IntField.neg constructor sets the inputFormatters to only allow digits and
22+
the minus '-' sign.
23+
1524
### Fixed
1625

1726
- some sections of the README file.

lib/src/numeric/hex_field.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import 'package:well_formed/well_formed.dart';
55

66
/// Hexadecimal-only Form Field.
77
///
8-
/// Hexadecimal: any one of the sixteen hexadecimal hexs [0–9a-fA–F].
9-
/// Non-hex characters must somehow be filtered out so that they do not appear
10-
/// in the form field. To achieve this, this widget:
8+
/// Hexadecimal: any one of the sixteen hexadecimal digits [0–9a-fA–F]. Non-hex
9+
/// characters must somehow be filtered out so that they do not appear in the
10+
/// form field. To achieve this, this widget:
1111
///
1212
/// - sets up a validator to block non-hex characters;
1313
/// - sets the [inputFormatters] to deny non-hexadecimal characters.

lib/src/numeric/int_field.dart

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import 'package:well_formed/well_formed.dart';
1313
/// appear in the form field. This is accomplished by setting the following:
1414
///
1515
/// - [Int] as the validator to limit input data to integer values
16+
/// - the [inputFormatters] to deny non-digt characters except the minus
17+
/// '-' and plus '+' signs.
1618
/// - [TextInputType.numberWithOptions] as the keyboardType.
1719
class IntField extends StatelessWidget {
1820
/// Integer Numbers Form Field.
@@ -43,8 +45,8 @@ class IntField extends StatelessWidget {
4345
VoidCallback? onEditingComplete,
4446
ValueChanged<String>? onFieldSubmitted,
4547
FormFieldSetter<String>? onSaved,
46-
List<TextInputFormatter>? inputFormatters,
4748
bool? enabled,
49+
List<TextInputFormatter>? inputFormatters,
4850
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
4951
bool enableInteractiveSelection = true,
5052
AutovalidateMode? autovalidateMode,
@@ -53,7 +55,8 @@ class IntField extends StatelessWidget {
5355
return BasicTextField(
5456
validator: Pair.str(Int(mal: malformed), validator ?? _dummy),
5557
keyboardType: const TextInputType.numberWithOptions(signed: true),
56-
inputFormatters: inputFormatters,
58+
inputFormatters: inputFormatters ??
59+
[FilteringTextInputFormatter.allow(RegExp('[0-9+-]'))],
5760
blank: blank,
5861
trim: trim,
5962
decoration: decoration ?? const InputDecoration(),
@@ -112,7 +115,6 @@ class IntField extends StatelessWidget {
112115
VoidCallback? onEditingComplete,
113116
ValueChanged<String>? onFieldSubmitted,
114117
FormFieldSetter<String>? onSaved,
115-
List<TextInputFormatter>? inputFormatters,
116118
bool? enabled,
117119
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
118120
bool enableInteractiveSelection = true,
@@ -139,15 +141,17 @@ class IntField extends StatelessWidget {
139141
onEditingComplete: onEditingComplete,
140142
onFieldSubmitted: onFieldSubmitted,
141143
onSaved: onSaved,
142-
inputFormatters: inputFormatters,
143144
enabled: enabled,
144145
scrollPadding: scrollPadding,
145146
enableInteractiveSelection: enableInteractiveSelection,
146147
autovalidateMode: autovalidateMode,
147148
key: key,
148149
);
149150

150-
/// Constrains entered data to positive integers.
151+
/// Constrains data to positive integers.
152+
///
153+
/// It sets the [inputFormatters] to deny non-digt characters except the plus
154+
/// '+' sign.
151155
///
152156
/// [trim] whether or not to trim the input value.
153157
/// [validator] an optional extra validation step.
@@ -177,14 +181,16 @@ class IntField extends StatelessWidget {
177181
VoidCallback? onEditingComplete,
178182
ValueChanged<String>? onFieldSubmitted,
179183
FormFieldSetter<String>? onSaved,
180-
List<TextInputFormatter>? inputFormatters,
181184
bool? enabled,
182185
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
183186
bool enableInteractiveSelection = true,
184187
AutovalidateMode? autovalidateMode,
185188
Key? key,
186189
}) : this(
187190
validator: Pair.str(Int.pos(neg: neg), validator ?? _dummy),
191+
inputFormatters: [
192+
FilteringTextInputFormatter.allow(RegExp('[0-9+]')),
193+
],
188194
malformed: malformed,
189195
blank: blank,
190196
trim: trim,
@@ -204,7 +210,6 @@ class IntField extends StatelessWidget {
204210
onEditingComplete: onEditingComplete,
205211
onFieldSubmitted: onFieldSubmitted,
206212
onSaved: onSaved,
207-
inputFormatters: inputFormatters,
208213
enabled: enabled,
209214
scrollPadding: scrollPadding,
210215
enableInteractiveSelection: enableInteractiveSelection,
@@ -244,7 +249,6 @@ class IntField extends StatelessWidget {
244249
VoidCallback? onEditingComplete,
245250
ValueChanged<String>? onFieldSubmitted,
246251
FormFieldSetter<String>? onSaved,
247-
List<TextInputFormatter>? inputFormatters,
248252
bool? enabled,
249253
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
250254
bool enableInteractiveSelection = true,
@@ -271,7 +275,6 @@ class IntField extends StatelessWidget {
271275
onEditingComplete: onEditingComplete,
272276
onFieldSubmitted: onFieldSubmitted,
273277
onSaved: onSaved,
274-
inputFormatters: inputFormatters,
275278
enabled: enabled,
276279
scrollPadding: scrollPadding,
277280
enableInteractiveSelection: enableInteractiveSelection,
@@ -281,6 +284,9 @@ class IntField extends StatelessWidget {
281284

282285
/// Constrains entered data to negative integers.
283286
///
287+
/// It sets the [inputFormatters] to deny non-digt characters except the minus
288+
/// '-' sign.
289+
///
284290
/// [trim] whether or not to trim the input value.
285291
/// [validator] an optional extra validation step.
286292
/// [blank] the error message in case of blank field; if omitted, the field
@@ -309,14 +315,16 @@ class IntField extends StatelessWidget {
309315
VoidCallback? onEditingComplete,
310316
ValueChanged<String>? onFieldSubmitted,
311317
FormFieldSetter<String>? onSaved,
312-
List<TextInputFormatter>? inputFormatters,
313318
bool? enabled,
314319
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
315320
bool enableInteractiveSelection = true,
316321
AutovalidateMode? autovalidateMode,
317322
Key? key,
318323
}) : this(
319324
validator: Pair.str(Int.neg(pos: pos), validator ?? _dummy),
325+
inputFormatters: [
326+
FilteringTextInputFormatter.allow(RegExp('[0-9-]')),
327+
],
320328
malformed: malformed,
321329
blank: blank,
322330
trim: trim,
@@ -336,7 +344,6 @@ class IntField extends StatelessWidget {
336344
onEditingComplete: onEditingComplete,
337345
onFieldSubmitted: onFieldSubmitted,
338346
onSaved: onSaved,
339-
inputFormatters: inputFormatters,
340347
enabled: enabled,
341348
scrollPadding: scrollPadding,
342349
enableInteractiveSelection: enableInteractiveSelection,
@@ -379,7 +386,6 @@ class IntField extends StatelessWidget {
379386
VoidCallback? onEditingComplete,
380387
ValueChanged<String>? onFieldSubmitted,
381388
FormFieldSetter<String>? onSaved,
382-
List<TextInputFormatter>? inputFormatters,
383389
bool? enabled,
384390
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
385391
bool enableInteractiveSelection = true,
@@ -409,7 +415,6 @@ class IntField extends StatelessWidget {
409415
onEditingComplete: onEditingComplete,
410416
onFieldSubmitted: onFieldSubmitted,
411417
onSaved: onSaved,
412-
inputFormatters: inputFormatters,
413418
enabled: enabled,
414419
scrollPadding: scrollPadding,
415420
enableInteractiveSelection: enableInteractiveSelection,

test/numeric/int_field_test.dart

Lines changed: 133 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
22
import 'package:flutter/services.dart';
33
import 'package:flutter_test/flutter_test.dart';
44
import 'package:formdator/formdator.dart';
5-
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';
65
import 'package:well_formed/src/core/well_formed.dart';
76
import 'package:well_formed/src/numeric/int_field.dart';
87

@@ -728,35 +727,139 @@ Future<void> main() async {
728727
}
729728
});
730729

731-
/// non-digit characters must be filtered out by the input formatter so that
732-
/// they do not appear in the form field.
733-
testWidgets('inputFormatters', (WidgetTester tester) async {
734-
final formatters = [
735-
MaskTextInputFormatter(
736-
mask: '###.###.###-##',
737-
filter: {"#": RegExp(r'\d')},
738-
),
739-
];
740-
await tester.pumpWidget(
741-
WellFormed.app([
742-
IntField(key: kDef, inputFormatters: formatters),
743-
IntField.min(1, key: kMin, inputFormatters: formatters),
744-
IntField.pos(key: kPos, inputFormatters: formatters),
745-
IntField.max(10, key: kMax, inputFormatters: formatters),
746-
IntField.neg(key: kNeg, inputFormatters: formatters),
747-
IntField.range(15, 25, key: kRange, inputFormatters: formatters),
748-
]),
749-
);
750-
await tester.pumpAndSettle();
751-
for (var i = 0; i < keys.length; ++i) {
752-
final unmasked = '$i$i$i$i$i$i$i$i$i$i$i'; // E.g. 11111111111
753-
final masked = '$i$i$i.$i$i$i.$i$i$i-$i$i'; // E.g. 111.111.111-11
754-
await tester.enterText(find.byKey(keys[i]), unmasked);
755-
await tester.pumpAndSettle();
756-
final elem = tester.widget(find.widgetWithText(TextField, masked));
757-
expect((elem as TextField).inputFormatters, formatters);
758-
expect(find.text(masked), findsOneWidget);
759-
}
730+
/// The minus '-' and plus '+' signs must be accepted along with the digits
731+
/// 0–9.
732+
group('inputFormatters', () {
733+
group('no prefix', () {
734+
const masked = '12.34/5';
735+
const unmasked = '12345';
736+
testWidgets('default ctor', (WidgetTester tester) async {
737+
await tester.pumpWidget(WellFormed.app([IntField(key: kDef)]));
738+
await tester.enterText(find.byKey(kDef), masked);
739+
await tester.pumpAndSettle();
740+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
741+
});
742+
testWidgets('min ctor', (WidgetTester tester) async {
743+
await tester.pumpWidget(WellFormed.app([IntField.min(1, key: kMin)]));
744+
await tester.enterText(find.byKey(kMin), masked);
745+
await tester.pumpAndSettle();
746+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
747+
});
748+
testWidgets('pos ctor', (WidgetTester tester) async {
749+
await tester.pumpWidget(WellFormed.app([IntField.pos(key: kMin)]));
750+
await tester.enterText(find.byKey(kMin), masked);
751+
await tester.pumpAndSettle();
752+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
753+
});
754+
testWidgets('max ctor', (WidgetTester tester) async {
755+
await tester
756+
.pumpWidget(WellFormed.app([IntField.max(99999, key: kMax)]));
757+
await tester.enterText(find.byKey(kMax), masked);
758+
await tester.pumpAndSettle();
759+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
760+
});
761+
testWidgets('neg ctor', (WidgetTester tester) async {
762+
await tester.pumpWidget(WellFormed.app([IntField.neg(key: kMax)]));
763+
await tester.enterText(find.byKey(kMax), masked);
764+
await tester.pumpAndSettle();
765+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
766+
});
767+
testWidgets('range ctor', (WidgetTester tester) async {
768+
await tester.pumpWidget(
769+
WellFormed.app([IntField.range(1, 99999, key: kRange)]),
770+
);
771+
await tester.enterText(find.byKey(kRange), masked);
772+
await tester.pumpAndSettle();
773+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
774+
});
775+
});
776+
group('plus sign prefix', () {
777+
const masked = '+12.34/5';
778+
const unmasked = '+12345';
779+
const mod = '12345'; // modulus: no sign.
780+
781+
testWidgets('default ctor', (WidgetTester tester) async {
782+
await tester.pumpWidget(WellFormed.app([IntField(key: kDef)]));
783+
await tester.enterText(find.byKey(kDef), masked);
784+
await tester.pumpAndSettle();
785+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
786+
});
787+
testWidgets('min ctor', (WidgetTester tester) async {
788+
await tester.pumpWidget(WellFormed.app([IntField.min(1, key: kMin)]));
789+
await tester.enterText(find.byKey(kMin), masked);
790+
await tester.pumpAndSettle();
791+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
792+
});
793+
testWidgets('pos ctor', (WidgetTester tester) async {
794+
await tester.pumpWidget(WellFormed.app([IntField.pos(key: kMin)]));
795+
await tester.enterText(find.byKey(kMin), masked);
796+
await tester.pumpAndSettle();
797+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
798+
});
799+
testWidgets('max ctor', (WidgetTester tester) async {
800+
await tester
801+
.pumpWidget(WellFormed.app([IntField.max(99999, key: kMax)]));
802+
await tester.enterText(find.byKey(kMax), masked);
803+
await tester.pumpAndSettle();
804+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
805+
});
806+
testWidgets('neg ctor', (WidgetTester tester) async {
807+
await tester.pumpWidget(WellFormed.app([IntField.neg(key: kMin)]));
808+
await tester.enterText(find.byKey(kMin), masked);
809+
await tester.pumpAndSettle();
810+
expect(find.widgetWithText(TextFormField, mod), findsOneWidget);
811+
});
812+
testWidgets('range ctor', (WidgetTester tester) async {
813+
await tester.pumpWidget(
814+
WellFormed.app([IntField.range(1, 99999, key: kRange)]),
815+
);
816+
await tester.enterText(find.byKey(kRange), masked);
817+
await tester.pumpAndSettle();
818+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
819+
});
820+
});
821+
group('minus sign prefix', () {
822+
const masked = '-12.34/5';
823+
const unmasked = '-12345';
824+
const mod = '12345';
825+
826+
testWidgets('default ctor', (WidgetTester tester) async {
827+
await tester.pumpWidget(WellFormed.app([IntField(key: kDef)]));
828+
await tester.enterText(find.byKey(kDef), masked);
829+
await tester.pumpAndSettle();
830+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
831+
});
832+
testWidgets('min ctor', (WidgetTester tester) async {
833+
await tester
834+
.pumpWidget(WellFormed.app([IntField.min(-99999, key: kMin)]));
835+
await tester.enterText(find.byKey(kMin), masked);
836+
await tester.pumpAndSettle();
837+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
838+
});
839+
840+
/// Must get rid of the minus '-' sign.
841+
testWidgets('pos ctor', (WidgetTester tester) async {
842+
await tester.pumpWidget(WellFormed.app([IntField.pos(key: kMin)]));
843+
await tester.enterText(find.byKey(kMin), masked);
844+
await tester.pumpAndSettle();
845+
expect(find.widgetWithText(TextFormField, mod), findsOneWidget);
846+
});
847+
testWidgets('max ctor', (WidgetTester tester) async {
848+
await tester
849+
.pumpWidget(WellFormed.app([IntField.max(99999, key: kMax)]));
850+
await tester.enterText(find.byKey(kMax), masked);
851+
await tester.pumpAndSettle();
852+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
853+
});
854+
testWidgets('range ctor', (WidgetTester tester) async {
855+
await tester.pumpWidget(
856+
WellFormed.app([IntField.range(1, 99999, key: kRange)]),
857+
);
858+
await tester.enterText(find.byKey(kRange), masked);
859+
await tester.pumpAndSettle();
860+
expect(find.widgetWithText(TextFormField, unmasked), findsOneWidget);
861+
});
862+
});
760863
});
761864
testWidgets('enabled', (WidgetTester tester) async {
762865
const enabled = false;

0 commit comments

Comments
 (0)