[flutter_releases] Flutter 1.22.3 framework cherrypicks (#69234)
* Fix TextField bug when the formatter repeatedly format (#67892)
* Adjust constraints (#68437)
* update engine
Co-authored-by: xubaolin <xubaolin@oppo.com>
Co-authored-by: Michael Thomsen <mit@google.com>
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index 596deba..45c0882 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-b8752bbfff0419c8bf616b602bc59fd28f6a3d1b
+a1440ca392ca23e874a105c5f3248b495bd0e247
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index b47d1d4..98b51f0 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -2147,8 +2147,15 @@
_lastFormattedValue = value;
}
- // Setting _value here ensures the selection and composing region info is passed.
- _value = value;
+ if (value == _value) {
+ // If the value was modified by the formatter, the remote should be notified to keep in sync,
+ // if not modified, it will short-circuit.
+ _updateRemoteEditingValueIfNeeded();
+ } else {
+ // Setting _value here ensures the selection and composing region info is passed.
+ _value = value;
+ }
+
// Use the last formatted value when an identical repeat pass is detected.
if (isRepeat && textChanged && _lastFormattedValue != null) {
_value = _lastFormattedValue;
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index 8dee45c..338f3a6 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -20,6 +20,30 @@
import 'editable_text_utils.dart';
import 'semantics_tester.dart';
+Matcher matchesMethodCall(String method, { dynamic args }) => _MatchesMethodCall(method, arguments: args == null ? null : wrapMatcher(args));
+
+class _MatchesMethodCall extends Matcher {
+ const _MatchesMethodCall(this.name, {this.arguments});
+
+ final String name;
+ final Matcher arguments;
+
+ @override
+ bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
+ if (item is MethodCall && item.method == name)
+ return arguments?.matches(item.arguments, matchState) ?? true;
+ return false;
+ }
+
+ @override
+ Description describe(Description description) {
+ final Description newDescription = description.add('has method name: ').addDescriptionOf(name);
+ if (arguments != null)
+ newDescription.add(' with arguments: ').addDescriptionOf(arguments);
+ return newDescription;
+ }
+}
+
TextEditingController controller;
final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Node');
final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'EditableText Scope Node');
@@ -4841,6 +4865,84 @@
);
});
+ testWidgets('Send text input state to engine when the input formatter rejects user input', (WidgetTester tester) async {
+ // Regression test for https://github.com/flutter/flutter/issues/67828
+ final List<MethodCall> log = <MethodCall>[];
+ SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+ log.add(methodCall);
+ });
+ final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {
+ return const TextEditingValue(text: 'Flutter is the best!');
+ });
+ final TextEditingController controller = TextEditingController();
+
+ final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node');
+ Widget builder() {
+ return StatefulBuilder(
+ builder: (BuildContext context, StateSetter setter) {
+ return MaterialApp(
+ home: MediaQuery(
+ data: const MediaQueryData(devicePixelRatio: 1.0),
+ child: Directionality(
+ textDirection: TextDirection.ltr,
+ child: Center(
+ child: Material(
+ child: EditableText(
+ controller: controller,
+ focusNode: focusNode,
+ style: textStyle,
+ cursorColor: Colors.red,
+ backgroundCursorColor: Colors.red,
+ keyboardType: TextInputType.multiline,
+ inputFormatters: <TextInputFormatter>[
+ formatter,
+ ],
+ onChanged: (String value) { },
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ );
+ }
+
+ await tester.pumpWidget(builder());
+ await tester.tap(find.byType(EditableText));
+ await tester.showKeyboard(find.byType(EditableText));
+ await tester.pump();
+
+ log.clear();
+
+ final EditableTextState state = tester.firstState(find.byType(EditableText));
+
+ // setEditingState is called when remote value modified by the formatter.
+ state.updateEditingValue(const TextEditingValue(
+ text: 'I will be modified by the formatter.',
+ ));
+ expect(log.length, 1);
+ expect(log, contains(matchesMethodCall(
+ 'TextInput.setEditingState',
+ args: allOf(
+ containsPair('text', 'Flutter is the best!'),
+ ),
+ )));
+
+ log.clear();
+
+ state.updateEditingValue(const TextEditingValue(
+ text: 'I will be modified by the formatter.',
+ ));
+ expect(log.length, 1);
+ expect(log, contains(matchesMethodCall(
+ 'TextInput.setEditingState',
+ args: allOf(
+ containsPair('text', 'Flutter is the best!'),
+ ),
+ )));
+ });
+
testWidgets('autofocus:true on first frame does not throw', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(text: testText);
controller.selection = const TextSelection(
diff --git a/packages/flutter_tools/templates/package/pubspec.yaml.tmpl b/packages/flutter_tools/templates/package/pubspec.yaml.tmpl
index 6a56bd9..122490b 100644
--- a/packages/flutter_tools/templates/package/pubspec.yaml.tmpl
+++ b/packages/flutter_tools/templates/package/pubspec.yaml.tmpl
@@ -6,7 +6,7 @@
environment:
sdk: ">=2.7.0 <3.0.0"
- flutter: ">=1.17.0 <2.0.0"
+ flutter: ">=1.17.0"
dependencies:
flutter:
diff --git a/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl b/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl
index c2f83ec..4ce3f0d 100644
--- a/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl
+++ b/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl
@@ -6,7 +6,7 @@
environment:
sdk: ">=2.7.0 <3.0.0"
- flutter: ">=1.20.0 <2.0.0"
+ flutter: ">=1.20.0"
dependencies:
flutter: