Unverified Commit 90f8ac5b authored by Renzo Olivares's avatar Renzo Olivares Committed by GitHub

TapAndDragGestureRecognizer should declare victory immediately when drag is detected (#123055)

TapAndDragGestureRecognizer should declare victory immediately when drag is detected
parent a690c048
...@@ -3112,22 +3112,46 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec ...@@ -3112,22 +3112,46 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec
if (widget.onDragSelectionStart != null || if (widget.onDragSelectionStart != null ||
widget.onDragSelectionUpdate != null || widget.onDragSelectionUpdate != null ||
widget.onDragSelectionEnd != null) { widget.onDragSelectionEnd != null) {
gestures[TapAndDragGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapAndDragGestureRecognizer>( switch (defaultTargetPlatform) {
() => TapAndDragGestureRecognizer(debugOwner: this), case TargetPlatform.android:
(TapAndDragGestureRecognizer instance) { case TargetPlatform.fuchsia:
instance case TargetPlatform.iOS:
// Text selection should start from the position of the first pointer gestures[TapAndHorizontalDragGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapAndHorizontalDragGestureRecognizer>(
// down event. () => TapAndHorizontalDragGestureRecognizer(debugOwner: this),
..dragStartBehavior = DragStartBehavior.down (TapAndHorizontalDragGestureRecognizer instance) {
..dragUpdateThrottleFrequency = _kDragSelectionUpdateThrottle instance
..onTapDown = _handleTapDown // Text selection should start from the position of the first pointer
..onDragStart = _handleDragStart // down event.
..onDragUpdate = _handleDragUpdate ..dragStartBehavior = DragStartBehavior.down
..onDragEnd = _handleDragEnd ..dragUpdateThrottleFrequency = _kDragSelectionUpdateThrottle
..onTapUp = _handleTapUp ..onTapDown = _handleTapDown
..onCancel = _handleTapCancel; ..onDragStart = _handleDragStart
}, ..onDragUpdate = _handleDragUpdate
); ..onDragEnd = _handleDragEnd
..onTapUp = _handleTapUp
..onCancel = _handleTapCancel;
},
);
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
gestures[TapAndPanGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapAndPanGestureRecognizer>(
() => TapAndPanGestureRecognizer(debugOwner: this),
(TapAndPanGestureRecognizer instance) {
instance
// Text selection should start from the position of the first pointer
// down event.
..dragStartBehavior = DragStartBehavior.down
..dragUpdateThrottleFrequency = _kDragSelectionUpdateThrottle
..onTapDown = _handleTapDown
..onDragStart = _handleDragStart
..onDragUpdate = _handleDragUpdate
..onDragEnd = _handleDragEnd
..onTapUp = _handleTapUp
..onCancel = _handleTapCancel;
},
);
}
} }
if (widget.onForcePressStart != null || widget.onForcePressEnd != null) { if (widget.onForcePressStart != null || widget.onForcePressEnd != null) {
......
...@@ -5412,6 +5412,130 @@ void main() { ...@@ -5412,6 +5412,130 @@ void main() {
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }), variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
); );
testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS) - multiline', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
await tester.pumpWidget(
CupertinoApp(
home: CupertinoPageScaffold(
child: CupertinoTextField(
dragStartBehavior: DragStartBehavior.down,
controller: controller,
maxLines: null,
),
),
),
);
const String testValue = 'abc\ndef\nghi';
await tester.enterText(find.byType(CupertinoTextField), testValue);
await tester.pumpAndSettle(const Duration(milliseconds: 200));
final Offset aPos = textOffsetToPosition(tester, testValue.indexOf('a'));
final Offset iPos = textOffsetToPosition(tester, testValue.indexOf('i'));
// Tap on text field to gain focus, and set selection to '|a'. On iOS
// the selection is set to the word edge closest to the tap position.
// We await for kDoubleTapTimeout after the up event, so our next down event
// does not register as a double tap.
final TestGesture gesture = await tester.startGesture(aPos);
await tester.pump();
await gesture.up();
await tester.pumpAndSettle(kDoubleTapTimeout);
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, 0);
// If the position we tap during a drag start is on the collapsed selection, then
// we can move the cursor with a drag.
// Here we tap on '|a', where our selection was previously, and move to '|i'.
await gesture.down(aPos);
await tester.pump();
await gesture.moveTo(iPos);
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, testValue.indexOf('i'));
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);
testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS) - ListView', (WidgetTester tester) async {
// This is a regression test for
// https://github.com/flutter/flutter/issues/122519
final TextEditingController controller = TextEditingController();
await tester.pumpWidget(
CupertinoApp(
home: CupertinoPageScaffold(
child: CupertinoTextField(
dragStartBehavior: DragStartBehavior.down,
controller: controller,
maxLines: null,
),
),
),
);
const String testValue = 'abc\ndef\nghi';
await tester.enterText(find.byType(CupertinoTextField), testValue);
await tester.pumpAndSettle(const Duration(milliseconds: 200));
final Offset aPos = textOffsetToPosition(tester, testValue.indexOf('a'));
final Offset gPos = textOffsetToPosition(tester, testValue.indexOf('g'));
final Offset iPos = textOffsetToPosition(tester, testValue.indexOf('i'));
// Tap on text field to gain focus, and set selection to '|a'. On iOS
// the selection is set to the word edge closest to the tap position.
// We await for kDoubleTapTimeout after the up event, so our next down event
// does not register as a double tap.
final TestGesture gesture = await tester.startGesture(aPos);
await tester.pump();
await gesture.up();
await tester.pumpAndSettle(kDoubleTapTimeout);
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, 0);
// If the position we tap during a drag start is on the collapsed selection, then
// we can move the cursor with a drag.
// Here we tap on '|a', where our selection was previously, and attempt move
// to '|g'. The cursor will not move because the `VerticalDragGestureRecognizer`
// in the scrollable will beat the `TapAndHorizontalDragGestureRecognizer`
// in the TextField. This is because moving from `|a` to `|g` is a completely
// vertical movement.
await gesture.down(aPos);
await tester.pump();
await gesture.moveTo(gPos);
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, 0);
// Release the pointer.
await gesture.up();
await tester.pumpAndSettle();
// If the position we tap during a drag start is on the collapsed selection, then
// we can move the cursor with a drag.
// Here we tap on '|a', where our selection was previously, and move to '|i'.
// Unlike our previous attempt to drag to `|g`, this works because moving
// to `|i` includes a horizontal movement so the `TapAndHorizontalDragGestureRecognizer`
// in TextField can beat the `VerticalDragGestureRecognizer` in the scrollable.
await gesture.down(aPos);
await tester.pump();
await gesture.moveTo(iPos);
await tester.pumpAndSettle();
await gesture.up();
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, testValue.indexOf('i'));
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);
testWidgets('Can move cursor when dragging (Android)', (WidgetTester tester) async { testWidgets('Can move cursor when dragging (Android)', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
......
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