Unverified Commit 40c4da5c authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Revert "Re-land "Support Scribble Handwriting" (#96615) (#96881)" (#97405)

This reverts commit c54ce015.
parent a627f443
......@@ -297,7 +297,6 @@ class CupertinoTextField extends StatefulWidget {
this.autofillHints = const <String>[],
this.clipBehavior = Clip.hardEdge,
this.restorationId,
this.scribbleEnabled = true,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
......@@ -469,7 +468,6 @@ class CupertinoTextField extends StatefulWidget {
this.autofillHints = const <String>[],
this.clipBehavior = Clip.hardEdge,
this.restorationId,
this.scribbleEnabled = true,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
......@@ -828,9 +826,6 @@ class CupertinoTextField extends StatefulWidget {
/// {@macro flutter.material.textfield.restorationId}
final String? restorationId;
/// {@macro flutter.widgets.editableText.scribbleEnabled}
final bool scribbleEnabled;
/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;
......@@ -876,7 +871,6 @@ class CupertinoTextField extends StatefulWidget {
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));
}
}
......@@ -997,9 +991,6 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
if (cause == SelectionChangedCause.keyboard)
return false;
if (cause == SelectionChangedCause.scribble)
return true;
if (_effectiveController.text.isNotEmpty)
return true;
......@@ -1329,7 +1320,6 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
autofillClient: this,
clipBehavior: widget.clipBehavior,
restorationId: 'editable',
scribbleEnabled: widget.scribbleEnabled,
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
),
),
......
......@@ -329,7 +329,6 @@ class TextField extends StatefulWidget {
this.autofillHints = const <String>[],
this.clipBehavior = Clip.hardEdge,
this.restorationId,
this.scribbleEnabled = true,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
......@@ -782,9 +781,6 @@ class TextField extends StatefulWidget {
/// {@endtemplate}
final String? restorationId;
/// {@macro flutter.widgets.editableText.scribbleEnabled}
final bool scribbleEnabled;
/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;
......@@ -829,7 +825,6 @@ class TextField extends StatefulWidget {
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));
}
}
......@@ -1047,7 +1042,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
if (!_isEnabled)
return false;
if (cause == SelectionChangedCause.longPress || cause == SelectionChangedCause.scribble)
if (cause == SelectionChangedCause.longPress)
return true;
if (_effectiveController.text.isNotEmpty)
......@@ -1291,7 +1286,6 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
autocorrectionTextRectColor: autocorrectionTextRectColor,
clipBehavior: widget.clipBehavior,
restorationId: 'editable',
scribbleEnabled: widget.scribbleEnabled,
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
),
),
......
......@@ -1265,16 +1265,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
// [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);
......
......@@ -955,9 +955,6 @@ enum SelectionChangedCause {
/// 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 @@ abstract class TextInputClient {
///
/// [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 @@ class TextInputConnection {
Matrix4? _cachedTransform;
Rect? _cachedRect;
Rect? _cachedCaretRect;
List<SelectionRect> _cachedSelectionRects = <SelectionRect>[];
static int _nextId = 1;
final int _id;
......@@ -1250,12 +1176,6 @@ class TextInputConnection {
/// 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 @@ class TextInputConnection {
);
}
/// 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 @@ class TextInput {
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 @@ class TextInput {
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 @@ class TextInput {
);
}
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 @@ class TextInput {
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);
}
}
......@@ -2454,7 +2454,7 @@ void main() {
);
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(
......@@ -3252,7 +3252,7 @@ void main() {
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),
);
......
......@@ -9179,38 +9179,6 @@ void main() {
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',
......
......@@ -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 @@ class FakeAutofillClient implements TextInputClient, AutofillClient {
@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 {
......
......@@ -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 @@ class FakeDeltaTextInputClient implements DeltaTextInputClient {
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);
}
......@@ -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 @@ void main() {
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 @@ class FakeTextInputClient implements TextInputClient {
latestMethodCall = 'showAutocorrectionPromptRect';
}
@override
void showToolbar() {
latestMethodCall = 'showToolbar';
}
TextInputConfiguration get configuration => const TextInputConfiguration();
@override
void insertTextPlaceholder(Size size) {
latestMethodCall = 'insertTextPlaceholder';
}
@override
void removeTextPlaceholder() {
latestMethodCall = 'removeTextPlaceholder';
}
}
......@@ -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 FakeTextChannel implements MethodChannel {
}
}
}
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';
}
}
......@@ -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 @@ class TestTextInput {
(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 */ },
);
}
}
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