diff --git a/lib/components/IPField.dart b/lib/components/IPField.dart index d71a1c7..108f8e9 100644 --- a/lib/components/IPField.dart +++ b/lib/components/IPField.dart @@ -50,10 +50,69 @@ class IPField extends StatelessWidget { maxLength: ipOnly ? 15 : null, maxLengthEnforced: ipOnly ? true : false, inputFormatters: ipOnly - ? [WhitelistingTextInputFormatter(RegExp(r'[\d\.]+'))] + ? [IPTextInputFormatter()] : [WhitelistingTextInputFormatter(RegExp(r'[^\s]+'))], textInputAction: this.textInputAction, placeholder: help, )); } } + +class IPTextInputFormatter extends TextInputFormatter { + final Pattern whitelistedPattern = RegExp(r'[\d\.,]+'); + + @override + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + return _selectionAwareTextManipulation( + newValue, + (String substring) { + return whitelistedPattern + .allMatches(substring) + .map((Match match) => match.group(0)) + .join().replaceAll(RegExp(r','), '.'); + }, + ); + } +} + +TextEditingValue _selectionAwareTextManipulation( + TextEditingValue value, + String substringManipulation(String substring), + ) { + final int selectionStartIndex = value.selection.start; + final int selectionEndIndex = value.selection.end; + String manipulatedText; + TextSelection manipulatedSelection; + if (selectionStartIndex < 0 || selectionEndIndex < 0) { + manipulatedText = substringManipulation(value.text); + } else { + final String beforeSelection = substringManipulation( + value.text.substring(0, selectionStartIndex) + ); + final String inSelection = substringManipulation( + value.text.substring(selectionStartIndex, selectionEndIndex) + ); + final String afterSelection = substringManipulation( + value.text.substring(selectionEndIndex) + ); + manipulatedText = beforeSelection + inSelection + afterSelection; + if (value.selection.baseOffset > value.selection.extentOffset) { + manipulatedSelection = value.selection.copyWith( + baseOffset: beforeSelection.length + inSelection.length, + extentOffset: beforeSelection.length, + ); + } else { + manipulatedSelection = value.selection.copyWith( + baseOffset: beforeSelection.length, + extentOffset: beforeSelection.length + inSelection.length, + ); + } + } + return TextEditingValue( + text: manipulatedText, + selection: manipulatedSelection ?? const TextSelection.collapsed(offset: -1), + composing: manipulatedText == value.text + ? value.composing + : TextRange.empty, + ); +}