Unverified Commit 153f3d23 authored by J-P Nurmi's avatar J-P Nurmi Committed by GitHub

Fix Editable(Text) shortcuts to respect read-only on desktop (#69891)

parent 22ec357b
...@@ -776,7 +776,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { ...@@ -776,7 +776,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
} }
return; return;
} }
if (key == LogicalKeyboardKey.keyX) { if (key == LogicalKeyboardKey.keyX && !_readOnly) {
if (!selection!.isCollapsed) { if (!selection!.isCollapsed) {
Clipboard.setData(ClipboardData(text: selection!.textInside(_plainText))); Clipboard.setData(ClipboardData(text: selection!.textInside(_plainText)));
textSelectionDelegate.textEditingValue = TextEditingValue( textSelectionDelegate.textEditingValue = TextEditingValue(
...@@ -787,7 +787,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { ...@@ -787,7 +787,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
} }
return; return;
} }
if (key == LogicalKeyboardKey.keyV) { if (key == LogicalKeyboardKey.keyV && !_readOnly) {
// Snapshot the input before using `await`. // Snapshot the input before using `await`.
// See https://github.com/flutter/flutter/issues/11427 // See https://github.com/flutter/flutter/issues/11427
final TextEditingValue value = textSelectionDelegate.textEditingValue; final TextEditingValue value = textSelectionDelegate.textEditingValue;
...@@ -818,6 +818,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { ...@@ -818,6 +818,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
void _handleDelete({ required bool forward }) { void _handleDelete({ required bool forward }) {
assert(_selection != null); assert(_selection != null);
if (_readOnly) {
return;
}
String textBefore = selection!.textBefore(_plainText); String textBefore = selection!.textBefore(_plainText);
String textAfter = selection!.textAfter(_plainText); String textAfter = selection!.textAfter(_plainText);
int cursorPosition = selection!.start; int cursorPosition = selection!.start;
......
...@@ -4364,6 +4364,181 @@ void main() { ...@@ -4364,6 +4364,181 @@ void main() {
// On web, using keyboard for selection is handled by the browser. // On web, using keyboard for selection is handled by the browser.
}, skip: kIsWeb); }, skip: kIsWeb);
testWidgets('keyboard shortcuts respect read-only', (WidgetTester tester) async {
final String platform = describeEnum(defaultTargetPlatform).toLowerCase();
final TextEditingController controller = TextEditingController(text: testText);
controller.selection = const TextSelection(
baseOffset: 0,
extentOffset: testText.length ~/2,
affinity: TextAffinity.upstream,
);
TextSelection? selection;
await tester.pumpWidget(MaterialApp(
home: Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: 400,
child: EditableText(
readOnly: true,
controller: controller,
autofocus: true,
focusNode: FocusNode(),
style: Typography.material2018(platform: TargetPlatform.android).black.subtitle1!,
cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey,
selectionControls: materialTextSelectionControls,
keyboardType: TextInputType.text,
textAlign: TextAlign.right,
onSelectionChanged: (TextSelection newSelection, SelectionChangedCause? newCause) {
selection = newSelection;
},
),
),
),
));
await tester.pump(); // Wait for autofocus to take effect.
const String clipboardContent = 'read-only';
await Clipboard.setData(const ClipboardData(text: clipboardContent));
// Paste
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.keyV,
],
shortcutModifier: true,
platform: platform,
);
expect(selection, isNull, reason: 'on $platform');
expect(controller.text, equals(testText), reason: 'on $platform');
// Select All
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.keyA,
],
shortcutModifier: true,
platform: platform,
);
expect(
selection!,
equals(
const TextSelection(
baseOffset: 0,
extentOffset: testText.length,
affinity: TextAffinity.upstream,
),
),
reason: 'on $platform',
);
expect(controller.text, equals(testText), reason: 'on $platform');
// Cut
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.keyX,
],
shortcutModifier: true,
platform: platform,
);
expect(
selection!,
equals(
const TextSelection(
baseOffset: 0,
extentOffset: testText.length,
affinity: TextAffinity.upstream,
),
),
reason: 'on $platform',
);
expect(controller.text, equals(testText), reason: 'on $platform');
expect(
(await Clipboard.getData(Clipboard.kTextPlain))!.text,
equals(clipboardContent),
reason: 'on $platform',
);
// Copy
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.keyC,
],
shortcutModifier: true,
platform: platform,
);
expect(
selection!,
equals(
const TextSelection(
baseOffset: 0,
extentOffset: testText.length,
affinity: TextAffinity.upstream,
),
),
reason: 'on $platform',
);
expect(controller.text, equals(testText), reason: 'on $platform');
expect(
(await Clipboard.getData(Clipboard.kTextPlain))!.text,
equals(testText),
reason: 'on $platform',
);
// Delete
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.delete,
],
platform: platform,
);
expect(
selection!,
equals(
const TextSelection(
baseOffset: 0,
extentOffset: testText.length,
affinity: TextAffinity.upstream,
),
),
reason: 'on $platform',
);
expect(controller.text, equals(testText), reason: 'on $platform');
// Backspace
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.backspace,
],
platform: platform,
);
expect(
selection!,
equals(
const TextSelection(
baseOffset: 0,
extentOffset: testText.length,
affinity: TextAffinity.upstream,
),
),
reason: 'on $platform',
);
expect(controller.text, equals(testText), reason: 'on $platform');
},
skip: kIsWeb,
variant: TargetPlatformVariant.all());
// Regression test for https://github.com/flutter/flutter/issues/31287 // Regression test for https://github.com/flutter/flutter/issues/31287
testWidgets('text selection handle visibility', (WidgetTester tester) async { testWidgets('text selection handle visibility', (WidgetTester tester) async {
// Text with two separate words to select. // Text with two separate words to select.
......
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