Unverified Commit 61db3bc8 authored by godofredoc's avatar godofredoc Committed by GitHub

Revert "Single tap on the previous selection should toggle the toolbar on iOS…" (#111662)

parent b8df71fc
...@@ -102,6 +102,7 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe ...@@ -102,6 +102,7 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
@override @override
void onSingleTapUp(TapUpDetails details) { void onSingleTapUp(TapUpDetails details) {
editableText.hideToolbar();
// Because TextSelectionGestureDetector listens to taps that happen on // Because TextSelectionGestureDetector listens to taps that happen on
// widgets in front of it, tapping the clear button will also trigger // widgets in front of it, tapping the clear button will also trigger
// this handler. If the clear button widget recognizes the up event, // this handler. If the clear button widget recognizes the up event,
......
...@@ -103,6 +103,7 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete ...@@ -103,6 +103,7 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete
@override @override
void onSingleTapUp(TapUpDetails details) { void onSingleTapUp(TapUpDetails details) {
editableText.hideToolbar();
super.onSingleTapUp(details); super.onSingleTapUp(details);
_state._requestKeyboard(); _state._requestKeyboard();
_state.widget.onTap?.call(); _state.widget.onTap?.call();
......
...@@ -3315,10 +3315,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -3315,10 +3315,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
} }
/// Toggles the visibility of the toolbar. /// Toggles the visibility of the toolbar.
void toggleToolbar([bool hideHandles = true]) { void toggleToolbar() {
assert(_selectionOverlay != null); assert(_selectionOverlay != null);
if (_selectionOverlay!.toolbarIsVisible) { if (_selectionOverlay!.toolbarIsVisible) {
hideToolbar(hideHandles); hideToolbar();
} else { } else {
showToolbar(); showToolbar();
} }
......
...@@ -1634,19 +1634,6 @@ class TextSelectionGestureDetectorBuilder { ...@@ -1634,19 +1634,6 @@ class TextSelectionGestureDetectorBuilder {
&& renderEditable.selection!.end >= textPosition.offset; && renderEditable.selection!.end >= textPosition.offset;
} }
bool _tapWasOnSelection(Offset position) {
if (renderEditable.selection == null) {
return false;
}
final TextPosition textPosition = renderEditable.getPositionForPoint(
position,
);
return renderEditable.selection!.start < textPosition.offset
&& renderEditable.selection!.end > textPosition.offset;
}
// Expand the selection to the given global position. // Expand the selection to the given global position.
// //
// Either base or extent will be moved to the last tapped position, whichever // Either base or extent will be moved to the last tapped position, whichever
...@@ -1877,7 +1864,6 @@ class TextSelectionGestureDetectorBuilder { ...@@ -1877,7 +1864,6 @@ class TextSelectionGestureDetectorBuilder {
case TargetPlatform.linux: case TargetPlatform.linux:
case TargetPlatform.macOS: case TargetPlatform.macOS:
case TargetPlatform.windows: case TargetPlatform.windows:
editableText.hideToolbar();
// On desktop platforms the selection is set on tap down. // On desktop platforms the selection is set on tap down.
if (_isShiftTapping) { if (_isShiftTapping) {
_isShiftTapping = false; _isShiftTapping = false;
...@@ -1885,7 +1871,6 @@ class TextSelectionGestureDetectorBuilder { ...@@ -1885,7 +1871,6 @@ class TextSelectionGestureDetectorBuilder {
break; break;
case TargetPlatform.android: case TargetPlatform.android:
case TargetPlatform.fuchsia: case TargetPlatform.fuchsia:
editableText.hideToolbar();
if (isShiftPressedValid) { if (isShiftPressedValid) {
_isShiftTapping = true; _isShiftTapping = true;
_extendSelection(details.globalPosition, SelectionChangedCause.tap); _extendSelection(details.globalPosition, SelectionChangedCause.tap);
...@@ -1919,16 +1904,7 @@ class TextSelectionGestureDetectorBuilder { ...@@ -1919,16 +1904,7 @@ class TextSelectionGestureDetectorBuilder {
case PointerDeviceKind.touch: case PointerDeviceKind.touch:
case PointerDeviceKind.unknown: case PointerDeviceKind.unknown:
// On iOS/iPadOS a touch tap places the cursor at the edge of the word. // On iOS/iPadOS a touch tap places the cursor at the edge of the word.
final TextSelection previousSelection = editableText.textEditingValue.selection;
// If the tap was within the previous selection, then the selection should stay the same.
if (!_tapWasOnSelection(details.globalPosition)) {
renderEditable.selectWordEdge(cause: SelectionChangedCause.tap); renderEditable.selectWordEdge(cause: SelectionChangedCause.tap);
}
if (previousSelection == editableText.textEditingValue.selection && renderEditable.hasFocus) {
editableText.toggleToolbar(false);
} else {
editableText.hideToolbar(false);
}
break; break;
} }
break; break;
......
...@@ -1752,85 +1752,9 @@ void main() { ...@@ -1752,85 +1752,9 @@ void main() {
expect(controller.selection.isCollapsed, isTrue); expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, isTargetPlatformMobile ? 7 : 6); expect(controller.selection.baseOffset, isTargetPlatformMobile ? 7 : 6);
// Toolbar shows on mobile. // No toolbar.
expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(2) : findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets(
'Tapping on a non-collapsed selection toggles the toolbar and retains the selection',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
// On iOS/iPadOS, during a tap we select the edge of the word closest to the tap.
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextField(
controller: controller,
),
),
),
);
final Offset vPos = textOffsetToPosition(tester, 29); // Index of 'Bonav|enture'.
final Offset ePos = textOffsetToPosition(tester, 35) + const Offset(7.0, 0.0); // Index of 'Bonaventure|' + Offset(7.0,0), which taps slightly to the right of the end of the text.
final Offset wPos = textOffsetToPosition(tester, 3); // Index of 'Atw|ater'.
// This tap just puts the cursor somewhere different than where the double
// tap will occur to test that the double tap moves the existing cursor first.
await tester.tapAt(wPos);
await tester.pump(const Duration(milliseconds: 500));
await tester.tapAt(vPos);
await tester.pump(const Duration(milliseconds: 50));
// First tap moved the cursor.
expect(controller.selection.isCollapsed, true);
expect(
controller.selection.baseOffset,
35,
);
await tester.tapAt(vPos);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
// Second tap selects the word around the cursor.
expect(
controller.selection,
const TextSelection(baseOffset: 24, extentOffset: 35),
);
// Selected text shows 3 toolbar buttons.
expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3));
// Tap the selected word to hide the toolbar and retain the selection.
await tester.tapAt(vPos);
await tester.pumpAndSettle();
expect(
controller.selection,
const TextSelection(baseOffset: 24, extentOffset: 35),
);
expect(find.byType(CupertinoButton), findsNothing);
// Tap the selected word to show the toolbar and retain the selection.
await tester.tapAt(vPos);
await tester.pumpAndSettle();
expect(
controller.selection,
const TextSelection(baseOffset: 24, extentOffset: 35),
);
expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3));
// Tap past the selected word to move the cursor and hide the toolbar.
await tester.tapAt(ePos);
await tester.pumpAndSettle();
expect(
controller.selection,
const TextSelection.collapsed(offset: 35),
);
expect(find.byType(CupertinoButton), findsNothing); expect(find.byType(CupertinoButton), findsNothing);
}, }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);
testWidgets( testWidgets(
'double tap selects word and first tap of double tap moves cursor', 'double tap selects word and first tap of double tap moves cursor',
...@@ -2777,13 +2701,11 @@ void main() { ...@@ -2777,13 +2701,11 @@ void main() {
// Double tap selecting the same word somewhere else is fine. // Double tap selecting the same word somewhere else is fine.
await tester.tapAt(textFieldStart + const Offset(100.0, 5.0)); await tester.tapAt(textFieldStart + const Offset(100.0, 5.0));
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
// First tap hides the toolbar, and retains the selection. // First tap moved the cursor.
expect( expect(
controller.selection, controller.selection,
const TextSelection(baseOffset: 0, extentOffset: 7), const TextSelection.collapsed(offset: 7, affinity: TextAffinity.upstream),
); );
expect(find.byType(CupertinoButton), findsNothing);
// Second tap shows the toolbar, and retains the selection.
await tester.tapAt(textFieldStart + const Offset(100.0, 5.0)); await tester.tapAt(textFieldStart + const Offset(100.0, 5.0));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
...@@ -2794,12 +2716,11 @@ void main() { ...@@ -2794,12 +2716,11 @@ void main() {
await tester.tapAt(textFieldStart + const Offset(150.0, 5.0)); await tester.tapAt(textFieldStart + const Offset(150.0, 5.0));
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
// First tap moved the cursor and hides the toolbar. // First tap moved the cursor.
expect( expect(
controller.selection, controller.selection,
const TextSelection.collapsed(offset: 8), const TextSelection.collapsed(offset: 8),
); );
expect(find.byType(CupertinoButton), findsNothing);
await tester.tapAt(textFieldStart + const Offset(150.0, 5.0)); await tester.tapAt(textFieldStart + const Offset(150.0, 5.0));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
......
...@@ -7551,88 +7551,10 @@ void main() { ...@@ -7551,88 +7551,10 @@ void main() {
expect(controller.selection.isCollapsed, isTrue); expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, isTargetPlatformMobile ? 7 : 6); expect(controller.selection.baseOffset, isTargetPlatformMobile ? 7 : 6);
// Toolbar shows on iOS. // No toolbar.
expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(2) : findsNothing);
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }),
);
testWidgets(
'Tapping on a non-collapsed selection toggles the toolbar and retains the selection',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
// On iOS/iPadOS, during a tap we select the edge of the word closest to the tap.
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: TextField(
controller: controller,
),
),
),
),
);
final Offset vPos = textOffsetToPosition(tester, 29); // Index of 'Bonav|enture'.
final Offset ePos = textOffsetToPosition(tester, 35) + const Offset(7.0, 0.0); // Index of 'Bonaventure|' + Offset(7.0,0), which taps slightly to the right of the end of the text.
final Offset wPos = textOffsetToPosition(tester, 3); // Index of 'Atw|ater'.
// This tap just puts the cursor somewhere different than where the double
// tap will occur to test that the double tap moves the existing cursor first.
await tester.tapAt(wPos);
await tester.pump(const Duration(milliseconds: 500));
await tester.tapAt(vPos);
await tester.pump(const Duration(milliseconds: 50));
// First tap moved the cursor.
expect(controller.selection.isCollapsed, true);
expect(
controller.selection.baseOffset,
35,
);
await tester.tapAt(vPos);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
// Second tap selects the word around the cursor.
expect(
controller.selection,
const TextSelection(baseOffset: 24, extentOffset: 35),
);
// Selected text shows 3 toolbar buttons.
expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3));
// Tap the selected word to hide the toolbar and retain the selection.
await tester.tapAt(vPos);
await tester.pumpAndSettle();
expect(
controller.selection,
const TextSelection(baseOffset: 24, extentOffset: 35),
);
expect(find.byType(CupertinoButton), findsNothing);
// Tap the selected word to show the toolbar and retain the selection.
await tester.tapAt(vPos);
await tester.pumpAndSettle();
expect(
controller.selection,
const TextSelection(baseOffset: 24, extentOffset: 35),
);
expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3));
// Tap past the selected word to move the cursor and hide the toolbar.
await tester.tapAt(ePos);
await tester.pumpAndSettle();
expect(
controller.selection,
const TextSelection.collapsed(offset: 35),
);
expect(find.byType(CupertinoButton), findsNothing); expect(find.byType(CupertinoButton), findsNothing);
}, },
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }), variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }),
); );
testWidgets( testWidgets(
...@@ -9023,13 +8945,11 @@ void main() { ...@@ -9023,13 +8945,11 @@ void main() {
// Double tap selecting the same word somewhere else is fine. // Double tap selecting the same word somewhere else is fine.
await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); await tester.tapAt(textfieldStart + const Offset(100.0, 9.0));
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
// First tap hides the toolbar and retains the selection. // First tap moved the cursor.
expect( expect(
controller.selection, controller.selection,
const TextSelection(baseOffset: 0, extentOffset: 7), const TextSelection.collapsed(offset: 7, affinity: TextAffinity.upstream),
); );
expect(find.byType(CupertinoButton), findsNothing);
// Second tap shows the toolbar and retains the selection.
await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); await tester.tapAt(textfieldStart + const Offset(100.0, 9.0));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
...@@ -9040,12 +8960,11 @@ void main() { ...@@ -9040,12 +8960,11 @@ void main() {
await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); await tester.tapAt(textfieldStart + const Offset(150.0, 9.0));
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
// First tap moved the cursor and hides the toolbar. // First tap moved the cursor.
expect( expect(
controller.selection, controller.selection,
const TextSelection.collapsed(offset: 8), const TextSelection.collapsed(offset: 8),
); );
expect(find.byType(CupertinoButton), findsNothing);
await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); await tester.tapAt(textfieldStart + const Offset(150.0, 9.0));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
......
...@@ -569,38 +569,6 @@ void main() { ...@@ -569,38 +569,6 @@ void main() {
} }
}, variant: TargetPlatformVariant.all()); }, variant: TargetPlatformVariant.all());
testWidgets('test TextSelectionGestureDetectorBuilder toggles toolbar on single tap on previous selection iOS', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeEditableTextState state = tester.state(find.byType(FakeEditableText));
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
expect(state.showToolbarCalled, isFalse);
expect(state.toggleToolbarCalled, isFalse);
renderEditable.selection = const TextSelection(baseOffset: 2, extentOffset: 6);
renderEditable.hasFocus = true;
final TestGesture gesture = await tester.startGesture(
const Offset(25.0, 200.0),
pointer: 0,
);
await gesture.up();
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
expect(renderEditable.selectWordEdgeCalled, isFalse);
expect(state.toggleToolbarCalled, isTrue);
break;
case TargetPlatform.macOS:
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(renderEditable.selectPositionAtCalled, isTrue);
break;
}
}, variant: TargetPlatformVariant.all());
testWidgets('test TextSelectionGestureDetectorBuilder double tap', (WidgetTester tester) async { testWidgets('test TextSelectionGestureDetectorBuilder double tap', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester); await pumpTextSelectionGestureDetectorBuilder(tester);
final TestGesture gesture = await tester.startGesture( final TestGesture gesture = await tester.startGesture(
...@@ -1396,7 +1364,6 @@ class FakeEditableText extends EditableText { ...@@ -1396,7 +1364,6 @@ class FakeEditableText extends EditableText {
class FakeEditableTextState extends EditableTextState { class FakeEditableTextState extends EditableTextState {
final GlobalKey _editableKey = GlobalKey(); final GlobalKey _editableKey = GlobalKey();
bool showToolbarCalled = false; bool showToolbarCalled = false;
bool toggleToolbarCalled = false;
@override @override
RenderEditable get renderEditable => _editableKey.currentContext!.findRenderObject()! as RenderEditable; RenderEditable get renderEditable => _editableKey.currentContext!.findRenderObject()! as RenderEditable;
...@@ -1408,8 +1375,7 @@ class FakeEditableTextState extends EditableTextState { ...@@ -1408,8 +1375,7 @@ class FakeEditableTextState extends EditableTextState {
} }
@override @override
void toggleToolbar([bool hideHandles = true]) { void toggleToolbar() {
toggleToolbarCalled = true;
return; return;
} }
......
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