Unverified Commit 0d8de393 authored by Mouad Debbar's avatar Mouad Debbar Committed by GitHub

[web] Don't show handles when selection change is caused by keyboard (#65127)

parent 389b5b6c
......@@ -1643,7 +1643,11 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
}
_formatAndSetValue(value);
if (_isSelectionOnlyChange(value)) {
_handleSelectionChanged(value.selection, renderEditable, SelectionChangedCause.keyboard);
} else {
_formatAndSetValue(value);
}
if (_hasInputConnection) {
// To keep the cursor from blinking while typing, we want to restart the
......@@ -1653,6 +1657,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
}
bool _isSelectionOnlyChange(TextEditingValue value) {
return value.text == _value.text && value.composing == _value.composing;
}
@override
void performAction(TextInputAction action) {
switch (action) {
......
......@@ -7795,6 +7795,48 @@ void main() {
},
);
testWidgets('Does not show handles when updated from the web engine', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'abc def ghi',
);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: TextField(controller: controller),
),
),
);
// Interact with the text field to establish the input connection.
final Offset topLeft = tester.getTopLeft(find.byType(EditableText));
final TestGesture gesture = await tester.startGesture(
topLeft + const Offset(0.0, 5.0),
kind: PointerDeviceKind.mouse,
);
addTearDown(gesture.removePointer);
await tester.pump(const Duration(milliseconds: 50));
await gesture.up();
await tester.pumpAndSettle();
final EditableTextState state = tester.state(find.byType(EditableText));
expect(state.selectionOverlay.handlesAreVisible, isFalse);
expect(controller.selection, const TextSelection.collapsed(offset: 0));
if (kIsWeb) {
tester.testTextInput.updateEditingValue(const TextEditingValue(
selection: TextSelection(baseOffset: 2, extentOffset: 7),
));
// Wait for all the `setState` calls to be flushed.
await tester.pumpAndSettle();
expect(
state.currentTextEditingValue.selection,
const TextSelection(baseOffset: 2, extentOffset: 7),
);
expect(state.selectionOverlay.handlesAreVisible, isFalse);
}
});
testWidgets('Tapping selection handles toggles the toolbar', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'abc def ghi',
......
......@@ -1398,6 +1398,46 @@ void main() {
}
});
testWidgets('Read-only fields do not format text', (WidgetTester tester) async {
SelectionChangedCause selectionCause;
final TextEditingController controller =
TextEditingController(text: 'Lorem ipsum dolor sit amet');
await tester.pumpWidget(
MaterialApp(
home: EditableText(
readOnly: true,
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
selectionControls: materialTextSelectionControls,
onSelectionChanged: (TextSelection selection, SelectionChangedCause cause) {
selectionCause = cause;
},
),
),
);
// Interact with the field to establish the input connection.
final Offset topLeft = tester.getTopLeft(find.byType(EditableText));
await tester.tapAt(topLeft + const Offset(0.0, 5.0));
await tester.pump();
expect(tester.testTextInput.hasAnyClients, kIsWeb ? isTrue : isFalse);
if (kIsWeb) {
tester.testTextInput.updateEditingValue(const TextEditingValue(
text: 'Foo bar',
selection: TextSelection(baseOffset: 0, extentOffset: 3),
));
// On web, the only way a text field can be updated from the engine is if
// a keyboard is used.
expect(selectionCause, SelectionChangedCause.keyboard);
}
});
testWidgets('Fires onChanged when text changes via TextSelectionOverlay', (WidgetTester tester) async {
String changedValue;
final Widget widget = MaterialApp(
......
......@@ -3971,4 +3971,45 @@ void main() {
TargetPlatform.windows,
}),
);
testWidgets('Does not show handles when updated from the web engine', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(
child: SelectableText('abc def ghi'),
),
),
);
// Interact with the selectable text to establish the input connection.
final Offset topLeft = tester.getTopLeft(find.byType(EditableText));
final TestGesture gesture = await tester.startGesture(
topLeft + const Offset(0.0, 5.0),
kind: PointerDeviceKind.mouse,
);
addTearDown(gesture.removePointer);
await tester.pump(const Duration(milliseconds: 50));
await gesture.up();
await tester.pumpAndSettle();
final EditableTextState state = tester.state(find.byType(EditableText));
expect(state.selectionOverlay.handlesAreVisible, isFalse);
expect(
state.currentTextEditingValue.selection,
const TextSelection.collapsed(offset: 0),
);
if (kIsWeb) {
tester.testTextInput.updateEditingValue(const TextEditingValue(
selection: TextSelection(baseOffset: 2, extentOffset: 7),
));
// Wait for all the `setState` calls to be flushed.
await tester.pumpAndSettle();
expect(
state.currentTextEditingValue.selection,
const TextSelection(baseOffset: 2, extentOffset: 7),
);
expect(state.selectionOverlay.handlesAreVisible, isFalse);
}
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment