Unverified Commit 916b2aa7 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Linux and Windows right clicking text behavior (#101588)

parent 8ffb1d21
......@@ -1615,14 +1615,29 @@ class TextSelectionGestureDetectorBuilder {
/// By default, selects the word if possible and shows the toolbar.
@protected
void onSecondaryTap() {
if (delegate.selectionEnabled) {
if (!_lastSecondaryTapWasOnSelection) {
renderEditable.selectWord(cause: SelectionChangedCause.tap);
}
if (shouldShowSelectionToolbar) {
editableText.hideToolbar();
editableText.showToolbar();
}
if (!delegate.selectionEnabled) {
return;
}
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
if (!_lastSecondaryTapWasOnSelection) {
renderEditable.selectWord(cause: SelectionChangedCause.tap);
}
if (shouldShowSelectionToolbar) {
editableText.hideToolbar();
editableText.showToolbar();
}
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
if (!renderEditable.hasFocus) {
renderEditable.selectPosition(cause: SelectionChangedCause.tap);
}
editableText.toggleToolbar();
break;
}
}
......
......@@ -5496,4 +5496,87 @@ void main() {
expect(controller.selection.baseOffset, 23);
expect(controller.selection.extentOffset, 14);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.linux, TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.windows }));
// Regression test for https://github.com/flutter/flutter/issues/101587.
testWidgets('Right clicking menu behavior', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'blah1 blah2',
);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextField(
controller: controller,
),
),
),
);
// Initially, the menu is not shown and there is no selection.
expect(find.byType(CupertinoButton), findsNothing);
expect(controller.selection, const TextSelection(baseOffset: -1, extentOffset: -1));
final Offset midBlah1 = textOffsetToPosition(tester, 2);
final Offset midBlah2 = textOffsetToPosition(tester, 8);
// Right click the second word.
final TestGesture gesture = await tester.startGesture(
midBlah2,
kind: PointerDeviceKind.mouse,
buttons: kSecondaryMouseButton,
);
addTearDown(gesture.removePointer);
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
expect(controller.selection, const TextSelection(baseOffset: 6, extentOffset: 11));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(controller.selection, const TextSelection.collapsed(offset: 8));
expect(find.text('Cut'), findsNothing);
expect(find.text('Copy'), findsNothing);
expect(find.text('Paste'), findsOneWidget);
break;
}
// Right click the first word.
await gesture.down(midBlah1);
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 5));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(controller.selection, const TextSelection.collapsed(offset: 8));
expect(find.text('Cut'), findsNothing);
expect(find.text('Copy'), findsNothing);
expect(find.text('Paste'), findsNothing);
break;
}
},
variant: TargetPlatformVariant.all(),
skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu.
);
}
......@@ -4613,8 +4613,8 @@ void main() {
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(newSelection!.baseOffset, 4);
expect(newSelection!.extentOffset, 7);
expect(newSelection!.isCollapsed, isTrue);
expect(newSelection!.baseOffset, 5);
newSelection = null;
await tester.tap(find.text('Select all'));
......
......@@ -455,7 +455,7 @@ void main() {
expect(renderEditable.selectPositionAtCalled, isTrue);
});
testWidgets('TextSelectionGestureDetectorBuilder right click', (WidgetTester tester) async {
testWidgets('TextSelectionGestureDetectorBuilder right click Apple platforms', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/80119
await pumpTextSelectionGestureDetectorBuilder(tester);
......@@ -496,7 +496,60 @@ void main() {
await gesture.up();
await tester.pump();
expect(renderEditable.selectWordCalled, isFalse);
});
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }),
);
testWidgets('TextSelectionGestureDetectorBuilder right click non-Apple platforms', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/80119
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
renderEditable.text = const TextSpan(text: 'one two three four five six seven');
await tester.pump();
final TestGesture gesture = await tester.createGesture(
pointer: 0,
kind: PointerDeviceKind.mouse,
buttons: kSecondaryButton,
);
addTearDown(gesture.removePointer);
// Get the location of the 10th character
final Offset charLocation = renderEditable
.getLocalRectForCaret(const TextPosition(offset: 10)).center;
final Offset globalCharLocation = charLocation + tester.getTopLeft(find.byType(FakeEditable));
// Right clicking on an unfocused field should place the cursor, not select
// the word.
await gesture.down(globalCharLocation);
await gesture.up();
await tester.pump();
expect(renderEditable.selectWordCalled, isFalse);
expect(renderEditable.selectPositionCalled, isTrue);
// Right clicking on a focused field with selection shouldn't change the
// selection.
renderEditable.selectPositionCalled = false;
renderEditable.selection = const TextSelection(baseOffset: 3, extentOffset: 20);
renderEditable.hasFocus = true;
await gesture.down(globalCharLocation);
await gesture.up();
await tester.pump();
expect(renderEditable.selectWordCalled, isFalse);
expect(renderEditable.selectPositionCalled, isFalse);
// Right clicking on a focused field with a reverse (right to left)
// selection shouldn't change the selection.
renderEditable.selection = const TextSelection(baseOffset: 20, extentOffset: 3);
await gesture.down(globalCharLocation);
await gesture.up();
await tester.pump();
expect(renderEditable.selectWordCalled, isFalse);
expect(renderEditable.selectPositionCalled, isFalse);
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }),
);
testWidgets('test TextSelectionGestureDetectorBuilder tap', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
......@@ -1083,6 +1136,11 @@ class FakeEditableTextState extends EditableTextState {
return true;
}
@override
void toggleToolbar() {
return;
}
@override
Widget build(BuildContext context) {
super.build(context);
......@@ -1144,11 +1202,21 @@ class FakeRenderEditable extends RenderEditable {
selectPositionAtTo = to;
}
bool selectPositionCalled = false;
@override
void selectPosition({ required SelectionChangedCause cause }) {
selectPositionCalled = true;
return super.selectPosition(cause: cause);
}
bool selectWordCalled = false;
@override
void selectWord({ required SelectionChangedCause cause }) {
selectWordCalled = true;
}
@override
bool hasFocus = false;
}
class CustomTextSelectionControls extends TextSelectionControls {
......
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