Skip to content

Commit

Permalink
DefaultTextEditingShortcuts should use meta-based shortcut for iOS (#…
Browse files Browse the repository at this point in the history
…103077)
  • Loading branch information
chunhtai authored May 5, 2022
1 parent 72dff58 commit 7cdcfb2
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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
Expand Down
89 changes: 89 additions & 0 deletions packages/flutter/test/widgets/app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
30 changes: 15 additions & 15 deletions packages/flutter/test/widgets/editable_text_shortcuts_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand All @@ -1181,7 +1181,7 @@ void main() {
expect(controller.selection, const TextSelection.collapsed(
offset: 20,
));
}, variant: allExceptMacOS);
}, variant: allExceptApple);
});

group('right', () {
Expand Down Expand Up @@ -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;
Expand All @@ -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', () {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1406,7 +1406,7 @@ void main() {
offset: 35, // After "people".
affinity: TextAffinity.upstream,
));
}, variant: allExceptMacOS);
}, variant: allExceptApple);
});

group('vertical movement', () {
Expand Down
Loading

0 comments on commit 7cdcfb2

Please sign in to comment.