Shift tap on an unfocused field (#97543)

This commit is contained in:
Justin McCandless 2022-02-10 16:05:19 -08:00 committed by GitHub
parent ea6025ca49
commit 33a16f44aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 128 additions and 3 deletions

View file

@ -951,17 +951,20 @@ class TextSelectionGestureDetectorBuilder {
// Either base or extent will be moved to the last tapped position, whichever
// is closest. The selection will never shrink or pivot, only grow.
//
// If fromSelection is given, will expand from that selection instead of the
// current selection in renderEditable.
//
// See also:
//
// * [_extendSelection], which is similar but pivots the selection around
// the base.
void _expandSelection(Offset offset, SelectionChangedCause cause) {
void _expandSelection(Offset offset, SelectionChangedCause cause, [TextSelection? fromSelection]) {
assert(cause != null);
assert(offset != null);
assert(renderEditable.selection?.baseOffset != null);
final TextPosition tappedPosition = renderEditable.getPositionForPoint(offset);
final TextSelection selection = renderEditable.selection!;
final TextSelection selection = fromSelection ?? renderEditable.selection!;
final bool baseIsCloser =
(tappedPosition.offset - selection.baseOffset).abs()
< (tappedPosition.offset - selection.extentOffset).abs();
@ -1069,7 +1072,16 @@ class TextSelectionGestureDetectorBuilder {
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
_expandSelection(details.globalPosition, SelectionChangedCause.tap);
// On these platforms, a shift-tapped unfocused field expands from 0,
// not from the previous selection.
final TextSelection? fromSelection = renderEditable.hasFocus
? null
: const TextSelection.collapsed(offset: 0);
_expandSelection(
details.globalPosition,
SelectionChangedCause.tap,
fromSelection,
);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:

View file

@ -5053,6 +5053,62 @@ void main() {
expect(controller.selection.extentOffset, 4);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }));
testWidgets('shift tapping an unfocused field', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
final FocusNode focusNode = FocusNode();
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextField(
controller: controller,
focusNode: focusNode,
),
),
),
);
expect(focusNode.hasFocus, isFalse);
// Put the cursor at the end of the field.
await tester.tapAt(textOffsetToPosition(tester, controller.text.length));
await tester.pump(kDoubleTapTimeout);
await tester.pumpAndSettle();
expect(focusNode.hasFocus, isTrue);
expect(controller.selection.baseOffset, 35);
expect(controller.selection.extentOffset, 35);
// Unfocus the field, but the selection remains.
focusNode.unfocus();
await tester.pumpAndSettle();
expect(focusNode.hasFocus, isFalse);
expect(controller.selection.baseOffset, 35);
expect(controller.selection.extentOffset, 35);
// Shift tap in the middle of the field.
await tester.sendKeyDownEvent(LogicalKeyboardKey.shift);
await tester.tapAt(textOffsetToPosition(tester, 20));
await tester.pumpAndSettle();
expect(focusNode.hasFocus, isTrue);
switch (defaultTargetPlatform) {
// Apple platforms start the selection from 0.
case TargetPlatform.iOS:
case TargetPlatform.macOS:
expect(controller.selection.baseOffset, 0);
break;
// Other platforms start from the previous selection.
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(controller.selection.baseOffset, 35);
break;
}
expect(controller.selection.extentOffset, 20);
}, variant: TargetPlatformVariant.all());
testWidgets('can shift + tap + drag to select with a keyboard (Apple platforms)', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',

View file

@ -10560,6 +10560,63 @@ void main() {
expect(controller.selection.extentOffset, 4);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }));
testWidgets('shift tapping an unfocused field', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
final FocusNode focusNode = FocusNode();
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: TextField(
controller: controller,
focusNode: focusNode,
),
),
),
),
);
expect(focusNode.hasFocus, isFalse);
// Put the cursor at the end of the field.
await tester.tapAt(textOffsetToPosition(tester, controller.text.length));
await tester.pump(kDoubleTapTimeout);
await tester.pumpAndSettle();
expect(focusNode.hasFocus, isTrue);
expect(controller.selection.baseOffset, 35);
expect(controller.selection.extentOffset, 35);
// Unfocus the field, but the selection remains.
focusNode.unfocus();
await tester.pumpAndSettle();
expect(focusNode.hasFocus, isFalse);
expect(controller.selection.baseOffset, 35);
expect(controller.selection.extentOffset, 35);
// Shift tap in the middle of the field.
await tester.sendKeyDownEvent(LogicalKeyboardKey.shift);
await tester.tapAt(textOffsetToPosition(tester, 20));
await tester.pumpAndSettle();
expect(focusNode.hasFocus, isTrue);
switch (defaultTargetPlatform) {
// Apple platforms start the selection from 0.
case TargetPlatform.iOS:
case TargetPlatform.macOS:
expect(controller.selection.baseOffset, 0);
break;
// Other platforms start from the previous selection.
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(controller.selection.baseOffset, 35);
break;
}
expect(controller.selection.extentOffset, 20);
}, variant: TargetPlatformVariant.all());
testWidgets('can shift + tap + drag to select with a keyboard (Apple platforms)', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',