From 211d83d772926d62626be1216f6e5dab51ce197b Mon Sep 17 00:00:00 2001 From: Kishan Rathore <34465683+rkishan516@users.noreply.github.com> Date: Thu, 6 Feb 2025 02:41:26 +0530 Subject: [PATCH] fix: RangeError when selecting text in SelectionArea (#162228) fix: RangeError when selecting text in SelectionArea fixes #161931 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --- .../lib/src/widgets/selectable_region.dart | 2 +- .../test/widgets/selectable_region_test.dart | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 7829d697c8..990ef8dc37 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -3027,7 +3027,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai if (event.forward) { currentSelectionStartIndex = currentSelectionEndIndex = 0; } else { - currentSelectionStartIndex = currentSelectionEndIndex = selectables.length; + currentSelectionStartIndex = currentSelectionEndIndex = selectables.length - 1; } } int targetIndex = event.isEnd ? currentSelectionEndIndex : currentSelectionStartIndex; diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 0becfed643..f05d5dafa9 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -4827,6 +4827,92 @@ void main() { expect(paragraph1.selections[0].end, 2); }, variant: TargetPlatformVariant.all()); + testWidgets( + 'should not throw range error when selecting previous paragraph', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + selectionControls: materialTextSelectionControls, + child: const Column( + children: [ + Text('How are you?'), + Text('Good, and you?'), + Text('Fine, thank you.'), + ], + ), + ), + ), + ); + // Select from offset 2 of paragraph3 to offset 6 of paragraph3. + final RenderParagraph paragraph3 = tester.renderObject( + find.descendant(of: find.text('Fine, thank you.'), matching: find.byType(RichText)), + ); + final TestGesture gesture = await tester.startGesture( + textOffsetToPosition(paragraph3, 2), + kind: PointerDeviceKind.mouse, + ); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.moveTo(textOffsetToPosition(paragraph3, 6)); + await gesture.up(); + await tester.pump(); + + final bool alt; + final bool meta; + switch (defaultTargetPlatform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + meta = false; + alt = true; + case TargetPlatform.iOS: + case TargetPlatform.macOS: + meta = true; + alt = false; + } + + // How are you? + // Good, and you? + // Fi[ne, ]thank you. + expect(paragraph3.selections.length, 1); + expect(paragraph3.selections[0].start, 2); + expect(paragraph3.selections[0].end, 6); + + await sendKeyCombination( + tester, + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: alt, meta: meta), + ); + await tester.pump(); + // How are you? + // Good, and you? + // [Fine, ]thank you. + expect(paragraph3.selections.length, 1); + expect(paragraph3.selections[0].start, 0); + expect(paragraph3.selections[0].end, 6); + + await sendKeyCombination( + tester, + const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true), + ); + await tester.pump(); + // How are you? + // Good, and you[? + // Fine, ]thank you. + final RenderParagraph paragraph2 = tester.renderObject( + find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText)), + ); + expect(paragraph3.selections.length, 1); + expect(paragraph3.selections[0].start, 0); + expect(paragraph3.selections[0].end, 6); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 13); + expect(paragraph2.selections[0].end, 14); + }, + variant: TargetPlatformVariant.all(), + ); + testWidgets( 'can use keyboard to granularly extend selection - document', (WidgetTester tester) async {