Unverified Commit 715fcaac authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Can't drag the cursor with the mouse (#103002)

parent 8afaf7b5
...@@ -1208,12 +1208,28 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with S ...@@ -1208,12 +1208,28 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with S
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
width: interactiveRect.width, width: interactiveRect.width,
height: interactiveRect.height, height: interactiveRect.height,
child: GestureDetector( child: RawGestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
dragStartBehavior: widget.dragStartBehavior, gestures: <Type, GestureRecognizerFactory>{
onPanStart: widget.onSelectionHandleDragStart, PanGestureRecognizer: GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
onPanUpdate: widget.onSelectionHandleDragUpdate, () => PanGestureRecognizer(
onPanEnd: widget.onSelectionHandleDragEnd, debugOwner: this,
// Mouse events select the text and do not drag the cursor.
supportedDevices: <PointerDeviceKind>{
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
},
),
(PanGestureRecognizer instance) {
instance
..dragStartBehavior = widget.dragStartBehavior
..onStart = widget.onSelectionHandleDragStart
..onUpdate = widget.onSelectionHandleDragUpdate
..onEnd = widget.onSelectionHandleDragEnd;
},
),
},
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: padding.left, left: padding.left,
......
...@@ -2897,7 +2897,7 @@ void main() { ...@@ -2897,7 +2897,7 @@ void main() {
// The selection doesn't move beyond the left handle. There's always at // The selection doesn't move beyond the left handle. There's always at
// least 1 char selected. // least 1 char selected.
expect(controller.selection.extentOffset, 5); expect(controller.selection.extentOffset, 5);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('Can select text by dragging with a mouse', (WidgetTester tester) async { testWidgets('Can select text by dragging with a mouse', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
...@@ -3571,7 +3571,7 @@ void main() { ...@@ -3571,7 +3571,7 @@ void main() {
expect(left.opacity.value, equals(1.0)); expect(left.opacity.value, equals(1.0));
expect(right.opacity.value, equals(1.0)); expect(right.opacity.value, equals(1.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('when CupertinoTextField would be blocked by keyboard, it is shown with enough space for the selection handle', (WidgetTester tester) async { testWidgets('when CupertinoTextField would be blocked by keyboard, it is shown with enough space for the selection handle', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
......
...@@ -9400,7 +9400,7 @@ void main() { ...@@ -9400,7 +9400,7 @@ void main() {
expect(left.opacity.value, equals(1.0)); expect(left.opacity.value, equals(1.0));
expect(right.opacity.value, equals(1.0)); expect(right.opacity.value, equals(1.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('iPad Scribble selection change shows selection handles', (WidgetTester tester) async { testWidgets('iPad Scribble selection change shows selection handles', (WidgetTester tester) async {
const String testText = 'lorem ipsum'; const String testText = 'lorem ipsum';
......
...@@ -7825,7 +7825,7 @@ void main() { ...@@ -7825,7 +7825,7 @@ void main() {
// On web, we don't show the Flutter toolbar and instead rely on the browser // On web, we don't show the Flutter toolbar and instead rely on the browser
// toolbar. Until we change that, this test should remain skipped. // toolbar. Until we change that, this test should remain skipped.
skip: kIsWeb, // [intended] skip: kIsWeb, // [intended]
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }) variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })
); );
testWidgets("scrolling doesn't bounce", (WidgetTester tester) async { testWidgets("scrolling doesn't bounce", (WidgetTester tester) async {
......
...@@ -4279,7 +4279,7 @@ void main() { ...@@ -4279,7 +4279,7 @@ void main() {
expect(left.opacity.value, equals(1.0)); expect(left.opacity.value, equals(1.0));
expect(right.opacity.value, equals(1.0)); expect(right.opacity.value, equals(1.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('Long press shows handles and toolbar', (WidgetTester tester) async { testWidgets('Long press shows handles and toolbar', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
......
...@@ -10,6 +10,7 @@ import 'package:flutter/services.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'clipboard_utils.dart'; import 'clipboard_utils.dart';
import 'editable_text_utils.dart';
void main() { void main() {
late int tapCount; late int tapCount;
...@@ -628,7 +629,7 @@ void main() { ...@@ -628,7 +629,7 @@ void main() {
}); });
testWidgets('Mouse drag does not show handles nor toolbar', (WidgetTester tester) async { testWidgets('Mouse drag does not show handles nor toolbar', (WidgetTester tester) async {
// Regressing test for https://github.com/flutter/flutter/issues/69001 // Regression test for https://github.com/flutter/flutter/issues/69001
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
home: Scaffold( home: Scaffold(
...@@ -652,6 +653,231 @@ void main() { ...@@ -652,6 +653,231 @@ void main() {
expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse); expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse);
}); });
testWidgets('Mouse drag selects and cannot drag cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
forcePressEnabled: false,
selectionEnabled: true,
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
await tester.pumpWidget(
MaterialApp(
home: provider.buildGestureDetector(
behavior: HitTestBehavior.translucent,
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
selectionControls: materialTextSelectionControls,
),
),
),
);
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, -1);
final Offset position = textOffsetToPosition(tester, 4);
await tester.tapAt(position);
await tester.pump();
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 4);
final TestGesture gesture = await tester.startGesture(position, kind: PointerDeviceKind.mouse);
addTearDown(gesture.removePointer);
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 7));
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 10));
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, isFalse);
expect(controller.selection.baseOffset, 4);
expect(controller.selection.extentOffset, 10);
});
testWidgets('Touch drag moves the cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
forcePressEnabled: false,
selectionEnabled: true,
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
await tester.pumpWidget(
MaterialApp(
home: provider.buildGestureDetector(
behavior: HitTestBehavior.translucent,
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
selectionControls: materialTextSelectionControls,
),
),
),
);
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, -1);
final Offset position = textOffsetToPosition(tester, 4);
await tester.tapAt(position);
await tester.pump();
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 4);
final TestGesture gesture = await tester.startGesture(position);
addTearDown(gesture.removePointer);
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 7));
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 10));
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 10);
});
testWidgets('Stylus drag moves the cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
forcePressEnabled: false,
selectionEnabled: true,
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
await tester.pumpWidget(
MaterialApp(
home: provider.buildGestureDetector(
behavior: HitTestBehavior.translucent,
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
selectionControls: materialTextSelectionControls,
),
),
),
);
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, -1);
final Offset position = textOffsetToPosition(tester, 4);
await tester.tapAt(position);
await tester.pump();
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 4);
final TestGesture gesture = await tester.startGesture(position, kind: PointerDeviceKind.stylus);
addTearDown(gesture.removePointer);
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 7));
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 10));
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 10);
});
testWidgets('Drag of unknown type moves the cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
forcePressEnabled: false,
selectionEnabled: true,
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
await tester.pumpWidget(
MaterialApp(
home: provider.buildGestureDetector(
behavior: HitTestBehavior.translucent,
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
selectionControls: materialTextSelectionControls,
),
),
),
);
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, -1);
final Offset position = textOffsetToPosition(tester, 4);
await tester.tapAt(position);
await tester.pump();
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 4);
final TestGesture gesture = await tester.startGesture(position, kind: PointerDeviceKind.unknown);
addTearDown(gesture.removePointer);
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 7));
await tester.pump();
await gesture.moveTo(textOffsetToPosition(tester, 10));
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 10);
});
testWidgets('test TextSelectionGestureDetectorBuilder drag with RenderEditable viewport offset change', (WidgetTester tester) async { testWidgets('test TextSelectionGestureDetectorBuilder drag with RenderEditable viewport offset change', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester); await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable)); final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
...@@ -767,7 +993,7 @@ void main() { ...@@ -767,7 +993,7 @@ void main() {
of: find.byType(CompositedTransformFollower), of: find.byType(CompositedTransformFollower),
matching: find.descendant( matching: find.descendant(
of: find.byType(FadeTransition), of: find.byType(FadeTransition),
matching: find.byType(GestureDetector), matching: find.byType(RawGestureDetector),
), ),
); );
......
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