From a9164a4d76c7fbcfad6ef277b7ece58ff3d037ae Mon Sep 17 00:00:00 2001 From: Paurakh Sharma Humagain Date: Fri, 23 Jun 2023 22:32:47 +0545 Subject: [PATCH] fix: Inconsistency of SelectionArea when scrolling (#128765) This PR fixes inconsistency of SelectionArea when scrolling by removing the `_clearSelection` on `longPressUpdate` gesture. This in turn makes the selection UX much better. *List which issues are fixed by this PR. You must list at least one issue.* Fixes: https://github.com/flutter/flutter/issues/120892 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/widgets/selectable_region.dart | 3 +- .../test/widgets/selectable_region_test.dart | 76 +++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 3f49cfbd46..1786b00ff7 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -439,8 +439,7 @@ class SelectableRegionState extends State with TextSelectionDe instance ..onLongPressStart = _handleTouchLongPressStart ..onLongPressMoveUpdate = _handleTouchLongPressMoveUpdate - ..onLongPressEnd = _handleTouchLongPressEnd - ..onLongPressCancel = _clearSelection; + ..onLongPressEnd = _handleTouchLongPressEnd; }, ); } diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index af9dfdb354..00b826f0ca 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -310,6 +310,82 @@ void main() { expect(edgeEvent.globalPosition, const Offset(200.0, 50.0)); }); + testWidgets( + 'touch long press cancel does not send ClearSelectionEvent', + (WidgetTester tester) async { + final UniqueKey spy = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: SelectionSpy(key: spy), + ), + ), + ); + await tester.pumpAndSettle(); + + final RenderSelectionSpy renderSelectionSpy = + tester.renderObject(find.byKey(spy)); + renderSelectionSpy.events.clear(); + final TestGesture gesture = + await tester.startGesture(const Offset(200.0, 200.0)); + + addTearDown(gesture.removePointer); + + await tester.pump(const Duration(milliseconds: 500)); + await gesture.cancel(); + expect( + renderSelectionSpy.events.any((SelectionEvent element) => element is ClearSelectionEvent), + isFalse, + ); + }, + ); + + testWidgets( + 'scrolling after the selection does not send ClearSelectionEvent', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/128765 + final UniqueKey spy = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + home: SizedBox( + height: 750, + child: SingleChildScrollView( + child: SizedBox( + height: 2000, + child: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: SelectionSpy(key: spy), + ), + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + + final RenderSelectionSpy renderSelectionSpy = tester.renderObject(find.byKey(spy)); + renderSelectionSpy.events.clear(); + final TestGesture selectGesture = await tester.startGesture(const Offset(200.0, 200.0)); + addTearDown(selectGesture.removePointer); + await tester.pump(const Duration(milliseconds: 500)); + await selectGesture.up(); + expect(renderSelectionSpy.events.length, 1); + expect(renderSelectionSpy.events[0], isA()); + + renderSelectionSpy.events.clear(); + final TestGesture scrollGesture = + await tester.startGesture(const Offset(250.0, 850.0)); + await tester.pump(const Duration(milliseconds: 500)); + await scrollGesture.moveTo(Offset.zero); + await scrollGesture.up(); + await tester.pumpAndSettle(); + expect(renderSelectionSpy.events.length, 0); + }, + ); + testWidgets('mouse long press does not send select-word event', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); await tester.pumpWidget(