Skip to content

Commit

Permalink
Text handle drag swap on Apple platforms (#105069)
Browse files Browse the repository at this point in the history
Dragging the base text selection handle on Apple makes it the extent.
  • Loading branch information
justinmc authored Jun 10, 2022
1 parent d8783ff commit 213bf37
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 19 deletions.
65 changes: 50 additions & 15 deletions packages/flutter/lib/src/widgets/text_selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -459,13 +459,31 @@ class TextSelectionOverlay {
return;
}

final TextSelection newSelection = TextSelection(
baseOffset: _selection.baseOffset,
extentOffset: position.offset,
);

if (newSelection.baseOffset >= newSelection.extentOffset) {
return; // Don't allow order swapping.
final TextSelection newSelection;
switch (defaultTargetPlatform) {
// On Apple platforms, dragging the base handle makes it the extent.
case TargetPlatform.iOS:
case TargetPlatform.macOS:
newSelection = TextSelection(
extentOffset: position.offset,
baseOffset: _selection.start,
);
if (position.offset <= _selection.start) {
return; // Don't allow order swapping.
}
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
newSelection = TextSelection(
baseOffset: _selection.baseOffset,
extentOffset: position.offset,
);
if (newSelection.baseOffset >= newSelection.extentOffset) {
return; // Don't allow order swapping.
}
break;
}

_handleSelectionHandleChanged(newSelection, isEnd: true);
Expand All @@ -489,13 +507,31 @@ class TextSelectionOverlay {
return;
}

final TextSelection newSelection = TextSelection(
baseOffset: position.offset,
extentOffset: _selection.extentOffset,
);

if (newSelection.baseOffset >= newSelection.extentOffset) {
return; // Don't allow order swapping.
final TextSelection newSelection;
switch (defaultTargetPlatform) {
// On Apple platforms, dragging the base handle makes it the extent.
case TargetPlatform.iOS:
case TargetPlatform.macOS:
newSelection = TextSelection(
extentOffset: position.offset,
baseOffset: _selection.end,
);
if (newSelection.extentOffset >= _selection.end) {
return; // Don't allow order swapping.
}
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
newSelection = TextSelection(
baseOffset: position.offset,
extentOffset: _selection.extentOffset,
);
if (newSelection.baseOffset >= newSelection.extentOffset) {
return; // Don't allow order swapping.
}
break;
}

_handleSelectionHandleChanged(newSelection, isEnd: false);
Expand Down Expand Up @@ -1116,7 +1152,6 @@ class _SelectionHandleOverlay extends StatefulWidget {
}

class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with SingleTickerProviderStateMixin {

late AnimationController _controller;
Animation<double> get _opacity => _controller.view;

Expand Down
53 changes: 49 additions & 4 deletions packages/flutter/test/material/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2077,7 +2077,7 @@ void main() {
expect(selection.extentOffset, 7);

final RenderEditable renderEditable = findRenderEditable(tester);
final List<TextSelectionPoint> endpoints = globalize(
List<TextSelectionPoint> endpoints = globalize(
renderEditable.getEndpointsForSelection(selection),
renderEditable,
);
Expand All @@ -2100,6 +2100,36 @@ void main() {

// Drag the left handle 2 letters to the left.
handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
newHandlePos = textOffsetToPosition(tester, 2);
gesture = await tester.startGesture(handlePos, pointer: 7);
await tester.pump();
await gesture.moveTo(newHandlePos);
await tester.pump();
await gesture.up();
await tester.pump();

switch (defaultTargetPlatform) {
// On Apple platforms, dragging the base handle makes it the extent.
case TargetPlatform.iOS:
case TargetPlatform.macOS:
expect(controller.selection.baseOffset, 11);
expect(controller.selection.extentOffset, 2);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(controller.selection.baseOffset, 2);
expect(controller.selection.extentOffset, 11);
break;
}

// Drag the left handle 2 letters to the left again.
endpoints = globalize(
renderEditable.getEndpointsForSelection(controller.selection),
renderEditable,
);
handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
newHandlePos = textOffsetToPosition(tester, 0);
gesture = await tester.startGesture(handlePos, pointer: 7);
await tester.pump();
Expand All @@ -2108,9 +2138,24 @@ void main() {
await gesture.up();
await tester.pump();

expect(controller.selection.baseOffset, 0);
expect(controller.selection.extentOffset, 11);
});
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
// The left handle was already the extent, and it remains so.
expect(controller.selection.baseOffset, 11);
expect(controller.selection.extentOffset, 0);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(controller.selection.baseOffset, 0);
expect(controller.selection.extentOffset, 11);
break;
}
},
variant: TargetPlatformVariant.all(),
);

testWidgets('Cannot drag one handle past the other', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
Expand Down

0 comments on commit 213bf37

Please sign in to comment.