Skip to content

Commit

Permalink
Fix right clicking a field to focus (#103228)
Browse files Browse the repository at this point in the history
  • Loading branch information
justinmc authored May 19, 2022
1 parent 0f23e96 commit 384800b
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 14 deletions.
1 change: 1 addition & 0 deletions packages/flutter/lib/src/rendering/editable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1958,6 +1958,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
extentOffset: extentOffset,
affinity: fromPosition.affinity,
);

_setSelection(newSelection, cause);
}

Expand Down
44 changes: 30 additions & 14 deletions packages/flutter/lib/src/widgets/editable_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2441,6 +2441,23 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_selectionOverlay?.updateForScroll();
}

void _createSelectionOverlay() {
_selectionOverlay = TextSelectionOverlay(
clipboardStatus: _clipboardStatus,
context: context,
value: _value,
debugRequiredFor: widget,
toolbarLayerLink: _toolbarLayerLink,
startHandleLayerLink: _startHandleLayerLink,
endHandleLayerLink: _endHandleLayerLink,
renderObject: renderEditable,
selectionControls: widget.selectionControls,
selectionDelegate: this,
dragStartBehavior: widget.dragStartBehavior,
onSelectionHandleTapped: widget.onSelectionHandleTapped,
);
}

@pragma('vm:notify-debugger-on-exception')
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause? cause) {
// We return early if the selection is not valid. This can happen when the
Expand Down Expand Up @@ -2478,20 +2495,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_selectionOverlay = null;
} else {
if (_selectionOverlay == null) {
_selectionOverlay = TextSelectionOverlay(
clipboardStatus: _clipboardStatus,
context: context,
value: _value,
debugRequiredFor: widget,
toolbarLayerLink: _toolbarLayerLink,
startHandleLayerLink: _startHandleLayerLink,
endHandleLayerLink: _endHandleLayerLink,
renderObject: renderEditable,
selectionControls: widget.selectionControls,
selectionDelegate: this,
dragStartBehavior: widget.dragStartBehavior,
onSelectionHandleTapped: widget.onSelectionHandleTapped,
);
_createSelectionOverlay();
} else {
_selectionOverlay!.update(_value);
}
Expand Down Expand Up @@ -2943,6 +2947,18 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if (shouldShowCaret) {
_scheduleShowCaretOnScreen(withAnimation: true);
}

// Even if the value doesn't change, it may be necessary to focus and build
// the selection overlay. For example, this happens when right clicking an
// unfocused field that previously had a selection in the same spot.
if (value == textEditingValue) {
if (!widget.focusNode.hasFocus) {
widget.focusNode.requestFocus();
_createSelectionOverlay();
}
return;
}

_formatAndSetValue(value, cause, userInteraction: true);
}

Expand Down
52 changes: 52 additions & 0 deletions packages/flutter/test/cupertino/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5663,4 +5663,56 @@ void main() {
variant: TargetPlatformVariant.all(),
skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu.
);

testWidgets('Can right click to focus multiple times', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/pull/103228
final FocusNode focusNode1 = FocusNode();
final FocusNode focusNode2 = FocusNode();
final UniqueKey key1 = UniqueKey();
final UniqueKey key2 = UniqueKey();
await tester.pumpWidget(
CupertinoApp(
home: Column(
children: <Widget>[
CupertinoTextField(
key: key1,
focusNode: focusNode1,
),
CupertinoTextField(
key: key2,
focusNode: focusNode2,
),
],
),
),
);

// Interact with the field to establish the input connection.
await tester.tapAt(
tester.getCenter(find.byKey(key1)),
buttons: kSecondaryMouseButton,
);
await tester.pump();

expect(focusNode1.hasFocus, isTrue);
expect(focusNode2.hasFocus, isFalse);

await tester.tapAt(
tester.getCenter(find.byKey(key2)),
buttons: kSecondaryMouseButton,
);
await tester.pump();

expect(focusNode1.hasFocus, isFalse);
expect(focusNode2.hasFocus, isTrue);

await tester.tapAt(
tester.getCenter(find.byKey(key1)),
buttons: kSecondaryMouseButton,
);
await tester.pump();

expect(focusNode1.hasFocus, isTrue);
expect(focusNode2.hasFocus, isFalse);
});
}
54 changes: 54 additions & 0 deletions packages/flutter/test/material/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11399,4 +11399,58 @@ void main() {
variant: TargetPlatformVariant.all(),
skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu.
);

testWidgets('Can right click to focus multiple times', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/pull/103228
final FocusNode focusNode1 = FocusNode();
final FocusNode focusNode2 = FocusNode();
final UniqueKey key1 = UniqueKey();
final UniqueKey key2 = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Column(
children: <Widget>[
TextField(
key: key1,
focusNode: focusNode1,
),
TextField(
key: key2,
focusNode: focusNode2,
),
],
),
),
),
);

// Interact with the field to establish the input connection.
await tester.tapAt(
tester.getCenter(find.byKey(key1)),
buttons: kSecondaryButton,
);
await tester.pump();

expect(focusNode1.hasFocus, isTrue);
expect(focusNode2.hasFocus, isFalse);

await tester.tapAt(
tester.getCenter(find.byKey(key2)),
buttons: kSecondaryButton,
);
await tester.pump();

expect(focusNode1.hasFocus, isFalse);
expect(focusNode2.hasFocus, isTrue);

await tester.tapAt(
tester.getCenter(find.byKey(key1)),
buttons: kSecondaryButton,
);
await tester.pump();

expect(focusNode1.hasFocus, isTrue);
expect(focusNode2.hasFocus, isFalse);
});
}

0 comments on commit 384800b

Please sign in to comment.