Revert "Support Scribble Handwriting" (#96615)
diff --git a/AUTHORS b/AUTHORS
index f79d1cc..c6f1a90 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -89,4 +89,3 @@
Kai Yu <yk3372@gmail.com>
Denis Grafov <grafov.denis@gmail.com>
TheOneWithTheBraid <the-one@with-the-braid.cf>
-Twin Sun, LLC <google-contrib@twinsunsolutions.com>
diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart
index a1e37a9..c2efc04 100644
--- a/packages/flutter/lib/src/cupertino/text_field.dart
+++ b/packages/flutter/lib/src/cupertino/text_field.dart
@@ -297,7 +297,6 @@
this.autofillHints = const <String>[],
this.clipBehavior = Clip.hardEdge,
this.restorationId,
- this.scribbleEnabled = true,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
@@ -455,7 +454,6 @@
this.autofillHints = const <String>[],
this.clipBehavior = Clip.hardEdge,
this.restorationId,
- this.scribbleEnabled = true,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
@@ -800,9 +798,6 @@
/// {@macro flutter.material.textfield.restorationId}
final String? restorationId;
- /// {@macro flutter.widgets.editableText.scribbleEnabled}
- final bool scribbleEnabled;
-
/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;
@@ -848,7 +843,6 @@
properties.add(DiagnosticsProperty<TextAlignVertical>('textAlignVertical', textAlignVertical, defaultValue: null));
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior, defaultValue: Clip.hardEdge));
- properties.add(DiagnosticsProperty<bool>('scribbleEnabled', scribbleEnabled, defaultValue: true));
properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
}
}
@@ -969,9 +963,6 @@
if (cause == SelectionChangedCause.keyboard)
return false;
- if (cause == SelectionChangedCause.scribble)
- return true;
-
if (_effectiveController.text.isNotEmpty)
return true;
@@ -1301,7 +1292,6 @@
autofillClient: this,
clipBehavior: widget.clipBehavior,
restorationId: 'editable',
- scribbleEnabled: widget.scribbleEnabled,
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
),
),
diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart
index 076f084..0fc2a87 100644
--- a/packages/flutter/lib/src/material/text_field.dart
+++ b/packages/flutter/lib/src/material/text_field.dart
@@ -329,7 +329,6 @@
this.autofillHints = const <String>[],
this.clipBehavior = Clip.hardEdge,
this.restorationId,
- this.scribbleEnabled = true,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
@@ -769,9 +768,6 @@
/// {@endtemplate}
final String? restorationId;
- /// {@macro flutter.widgets.editableText.scribbleEnabled}
- final bool scribbleEnabled;
-
/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;
@@ -816,7 +812,6 @@
properties.add(DiagnosticsProperty<ScrollController>('scrollController', scrollController, defaultValue: null));
properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null));
properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior, defaultValue: Clip.hardEdge));
- properties.add(DiagnosticsProperty<bool>('scribbleEnabled', scribbleEnabled, defaultValue: true));
properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
}
}
@@ -1034,7 +1029,7 @@
if (!_isEnabled)
return false;
- if (cause == SelectionChangedCause.longPress || cause == SelectionChangedCause.scribble)
+ if (cause == SelectionChangedCause.longPress)
return true;
if (_effectiveController.text.isNotEmpty)
@@ -1278,7 +1273,6 @@
autocorrectionTextRectColor: autocorrectionTextRectColor,
clipBehavior: widget.clipBehavior,
restorationId: 'editable',
- scribbleEnabled: widget.scribbleEnabled,
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
),
),
diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart
index 5f8cebf..f8113e3 100644
--- a/packages/flutter/lib/src/rendering/editable.dart
+++ b/packages/flutter/lib/src/rendering/editable.dart
@@ -1265,16 +1265,6 @@
// [assembleSemanticsNode] invocations.
Queue<SemanticsNode>? _cachedChildNodes;
- /// Returns a list of rects that bound the given selection.
- ///
- /// See [TextPainter.getBoxesForSelection] for more details.
- List<Rect> getBoxesForSelection(TextSelection selection) {
- _computeTextMetricsIfNeeded();
- return _textPainter.getBoxesForSelection(selection)
- .map((TextBox textBox) => textBox.toRect().shift(_paintOffset))
- .toList();
- }
-
@override
void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart
index 7bf468a..aaddbf5 100644
--- a/packages/flutter/lib/src/services/text_input.dart
+++ b/packages/flutter/lib/src/services/text_input.dart
@@ -955,9 +955,6 @@
/// The user used the mouse to change the selection by dragging over a piece
/// of text.
drag,
-
- /// The user used iPadOS 14+ Scribble to change the selection.
- scribble,
}
/// A mixin for manipulating the selection, provided for toolbar or shortcut
@@ -1108,76 +1105,6 @@
///
/// [TextInputClient] should cleanup its connection and finalize editing.
void connectionClosed();
-
- /// Requests that the client show the editing toolbar, for example when the
- /// platform changes the selection through a non-flutter method such as
- /// scribble.
- void showToolbar() {}
-
- /// Requests that the client add a text placeholder to reserve visual space
- /// in the text.
- ///
- /// For example, this is called when responding to UIKit requesting
- /// a text placeholder be added at the current selection, such as when
- /// requesting additional writing space with iPadOS14 Scribble.
- void insertTextPlaceholder(Size size) {}
-
- /// Requests that the client remove the text placeholder.
- void removeTextPlaceholder() {}
-}
-
-/// An interface to receive focus from the engine.
-///
-/// This is currently only used to handle UIIndirectScribbleInteraction.
-abstract class ScribbleClient {
- /// A unique identifier for this element.
- String get elementIdentifier;
-
- /// Called by the engine when the [ScribbleClient] should receive focus.
- ///
- /// For example, this method is called during a UIIndirectScribbleInteraction.
- void onScribbleFocus(Offset offset);
-
- /// Tests whether the [ScribbleClient] overlaps the given rectangle bounds.
- bool isInScribbleRect(Rect rect);
-
- /// The current bounds of the [ScribbleClient].
- Rect get bounds;
-}
-
-/// Represents a selection rect for a character and it's position in the text.
-///
-/// This is used to report the current text selection rect and position data
-/// to the engine for Scribble support on iPadOS 14.
-@immutable
-class SelectionRect {
- /// Constructor for creating a [SelectionRect] from a text [position] and
- /// [bounds].
- const SelectionRect({required this.position, required this.bounds});
-
- /// The position of this selection rect within the text String.
- final int position;
-
- /// The rectangle representing the bounds of this selection rect within the
- /// currently focused [RenderEditable]'s coordinate space.
- final Rect bounds;
-
- @override
- bool operator ==(Object other) {
- if (identical(this, other))
- return true;
- if (runtimeType != other.runtimeType)
- return false;
- return other is SelectionRect
- && other.position == position
- && other.bounds == bounds;
- }
-
- @override
- int get hashCode => hashValues(position, bounds);
-
- @override
- String toString() => 'SelectionRect($position, $bounds)';
}
/// An interface to receive granular information from [TextInput].
@@ -1227,7 +1154,6 @@
Matrix4? _cachedTransform;
Rect? _cachedRect;
Rect? _cachedCaretRect;
- List<SelectionRect> _cachedSelectionRects = <SelectionRect>[];
static int _nextId = 1;
final int _id;
@@ -1250,12 +1176,6 @@
/// Whether this connection is currently interacting with the text input control.
bool get attached => TextInput._instance._currentConnection == this;
- /// Whether there is currently a Scribble interaction in progress.
- ///
- /// This is used to make sure selection handles are shown when UIKit changes
- /// the selection during a Scribble interaction.
- bool get scribbleInProgress => TextInput._instance.scribbleInProgress;
-
/// Requests that the text input control become visible.
void show() {
assert(attached);
@@ -1354,19 +1274,6 @@
);
}
- /// Send the bounding boxes of the current selected glyphs in the client to
- /// the platform's text input plugin.
- ///
- /// These are used by the engine during a UIDirectScribbleInteraction.
- void setSelectionRects(List<SelectionRect> selectionRects) {
- if (!listEquals(_cachedSelectionRects, selectionRects)) {
- _cachedSelectionRects = selectionRects;
- TextInput._instance._setSelectionRects(selectionRects.map((SelectionRect rect) {
- return <num>[rect.bounds.left, rect.bounds.top, rect.bounds.width, rect.bounds.height, rect.position];
- }).toList());
- }
- }
-
/// Send text styling information.
///
/// This information is used by the Flutter Web Engine to change the style
@@ -1628,43 +1535,10 @@
TextInputConnection? _currentConnection;
late TextInputConfiguration _currentConfiguration;
- final Map<String, ScribbleClient> _scribbleClients = <String, ScribbleClient>{};
- bool _scribbleInProgress = false;
-
- /// Used for testing within the Flutter SDK to get the currently registered [ScribbleClient] list.
- @visibleForTesting
- static Map<String, ScribbleClient> get scribbleClients => TextInput._instance._scribbleClients;
-
- /// Returns true if a scribble interaction is currently happening.
- bool get scribbleInProgress => _scribbleInProgress;
-
Future<dynamic> _handleTextInputInvocation(MethodCall methodCall) async {
- final String method = methodCall.method;
- if (method == 'TextInputClient.focusElement') {
- final List<dynamic> args = methodCall.arguments as List<dynamic>;
- _scribbleClients[args[0]]?.onScribbleFocus(Offset((args[1] as num).toDouble(), (args[2] as num).toDouble()));
- return;
- } else if (method == 'TextInputClient.requestElementsInRect') {
- final List<double> args = (methodCall.arguments as List<dynamic>).cast<num>().map<double>((num value) => value.toDouble()).toList();
- return _scribbleClients.keys.where((String elementIdentifier) {
- final Rect rect = Rect.fromLTWH(args[0], args[1], args[2], args[3]);
- if (!(_scribbleClients[elementIdentifier]?.isInScribbleRect(rect) ?? false))
- return false;
- final Rect bounds = _scribbleClients[elementIdentifier]?.bounds ?? Rect.zero;
- return !(bounds == Rect.zero || bounds.hasNaN || bounds.isInfinite);
- }).map((String elementIdentifier) {
- final Rect bounds = _scribbleClients[elementIdentifier]!.bounds;
- return <dynamic>[elementIdentifier, ...<dynamic>[bounds.left, bounds.top, bounds.width, bounds.height]];
- }).toList();
- } else if (method == 'TextInputClient.scribbleInteractionBegan') {
- _scribbleInProgress = true;
- return;
- } else if (method == 'TextInputClient.scribbleInteractionFinished') {
- _scribbleInProgress = false;
- return;
- }
if (_currentConnection == null)
return;
+ final String method = methodCall.method;
// The requestExistingInputState request needs to be handled regardless of
// the client ID, as long as we have a _currentConnection.
@@ -1756,15 +1630,6 @@
case 'TextInputClient.showAutocorrectionPromptRect':
_currentConnection!._client.showAutocorrectionPromptRect(args[1] as int, args[2] as int);
break;
- case 'TextInputClient.showToolbar':
- _currentConnection!._client.showToolbar();
- break;
- case 'TextInputClient.insertTextPlaceholder':
- _currentConnection!._client.insertTextPlaceholder(Size((args[1] as num).toDouble(), (args[2] as num).toDouble()));
- break;
- case 'TextInputClient.removeTextPlaceholder':
- _currentConnection!._client.removeTextPlaceholder();
- break;
default:
throw MissingPluginException();
}
@@ -1838,13 +1703,6 @@
);
}
- void _setSelectionRects(List<List<num>> args) {
- _channel.invokeMethod<void>(
- 'TextInput.setSelectionRects',
- args,
- );
- }
-
void _setStyle(Map<String, dynamic> args) {
_channel.invokeMethod<void>(
'TextInput.setStyle',
@@ -1907,18 +1765,4 @@
shouldSave,
);
}
-
- /// Registers a [ScribbleClient] with [elementIdentifier] that can be focused
- /// by the engine.
- ///
- /// For example, the registered [ScribbleClient] list is used to respond to
- /// UIIndirectScribbleInteraction on an iPad.
- static void registerScribbleElement(String elementIdentifier, ScribbleClient scribbleClient) {
- TextInput._instance._scribbleClients[elementIdentifier] = scribbleClient;
- }
-
- /// Unregisters a [ScribbleClient] with [elementIdentifier].
- static void unregisterScribbleElement(String elementIdentifier) {
- TextInput._instance._scribbleClients.remove(elementIdentifier);
- }
}
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index fe13c45..67f5674 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -6,7 +6,7 @@
import 'dart:math' as math;
import 'dart:ui' as ui hide TextStyle;
-import 'package:characters/characters.dart' show CharacterRange, StringCharacters;
+import 'package:characters/characters.dart' show CharacterRange;
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'package:flutter/rendering.dart';
@@ -58,10 +58,6 @@
// is shown in an obscured text field.
const int _kObscureShowLatestCharCursorTicks = 3;
-// The minimum width of an iPad screen. The smallest iPad is currently the
-// iPad Mini 6th Gen according to ios-resolution.com.
-const double _kIPadWidth = 1488.0;
-
/// A controller for an editable text field.
///
/// Whenever the user modifies a text field with an associated
@@ -527,7 +523,6 @@
this.clipBehavior = Clip.hardEdge,
this.restorationId,
this.scrollBehavior,
- this.scribbleEnabled = true,
this.enableIMEPersonalizedLearning = true,
}) : assert(controller != null),
assert(focusNode != null),
@@ -1215,15 +1210,6 @@
/// [scrollPhysics].
final ScrollPhysics? scrollPhysics;
- /// {@template flutter.widgets.editableText.scribbleEnabled}
- /// Whether iOS 14 Scribble features are enabled for this widget.
- ///
- /// Only available on iPads.
- ///
- /// Defaults to true.
- /// {@endtemplate}
- final bool scribbleEnabled;
-
/// {@template flutter.widgets.editableText.selectionEnabled}
/// Same as [enableInteractiveSelection].
///
@@ -1524,7 +1510,6 @@
properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null));
properties.add(DiagnosticsProperty<Iterable<String>>('autofillHints', autofillHints, defaultValue: null));
properties.add(DiagnosticsProperty<TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null));
- properties.add(DiagnosticsProperty<bool>('scribbleEnabled', scribbleEnabled, defaultValue: true));
properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
}
}
@@ -1888,7 +1873,7 @@
if (value.text == _value.text && value.composing == _value.composing) {
// `selection` is the only change.
- _handleSelectionChanged(value.selection, (_textInputConnection?.scribbleInProgress ?? false) ? SelectionChangedCause.scribble : SelectionChangedCause.keyboard);
+ _handleSelectionChanged(value.selection, SelectionChangedCause.keyboard);
} else {
hideToolbar();
_currentPromptRectRange = null;
@@ -2671,11 +2656,6 @@
// Place cursor at the end if the selection is invalid when we receive focus.
_handleSelectionChanged(TextSelection.collapsed(offset: _value.text.length), null);
}
-
- _cachedText = '';
- _cachedFirstRect = null;
- _cachedSize = Size.zero;
- _cachedPlaceholder = -1;
} else {
WidgetsBinding.instance!.removeObserver(this);
setState(() { _currentPromptRectRange = null; });
@@ -2683,78 +2663,13 @@
updateKeepAlive();
}
- String _cachedText = '';
- Rect? _cachedFirstRect;
- Size _cachedSize = Size.zero;
- int _cachedPlaceholder = -1;
- TextStyle? _cachedTextStyle;
-
- void _updateSelectionRects({bool force = false}) {
- if (!widget.scribbleEnabled)
- return;
- if (defaultTargetPlatform != TargetPlatform.iOS)
- return;
- // This is to avoid sending selection rects on non-iPad devices.
- if (WidgetsBinding.instance!.window.physicalSize.shortestSide < _kIPadWidth)
- return;
-
- final String text = renderEditable.text?.toPlainText(includeSemanticsLabels: false, includePlaceholders: false) ?? '';
- final List<Rect> firstSelectionBoxes = renderEditable.getBoxesForSelection(const TextSelection(baseOffset: 0, extentOffset: 1));
- final Rect? firstRect = firstSelectionBoxes.isNotEmpty ? firstSelectionBoxes.first : null;
- final ScrollDirection scrollDirection = _scrollController.position.userScrollDirection;
- final Size size = renderEditable.size;
- final bool textChanged = text != _cachedText;
- final bool textStyleChanged = _cachedTextStyle != widget.style;
- final bool firstRectChanged = _cachedFirstRect != firstRect;
- final bool sizeChanged = _cachedSize != size;
- final bool placeholderChanged = _cachedPlaceholder != _placeholderLocation;
- if (scrollDirection == ScrollDirection.idle && (force || textChanged || textStyleChanged || firstRectChanged || sizeChanged || placeholderChanged)) {
- _cachedText = text;
- _cachedFirstRect = firstRect;
- _cachedTextStyle = widget.style;
- _cachedSize = size;
- _cachedPlaceholder = _placeholderLocation;
- bool belowRenderEditableBottom = false;
- final List<SelectionRect> rects = List<SelectionRect?>.generate(
- _cachedText.characters.length,
- (int i) {
- if (belowRenderEditableBottom)
- return null;
-
- final int offset = _cachedText.characters.getRange(0, i).string.length;
- final SelectionRect selectionRect = SelectionRect(
- bounds: renderEditable.getBoxesForSelection(TextSelection(baseOffset: offset, extentOffset: offset + _cachedText.characters.characterAt(i).string.length)).first,
- position: offset,
- );
- if (renderEditable.paintBounds.bottom < selectionRect.bounds.top) {
- belowRenderEditableBottom = true;
- return null;
- }
- return selectionRect;
- },
- ).where((SelectionRect? selectionRect) {
- if (selectionRect == null)
- return false;
- if (renderEditable.paintBounds.right < selectionRect.bounds.left || selectionRect.bounds.right < renderEditable.paintBounds.left)
- return false;
- if (renderEditable.paintBounds.bottom < selectionRect.bounds.top || selectionRect.bounds.bottom < renderEditable.paintBounds.top)
- return false;
- return true;
- }).map<SelectionRect>((SelectionRect? selectionRect) => selectionRect!).toList();
- _textInputConnection!.setSelectionRects(rects);
- }
- }
-
void _updateSizeAndTransform() {
if (_hasInputConnection) {
final Size size = renderEditable.size;
final Matrix4 transform = renderEditable.getTransformTo(null);
_textInputConnection!.setEditableSizeAndTransform(size, transform);
- _updateSelectionRects();
SchedulerBinding.instance!
.addPostFrameCallback((Duration _) => _updateSizeAndTransform());
- } else if (_placeholderLocation != -1) {
- removeTextPlaceholder();
}
}
@@ -2837,7 +2752,6 @@
///
/// Returns `false` if a toolbar couldn't be shown, such as when the toolbar
/// is already shown, or when no text selection currently exists.
- @override
bool showToolbar() {
// Web is using native dom elements to enable clipboard functionality of the
// toolbar: copy, paste, select, cut. It might also provide additional
@@ -2876,36 +2790,6 @@
}
}
- // Tracks the location a [_ScribblePlaceholder] should be rendered in the
- // text.
- //
- // A value of -1 indicates there should be no placeholder, otherwise the
- // value should be between 0 and the length of the text, inclusive.
- int _placeholderLocation = -1;
-
- @override
- void insertTextPlaceholder(Size size) {
- if (!widget.scribbleEnabled)
- return;
-
- if (!widget.controller.selection.isValid)
- return;
-
- setState(() {
- _placeholderLocation = _value.text.length - widget.controller.selection.end;
- });
- }
-
- @override
- void removeTextPlaceholder() {
- if (!widget.scribbleEnabled)
- return;
-
- setState(() {
- _placeholderLocation = -1;
- });
- }
-
@override
String get autofillId => 'EditableText-$hashCode';
@@ -3107,62 +2991,53 @@
onCopy: _semanticsOnCopy(controls),
onCut: _semanticsOnCut(controls),
onPaste: _semanticsOnPaste(controls),
- child: _ScribbleFocusable(
- focusNode: widget.focusNode,
- editableKey: _editableKey,
- enabled: widget.scribbleEnabled,
- updateSelectionRects: () {
- _openInputConnection();
- _updateSelectionRects(force: true);
- },
- child: _Editable(
- key: _editableKey,
- startHandleLayerLink: _startHandleLayerLink,
- endHandleLayerLink: _endHandleLayerLink,
- inlineSpan: buildTextSpan(),
- value: _value,
- cursorColor: _cursorColor,
- backgroundCursorColor: widget.backgroundCursorColor,
- showCursor: EditableText.debugDeterministicCursor
- ? ValueNotifier<bool>(widget.showCursor)
- : _cursorVisibilityNotifier,
- forceLine: widget.forceLine,
- readOnly: widget.readOnly,
- hasFocus: _hasFocus,
- maxLines: widget.maxLines,
- minLines: widget.minLines,
- expands: widget.expands,
- strutStyle: widget.strutStyle,
- selectionColor: widget.selectionColor,
- textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
- textAlign: widget.textAlign,
- textDirection: _textDirection,
- locale: widget.locale,
- textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
- textWidthBasis: widget.textWidthBasis,
- obscuringCharacter: widget.obscuringCharacter,
- obscureText: widget.obscureText,
- autocorrect: widget.autocorrect,
- smartDashesType: widget.smartDashesType,
- smartQuotesType: widget.smartQuotesType,
- enableSuggestions: widget.enableSuggestions,
- offset: offset,
- onCaretChanged: _handleCaretChanged,
- rendererIgnoresPointer: widget.rendererIgnoresPointer,
- cursorWidth: widget.cursorWidth,
- cursorHeight: widget.cursorHeight,
- cursorRadius: widget.cursorRadius,
- cursorOffset: widget.cursorOffset ?? Offset.zero,
- selectionHeightStyle: widget.selectionHeightStyle,
- selectionWidthStyle: widget.selectionWidthStyle,
- paintCursorAboveText: widget.paintCursorAboveText,
- enableInteractiveSelection: widget.enableInteractiveSelection,
- textSelectionDelegate: this,
- devicePixelRatio: _devicePixelRatio,
- promptRectRange: _currentPromptRectRange,
- promptRectColor: widget.autocorrectionTextRectColor,
- clipBehavior: widget.clipBehavior,
- ),
+ child: _Editable(
+ key: _editableKey,
+ startHandleLayerLink: _startHandleLayerLink,
+ endHandleLayerLink: _endHandleLayerLink,
+ inlineSpan: buildTextSpan(),
+ value: _value,
+ cursorColor: _cursorColor,
+ backgroundCursorColor: widget.backgroundCursorColor,
+ showCursor: EditableText.debugDeterministicCursor
+ ? ValueNotifier<bool>(widget.showCursor)
+ : _cursorVisibilityNotifier,
+ forceLine: widget.forceLine,
+ readOnly: widget.readOnly,
+ hasFocus: _hasFocus,
+ maxLines: widget.maxLines,
+ minLines: widget.minLines,
+ expands: widget.expands,
+ strutStyle: widget.strutStyle,
+ selectionColor: widget.selectionColor,
+ textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
+ textAlign: widget.textAlign,
+ textDirection: _textDirection,
+ locale: widget.locale,
+ textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
+ textWidthBasis: widget.textWidthBasis,
+ obscuringCharacter: widget.obscuringCharacter,
+ obscureText: widget.obscureText,
+ autocorrect: widget.autocorrect,
+ smartDashesType: widget.smartDashesType,
+ smartQuotesType: widget.smartQuotesType,
+ enableSuggestions: widget.enableSuggestions,
+ offset: offset,
+ onCaretChanged: _handleCaretChanged,
+ rendererIgnoresPointer: widget.rendererIgnoresPointer,
+ cursorWidth: widget.cursorWidth,
+ cursorHeight: widget.cursorHeight,
+ cursorRadius: widget.cursorRadius,
+ cursorOffset: widget.cursorOffset ?? Offset.zero,
+ selectionHeightStyle: widget.selectionHeightStyle,
+ selectionWidthStyle: widget.selectionWidthStyle,
+ paintCursorAboveText: widget.paintCursorAboveText,
+ enableInteractiveSelection: widget.enableInteractiveSelection,
+ textSelectionDelegate: this,
+ devicePixelRatio: _devicePixelRatio,
+ promptRectRange: _currentPromptRectRange,
+ promptRectColor: widget.autocorrectionTextRectColor,
+ clipBehavior: widget.clipBehavior,
),
),
);
@@ -3192,24 +3067,6 @@
}
return TextSpan(style: widget.style, text: text);
}
- if (_placeholderLocation >= 0 && _placeholderLocation <= _value.text.length) {
- final List<_ScribblePlaceholder> placeholders = <_ScribblePlaceholder>[];
- final int placeholderLocation = _value.text.length - _placeholderLocation;
- if (_isMultiline) {
- // The zero size placeholder here allows the line to break and keep the caret on the first line.
- placeholders.add(const _ScribblePlaceholder(child: SizedBox(), size: Size.zero));
- placeholders.add(_ScribblePlaceholder(child: const SizedBox(), size: Size(renderEditable.size.width, 0.0)));
- } else {
- placeholders.add(const _ScribblePlaceholder(child: SizedBox(), size: Size(100.0, 0.0)));
- }
- return TextSpan(style: widget.style, children: <InlineSpan>[
- TextSpan(text: _value.text.substring(0, placeholderLocation)),
- ...placeholders,
- TextSpan(text: _value.text.substring(placeholderLocation)),
- ],
- );
- }
-
// Read only mode should not paint text composing.
return widget.controller.buildTextSpan(
context: context,
@@ -3414,142 +3271,6 @@
}
}
-class _ScribbleFocusable extends StatefulWidget {
- const _ScribbleFocusable({
- Key? key,
- required this.child,
- required this.focusNode,
- required this.editableKey,
- required this.updateSelectionRects,
- required this.enabled,
- }): super(key: key);
-
- final Widget child;
- final FocusNode focusNode;
- final GlobalKey editableKey;
- final VoidCallback updateSelectionRects;
- final bool enabled;
-
- @override
- _ScribbleFocusableState createState() => _ScribbleFocusableState();
-}
-
-class _ScribbleFocusableState extends State<_ScribbleFocusable> implements ScribbleClient {
- _ScribbleFocusableState(): _elementIdentifier = (_nextElementIdentifier++).toString();
-
- @override
- void initState() {
- super.initState();
- if (widget.enabled) {
- TextInput.registerScribbleElement(elementIdentifier, this);
- }
- }
-
- @override
- void didUpdateWidget(_ScribbleFocusable oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (!oldWidget.enabled && widget.enabled) {
- TextInput.registerScribbleElement(elementIdentifier, this);
- }
-
- if (oldWidget.enabled && !widget.enabled) {
- TextInput.unregisterScribbleElement(elementIdentifier);
- }
- }
-
- @override
- void dispose() {
- TextInput.unregisterScribbleElement(elementIdentifier);
- super.dispose();
- }
-
- RenderEditable? get renderEditable => widget.editableKey.currentContext?.findRenderObject() as RenderEditable?;
-
- static int _nextElementIdentifier = 1;
- final String _elementIdentifier;
-
- @override
- String get elementIdentifier => _elementIdentifier;
-
- @override
- void onScribbleFocus(Offset offset) {
- widget.focusNode.requestFocus();
- renderEditable?.selectPositionAt(from: offset, cause: SelectionChangedCause.scribble);
- widget.updateSelectionRects();
- }
-
- @override
- bool isInScribbleRect(Rect rect) {
- final Rect _bounds = bounds;
- if (renderEditable?.readOnly ?? false)
- return false;
- if (_bounds == Rect.zero)
- return false;
- if (!_bounds.overlaps(rect))
- return false;
- final Rect intersection = _bounds.intersect(rect);
- final HitTestResult result = HitTestResult();
- WidgetsBinding.instance?.hitTest(result, intersection.center);
- return result.path.any((HitTestEntry entry) => entry.target == renderEditable);
- }
-
- @override
- Rect get bounds {
- final RenderBox? box = context.findRenderObject() as RenderBox?;
- if (box == null || !mounted || !box.attached)
- return Rect.zero;
- final Matrix4 transform = box.getTransformTo(null);
- return MatrixUtils.transformRect(transform, Rect.fromLTWH(0, 0, box.size.width, box.size.height));
- }
-
- @override
- Widget build(BuildContext context) {
- return widget.child;
- }
-}
-
-class _ScribblePlaceholder extends WidgetSpan {
- const _ScribblePlaceholder({
- required Widget child,
- ui.PlaceholderAlignment alignment = ui.PlaceholderAlignment.bottom,
- TextBaseline? baseline,
- TextStyle? style,
- required this.size,
- }) : assert(child != null),
- assert(baseline != null || !(
- identical(alignment, ui.PlaceholderAlignment.aboveBaseline) ||
- identical(alignment, ui.PlaceholderAlignment.belowBaseline) ||
- identical(alignment, ui.PlaceholderAlignment.baseline)
- )),
- super(
- alignment: alignment,
- baseline: baseline,
- style: style,
- child: child,
- );
-
- /// The size of the span, used in place of adding a placeholder size to the [TextPainter].
- final Size size;
-
- @override
- void build(ui.ParagraphBuilder builder, { double textScaleFactor = 1.0, List<PlaceholderDimensions>? dimensions }) {
- assert(debugAssertIsValid());
- final bool hasStyle = style != null;
- if (hasStyle) {
- builder.pushStyle(style!.getTextStyle(textScaleFactor: textScaleFactor));
- }
- builder.addPlaceholder(
- size.width,
- size.height,
- alignment,
- scale: textScaleFactor,
- );
- if (hasStyle) {
- builder.pop();
- }
- }
-}
-
/// An interface for retriving the logical text boundary (left-closed-right-open)
/// at a given location in a document.
///
diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart
index 874aa11..6d66fd1 100644
--- a/packages/flutter/test/cupertino/text_field_test.dart
+++ b/packages/flutter/test/cupertino/text_field_test.dart
@@ -2368,7 +2368,7 @@
);
final RenderEditable renderEditable = tester.renderObject<RenderEditable>(
- find.byElementPredicate((Element element) => element.renderObject is RenderEditable).last,
+ find.byElementPredicate((Element element) => element.renderObject is RenderEditable),
);
List<TextSelectionPoint> lastCharEndpoint = renderEditable.getEndpointsForSelection(
@@ -3166,7 +3166,7 @@
expect(
tester.renderObject<RenderEditable>(
- find.byElementPredicate((Element element) => element.renderObject is RenderEditable).last,
+ find.byElementPredicate((Element element) => element.renderObject is RenderEditable),
).text!.style!.color,
isSameColorAs(CupertinoColors.white),
);
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 7464689..3fef737 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -9255,38 +9255,6 @@
expect(right.opacity.value, equals(1.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
- testWidgets('iPad Scribble selection change shows selection handles', (WidgetTester tester) async {
- const String testText = 'lorem ipsum';
- final TextEditingController controller = TextEditingController(text: testText);
-
- await tester.pumpWidget(
- MaterialApp(
- home: Material(
- child: TextField(
- controller: controller,
- ),
- ),
- ),
- );
-
- await tester.showKeyboard(find.byType(EditableText));
- await tester.testTextInput.startScribbleInteraction();
- tester.testTextInput.updateEditingValue(const TextEditingValue(
- text: testText,
- selection: TextSelection(baseOffset: 2, extentOffset: 7),
- ));
- await tester.pumpAndSettle();
-
- final List<FadeTransition> transitions =
- find.byType(FadeTransition).evaluate().map((Element e) => e.widget).cast<FadeTransition>().toList();
- expect(transitions.length, 2);
- final FadeTransition left = transitions[0];
- final FadeTransition right = transitions[1];
-
- expect(left.opacity.value, equals(1.0));
- expect(right.opacity.value, equals(1.0));
- }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }));
-
testWidgets('Tap shows handles but not toolbar', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'abc def ghi',
diff --git a/packages/flutter/test/services/autofill_test.dart b/packages/flutter/test/services/autofill_test.dart
index e463a08..11fdcd9 100644
--- a/packages/flutter/test/services/autofill_test.dart
+++ b/packages/flutter/test/services/autofill_test.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:ui';
-
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -143,21 +141,6 @@
@override
void autofill(TextEditingValue newEditingValue) => updateEditingValue(newEditingValue);
-
- @override
- void showToolbar() {
- latestMethodCall = 'showToolbar';
- }
-
- @override
- void insertTextPlaceholder(Size size) {
- latestMethodCall = 'insertTextPlaceholder';
- }
-
- @override
- void removeTextPlaceholder() {
- latestMethodCall = 'removeTextPlaceholder';
- }
}
class FakeAutofillScope with AutofillScopeMixin implements AutofillScope {
diff --git a/packages/flutter/test/services/delta_text_input_test.dart b/packages/flutter/test/services/delta_text_input_test.dart
index eca5455..e87a665 100644
--- a/packages/flutter/test/services/delta_text_input_test.dart
+++ b/packages/flutter/test/services/delta_text_input_test.dart
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'dart:convert' show jsonDecode;
-import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -115,20 +114,5 @@
latestMethodCall = 'showAutocorrectionPromptRect';
}
- @override
- void insertTextPlaceholder(Size size) {
- latestMethodCall = 'insertTextPlaceholder';
- }
-
- @override
- void removeTextPlaceholder() {
- latestMethodCall = 'removeTextPlaceholder';
- }
-
- @override
- void showToolbar() {
- latestMethodCall = 'showToolbar';
- }
-
TextInputConfiguration get configuration => const TextInputConfiguration(enableDeltaModel: true);
}
diff --git a/packages/flutter/test/services/text_input_test.dart b/packages/flutter/test/services/text_input_test.dart
index 8591a04..09e5831 100644
--- a/packages/flutter/test/services/text_input_test.dart
+++ b/packages/flutter/test/services/text_input_test.dart
@@ -4,7 +4,6 @@
import 'dart:convert' show jsonDecode;
-import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -497,148 +496,6 @@
expect(client.latestMethodCall, 'showAutocorrectionPromptRect');
});
-
- test('TextInputClient showToolbar method is called', () async {
- // Assemble a TextInputConnection so we can verify its change in state.
- final FakeTextInputClient client = FakeTextInputClient(TextEditingValue.empty);
- const TextInputConfiguration configuration = TextInputConfiguration();
- TextInput.attach(client, configuration);
-
- expect(client.latestMethodCall, isEmpty);
-
- // Send showToolbar message.
- final ByteData? messageBytes =
- const JSONMessageCodec().encodeMessage(<String, dynamic>{
- 'args': <dynamic>[1, 0, 1],
- 'method': 'TextInputClient.showToolbar',
- });
- await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- 'flutter/textinput',
- messageBytes,
- (ByteData? _) {},
- );
-
- expect(client.latestMethodCall, 'showToolbar');
- });
- });
-
- group('Scribble interactions', () {
- tearDown(() {
- TextInputConnection.debugResetId();
- });
-
- test('TextInputClient scribbleInteractionBegan and scribbleInteractionFinished', () async {
- // Assemble a TextInputConnection so we can verify its change in state.
- final FakeTextInputClient client = FakeTextInputClient(TextEditingValue.empty);
- const TextInputConfiguration configuration = TextInputConfiguration();
- final TextInputConnection connection = TextInput.attach(client, configuration);
-
- expect(connection.scribbleInProgress, false);
-
- // Send scribbleInteractionBegan message.
- ByteData? messageBytes =
- const JSONMessageCodec().encodeMessage(<String, dynamic>{
- 'args': <dynamic>[1, 0, 1],
- 'method': 'TextInputClient.scribbleInteractionBegan',
- });
- await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- 'flutter/textinput',
- messageBytes,
- (ByteData? _) {},
- );
-
- expect(connection.scribbleInProgress, true);
-
- // Send scribbleInteractionFinished message.
- messageBytes =
- const JSONMessageCodec().encodeMessage(<String, dynamic>{
- 'args': <dynamic>[1, 0, 1],
- 'method': 'TextInputClient.scribbleInteractionFinished',
- });
- await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- 'flutter/textinput',
- messageBytes,
- (ByteData? _) {},
- );
-
- expect(connection.scribbleInProgress, false);
- });
-
- test('TextInputClient focusElement', () async {
- // Assemble a TextInputConnection so we can verify its change in state.
- final FakeTextInputClient client = FakeTextInputClient(TextEditingValue.empty);
- const TextInputConfiguration configuration = TextInputConfiguration();
- TextInput.attach(client, configuration);
-
- final FakeScribbleElement targetElement = FakeScribbleElement(elementIdentifier: 'target');
- TextInput.registerScribbleElement(targetElement.elementIdentifier, targetElement);
- final FakeScribbleElement otherElement = FakeScribbleElement(elementIdentifier: 'other');
- TextInput.registerScribbleElement(otherElement.elementIdentifier, otherElement);
-
- expect(targetElement.latestMethodCall, isEmpty);
- expect(otherElement.latestMethodCall, isEmpty);
-
- // Send focusElement message.
- final ByteData? messageBytes =
- const JSONMessageCodec().encodeMessage(<String, dynamic>{
- 'args': <dynamic>[targetElement.elementIdentifier, 0.0, 0.0],
- 'method': 'TextInputClient.focusElement',
- });
- await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- 'flutter/textinput',
- messageBytes,
- (ByteData? _) {},
- );
-
- TextInput.unregisterScribbleElement(targetElement.elementIdentifier);
- TextInput.unregisterScribbleElement(otherElement.elementIdentifier);
-
- expect(targetElement.latestMethodCall, 'onScribbleFocus');
- expect(otherElement.latestMethodCall, isEmpty);
- });
-
- test('TextInputClient requestElementsInRect', () async {
- // Assemble a TextInputConnection so we can verify its change in state.
- final FakeTextInputClient client = FakeTextInputClient(TextEditingValue.empty);
- const TextInputConfiguration configuration = TextInputConfiguration();
- TextInput.attach(client, configuration);
-
- final List<FakeScribbleElement> targetElements = <FakeScribbleElement>[
- FakeScribbleElement(elementIdentifier: 'target1', bounds: const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)),
- FakeScribbleElement(elementIdentifier: 'target2', bounds: const Rect.fromLTWH(0.0, 100.0, 100.0, 100.0)),
- ];
- final List<FakeScribbleElement> otherElements = <FakeScribbleElement>[
- FakeScribbleElement(elementIdentifier: 'other1', bounds: const Rect.fromLTWH(100.0, 0.0, 100.0, 100.0)),
- FakeScribbleElement(elementIdentifier: 'other2', bounds: const Rect.fromLTWH(100.0, 100.0, 100.0, 100.0)),
- ];
-
- void registerElements(FakeScribbleElement element) => TextInput.registerScribbleElement(element.elementIdentifier, element);
- void unregisterElements(FakeScribbleElement element) => TextInput.unregisterScribbleElement(element.elementIdentifier);
-
- <FakeScribbleElement>[...targetElements, ...otherElements].forEach(registerElements);
-
- // Send requestElementsInRect message.
- final ByteData? messageBytes =
- const JSONMessageCodec().encodeMessage(<String, dynamic>{
- 'args': <dynamic>[0.0, 50.0, 50.0, 100.0],
- 'method': 'TextInputClient.requestElementsInRect',
- });
- ByteData? responseBytes;
- await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- 'flutter/textinput',
- messageBytes,
- (ByteData? response) {
- responseBytes = response;
- },
- );
-
- <FakeScribbleElement>[...targetElements, ...otherElements].forEach(unregisterElements);
-
- final List<List<dynamic>> responses = (const JSONMessageCodec().decodeMessage(responseBytes) as List<dynamic>).cast<List<dynamic>>();
- expect(responses.first.length, 2);
- expect(responses.first.first, containsAllInOrder(<dynamic>[targetElements.first.elementIdentifier, 0.0, 0.0, 100.0, 100.0]));
- expect(responses.first.last, containsAllInOrder(<dynamic>[targetElements.last.elementIdentifier, 0.0, 100.0, 100.0, 100.0]));
- });
});
test('TextEditingValue.isComposingRangeValid', () async {
@@ -710,20 +567,5 @@
latestMethodCall = 'showAutocorrectionPromptRect';
}
- @override
- void showToolbar() {
- latestMethodCall = 'showToolbar';
- }
-
TextInputConfiguration get configuration => const TextInputConfiguration();
-
- @override
- void insertTextPlaceholder(Size size) {
- latestMethodCall = 'insertTextPlaceholder';
- }
-
- @override
- void removeTextPlaceholder() {
- latestMethodCall = 'removeTextPlaceholder';
- }
}
diff --git a/packages/flutter/test/services/text_input_utils.dart b/packages/flutter/test/services/text_input_utils.dart
index 2598c09..e1e3ddf 100644
--- a/packages/flutter/test/services/text_input_utils.dart
+++ b/packages/flutter/test/services/text_input_utils.dart
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'dart:convert' show utf8;
-import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -65,29 +64,3 @@
}
}
}
-
-class FakeScribbleElement implements ScribbleClient {
- FakeScribbleElement({required String elementIdentifier, Rect bounds = Rect.zero})
- : _elementIdentifier = elementIdentifier,
- _bounds = bounds;
-
- final String _elementIdentifier;
- final Rect _bounds;
- String latestMethodCall = '';
-
- @override
- Rect get bounds => _bounds;
-
- @override
- String get elementIdentifier => _elementIdentifier;
-
- @override
- bool isInScribbleRect(Rect rect) {
- return _bounds.overlaps(rect);
- }
-
- @override
- void onScribbleFocus(Offset offset) {
- latestMethodCall = 'onScribbleFocus';
- }
-}
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index 0010656..d94fd00 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -1662,329 +1662,6 @@
}
});
- testWidgets('Selection changes during Scribble interaction should have the scribble cause', (WidgetTester tester) async {
- late SelectionChangedCause selectionCause;
-
- final TextEditingController controller =
- TextEditingController(text: 'Lorem ipsum dolor sit amet');
-
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- onSelectionChanged: (TextSelection selection, SelectionChangedCause? cause) {
- if (cause != null)
- selectionCause = cause;
- },
- ),
- ),
- );
-
- await tester.showKeyboard(find.byType(EditableText));
-
- // A normal selection update from the framework has 'keyboard' as the cause.
- tester.testTextInput.updateEditingValue(TextEditingValue(
- text: controller.text,
- selection: const TextSelection(baseOffset: 2, extentOffset: 3),
- ));
- await tester.pumpAndSettle();
-
- expect(selectionCause, SelectionChangedCause.keyboard);
-
- // A selection update during a scribble interaction has 'scribble' as the cause.
- await tester.testTextInput.startScribbleInteraction();
- tester.testTextInput.updateEditingValue(TextEditingValue(
- text: controller.text,
- selection: const TextSelection(baseOffset: 3, extentOffset: 4),
- ));
- await tester.pumpAndSettle();
-
- expect(selectionCause, SelectionChangedCause.scribble);
- }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }));
-
- testWidgets('Requests focus and changes the selection when onScribbleFocus is called', (WidgetTester tester) async {
- final TextEditingController controller =
- TextEditingController(text: 'Lorem ipsum dolor sit amet');
- late SelectionChangedCause selectionCause;
-
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- onSelectionChanged: (TextSelection selection, SelectionChangedCause? cause) {
- if (cause != null)
- selectionCause = cause;
- },
- ),
- ),
- );
-
- await tester.testTextInput.scribbleFocusElement(TextInput.scribbleClients.keys.first, Offset.zero);
-
- expect(focusNode.hasFocus, true);
- expect(selectionCause, SelectionChangedCause.scribble);
-
- // On web, we should rely on the browser's implementation of Scribble, so the selection changed cause
- // will never be SelectionChangedCause.scribble.
- }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended]
-
- testWidgets('Declares itself for Scribble interaction if the bounds overlap the scribble rect and the widget is touchable', (WidgetTester tester) async {
- final TextEditingController controller =
- TextEditingController(text: 'Lorem ipsum dolor sit amet');
-
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- ),
- ),
- );
-
- final List<dynamic> elementEntry = <dynamic>[TextInput.scribbleClients.keys.first, 0.0, 0.0, 800.0, 600.0];
-
- List<List<dynamic>> elements = await tester.testTextInput.scribbleRequestElementsInRect(const Rect.fromLTWH(0, 0, 1, 1));
- expect(elements.first, containsAll(elementEntry));
-
- // Touch is outside the bounds of the widget.
- elements = await tester.testTextInput.scribbleRequestElementsInRect(const Rect.fromLTWH(-1, -1, 1, 1));
- expect(elements.length, 0);
-
- // Widget is read only.
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- readOnly: true,
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- ),
- ),
- );
-
- elements = await tester.testTextInput.scribbleRequestElementsInRect(const Rect.fromLTWH(0, 0, 1, 1));
- expect(elements.length, 0);
-
- // Widget is not touchable.
- await tester.pumpWidget(
- MaterialApp(
- home: Stack(children: <Widget>[
- EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- ),
- Positioned(
- left: 0,
- top: 0,
- right: 0,
- bottom: 0,
- child: Container(color: Colors.black),
- ),
- ],
- ),
- ),
- );
-
- elements = await tester.testTextInput.scribbleRequestElementsInRect(const Rect.fromLTWH(0, 0, 1, 1));
- expect(elements.length, 0);
-
- // Widget has scribble disabled.
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- scribbleEnabled: false,
- ),
- ),
- );
-
- elements = await tester.testTextInput.scribbleRequestElementsInRect(const Rect.fromLTWH(0, 0, 1, 1));
- expect(elements.length, 0);
-
-
- // On web, we should rely on the browser's implementation of Scribble, so the engine will
- // never request the scribble elements.
- }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended]
-
- testWidgets('single line Scribble fields can show a horizontal placeholder', (WidgetTester tester) async {
- final TextEditingController controller =
- TextEditingController(text: 'Lorem ipsum dolor sit amet');
-
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- ),
- ),
- );
-
- await tester.showKeyboard(find.byType(EditableText));
-
- tester.testTextInput.updateEditingValue(TextEditingValue(
- text: controller.text,
- selection: const TextSelection(baseOffset: 5, extentOffset: 5),
- ));
- await tester.pumpAndSettle();
-
- await tester.testTextInput.scribbleInsertPlaceholder();
- await tester.pumpAndSettle();
-
- TextSpan textSpan = findRenderEditable(tester).text! as TextSpan;
- expect(textSpan.children!.length, 3);
- expect((textSpan.children![0] as TextSpan).text, 'Lorem');
- expect(textSpan.children![1] is WidgetSpan, true);
- expect((textSpan.children![2] as TextSpan).text, ' ipsum dolor sit amet');
-
- await tester.testTextInput.scribbleRemovePlaceholder();
- await tester.pumpAndSettle();
-
- textSpan = findRenderEditable(tester).text! as TextSpan;
- expect(textSpan.children, null);
- expect(textSpan.text, 'Lorem ipsum dolor sit amet');
-
- // Widget has scribble disabled.
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- scribbleEnabled: false,
- ),
- ),
- );
-
- await tester.showKeyboard(find.byType(EditableText));
-
- tester.testTextInput.updateEditingValue(TextEditingValue(
- text: controller.text,
- selection: const TextSelection(baseOffset: 5, extentOffset: 5),
- ));
- await tester.pumpAndSettle();
-
- await tester.testTextInput.scribbleInsertPlaceholder();
- await tester.pumpAndSettle();
-
- textSpan = findRenderEditable(tester).text! as TextSpan;
- expect(textSpan.children, null);
- expect(textSpan.text, 'Lorem ipsum dolor sit amet');
-
- // On web, we should rely on the browser's implementation of Scribble, so the framework
- // will not handle placeholders.
- }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended]
-
- testWidgets('multiline Scribble fields can show a vertical placeholder', (WidgetTester tester) async {
- final TextEditingController controller =
- TextEditingController(text: 'Lorem ipsum dolor sit amet');
-
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- maxLines: 2,
- ),
- ),
- );
-
- await tester.showKeyboard(find.byType(EditableText));
-
- tester.testTextInput.updateEditingValue(TextEditingValue(
- text: controller.text,
- selection: const TextSelection(baseOffset: 5, extentOffset: 5),
- ));
- await tester.pumpAndSettle();
-
- await tester.testTextInput.scribbleInsertPlaceholder();
- await tester.pumpAndSettle();
-
- TextSpan textSpan = findRenderEditable(tester).text! as TextSpan;
- expect(textSpan.children!.length, 4);
- expect((textSpan.children![0] as TextSpan).text, 'Lorem');
- expect(textSpan.children![1] is WidgetSpan, true);
- expect(textSpan.children![2] is WidgetSpan, true);
- expect((textSpan.children![3] as TextSpan).text, ' ipsum dolor sit amet');
-
- await tester.testTextInput.scribbleRemovePlaceholder();
- await tester.pumpAndSettle();
-
- textSpan = findRenderEditable(tester).text! as TextSpan;
- expect(textSpan.children, null);
- expect(textSpan.text, 'Lorem ipsum dolor sit amet');
-
- // Widget has scribble disabled.
- await tester.pumpWidget(
- MaterialApp(
- home: EditableText(
- controller: controller,
- backgroundCursorColor: Colors.grey,
- focusNode: focusNode,
- style: textStyle,
- cursorColor: cursorColor,
- selectionControls: materialTextSelectionControls,
- maxLines: 2,
- scribbleEnabled: false,
- ),
- ),
- );
-
- await tester.showKeyboard(find.byType(EditableText));
-
- tester.testTextInput.updateEditingValue(TextEditingValue(
- text: controller.text,
- selection: const TextSelection(baseOffset: 5, extentOffset: 5),
- ));
- await tester.pumpAndSettle();
-
- await tester.testTextInput.scribbleInsertPlaceholder();
- await tester.pumpAndSettle();
-
- textSpan = findRenderEditable(tester).text! as TextSpan;
- expect(textSpan.children, null);
- expect(textSpan.text, 'Lorem ipsum dolor sit amet');
-
- // On web, we should rely on the browser's implementation of Scribble, so the framework
- // will not handle placeholders.
- }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended]
-
testWidgets('Sends "updateConfig" when read-only flag is flipped', (WidgetTester tester) async {
bool readOnly = true;
late StateSetter setState;
@@ -4017,85 +3694,6 @@
);
});
- testWidgets('selection rects are sent when they change', (WidgetTester tester) async {
- final List<MethodCall> log = <MethodCall>[];
- SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
- log.add(methodCall);
- });
-
- final TextEditingController controller = TextEditingController();
- controller.text = 'Text1';
-
- await tester.pumpWidget(
- MediaQuery(
- data: const MediaQueryData(),
- child: Directionality(
- textDirection: TextDirection.ltr,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- EditableText(
- key: ValueKey<String>(controller.text),
- controller: controller,
- focusNode: FocusNode(),
- style: Typography.material2018().black.subtitle1!,
- cursorColor: Colors.blue,
- backgroundCursorColor: Colors.grey,
- ),
- ],
- ),
- ),
- ),
- );
- await tester.showKeyboard(find.byKey(ValueKey<String>(controller.text)));
-
- // There should be a new platform message updating the selection rects.
- final MethodCall methodCall = log.firstWhere((MethodCall m) => m.method == 'TextInput.setSelectionRects');
- expect(methodCall.method, 'TextInput.setSelectionRects');
- expect((methodCall.arguments as List<dynamic>).length, 5);
-
- // On web, we should rely on the browser's implementation of Scribble, so we will not send selection rects.
- }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended]
-
- testWidgets('selection rects are not sent if scribbleEnabled is false', (WidgetTester tester) async {
- final List<MethodCall> log = <MethodCall>[];
- SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
- log.add(methodCall);
- });
-
- final TextEditingController controller = TextEditingController();
- controller.text = 'Text1';
-
- await tester.pumpWidget(
- MediaQuery(
- data: const MediaQueryData(),
- child: Directionality(
- textDirection: TextDirection.ltr,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- EditableText(
- key: ValueKey<String>(controller.text),
- controller: controller,
- focusNode: FocusNode(),
- style: Typography.material2018().black.subtitle1!,
- cursorColor: Colors.blue,
- backgroundCursorColor: Colors.grey,
- scribbleEnabled: false,
- ),
- ],
- ),
- ),
- ),
- );
- await tester.showKeyboard(find.byKey(ValueKey<String>(controller.text)));
-
- // There should be a new platform message updating the selection rects.
- expect(log.where((MethodCall m) => m.method == 'TextInput.setSelectionRects').length, 0);
-
- // On web, we should rely on the browser's implementation of Scribble, so we will not send selection rects.
- }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended]
-
testWidgets('text styling info is sent on show keyboard', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
diff --git a/packages/flutter_test/lib/src/test_text_input.dart b/packages/flutter_test/lib/src/test_text_input.dart
index 1a4f5d9..a9787c0 100644
--- a/packages/flutter_test/lib/src/test_text_input.dart
+++ b/packages/flutter_test/lib/src/test_text_input.dart
@@ -3,8 +3,6 @@
// found in the LICENSE file.
import 'dart:async';
-import 'dart:typed_data';
-import 'dart:ui' show Rect, Offset;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
@@ -273,84 +271,4 @@
(ByteData? data) { /* response from framework is discarded */ },
);
}
-
- /// Simulates a scribble interaction starting.
- Future<void> startScribbleInteraction() async {
- assert(isRegistered);
- await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- SystemChannels.textInput.name,
- SystemChannels.textInput.codec.encodeMethodCall(
- MethodCall(
- 'TextInputClient.scribbleInteractionBegan',
- <dynamic>[_client ?? -1,]
- ),
- ),
- (ByteData? data) { /* response from framework is discarded */ },
- );
- }
-
- /// Simulates a Scribble focus.
- Future<void> scribbleFocusElement(String elementIdentifier, Offset offset) async {
- assert(isRegistered);
- await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- SystemChannels.textInput.name,
- SystemChannels.textInput.codec.encodeMethodCall(
- MethodCall(
- 'TextInputClient.focusElement',
- <dynamic>[elementIdentifier, offset.dx, offset.dy]
- ),
- ),
- (ByteData? data) { /* response from framework is discarded */ },
- );
- }
-
- /// Simulates iOS asking for the list of Scribble elements during UIIndirectScribbleInteraction.
- Future<List<List<dynamic>>> scribbleRequestElementsInRect(Rect rect) async {
- assert(isRegistered);
- List<List<dynamic>> response = <List<dynamic>>[];
- await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- SystemChannels.textInput.name,
- SystemChannels.textInput.codec.encodeMethodCall(
- MethodCall(
- 'TextInputClient.requestElementsInRect',
- <dynamic>[rect.left, rect.top, rect.width, rect.height]
- ),
- ),
- (ByteData? data) {
- response = (SystemChannels.textInput.codec.decodeEnvelope(data!) as List<dynamic>).map((dynamic element) => element as List<dynamic>).toList();
- },
- );
-
- return response;
- }
-
- /// Simulates iOS inserting a UITextPlaceholder during a long press with the pencil.
- Future<void> scribbleInsertPlaceholder() async {
- assert(isRegistered);
- await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- SystemChannels.textInput.name,
- SystemChannels.textInput.codec.encodeMethodCall(
- MethodCall(
- 'TextInputClient.insertTextPlaceholder',
- <dynamic>[_client ?? -1, 0.0, 0.0]
- ),
- ),
- (ByteData? data) { /* response from framework is discarded */ },
- );
- }
-
- /// Simulates iOS removing a UITextPlaceholder after a long press with the pencil is released.
- Future<void> scribbleRemovePlaceholder() async {
- assert(isRegistered);
- await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
- SystemChannels.textInput.name,
- SystemChannels.textInput.codec.encodeMethodCall(
- MethodCall(
- 'TextInputClient.removeTextPlaceholder',
- <dynamic>[_client ?? -1]
- ),
- ),
- (ByteData? data) { /* response from framework is discarded */ },
- );
- }
}