Implement Double Tap Handling in TextField and Editable (#21264)
Thanks @NikoYuwono for getting this working! We appreciate your help!
* Implement Double Tap Handling in TextField and Editable
* Fix test broken by the change and add test for double tap
* Fix affected tests
* Remove unnecessary new
* Fix test
diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart
index 044011a..f7e503e 100644
--- a/packages/flutter/lib/src/material/text_field.dart
+++ b/packages/flutter/lib/src/material/text_field.dart
@@ -496,6 +496,11 @@
_cancelCurrentSplash();
}
+ void _handleDoubleTap() {
+ _renderEditable.handleDoubleTap();
+ _confirmCurrentSplash();
+ }
+
void _handleLongPress() {
_renderEditable.handleLongPress();
_confirmCurrentSplash();
@@ -614,6 +619,7 @@
onTapDown: _handleTapDown,
onTap: _handleTap,
onTapCancel: _handleTapCancel,
+ onDoubleTap: _handleDoubleTap,
onLongPress: _handleLongPress,
excludeFromSemantics: true,
child: child,
diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart
index 7c3d841..b038da0 100644
--- a/packages/flutter/lib/src/rendering/editable.dart
+++ b/packages/flutter/lib/src/rendering/editable.dart
@@ -32,6 +32,10 @@
/// of the cursor) to change.
tap,
+ /// The user tapped twice in quick succession on the text and that caused
+ /// the selection (or the location of the cursor) to change.
+ doubleTap,
+
/// The user long-pressed the text and that caused the selection (or the
/// location of the cursor) to change.
longPress,
@@ -168,6 +172,8 @@
_tap = TapGestureRecognizer(debugOwner: this)
..onTapDown = _handleTapDown
..onTap = _handleTap;
+ _doubleTap = DoubleTapGestureRecognizer(debugOwner: this)
+ ..onDoubleTap = _handleDoubleTap;
_longPress = LongPressGestureRecognizer(debugOwner: this)
..onLongPress = _handleLongPress;
}
@@ -185,7 +191,7 @@
/// If true [handleEvent] does nothing and it's assumed that this
/// renderer will be notified of input gestures via [handleTapDown],
- /// [handleTap], and [handleLongPress].
+ /// [handleTap], [handleDoubleTap], and [handleLongPress].
///
/// The default value of this property is false.
bool ignorePointer;
@@ -1022,6 +1028,7 @@
bool hitTestSelf(Offset position) => true;
TapGestureRecognizer _tap;
+ DoubleTapGestureRecognizer _doubleTap;
LongPressGestureRecognizer _longPress;
@override
@@ -1031,6 +1038,7 @@
assert(debugHandleEvent(event, entry));
if (event is PointerDownEvent && onSelectionChanged != null) {
_tap.addPointer(event);
+ _doubleTap.addPointer(event);
_longPress.addPointer(event);
}
}
@@ -1071,6 +1079,25 @@
}
/// If [ignorePointer] is false (the default) then this method is called by
+ /// the internal gesture recognizer's [DoubleTapGestureRecognizer.onDoubleTap]
+ /// callback.
+ ///
+ /// When [ignorePointer] is true, an ancestor widget must respond to long
+ /// press events by calling this method.
+ void handleDoubleTap() {
+ _layoutText(constraints.maxWidth);
+ assert(_lastTapDownPosition != null);
+ if (onSelectionChanged != null) {
+ final TextPosition position = _textPainter.getPositionForOffset(globalToLocal(_lastTapDownPosition));
+ onSelectionChanged(_selectWordAtOffset(position), this, SelectionChangedCause.doubleTap);
+ }
+ }
+ void _handleDoubleTap() {
+ assert(!ignorePointer);
+ handleDoubleTap();
+ }
+
+ /// If [ignorePointer] is false (the default) then this method is called by
/// the internal gesture recognizer's [LongPressRecognizer.onLongPress]
/// callback.
///
diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart
index cfecd3b..47485ba 100644
--- a/packages/flutter/test/cupertino/tab_scaffold_test.dart
+++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart
@@ -179,6 +179,7 @@
);
await tester.tap(find.widgetWithText(TextField, 'TextField 2'));
+ await tester.pump(const Duration(milliseconds: 300));
expect(
focusNodes.indexOf(focusNodes.singleWhere((FocusNode node) => node.hasFocus)),
@@ -189,6 +190,7 @@
await tester.pump();
await tester.tap(find.widgetWithText(TextField, 'TextField 1'));
+ await tester.pump(const Duration(milliseconds: 300));
expect(
focusNodes.indexOf(focusNodes.singleWhere((FocusNode node) => node.hasFocus)),
diff --git a/packages/flutter/test/material/search_test.dart b/packages/flutter/test/material/search_test.dart
index 9f2454b..b337a40 100644
--- a/packages/flutter/test/material/search_test.dart
+++ b/packages/flutter/test/material/search_test.dart
@@ -164,7 +164,7 @@
delegate: delegate,
));
await tester.tap(find.byTooltip('Search'));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
// Showing suggestions
expect(find.text('Suggestions'), findsOneWidget);
@@ -173,14 +173,14 @@
// Typing query Wow
delegate.querysForSuggestions.clear();
await tester.enterText(find.byType(TextField), 'Wow');
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
expect(delegate.query, 'Wow');
expect(delegate.querysForSuggestions, <String>['Wow']);
expect(delegate.querysForResults, hasLength(0));
await tester.tap(find.text('Suggestions'));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
// Showing Results
expect(find.text('Suggestions'), findsNothing);
@@ -195,7 +195,7 @@
// Taping search field to go back to suggestions
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
textField = tester.widget(find.byType(TextField));
expect(textField.focusNode.hasFocus, isTrue);
@@ -206,7 +206,7 @@
expect(delegate.querysForResults, <String>['Wow']);
await tester.enterText(find.byType(TextField), 'Foo');
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
expect(delegate.query, 'Foo');
expect(delegate.querysForSuggestions, <String>['Wow', 'Wow', 'Foo']);
@@ -214,7 +214,7 @@
// Go to results again
await tester.tap(find.text('Suggestions'));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
expect(find.text('Suggestions'), findsNothing);
expect(find.text('Results'), findsOneWidget);
diff --git a/packages/flutter/test/material/text_field_focus_test.dart b/packages/flutter/test/material/text_field_focus_test.dart
index 4bb79d6..b8219bc 100644
--- a/packages/flutter/test/material/text_field_focus_test.dart
+++ b/packages/flutter/test/material/text_field_focus_test.dart
@@ -6,6 +6,8 @@
import 'package:flutter/material.dart';
void main() {
+ const Duration doubleTapTimeout = Duration(milliseconds: 300);
+
testWidgets('Request focus shows keyboard', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
@@ -71,7 +73,7 @@
expect(tester.testTextInput.isVisible, isFalse);
await tester.tap(find.byType(TextField));
- await tester.idle();
+ await tester.pump(doubleTapTimeout);
expect(tester.testTextInput.isVisible, isTrue);
@@ -80,7 +82,7 @@
expect(tester.testTextInput.isVisible, isFalse);
await tester.tap(find.byType(TextField));
- await tester.idle();
+ await tester.pump(doubleTapTimeout);
expect(tester.testTextInput.isVisible, isTrue);
@@ -113,17 +115,17 @@
builder: (BuildContext context) => const SimpleDialog(title: Text('Dialog')),
);
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(tester.testTextInput.isVisible, isFalse);
Navigator.of(tester.element(find.text('Dialog'))).pop();
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(tester.testTextInput.isVisible, isFalse);
await tester.tap(find.byType(TextField));
- await tester.idle();
+ await tester.pump(doubleTapTimeout);
expect(tester.testTextInput.isVisible, isTrue);
@@ -224,7 +226,7 @@
expect(tester.testTextInput.isVisible, isFalse);
await tester.tap(find.byType(TextField));
- await tester.idle();
+ await tester.pump(doubleTapTimeout);
expect(tester.testTextInput.isVisible, isTrue);
});
}
diff --git a/packages/flutter/test/material/text_field_splash_test.dart b/packages/flutter/test/material/text_field_splash_test.dart
index 811a2b8..55a6a3a 100644
--- a/packages/flutter/test/material/text_field_splash_test.dart
+++ b/packages/flutter/test/material/text_field_splash_test.dart
@@ -121,32 +121,32 @@
cancelCount = 0;
await tester.tap(find.byKey(textField1));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(confirmCount, 1);
expect(cancelCount, 0);
// textField1 already has the focus, no new splash
await tester.tap(find.byKey(textField1));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(confirmCount, 1);
expect(cancelCount, 0);
// textField2 gets the focus and a splash
await tester.tap(find.byKey(textField2));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(confirmCount, 2);
expect(cancelCount, 0);
// Tap outside of textField1's editable. It still gets focus and splash.
await tester.tapAt(tester.getTopLeft(find.byKey(textField1)));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(confirmCount, 3);
expect(cancelCount, 0);
// Tap in the center of textField2's editable. It still gets the focus
// and the splash. There is no splash cancel.
await tester.tap(find.byKey(textField2));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(confirmCount, 4);
expect(cancelCount, 0);
});
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 5a1d8d6..bf156e2 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -118,6 +118,7 @@
final MockClipboard mockClipboard = MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+ const Duration doubleTapTimeout = Duration(milliseconds: 300);
const String kThreeLines =
'First line of text is '
'Second line goes until '
@@ -398,13 +399,13 @@
final int tapIndex = testValue.indexOf('e');
final Offset ePos = textOffsetToPosition(tester, tapIndex);
await tester.tapAt(ePos);
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(controller.selection.baseOffset, tapIndex);
expect(controller.selection.extentOffset, tapIndex);
});
- testWidgets('Can long press to select', (WidgetTester tester) async {
+ testWidgets('Can long press to select a word', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
await tester.pumpWidget(
@@ -434,6 +435,40 @@
expect(controller.selection.extentOffset, testValue.indexOf('f')+1);
});
+ testWidgets('Can double tap to select a word', (WidgetTester tester) async {
+ final TextEditingController controller = TextEditingController();
+
+ await tester.pumpWidget(
+ overlay(
+ child: TextField(
+ controller: controller,
+ ),
+ )
+ );
+
+ const String testValue = 'abc def ghi';
+ await tester.enterText(find.byType(TextField), testValue);
+ expect(controller.value.text, testValue);
+ await skipPastScrollingAnimation(tester);
+
+ expect(controller.selection.isCollapsed, true);
+
+ // Long press the 'e' to select 'def'.
+ final Offset ePos = textOffsetToPosition(tester, testValue.indexOf('e'));
+ final TestGesture firstTapGesture = await tester.startGesture(ePos);
+ await tester.pump(const Duration(milliseconds: 100));
+ await firstTapGesture.up();
+ await tester.pump();
+ final TestGesture secondTapGesture = await tester.startGesture(ePos);
+ await tester.pump();
+ await secondTapGesture.up();
+ await tester.pump();
+
+ // 'def' is selected.
+ expect(controller.selection.baseOffset, testValue.indexOf('d'));
+ expect(controller.selection.extentOffset, testValue.indexOf('f')+1);
+ });
+
testWidgets('Can drag handles to change selection', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
@@ -512,7 +547,7 @@
// Tap the selection handle to bring up the "paste / select all" menu.
await tester.tapAt(textOffsetToPosition(tester, testValue.indexOf('e')));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
RenderEditable renderEditable = findRenderEditable(tester);
List<TextSelectionPoint> endpoints = globalize(
@@ -520,7 +555,7 @@
renderEditable,
);
await tester.tapAt(endpoints[0].point + const Offset(1.0, 1.0));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
// SELECT ALL should select all the text.
@@ -536,7 +571,7 @@
// Tap again to bring back the menu.
await tester.tapAt(textOffsetToPosition(tester, testValue.indexOf('e')));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
renderEditable = findRenderEditable(tester);
endpoints = globalize(
@@ -544,7 +579,7 @@
renderEditable,
);
await tester.tapAt(endpoints[0].point + const Offset(1.0, 1.0));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
// PASTE right before the 'e'.
@@ -570,7 +605,7 @@
// Tap the selection handle to bring up the "paste / select all" menu.
await tester.tapAt(textOffsetToPosition(tester, testValue.indexOf('e')));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
final RenderEditable renderEditable = findRenderEditable(tester);
final List<TextSelectionPoint> endpoints = globalize(
@@ -578,7 +613,7 @@
renderEditable,
);
await tester.tapAt(endpoints[0].point + const Offset(1.0, 1.0));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
// Toolbar should fade in. Starting at 0% opacity.
final Element target = tester.element(find.text('SELECT ALL'));
@@ -1062,7 +1097,7 @@
// Focus the Input. The prefix should still display.
await tester.tap(find.byKey(secondKey));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(find.text('Prefix'), findsOneWidget);
expect(find.text('Suffix'), findsOneWidget);
@@ -1114,7 +1149,7 @@
expect(getOpacity(tester, find.text('Hint')), 1.0);
await tester.tap(find.byKey(secondKey));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
// Focus the Input. The hint, prefix, and suffix should appear
expect(getOpacity(tester, find.text('Prefix')), 1.0);
@@ -1180,7 +1215,7 @@
// Focus the input. The label, prefix, and suffix should appear.
await tester.tap(find.byKey(secondKey));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(const Duration(milliseconds: 300));
expect(getOpacity(tester, find.text('Prefix')), 1.0);
expect(getOpacity(tester, find.text('Suffix')), 1.0);
@@ -1229,7 +1264,7 @@
// Focus the Input. The label should start animating upwards.
await tester.tap(find.byKey(secondKey));
await tester.idle();
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 50));
Offset newPos = tester.getTopLeft(find.text('Second'));
@@ -1364,7 +1399,7 @@
// Initial state with null controller.
await tester.tap(find.byType(TextField));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(tester.testTextInput.editingState['text'], isEmpty);
// Update the controller from null to controller1.
@@ -1502,7 +1537,7 @@
await skipPastScrollingAnimation(tester);
await tester.tapAt(textOffsetToPosition(tester, '123'.indexOf('2')));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
final RenderEditable renderEditable = findRenderEditable(tester);
final List<TextSelectionPoint> endpoints = globalize(
@@ -1510,7 +1545,7 @@
renderEditable,
);
await tester.tapAt(endpoints[0].point + const Offset(1.0, 1.0));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
Clipboard.setData(const ClipboardData(text: '一4二\n5三6'));
@@ -1606,7 +1641,7 @@
expect(controller1.selection, isNot(equals(TextRange.empty)));
await tester.tap(find.byKey(key2));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(controller1.selection, equals(TextRange.empty));
});
@@ -1823,7 +1858,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
sendKeyEventWithCode(22, true, true, false); // RIGHT_ARROW keydown, SHIFT_ON
expect(controller.selection.extentOffset - controller.selection.baseOffset, 1);
@@ -1836,7 +1871,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
await tester.pumpAndSettle();
sendKeyEventWithCode(22, true, true, true); // RIGHT_ARROW keydown SHIFT_ON, CONTROL_ON
@@ -1852,7 +1887,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
sendKeyEventWithCode(20, true, true, false); // DOWN_ARROW keydown
await tester.pumpAndSettle();
@@ -1875,7 +1910,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
for (int i = 0; i < 5; i += 1) {
sendKeyEventWithCode(22, true, false, false); // RIGHT_ARROW keydown
@@ -1962,7 +1997,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
// Select the first 5 characters
for (int i = 0; i < 5; i += 1) {
@@ -2032,7 +2067,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
// Select the first 5 characters
for (int i = 0; i < 5; i += 1) {
@@ -2095,7 +2130,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
// Select All
sendKeyEventWithCode(_kAKeyCode, true, false, true); // keydown control A
@@ -2141,7 +2176,7 @@
await tester.idle();
await tester.tap(find.byType(TextField));
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
// Delete
for (int i = 0; i < 6; i += 1) {
@@ -2211,7 +2246,7 @@
await tester.idle();
await tester.tap(find.byType(TextField).first);
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
for (int i = 0; i < 5; i += 1) {
sendKeyEventWithCode(22, true, true, false); // RIGHT_ARROW keydown
@@ -2298,7 +2333,7 @@
const String testValue = 'a big house';
await tester.enterText(find.byType(TextField).first, testValue);
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
for (int i = 0; i < 5; i += 1) {
sendKeyEventWithCode(22, true, true, false); // RIGHT_ARROW keydown
@@ -2313,7 +2348,7 @@
await tester.enterText(find.byType(TextField).last, testValue);
- await tester.pumpAndSettle();
+ await tester.pumpAndSettle(doubleTapTimeout);
for (int i = 0; i < 5; i += 1) {
sendKeyEventWithCode(22, true, true, false); // RIGHT_ARROW keydown
@@ -2343,7 +2378,7 @@
// Tap the selection handle to bring up the "paste / select all" menu.
await tester.tapAt(textOffsetToPosition(tester, 0));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is
// Confirm that the selection was updated.
@@ -2450,7 +2485,7 @@
), ignoreTransform: true, ignoreRect: true));
await tester.tap(find.byKey(key));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(semantics, hasSemantics(TestSemantics.root(
children: <TestSemantics>[
@@ -2563,7 +2598,7 @@
// Focus the text field
await tester.tap(find.byKey(key));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(semantics, hasSemantics(TestSemantics.root(
children: <TestSemantics>[
@@ -2637,7 +2672,7 @@
// Focus the text field
await tester.tap(find.byKey(key));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
const int inputFieldId = 1;
@@ -2869,7 +2904,7 @@
), ignoreTransform: true, ignoreRect: true));
await tester.tap(find.byType(TextField));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(semantics, hasSemantics(TestSemantics.root(
children: <TestSemantics>[
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index 2dba2fe..8591cb9 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -20,6 +20,7 @@
final FocusScopeNode focusScopeNode = FocusScopeNode();
const TextStyle textStyle = TextStyle();
const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00);
+ const Duration doubleTapTimeout = Duration(milliseconds: 300);
setUp(() {
debugResetSemanticsIdCounter();
@@ -53,6 +54,7 @@
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -119,6 +121,7 @@
),
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -282,6 +285,7 @@
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -311,6 +315,7 @@
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -341,6 +346,7 @@
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -373,6 +379,7 @@
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -403,6 +410,7 @@
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -433,6 +441,7 @@
);
await tester.tap(find.byType(EditableText));
+ await tester.pump(doubleTapTimeout);
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
@@ -608,7 +617,7 @@
// Select EditableText to give it focus.
final Finder textFinder = find.byKey(editableTextKey);
await tester.tap(textFinder);
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
assert(focusNode.hasFocus);
@@ -645,7 +654,7 @@
// Select EditableText to give it focus.
final Finder textFinder = find.byKey(editableTextKey);
await tester.tap(textFinder);
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
assert(focusNode.hasFocus);
@@ -689,7 +698,7 @@
// Select EditableText to give it focus.
final Finder textFinder = find.byKey(editableTextKey);
await tester.tap(textFinder);
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
assert(focusNode.hasFocus);
@@ -733,7 +742,7 @@
// Select EditableText to give it focus.
final Finder textFinder = find.byKey(editableTextKey);
await tester.tap(textFinder);
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
assert(focusNode.hasFocus);
@@ -838,7 +847,7 @@
await tester.tap(find.byType(EditableText));
await tester.idle();
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(
semantics,
@@ -1479,7 +1488,7 @@
await _buildApp(controls, tester);
await tester.tap(find.byType(EditableText));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
expect(
semantics,
@@ -1565,7 +1574,7 @@
when(controls.canPaste(any)).thenReturn(true);
await _buildApp(controls, tester);
await tester.tap(find.byType(EditableText));
- await tester.pump();
+ await tester.pump(doubleTapTimeout);
final SemanticsOwner owner = tester.binding.pipelineOwner.semanticsOwner;
const int expectedNodeId = 4;