From bc67d224495cacd760e3087bab0e42d6e3c6fd48 Mon Sep 17 00:00:00 2001 From: Lau Ching Jun Date: Wed, 18 Dec 2019 13:56:44 -0800 Subject: [PATCH] Revert "iOS UITextInput autocorrection prompt (#45354)" (#47373) This reverts commit 0f8c0da0a9ded2a9b7aa3bd01fcc29db80bbab0a. --- .../flutter/lib/src/cupertino/text_field.dart | 5 +- .../flutter/lib/src/material/text_field.dart | 3 - .../flutter/lib/src/rendering/editable.dart | 61 +------------- .../flutter/lib/src/services/text_input.dart | 9 --- .../lib/src/widgets/editable_text.dart | 41 +--------- .../flutter/test/rendering/editable_test.dart | 38 --------- .../test/services/text_input_test.dart | 31 ------- .../test/widgets/editable_text_test.dart | 81 ------------------- 8 files changed, 3 insertions(+), 266 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index dabb121610..805f4a12f6 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -876,8 +876,6 @@ class _CupertinoTextFieldState extends State with AutomaticK color: enabled ? decorationColor : (decorationColor ?? disabledColor), ); - final Color selectionColor = CupertinoTheme.of(context).primaryColor.withOpacity(0.2); - final Widget paddedEditable = Padding( padding: widget.padding, child: RepaintBoundary( @@ -904,7 +902,7 @@ class _CupertinoTextFieldState extends State with AutomaticK maxLines: widget.maxLines, minLines: widget.minLines, expands: widget.expands, - selectionColor: selectionColor, + selectionColor: CupertinoTheme.of(context).primaryColor.withOpacity(0.2), selectionControls: widget.selectionEnabled ? cupertinoTextSelectionControls : null, onChanged: widget.onChanged, @@ -919,7 +917,6 @@ class _CupertinoTextFieldState extends State with AutomaticK cursorOpacityAnimates: true, cursorOffset: cursorOffset, paintCursorAboveText: true, - autocorrectionTextRectColor: selectionColor, backgroundCursorColor: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context), scrollPadding: widget.scrollPadding, keyboardAppearance: keyboardAppearance, diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 7cf3c73572..45e14d4b67 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -942,7 +942,6 @@ class _TextFieldState extends State implements TextSelectionGestureDe bool cursorOpacityAnimates; Offset cursorOffset; Color cursorColor = widget.cursorColor; - Color autocorrectionTextRectColor; Radius cursorRadius = widget.cursorRadius; switch (themeData.platform) { @@ -955,7 +954,6 @@ class _TextFieldState extends State implements TextSelectionGestureDe cursorColor ??= CupertinoTheme.of(context).primaryColor; cursorRadius ??= const Radius.circular(2.0); cursorOffset = Offset(iOSHorizontalOffset / MediaQuery.of(context).devicePixelRatio, 0); - autocorrectionTextRectColor = themeData.textSelectionColor; break; case TargetPlatform.android: @@ -1015,7 +1013,6 @@ class _TextFieldState extends State implements TextSelectionGestureDe dragStartBehavior: widget.dragStartBehavior, scrollController: widget.scrollController, scrollPhysics: widget.scrollPhysics, - autocorrectionTextRectColor: autocorrectionTextRectColor, ), ); diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 8a5769275b..dfef98c15c 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -210,8 +210,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { double devicePixelRatio = 1.0, bool enableInteractiveSelection, EdgeInsets floatingCursorAddedMargin = const EdgeInsets.fromLTRB(4, 4, 4, 5), - TextRange promptRectRange, - Color promptRectColor, @required this.textSelectionDelegate, }) : assert(textAlign != null), assert(textDirection != null, 'RenderEditable created without a textDirection.'), @@ -268,13 +266,10 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { _endHandleLayerLink = endHandleLayerLink, _obscureText = obscureText, _readOnly = readOnly, - _forceLine = forceLine, - _promptRectRange = promptRectRange { + _forceLine = forceLine { assert(_showCursor != null); assert(!_showCursor.value || cursorColor != null); this.hasFocus = hasFocus ?? false; - if (promptRectColor != null) - _promptRectPaint.color = promptRectColor; } /// Character used to obscure text if [obscureText] is true. @@ -1118,40 +1113,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { return enableInteractiveSelection ?? !obscureText; } - /// The color used to paint the prompt rectangle. - /// - /// The prompt rectangle will only be requested on non-web iOS applications. - Color get promptRectColor => _promptRectPaint.color; - set promptRectColor(Color newValue) { - // Painter.color can not be null. - if (newValue == null) { - setPromptRectRange(null); - return; - } - - if (promptRectColor == newValue) - return; - - _promptRectPaint.color = newValue; - if (_promptRectRange != null) - markNeedsPaint(); - } - - TextRange _promptRectRange; - /// Dismisses the currently displayed prompt rectangle and displays a new prompt rectangle - /// over [newRange] in the given color [promptRectColor]. - /// - /// The prompt rectangle will only be requested on non-web iOS applications. - /// - /// When set to null, the currently displayed prompt rectangle (if any) will be dismissed. - void setPromptRectRange(TextRange newRange) { - if (_promptRectRange == newRange) - return; - - _promptRectRange = newRange; - markNeedsPaint(); - } - /// The maximum amount the text is allowed to scroll. /// /// This value is only valid after layout and can change as additional @@ -1951,24 +1912,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { canvas.drawRect(box.toRect().shift(effectiveOffset), paint); } - final Paint _promptRectPaint = Paint(); - void _paintPromptRectIfNeeded(Canvas canvas, Offset effectiveOffset) { - if (_promptRectRange == null || promptRectColor == null) { - return; - } - - final List boxes = _textPainter.getBoxesForSelection( - TextSelection( - baseOffset: _promptRectRange.start, - extentOffset: _promptRectRange.end, - ), - ); - - for (TextBox box in boxes) { - canvas.drawRect(box.toRect().shift(effectiveOffset), _promptRectPaint); - } - } - void _paintContents(PaintingContext context, Offset offset) { assert(_textLayoutLastMaxWidth == constraints.maxWidth && _textLayoutLastMinWidth == constraints.minWidth, @@ -1991,8 +1934,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { _paintSelection(context.canvas, effectiveOffset); } - _paintPromptRectIfNeeded(context.canvas, effectiveOffset); - // On iOS, the cursor is painted over the text, on Android, it's painted // under it. if (paintCursorAboveText) diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index ab9bf3b531..a276897a1b 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -753,12 +753,6 @@ abstract class TextInputClient { /// Updates the floating cursor position and state. void updateFloatingCursor(RawFloatingCursorPoint point); - /// Requests that this client display a prompt rectangle for the given text range, - /// to indicate the range of text that will be changed by a pending autocorrection. - /// - /// This method will only be called on iOS. - void showAutocorrectionPromptRect(int start, int end); - /// Platform notified framework of closed connection. /// /// [TextInputClient] should cleanup its connection and finalize editing. @@ -1082,9 +1076,6 @@ class TextInput { case 'TextInputClient.onConnectionClosed': _currentConnection._client.connectionClosed(); break; - case 'TextInputClient.showAutocorrectionPromptRect': - _currentConnection._client.showAutocorrectionPromptRect(args[1], args[2]); - break; default: throw MissingPluginException(); } diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 5272642768..db503c4d33 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -395,7 +395,6 @@ class EditableText extends StatefulWidget { this.enableInteractiveSelection = true, this.scrollController, this.scrollPhysics, - this.autocorrectionTextRectColor, this.toolbarOptions = const ToolbarOptions( copy: true, cut: true, @@ -635,18 +634,6 @@ class EditableText extends StatefulWidget { /// Cannot be null. final Color cursorColor; - /// The color to use when painting the autocorrection Rect. - /// - /// For [CupertinoTextField]s, the value is set to the ambient - /// [CupertinoThemeData.primaryColor] with 20% opacity. For [TextField]s, the - /// value is null on non-iOS platforms and the same color used in [CupertinoTextField] - /// on iOS. - /// - /// Currently the autocorrection Rect only appears on iOS. - /// - /// Defaults to null, which disables autocorrection Rect painting. - final Color autocorrectionTextRectColor; - /// The color to use when painting the background cursor aligned with the text /// while rendering the floating cursor. /// @@ -750,10 +737,6 @@ class EditableText extends StatefulWidget { final bool autofocus; /// The color to use when painting the selection. - /// - /// For [CupertinoTextField]s, the value is set to the ambient - /// [CupertinoThemeData.primaryColor] with 20% opacity. For [TextField]s, the - /// value is set to the ambient [ThemeData.textSelectionColor]. final Color selectionColor; /// Optional delegate for building the text selection handles and toolbar. @@ -1229,7 +1212,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien if (value.text != _value.text) { hideToolbar(); _showCaretOnScreen(); - _currentPromptRectRange = null; if (widget.obscureText && value.text.length == _value.text.length + 1) { _obscureShowCharTicksPending = _kObscureShowLatestCharCursorTicks; _obscureLatestCharIndex = _value.selection.baseOffset; @@ -1752,7 +1734,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien WidgetsBinding.instance.removeObserver(this); // Clear the selection and composition state if this widget lost focus. _value = TextEditingValue(text: _value.text); - _currentPromptRectRange = null; } updateKeepAlive(); } @@ -1831,16 +1812,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien } } - // null if no promptRect should be shown. - TextRange _currentPromptRectRange; - - @override - void showAutocorrectionPromptRect(int start, int end) { - setState(() { - _currentPromptRectRange = TextRange(start: start, end: end); - }); - } - VoidCallback _semanticsOnCopy(TextSelectionControls controls) { return widget.selectionEnabled && copyEnabled && _hasFocus && controls?.canCopy(this) == true ? () => controls.handleCopy(this) @@ -1919,8 +1890,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien enableInteractiveSelection: widget.enableInteractiveSelection, textSelectionDelegate: this, devicePixelRatio: _devicePixelRatio, - promptRectRange: _currentPromptRectRange, - promptRectColor: widget.autocorrectionTextRectColor, ), ), ); @@ -1989,8 +1958,6 @@ class _Editable extends LeafRenderObjectWidget { this.textSelectionDelegate, this.paintCursorAboveText, this.devicePixelRatio, - this.promptRectRange, - this.promptRectColor, }) : assert(textDirection != null), assert(rendererIgnoresPointer != null), super(key: key); @@ -2031,8 +1998,6 @@ class _Editable extends LeafRenderObjectWidget { final TextSelectionDelegate textSelectionDelegate; final double devicePixelRatio; final bool paintCursorAboveText; - final TextRange promptRectRange; - final Color promptRectColor; @override RenderEditable createRenderObject(BuildContext context) { @@ -2069,8 +2034,6 @@ class _Editable extends LeafRenderObjectWidget { enableInteractiveSelection: enableInteractiveSelection, textSelectionDelegate: textSelectionDelegate, devicePixelRatio: devicePixelRatio, - promptRectRange: promptRectRange, - promptRectColor: promptRectColor, ); } @@ -2106,8 +2069,6 @@ class _Editable extends LeafRenderObjectWidget { ..cursorOffset = cursorOffset ..textSelectionDelegate = textSelectionDelegate ..devicePixelRatio = devicePixelRatio - ..paintCursorAboveText = paintCursorAboveText - ..promptRectColor = promptRectColor - ..setPromptRectRange(promptRectRange); + ..paintCursorAboveText = paintCursorAboveText; } } diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart index 39251aace9..c25d40298b 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -546,44 +546,6 @@ void main() { expect(selectionChangedCount, 1); }, skip: isBrowser); - test('promptRect disappears when promptRectColor is set to null', () { - const Color promptRectColor = Color(0x12345678); - final TextSelectionDelegate delegate = FakeEditableTextState(); - final RenderEditable editable = RenderEditable( - text: const TextSpan( - style: TextStyle(height: 1.0, fontSize: 10.0, fontFamily: 'Ahem'), - text: 'ABCDEFG', - ), - startHandleLayerLink: LayerLink(), - endHandleLayerLink: LayerLink(), - textAlign: TextAlign.start, - textDirection: TextDirection.ltr, - locale: const Locale('en', 'US'), - offset: ViewportOffset.fixed(10.0), - textSelectionDelegate: delegate, - selection: const TextSelection.collapsed(offset: 0), - promptRectColor: promptRectColor, - promptRectRange: const TextRange(start: 0, end: 1), - ); - editable.layout(BoxConstraints.loose(const Size(1000.0, 1000.0))); - - expect( - (Canvas canvas) => editable.paint(TestRecordingPaintingContext(canvas), Offset.zero), - paints..rect(color: promptRectColor), - ); - - editable.promptRectColor = null; - - editable.layout(BoxConstraints.loose(const Size(1000.0, 1000.0))); - pumpFrame(); - - expect(editable.promptRectColor, promptRectColor); - expect( - (Canvas canvas) => editable.paint(TestRecordingPaintingContext(canvas), Offset.zero), - isNot(paints..rect(color: promptRectColor)), - ); - }); - test('editable hasFocus correctly initialized', () { // Regression test for https://github.com/flutter/flutter/issues/21640 final TextSelectionDelegate delegate = FakeEditableTextState(); diff --git a/packages/flutter/test/services/text_input_test.dart b/packages/flutter/test/services/text_input_test.dart index b357792045..5de8e1b57f 100644 --- a/packages/flutter/test/services/text_input_test.dart +++ b/packages/flutter/test/services/text_input_test.dart @@ -72,10 +72,6 @@ void main() { }); group('TextInputConfiguration', () { - tearDown(() { - TextInputConnection.debugResetId(); - }); - test('sets expected defaults', () { const TextInputConfiguration configuration = TextInputConfiguration(); expect(configuration.inputType, TextInputType.text); @@ -176,28 +172,6 @@ void main() { expect(client.latestMethodCall, 'connectionClosed'); }); - - test('TextInputClient showAutocorrectionPromptRect method is called', () async { - // Assemble a TextInputConnection so we can verify its change in state. - final FakeTextInputClient client = FakeTextInputClient(); - const TextInputConfiguration configuration = TextInputConfiguration(); - TextInput.attach(client, configuration); - - expect(client.latestMethodCall, isEmpty); - - // Send onConnectionClosed message. - final ByteData messageBytes = const JSONMessageCodec().encodeMessage({ - 'args': [1, 0, 1], - 'method': 'TextInputClient.showAutocorrectionPromptRect', - }); - await ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( - 'flutter/textinput', - messageBytes, - (ByteData _) {}, - ); - - expect(client.latestMethodCall, 'showAutocorrectionPromptRect'); - }); }); } @@ -224,11 +198,6 @@ class FakeTextInputClient implements TextInputClient { latestMethodCall = 'connectionClosed'; } - @override - void showAutocorrectionPromptRect(int start, int end) { - latestMethodCall = 'showAutocorrectionPromptRect'; - } - TextInputConfiguration get configuration => const TextInputConfiguration(); } diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 7094ca64b1..3c1a3129a5 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -13,7 +13,6 @@ import 'package:flutter/services.dart'; import 'package:mockito/mockito.dart'; import 'package:flutter/foundation.dart'; -import '../rendering/mock_canvas.dart'; import 'editable_text_utils.dart'; import 'semantics_tester.dart'; @@ -1339,86 +1338,6 @@ void main() { assert(!onEditingCompleteCalled); }); - testWidgets( - 'iOS autocorrection rectangle should appear on demand' - 'and dismiss when the text changes or when focus is lost', - (WidgetTester tester) async { - const Color rectColor = Color(0xFFFF0000); - - void verifyAutocorrectionRectVisibility({ bool expectVisible }) { - PaintPattern evaluate() { - if (expectVisible) { - return paints..something(((Symbol method, List arguments) { - if (method != #drawRect) - return false; - final Paint paint = arguments[1]; - return paint.color == rectColor; - })); - } else { - return paints..everything(((Symbol method, List arguments) { - if (method != #drawRect) - return true; - final Paint paint = arguments[1]; - if (paint.color != rectColor) - return true; - throw 'Expected: autocorrection rect not visible, found: ${arguments[0]}'; - })); - } - } - - expect(findRenderEditable(tester), evaluate()); - } - - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(text: 'ABCDEFG'); - - final Widget widget = MaterialApp( - home: EditableText( - backgroundCursorColor: Colors.grey, - controller: controller, - focusNode: focusNode, - style: Typography(platform: TargetPlatform.android).black.subhead, - cursorColor: Colors.blue, - autocorrect: true, - autocorrectionTextRectColor: rectColor, - showCursor: false, - onEditingComplete: () { }, - ), - ); - - await tester.pumpWidget(widget); - - await tester.tap(find.byType(EditableText)); - await tester.pump(); - final EditableTextState state = tester.state(find.byType(EditableText)); - - assert(focusNode.hasFocus); - - // The prompt rect should be invisible initially. - verifyAutocorrectionRectVisibility(expectVisible: false); - - state.showAutocorrectionPromptRect(0, 1); - await tester.pump(); - - // Show prompt rect when told to. - verifyAutocorrectionRectVisibility(expectVisible: true); - - // Text changed, prompt rect goes away. - controller.text = '12345'; - await tester.pump(); - verifyAutocorrectionRectVisibility(expectVisible: false); - - state.showAutocorrectionPromptRect(0, 1); - await tester.pump(); - - verifyAutocorrectionRectVisibility(expectVisible: true); - - // Unfocus, prompt rect should go away. - focusNode.unfocus(); - await tester.pump(); - verifyAutocorrectionRectVisibility(expectVisible: false); - }); - testWidgets('Changing controller updates EditableText', (WidgetTester tester) async { final TextEditingController controller1 = TextEditingController(text: 'Wibble');