DefaultTextEditingShortcuts should use meta-based shortcut for iOS (#103077)
This commit is contained in:
@@ -231,25 +231,6 @@ class DefaultTextEditingShortcuts extends Shortcuts {
|
||||
|
||||
static final Map<ShortcutActivator, Intent> _fuchsiaShortcuts = _androidShortcuts;
|
||||
|
||||
// The following key combinations have no effect on text editing on this
|
||||
// platform:
|
||||
// * End
|
||||
// * Home
|
||||
// * Meta + X
|
||||
// * Meta + C
|
||||
// * Meta + V
|
||||
// * Meta + A
|
||||
// * Meta + shift? + Z
|
||||
// * Meta + shift? + arrow down
|
||||
// * Meta + shift? + arrow left
|
||||
// * Meta + shift? + arrow right
|
||||
// * Meta + shift? + arrow up
|
||||
// * Shift + end
|
||||
// * Shift + home
|
||||
// * Meta + shift? + delete
|
||||
// * Meta + shift? + backspace
|
||||
static final Map<ShortcutActivator, Intent> _iOSShortcuts = _commonShortcuts;
|
||||
|
||||
static final Map<ShortcutActivator, Intent> _linuxShortcuts = <ShortcutActivator, Intent>{
|
||||
..._commonShortcuts,
|
||||
const SingleActivator(LogicalKeyboardKey.home): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true),
|
||||
@@ -342,6 +323,10 @@ class DefaultTextEditingShortcuts extends Shortcuts {
|
||||
// * Control + shift? + Z
|
||||
};
|
||||
|
||||
// There is no complete documentation of iOS shortcuts. Use mac shortcuts for
|
||||
// now.
|
||||
static final Map<ShortcutActivator, Intent> _iOSShortcuts = _macShortcuts;
|
||||
|
||||
// The following key combinations have no effect on text editing on this
|
||||
// platform:
|
||||
// * Meta + X
|
||||
|
||||
@@ -643,11 +643,100 @@ void main() {
|
||||
);
|
||||
expect(MediaQuery.of(capturedContext), isNotNull);
|
||||
});
|
||||
|
||||
testWidgets('WidgetsApp provides meta based shortcuts for iOS and macOS', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode();
|
||||
final SelectAllSpy selectAllSpy = SelectAllSpy();
|
||||
final CopySpy copySpy = CopySpy();
|
||||
final PasteSpy pasteSpy = PasteSpy();
|
||||
final Map<Type, Action<Intent>> actions = <Type, Action<Intent>>{
|
||||
// Copy Paste
|
||||
SelectAllTextIntent: selectAllSpy,
|
||||
CopySelectionTextIntent: copySpy,
|
||||
PasteTextIntent: pasteSpy,
|
||||
};
|
||||
await tester.pumpWidget(
|
||||
WidgetsApp(
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return Actions(
|
||||
actions: actions,
|
||||
child: Focus(
|
||||
focusNode: focusNode,
|
||||
child: const Placeholder(),
|
||||
),
|
||||
);
|
||||
},
|
||||
color: const Color(0xFF123456),
|
||||
),
|
||||
);
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
expect(selectAllSpy.invoked, isFalse);
|
||||
expect(copySpy.invoked, isFalse);
|
||||
expect(pasteSpy.invoked, isFalse);
|
||||
|
||||
// Select all.
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.metaLeft);
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyA);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyA);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.metaLeft);
|
||||
await tester.pump();
|
||||
|
||||
expect(selectAllSpy.invoked, isTrue);
|
||||
expect(copySpy.invoked, isFalse);
|
||||
expect(pasteSpy.invoked, isFalse);
|
||||
|
||||
// Copy.
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.metaLeft);
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyC);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyC);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.metaLeft);
|
||||
await tester.pump();
|
||||
|
||||
expect(selectAllSpy.invoked, isTrue);
|
||||
expect(copySpy.invoked, isTrue);
|
||||
expect(pasteSpy.invoked, isFalse);
|
||||
|
||||
// Paste.
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.metaLeft);
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyV);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyV);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.metaLeft);
|
||||
await tester.pump();
|
||||
|
||||
expect(selectAllSpy.invoked, isTrue);
|
||||
expect(copySpy.invoked, isTrue);
|
||||
expect(pasteSpy.invoked, isTrue);
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), skip: kIsWeb); // [intended] Web uses a different set of shortcuts.
|
||||
}
|
||||
|
||||
typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation);
|
||||
typedef SimpleNavigatorRouterDelegatePopPage<T> = bool Function(Route<T> route, T result, SimpleNavigatorRouterDelegate delegate);
|
||||
|
||||
class SelectAllSpy extends Action<SelectAllTextIntent> {
|
||||
bool invoked = false;
|
||||
@override
|
||||
void invoke(SelectAllTextIntent intent) {
|
||||
invoked = true;
|
||||
}
|
||||
}
|
||||
|
||||
class CopySpy extends Action<CopySelectionTextIntent> {
|
||||
bool invoked = false;
|
||||
@override
|
||||
void invoke(CopySelectionTextIntent intent) {
|
||||
invoked = true;
|
||||
}
|
||||
}
|
||||
|
||||
class PasteSpy extends Action<PasteTextIntent> {
|
||||
bool invoked = false;
|
||||
@override
|
||||
void invoke(PasteTextIntent intent) {
|
||||
invoked = true;
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleRouteInformationParser extends RouteInformationParser<RouteInformation> {
|
||||
SimpleRouteInformationParser();
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ void main() {
|
||||
|
||||
group('Common text editing shortcuts: ',
|
||||
() {
|
||||
final TargetPlatformVariant allExceptMacOS = TargetPlatformVariant(TargetPlatform.values.toSet()..remove(TargetPlatform.macOS));
|
||||
final TargetPlatformVariant allExceptApple = TargetPlatformVariant(TargetPlatform.values.toSet()..removeAll(<TargetPlatform>[TargetPlatform.macOS, TargetPlatform.iOS]));
|
||||
|
||||
group('backspace', () {
|
||||
const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace;
|
||||
@@ -491,8 +491,8 @@ void main() {
|
||||
group('word modifier + backspace', () {
|
||||
const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace;
|
||||
SingleActivator wordModifierBackspace() {
|
||||
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
|
||||
return SingleActivator(trigger, control: !isMacOS, alt: isMacOS);
|
||||
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
|
||||
return SingleActivator(trigger, control: !isApple, alt: isApple);
|
||||
}
|
||||
|
||||
testWidgets('WordModifier-backspace', (WidgetTester tester) async {
|
||||
@@ -631,8 +631,8 @@ void main() {
|
||||
group('word modifier + delete', () {
|
||||
const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete;
|
||||
SingleActivator wordModifierDelete() {
|
||||
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
|
||||
return SingleActivator(trigger, control: !isMacOS, alt: isMacOS);
|
||||
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
|
||||
return SingleActivator(trigger, control: !isApple, alt: isApple);
|
||||
}
|
||||
|
||||
testWidgets('WordModifier-delete', (WidgetTester tester) async {
|
||||
@@ -764,8 +764,8 @@ void main() {
|
||||
group('line modifier + backspace', () {
|
||||
const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace;
|
||||
SingleActivator lineModifierBackspace() {
|
||||
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
|
||||
return SingleActivator(trigger, meta: isMacOS, alt: !isMacOS);
|
||||
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
|
||||
return SingleActivator(trigger, meta: isApple, alt: !isApple);
|
||||
}
|
||||
|
||||
testWidgets('alt-backspace', (WidgetTester tester) async {
|
||||
@@ -945,8 +945,8 @@ void main() {
|
||||
group('line modifier + delete', () {
|
||||
const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete;
|
||||
SingleActivator lineModifierDelete() {
|
||||
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
|
||||
return SingleActivator(trigger, meta: isMacOS, alt: !isMacOS);
|
||||
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
|
||||
return SingleActivator(trigger, meta: isApple, alt: !isApple);
|
||||
}
|
||||
|
||||
testWidgets('alt-delete', (WidgetTester tester) async {
|
||||
@@ -1167,7 +1167,7 @@ void main() {
|
||||
expect(controller.selection, const TextSelection.collapsed(
|
||||
offset: 4,
|
||||
));
|
||||
}, variant: allExceptMacOS);
|
||||
}, variant: allExceptApple);
|
||||
|
||||
testWidgets('line modifier + arrow key movement', (WidgetTester tester) async {
|
||||
controller.text = testText;
|
||||
@@ -1181,7 +1181,7 @@ void main() {
|
||||
expect(controller.selection, const TextSelection.collapsed(
|
||||
offset: 20,
|
||||
));
|
||||
}, variant: allExceptMacOS);
|
||||
}, variant: allExceptApple);
|
||||
});
|
||||
|
||||
group('right', () {
|
||||
@@ -1230,7 +1230,7 @@ void main() {
|
||||
expect(controller.selection, const TextSelection.collapsed(
|
||||
offset: 10,
|
||||
));
|
||||
}, variant: allExceptMacOS);
|
||||
}, variant: allExceptApple);
|
||||
|
||||
testWidgets('line modifier + arrow key movement', (WidgetTester tester) async {
|
||||
controller.text = testText;
|
||||
@@ -1245,7 +1245,7 @@ void main() {
|
||||
offset: 35, // Before the newline character.
|
||||
affinity: TextAffinity.upstream,
|
||||
));
|
||||
}, variant: allExceptMacOS);
|
||||
}, variant: allExceptApple);
|
||||
});
|
||||
|
||||
group('With initial non-collapsed selection', () {
|
||||
@@ -1352,7 +1352,7 @@ void main() {
|
||||
expect(controller.selection, const TextSelection.collapsed(
|
||||
offset: 28, // After "good".
|
||||
));
|
||||
}, variant: allExceptMacOS);
|
||||
}, variant: allExceptApple);
|
||||
|
||||
testWidgets('line modifier + arrow key movement', (WidgetTester tester) async {
|
||||
controller.text = testText;
|
||||
@@ -1406,7 +1406,7 @@ void main() {
|
||||
offset: 35, // After "people".
|
||||
affinity: TextAffinity.upstream,
|
||||
));
|
||||
}, variant: allExceptMacOS);
|
||||
}, variant: allExceptApple);
|
||||
});
|
||||
|
||||
group('vertical movement', () {
|
||||
|
||||
@@ -5204,19 +5204,19 @@ void main() {
|
||||
}
|
||||
if (shortcutModifier) {
|
||||
await tester.sendKeyDownEvent(
|
||||
platform == 'macos' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform == 'macos' || platform == 'ios' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform: platform,
|
||||
);
|
||||
}
|
||||
if (wordModifier) {
|
||||
await tester.sendKeyDownEvent(
|
||||
platform == 'macos' ? LogicalKeyboardKey.altLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform == 'macos' || platform == 'ios' ? LogicalKeyboardKey.altLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform: platform,
|
||||
);
|
||||
}
|
||||
if (lineModifier) {
|
||||
await tester.sendKeyDownEvent(
|
||||
platform == 'macos' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.altLeft,
|
||||
platform == 'macos' || platform == 'ios' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.altLeft,
|
||||
platform: platform,
|
||||
);
|
||||
}
|
||||
@@ -5226,19 +5226,19 @@ void main() {
|
||||
}
|
||||
if (lineModifier) {
|
||||
await tester.sendKeyUpEvent(
|
||||
platform == 'macos' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.altLeft,
|
||||
platform == 'macos' || platform == 'ios' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.altLeft,
|
||||
platform: platform,
|
||||
);
|
||||
}
|
||||
if (wordModifier) {
|
||||
await tester.sendKeyUpEvent(
|
||||
platform == 'macos' ? LogicalKeyboardKey.altLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform == 'macos' || platform == 'ios' ? LogicalKeyboardKey.altLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform: platform,
|
||||
);
|
||||
}
|
||||
if (shortcutModifier) {
|
||||
await tester.sendKeyUpEvent(
|
||||
platform == 'macos' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform == 'macos' || platform == 'ios' ? LogicalKeyboardKey.metaLeft : LogicalKeyboardKey.controlLeft,
|
||||
platform: platform,
|
||||
);
|
||||
}
|
||||
@@ -5547,7 +5547,6 @@ void main() {
|
||||
|
||||
switch (defaultTargetPlatform) {
|
||||
// These platforms extend by line.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.linux:
|
||||
@@ -5565,7 +5564,8 @@ void main() {
|
||||
);
|
||||
break;
|
||||
|
||||
// Mac expands by line.
|
||||
// Mac and iOS expand by line.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
expect(
|
||||
selection,
|
||||
@@ -6738,7 +6738,6 @@ void main() {
|
||||
switch (defaultTargetPlatform) {
|
||||
// These platforms don't handle shift + home/end at all.
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.fuchsia:
|
||||
expect(
|
||||
selectionAfterHome,
|
||||
@@ -6811,7 +6810,8 @@ void main() {
|
||||
);
|
||||
break;
|
||||
|
||||
// Mac goes to the start/end of the document.
|
||||
// Mac and iOS go to the start/end of the document.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
expect(
|
||||
selectionAfterHome,
|
||||
@@ -7088,7 +7088,6 @@ void main() {
|
||||
switch (defaultTargetPlatform) {
|
||||
// These platforms don't move the selection with shift + home/end at all.
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.fuchsia:
|
||||
expect(
|
||||
selection,
|
||||
@@ -7101,7 +7100,8 @@ void main() {
|
||||
);
|
||||
break;
|
||||
|
||||
// Mac selects to the start of the document.
|
||||
// Mac and iOS select to the start of the document.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
expect(
|
||||
selection,
|
||||
@@ -7145,7 +7145,6 @@ void main() {
|
||||
switch (defaultTargetPlatform) {
|
||||
// These platforms don't move the selection with home/end at all still.
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.fuchsia:
|
||||
expect(
|
||||
selection,
|
||||
@@ -7158,7 +7157,8 @@ void main() {
|
||||
);
|
||||
break;
|
||||
|
||||
// Mac selects to the start of the document.
|
||||
// Mac and iOS select to the start of the document.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
expect(
|
||||
selection,
|
||||
@@ -7280,7 +7280,6 @@ void main() {
|
||||
switch (defaultTargetPlatform) {
|
||||
// These platforms don't move the selection with home/end at all.
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.fuchsia:
|
||||
expect(
|
||||
selection,
|
||||
@@ -7293,7 +7292,8 @@ void main() {
|
||||
);
|
||||
break;
|
||||
|
||||
// Mac selects to the end of the document.
|
||||
// Mac and iOS select to the end of the document.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
expect(
|
||||
selection,
|
||||
@@ -7337,7 +7337,6 @@ void main() {
|
||||
switch (defaultTargetPlatform) {
|
||||
// These platforms don't move the selection with home/end at all still.
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.fuchsia:
|
||||
expect(
|
||||
selection,
|
||||
@@ -7350,7 +7349,8 @@ void main() {
|
||||
);
|
||||
break;
|
||||
|
||||
// Mac stays at the end of the document.
|
||||
// Mac and iOS stay at the end of the document.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
expect(
|
||||
selection,
|
||||
@@ -10213,7 +10213,7 @@ void main() {
|
||||
wordModifier: true,
|
||||
targetPlatform: defaultTargetPlatform,
|
||||
);
|
||||
if (defaultTargetPlatform == TargetPlatform.macOS) {
|
||||
if (defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS) {
|
||||
// word wo|rd word
|
||||
expect(controller.selection.isCollapsed, true);
|
||||
expect(controller.selection.baseOffset, 7);
|
||||
@@ -10264,7 +10264,7 @@ void main() {
|
||||
wordModifier: true,
|
||||
targetPlatform: defaultTargetPlatform,
|
||||
);
|
||||
if (defaultTargetPlatform == TargetPlatform.macOS) {
|
||||
if (defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS) {
|
||||
// word wo|rd word
|
||||
expect(controller.selection.isCollapsed, true);
|
||||
expect(controller.selection.baseOffset, 7);
|
||||
@@ -10353,7 +10353,6 @@ void main() {
|
||||
expect(controller.selection.isCollapsed, false);
|
||||
switch (defaultTargetPlatform) {
|
||||
// These platforms extend by line.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.linux:
|
||||
@@ -10362,7 +10361,8 @@ void main() {
|
||||
expect(controller.selection.extentOffset, 15);
|
||||
break;
|
||||
|
||||
// Mac expands by line.
|
||||
// Mac and iOS expand by line.
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
expect(controller.selection.baseOffset, 15);
|
||||
expect(controller.selection.extentOffset, 24);
|
||||
|
||||
Reference in New Issue
Block a user