blob: 69ca1a07415712c4b6abff850913abd1a757f1b9 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/keyboard/ui_bundled/menu_builder.h"
#import "ios/chrome/browser/keyboard/ui_bundled/UIKeyCommand+Chrome.h"
// Note: this class can be called very early on in the start process, before
// resource bundles are loaded. This means that to get localized strings, one
// shouldn't use `l10n_util::GetNSString()` and instead should use
// `NSLocalizedString(@"IDS_IOS_MY_STRING", @"")`, with
// `IDS_IOS_MY_STRING` present in the allowlist at
// //ios/chrome/app/resources/chrome_localize_strings_config.plist.
@implementation MenuBuilder
+ (void)buildMainMenuWithBuilder:(id<UIMenuBuilder>)builder {
// Only configure the builder for the main command system, not contextual
// menus.
if (builder.system != UIMenuSystem.mainSystem) {
return;
}
if (@available(iOS 26, *)) {
// Application: Replace the Application elements.
NSArray<UIMenuElement*>* applicationElements = @[
UIKeyCommand.cr_showSettings,
UIKeyCommand.cr_clearBrowsingData,
];
// Replace the existing elements, as none are relevant for Chrome.
[builder replaceChildrenOfMenuForIdentifier:UIMenuApplication
fromChildrenBlock:^(NSArray<UIMenuElement*>* _) {
return applicationElements;
}];
// File: Replace the File elements.
NSArray<UIMenuElement*>* fileElements = @[
UIKeyCommand.cr_openNewTab,
UIKeyCommand.cr_openNewIncognitoTab,
UIKeyCommand.cr_openNewWindow,
UIKeyCommand.cr_openNewIncognitoWindow,
UIKeyCommand.cr_openLocation,
UIKeyCommand.cr_voiceSearch,
];
// Replace the existing elements, as none are relevant for Chrome.
[builder replaceChildrenOfMenuForIdentifier:UIMenuFile
fromChildrenBlock:^(NSArray<UIMenuElement*>* _) {
return fileElements;
}];
// File: Add the Close elements as an inlined submenu.
UIMenu* closeMenu = [UIMenu menuWithTitle:@""
image:nil
identifier:nil
options:UIMenuOptionsDisplayInline
children:@[
UIKeyCommand.cr_closeTab,
UIKeyCommand.cr_closeAll,
]];
[builder insertChildMenu:closeMenu atEndOfMenuForIdentifier:UIMenuFile];
// Edit: Replace the Find elements.
NSArray<UIMenuElement*>* findElements = @[
UIKeyCommand.cr_find,
UIKeyCommand.cr_findNext,
UIKeyCommand.cr_findPrevious,
];
[builder replaceChildrenOfMenuForIdentifier:UIMenuFind
fromChildrenBlock:^(NSArray<UIMenuElement*>* _) {
return findElements;
}];
// Format: Remove the system entry to format text.
[builder removeMenuForIdentifier:UIMenuFormat];
// View: Add elements.
NSArray<UIMenuElement*>* viewElements = @[
UIKeyCommand.cr_stop,
UIKeyCommand.cr_reload,
UIKeyCommand.cr_goToTabGrid,
];
[self insertElements:viewElements
atStartOfMenuForIdentifier:UIMenuView
inBuilder:builder];
// History: Add new menu.
UIMenu* historyMenu = [UIMenu
menuWithTitle:NSLocalizedString(@"IDS_IOS_KEYBOARD_HISTORY", @"")
children:@[
UIKeyCommand.cr_back,
UIKeyCommand.cr_forward,
UIKeyCommand.cr_reopenLastClosedTab,
UIKeyCommand.cr_showHistory,
]];
[builder insertSiblingMenu:historyMenu afterMenuForIdentifier:UIMenuView];
// Bookmarks: Add new menu.
UIMenu* bookmarksMenu = [UIMenu
menuWithTitle:NSLocalizedString(@"IDS_IOS_KEYBOARD_BOOKMARKS", @"")
children:@[
UIKeyCommand.cr_showBookmarks,
UIKeyCommand.cr_addToBookmarks,
UIKeyCommand.cr_showReadingList,
UIKeyCommand.cr_addToReadingList,
]];
[builder insertSiblingMenu:bookmarksMenu
afterMenuForIdentifier:historyMenu.identifier];
// Window: Add elements.
NSArray<UIMenuElement*>* windowElements = @[
UIKeyCommand.cr_showNextTab,
UIKeyCommand.cr_showPreviousTab,
UIKeyCommand.cr_select1,
UIKeyCommand.cr_select2,
UIKeyCommand.cr_select3,
UIKeyCommand.cr_select9,
UIKeyCommand.cr_showDownloads,
];
[self insertElements:windowElements
atStartOfMenuForIdentifier:UIMenuWindow
inBuilder:builder];
// Help: Add elements.
NSArray<UIMenuElement*>* helpElements = @[
UIKeyCommand.cr_showHelp,
UIKeyCommand.cr_reportAnIssue,
];
[self insertElements:helpElements
atStartOfMenuForIdentifier:UIMenuHelp
inBuilder:builder];
} else {
// Application: Remove the Application menu, as it contains a system entry
// to open the Settings app, as it conflicts with the in-app settings key
// command.
[builder removeMenuForIdentifier:UIMenuApplication];
// File: Add elements.
NSArray<UIMenuElement*>* fileElements = @[
UIKeyCommand.cr_openNewTab,
UIKeyCommand.cr_openNewIncognitoTab,
UIKeyCommand.cr_openNewWindow,
UIKeyCommand.cr_openNewIncognitoWindow,
UIKeyCommand.cr_openLocation,
UIKeyCommand.cr_closeTab,
UIKeyCommand.cr_voiceSearch,
UIKeyCommand.cr_closeAll,
];
[self insertElements:fileElements
atStartOfMenuForIdentifier:UIMenuFile
inBuilder:builder];
// Edit: Replace the Find actions.
NSArray<UIMenuElement*>* findElements = @[
UIKeyCommand.cr_find,
UIKeyCommand.cr_findNext,
UIKeyCommand.cr_findPrevious,
];
[builder replaceChildrenOfMenuForIdentifier:UIMenuFind
fromChildrenBlock:^(NSArray<UIMenuElement*>* _) {
return findElements;
}];
// Format: Remove the system entry to format text.
[builder removeMenuForIdentifier:UIMenuFormat];
// View: Add elements.
NSArray<UIMenuElement*>* viewElements = @[
UIKeyCommand.cr_stop,
UIKeyCommand.cr_reload,
UIKeyCommand.cr_goToTabGrid,
];
[self insertElements:viewElements
atStartOfMenuForIdentifier:UIMenuView
inBuilder:builder];
// History: Add new menu.
UIMenu* historyMenu = [UIMenu
menuWithTitle:NSLocalizedString(@"IDS_IOS_KEYBOARD_HISTORY", @"")
children:@[
UIKeyCommand.cr_back,
UIKeyCommand.cr_forward,
UIKeyCommand.cr_reopenLastClosedTab,
UIKeyCommand.cr_showHistory,
UIKeyCommand.cr_clearBrowsingData,
]];
[builder insertSiblingMenu:historyMenu afterMenuForIdentifier:UIMenuView];
// Bookmarks: Add new menu.
UIMenu* bookmarksMenu = [UIMenu
menuWithTitle:NSLocalizedString(@"IDS_IOS_KEYBOARD_BOOKMARKS", @"")
children:@[
UIKeyCommand.cr_showBookmarks,
UIKeyCommand.cr_addToBookmarks,
UIKeyCommand.cr_showReadingList,
UIKeyCommand.cr_addToReadingList,
]];
[builder insertSiblingMenu:bookmarksMenu
afterMenuForIdentifier:historyMenu.identifier];
// Window: Add elements.
NSArray<UIMenuElement*>* windowElements = @[
UIKeyCommand.cr_showNextTab,
UIKeyCommand.cr_showPreviousTab,
UIKeyCommand.cr_select1,
UIKeyCommand.cr_select2,
UIKeyCommand.cr_select3,
UIKeyCommand.cr_select9,
UIKeyCommand.cr_showDownloads,
UIKeyCommand.cr_showSettings,
];
[self insertElements:windowElements
atStartOfMenuForIdentifier:UIMenuWindow
inBuilder:builder];
// Help: Add elements.
NSArray<UIMenuElement*>* helpElements = @[
UIKeyCommand.cr_showHelp,
UIKeyCommand.cr_reportAnIssue,
];
[self insertElements:helpElements
atStartOfMenuForIdentifier:UIMenuHelp
inBuilder:builder];
}
}
#pragma mark - Private
+ (void)insertElements:(NSArray<UIMenuElement*>*)childElements
atStartOfMenuForIdentifier:(UIMenuIdentifier)parentIdentifier
inBuilder:(id<UIMenuBuilder>)builder {
#if defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_26_0
if (@available(iOS 26, *)) {
[builder insertElements:childElements
atStartOfMenuForIdentifier:parentIdentifier];
return;
}
#endif // defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >=
// __IPHONE_26_0
[builder
replaceChildrenOfMenuForIdentifier:parentIdentifier
fromChildrenBlock:^(NSArray<UIMenuElement*>* elements) {
return [childElements
arrayByAddingObjectsFromArray:elements];
}];
}
@end