Unverified Commit 8557ffa0 authored by Josh Matthews's avatar Josh Matthews Committed by GitHub

Fix PlatformMenuItems with onSelectedIntent are never enabled (#121885)

Fix PlatformMenuItems with onSelectedIntent are never enabled
parent 91dea4d1
......@@ -738,7 +738,8 @@ class PlatformMenuItem with Diagnosticable {
/// An optional callback that is called when this [PlatformMenuItem] is
/// selected.
///
/// If unset, this menu item will be disabled.
/// At most one of [onSelected] and [onSelectedIntent] may be set. If neither
/// field is set, this menu item will be disabled.
final VoidCallback? onSelected;
/// Returns a callback, if any, to be invoked if the platform menu receives a
......@@ -760,7 +761,8 @@ class PlatformMenuItem with Diagnosticable {
/// An optional intent that is invoked when this [PlatformMenuItem] is
/// selected.
///
/// If unset, this menu item will be disabled.
/// At most one of [onSelected] and [onSelectedIntent] may be set. If neither
/// field is set, this menu item will be disabled.
final Intent? onSelectedIntent;
/// Returns all descendant [PlatformMenuItem]s of this item.
......@@ -805,7 +807,7 @@ class PlatformMenuItem with Diagnosticable {
return <String, Object?>{
_kIdKey: getId(item),
_kLabelKey: item.label,
_kEnabledKey: item.onSelected != null,
_kEnabledKey: item.onSelected != null || item.onSelectedIntent != null,
if (shortcut != null)...shortcut.serializeForMenu().toChannelRepresentation(),
};
}
......
......@@ -15,12 +15,12 @@ void main() {
late FakeMenuChannel fakeMenuChannel;
late PlatformMenuDelegate originalDelegate;
late DefaultPlatformMenuDelegate delegate;
final List<String> activated = <String>[];
final List<String> selected = <String>[];
final List<String> opened = <String>[];
final List<String> closed = <String>[];
void onActivate(String item) {
activated.add(item);
void onSelected(String item) {
selected.add(item);
}
void onOpen(String item) {
......@@ -36,7 +36,7 @@ void main() {
delegate = DefaultPlatformMenuDelegate(channel: fakeMenuChannel);
originalDelegate = WidgetsBinding.instance.platformMenuDelegate;
WidgetsBinding.instance.platformMenuDelegate = delegate;
activated.clear();
selected.clear();
opened.clear();
closed.clear();
});
......@@ -46,117 +46,69 @@ void main() {
});
group('PlatformMenuBar', () {
testWidgets('basic menu structure is transmitted to platform', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: PlatformMenuBar(
menus: createTestMenus(
onActivate: onActivate,
onOpen: onOpen,
onClose: onClose,
shortcuts: <String, MenuSerializableShortcut>{
subSubMenu10[0]: const SingleActivator(LogicalKeyboardKey.keyA, control: true),
subSubMenu10[1]: const SingleActivator(LogicalKeyboardKey.keyB, shift: true),
subSubMenu10[2]: const SingleActivator(LogicalKeyboardKey.keyC, alt: true),
subSubMenu10[3]: const SingleActivator(LogicalKeyboardKey.keyD, meta: true),
},
group('basic menu structure is transmitted to platform', () {
testWidgets('using onSelected', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: PlatformMenuBar(
menus: createTestMenus(
onSelected: onSelected,
onOpen: onOpen,
onClose: onClose,
shortcuts: <String, MenuSerializableShortcut>{
subSubMenu10[0]: const SingleActivator(LogicalKeyboardKey.keyA, control: true),
subSubMenu10[1]: const SingleActivator(LogicalKeyboardKey.keyB, shift: true),
subSubMenu10[2]: const SingleActivator(LogicalKeyboardKey.keyC, alt: true),
subSubMenu10[3]: const SingleActivator(LogicalKeyboardKey.keyD, meta: true),
},
),
child: const Center(child: Text('Body')),
),
child: const Center(child: Text('Body')),
),
),
),
);
expect(fakeMenuChannel.outgoingCalls.last.method, equals('Menu.setMenus'));
expect(
fakeMenuChannel.outgoingCalls.last.arguments,
equals(<String, Object?>{
'0': <Map<String, Object?>>[
<String, Object?>{
'id': 2,
'label': 'Menu 0',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 1,
'label': 'Sub Menu 00',
'enabled': true,
},
],
},
<String, Object?>{
'id': 18,
'label': 'Menu 1',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 4,
'label': 'Sub Menu 10',
'enabled': true,
},
<String, Object?>{'id': 5, 'isDivider': true},
<String, Object?>{
'id': 16,
'label': 'Sub Menu 11',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 7,
'label': 'Sub Sub Menu 110',
'enabled': true,
'shortcutTrigger': 97,
'shortcutModifiers': 8,
},
<String, Object?>{'id': 8, 'isDivider': true},
<String, Object?>{
'id': 10,
'label': 'Sub Sub Menu 111',
'enabled': true,
'shortcutTrigger': 98,
'shortcutModifiers': 2,
},
<String, Object?>{'id': 11, 'isDivider': true},
<String, Object?>{
'id': 12,
'label': 'Sub Sub Menu 112',
'enabled': true,
'shortcutTrigger': 99,
'shortcutModifiers': 4,
},
<String, Object?>{'id': 13, 'isDivider': true},
<String, Object?>{
'id': 14,
'label': 'Sub Sub Menu 113',
'enabled': true,
'shortcutTrigger': 100,
'shortcutModifiers': 1,
},
],
},
<String, Object?>{
'id': 17,
'label': 'Sub Menu 12',
'enabled': true,
},
],
},
<String, Object?>{
'id': 20,
'label': 'Menu 2',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 19,
'label': 'Sub Menu 20',
'enabled': false,
},
],
},
<String, Object?>{'id': 21, 'label': 'Menu 3', 'enabled': false, 'children': <Map<String, Object?>>[]},
],
}),
);
);
expect(
fakeMenuChannel.outgoingCalls.last.method,
equals('Menu.setMenus'),
);
expect(
fakeMenuChannel.outgoingCalls.last.arguments,
equals(expectedStructure),
);
});
testWidgets('using onSelectedIntent', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: PlatformMenuBar(
menus: createTestMenus(
onSelectedIntent: const DoNothingIntent(),
onOpen: onOpen,
onClose: onClose,
shortcuts: <String, MenuSerializableShortcut>{
subSubMenu10[0]: const SingleActivator(LogicalKeyboardKey.keyA, control: true),
subSubMenu10[1]: const SingleActivator(LogicalKeyboardKey.keyB, shift: true),
subSubMenu10[2]: const SingleActivator(LogicalKeyboardKey.keyC, alt: true),
subSubMenu10[3]: const SingleActivator(LogicalKeyboardKey.keyD, meta: true),
},
),
child: const Center(child: Text('Body')),
),
),
),
);
expect(
fakeMenuChannel.outgoingCalls.last.method,
equals('Menu.setMenus'),
);
expect(
fakeMenuChannel.outgoingCalls.last.arguments,
equals(expectedStructure),
);
});
});
testWidgets('asserts when more than one has locked the delegate', (WidgetTester tester) async {
await tester.pumpWidget(
......@@ -287,7 +239,8 @@ const List<String> subMenu2 = <String>[
];
List<PlatformMenuItem> createTestMenus({
void Function(String)? onActivate,
void Function(String)? onSelected,
Intent? onSelectedIntent,
void Function(String)? onOpen,
void Function(String)? onClose,
Map<String, MenuSerializableShortcut> shortcuts = const <String, MenuSerializableShortcut>{},
......@@ -301,7 +254,8 @@ List<PlatformMenuItem> createTestMenus({
menus: <PlatformMenuItem>[
PlatformMenuItem(
label: subMenu0[0],
onSelected: onActivate != null ? () => onActivate(subMenu0[0]) : null,
onSelected: onSelected != null ? () => onSelected(subMenu0[0]) : null,
onSelectedIntent: onSelectedIntent,
shortcut: shortcuts[subMenu0[0]],
),
],
......@@ -315,7 +269,8 @@ List<PlatformMenuItem> createTestMenus({
members: <PlatformMenuItem>[
PlatformMenuItem(
label: subMenu1[0],
onSelected: onActivate != null ? () => onActivate(subMenu1[0]) : null,
onSelected: onSelected != null ? () => onSelected(subMenu0[0]) : null,
onSelectedIntent: onSelectedIntent,
shortcut: shortcuts[subMenu1[0]],
),
],
......@@ -329,7 +284,8 @@ List<PlatformMenuItem> createTestMenus({
members: <PlatformMenuItem>[
PlatformMenuItem(
label: subSubMenu10[0],
onSelected: onActivate != null ? () => onActivate(subSubMenu10[0]) : null,
onSelected: onSelected != null ? () => onSelected(subSubMenu10[0]) : null,
onSelectedIntent: onSelectedIntent,
shortcut: shortcuts[subSubMenu10[0]],
),
],
......@@ -338,21 +294,24 @@ List<PlatformMenuItem> createTestMenus({
members: <PlatformMenuItem>[
PlatformMenuItem(
label: subSubMenu10[1],
onSelected: onActivate != null ? () => onActivate(subSubMenu10[1]) : null,
onSelected: onSelected != null ? () => onSelected(subSubMenu10[1]) : null,
onSelectedIntent: onSelectedIntent,
shortcut: shortcuts[subSubMenu10[1]],
),
],
),
PlatformMenuItem(
label: subSubMenu10[2],
onSelected: onActivate != null ? () => onActivate(subSubMenu10[2]) : null,
onSelected: onSelected != null ? () => onSelected(subSubMenu10[2]) : null,
onSelectedIntent: onSelectedIntent,
shortcut: shortcuts[subSubMenu10[2]],
),
PlatformMenuItemGroup(
members: <PlatformMenuItem>[
PlatformMenuItem(
label: subSubMenu10[3],
onSelected: onActivate != null ? () => onActivate(subSubMenu10[3]) : null,
onSelected: onSelected != null ? () => onSelected(subSubMenu10[3]) : null,
onSelectedIntent: onSelectedIntent,
shortcut: shortcuts[subSubMenu10[3]],
),
],
......@@ -361,7 +320,8 @@ List<PlatformMenuItem> createTestMenus({
),
PlatformMenuItem(
label: subMenu1[2],
onSelected: onActivate != null ? () => onActivate(subMenu1[2]) : null,
onSelected: onSelected != null ? () => onSelected(subMenu1[2]) : null,
onSelectedIntent: onSelectedIntent,
shortcut: shortcuts[subMenu1[2]],
),
],
......@@ -389,6 +349,92 @@ List<PlatformMenuItem> createTestMenus({
return result;
}
const Map<String, Object?> expectedStructure = <String, Object?>{
'0': <Map<String, Object?>>[
<String, Object?>{
'id': 2,
'label': 'Menu 0',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 1,
'label': 'Sub Menu 00',
'enabled': true,
},
],
},
<String, Object?>{
'id': 18,
'label': 'Menu 1',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 4,
'label': 'Sub Menu 10',
'enabled': true,
},
<String, Object?>{'id': 5, 'isDivider': true},
<String, Object?>{
'id': 16,
'label': 'Sub Menu 11',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 7,
'label': 'Sub Sub Menu 110',
'enabled': true,
'shortcutTrigger': 97,
'shortcutModifiers': 8,
},
<String, Object?>{'id': 8, 'isDivider': true},
<String, Object?>{
'id': 10,
'label': 'Sub Sub Menu 111',
'enabled': true,
'shortcutTrigger': 98,
'shortcutModifiers': 2,
},
<String, Object?>{'id': 11, 'isDivider': true},
<String, Object?>{
'id': 12,
'label': 'Sub Sub Menu 112',
'enabled': true,
'shortcutTrigger': 99,
'shortcutModifiers': 4,
},
<String, Object?>{'id': 13, 'isDivider': true},
<String, Object?>{
'id': 14,
'label': 'Sub Sub Menu 113',
'enabled': true,
'shortcutTrigger': 100,
'shortcutModifiers': 1,
},
],
},
<String, Object?>{
'id': 17,
'label': 'Sub Menu 12',
'enabled': true,
},
],
},
<String, Object?>{
'id': 20,
'label': 'Menu 2',
'enabled': true,
'children': <Map<String, Object?>>[
<String, Object?>{
'id': 19,
'label': 'Sub Menu 20',
'enabled': false,
},
],
},
<String, Object?>{'id': 21, 'label': 'Menu 3', 'enabled': false, 'children': <Map<String, Object?>>[]},
],
};
class FakeMenuChannel implements MethodChannel {
FakeMenuChannel(this.outgoing);
......
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