Unverified Commit 91b0bcf1 authored by Gary Qian's avatar Gary Qian Committed by GitHub

Improve text formatter repeat filter logic (#52055)

parent 665d380f
......@@ -1656,15 +1656,23 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
// Check if the new value is the same as the current local value, or is the same
// as the post-formatting value of the previous pass.
final bool textChanged = _value?.text != value?.text;
final bool isRepeat = value?.text == _lastFormattedUnmodifiedTextEditingValue?.text;
if (textChanged && !isRepeat && widget.inputFormatters != null && widget.inputFormatters.isNotEmpty) {
for (final TextInputFormatter formatter in widget.inputFormatters)
final bool isRepeatText = value?.text == _lastFormattedUnmodifiedTextEditingValue?.text;
final bool isRepeatSelection = value?.selection == _lastFormattedUnmodifiedTextEditingValue?.selection;
// Only format when the text has changed and there are available formatters.
if (!isRepeatText && textChanged && widget.inputFormatters != null && widget.inputFormatters.isNotEmpty) {
for (final TextInputFormatter formatter in widget.inputFormatters) {
value = formatter.formatEditUpdate(_value, value);
_value = value;
_updateRemoteEditingValueIfNeeded();
} else {
}
}
// If the text has changed or the selection has changed, we should update the
// locally stored TextEditingValue to the new one.
if (!isRepeatText || !isRepeatSelection) {
_value = value;
}
// Always attempt to send the value. If the value has changed, then it will send,
// otherwise, it will short-circuit.
_updateRemoteEditingValueIfNeeded();
if (textChanged && widget.onChanged != null)
widget.onChanged(value.text);
_lastFormattedUnmodifiedTextEditingValue = _receivedRemoteTextEditingValue;
......
......@@ -4238,6 +4238,61 @@ void main() {
expect(formatter.log, referenceLog);
});
testWidgets('formatter logic handles repeat filtering', (WidgetTester tester) async {
final MockTextFormatter formatter = MockTextFormatter();
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
focusNode: focusNode,
maxLines: 1, // Sets text keyboard implicitly.
style: textStyle,
cursorColor: cursorColor,
inputFormatters: <TextInputFormatter>[formatter],
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
controller.text = '';
await tester.idle();
final EditableTextState state =
tester.state<EditableTextState>(find.byType(EditableText));
expect(tester.testTextInput.editingState['text'], equals(''));
expect(state.wantKeepAlive, true);
state.updateEditingValue(const TextEditingValue(text: '01'));
state.updateEditingValue(const TextEditingValue(text: '012'));
state.updateEditingValue(const TextEditingValue(text: '0123')); // Text change causes reformat
state.updateEditingValue(const TextEditingValue(text: '0123')); // Repeat, does not format
state.updateEditingValue(const TextEditingValue(text: '0123')); // Repeat, does not format
state.updateEditingValue(const TextEditingValue(text: '0123', selection: TextSelection.collapsed(offset: 2))); // Selection change does not reformat
state.updateEditingValue(const TextEditingValue(text: '0123', selection: TextSelection.collapsed(offset: 2))); // Repeat, does not format
state.updateEditingValue(const TextEditingValue(text: '0123', selection: TextSelection.collapsed(offset: 2))); // Repeat, does not format
const List<String> referenceLog = <String>[
'[1]: , 01',
'[1]: normal aa',
'[2]: aa, 012',
'[2]: normal aaaa',
'[3]: aaaa, 0123',
'[3]: normal aaaaaa',
];
expect(formatter.log, referenceLog);
});
}
class MockTextFormatter extends TextInputFormatter {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment