forked from zelo72/mastodon-ios
feat: add keyboard shortcuts for settings and favorites
This commit is contained in:
parent
5cbfa28b93
commit
5c6618f13e
|
@ -78,9 +78,13 @@
|
|||
"home": "Home",
|
||||
"search": "Search",
|
||||
"notification": "Notification",
|
||||
"profile": "Profile",
|
||||
"keyboard": {
|
||||
"switch_to_tab": "Switch to %s"
|
||||
"profile": "Profile"
|
||||
},
|
||||
"keyboard": {
|
||||
"common": {
|
||||
"switch_to_tab": "Switch to %s",
|
||||
"show_favorites": "Show Favorites",
|
||||
"open_settings": "Open Settings"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
|
@ -480,6 +484,9 @@
|
|||
"clear": "Clear Media Cache",
|
||||
"signout": "Sign Out"
|
||||
}
|
||||
},
|
||||
"keyboard": {
|
||||
"close_settings_window": "Close Settings Window"
|
||||
}
|
||||
},
|
||||
"report": {
|
||||
|
|
|
@ -112,3 +112,16 @@ extension UIViewController {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
|
||||
/// https://stackoverflow.com/a/27301207/3797903
|
||||
var isModal: Bool {
|
||||
let presentingIsModal = presentingViewController != nil
|
||||
let presentingIsNavigation = navigationController != nil && navigationController?.presentingViewController?.presentedViewController == navigationController
|
||||
let presentingIsTabBar = tabBarController?.presentingViewController is UITabBarController
|
||||
|
||||
return presentingIsModal || presentingIsNavigation || presentingIsTabBar
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -189,6 +189,18 @@ internal enum L10n {
|
|||
return L10n.tr("Localizable", "Common.Controls.Firendship.UnmuteUser", String(describing: p1))
|
||||
}
|
||||
}
|
||||
internal enum Keyboard {
|
||||
internal enum Common {
|
||||
/// Open Settings
|
||||
internal static let openSettings = L10n.tr("Localizable", "Common.Controls.Keyboard.Common.OpenSettings")
|
||||
/// Show Favorites
|
||||
internal static let showFavorites = L10n.tr("Localizable", "Common.Controls.Keyboard.Common.ShowFavorites")
|
||||
/// Switch to %@
|
||||
internal static func switchToTab(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Keyboard.Common.SwitchToTab", String(describing: p1))
|
||||
}
|
||||
}
|
||||
}
|
||||
internal enum Status {
|
||||
/// content warning
|
||||
internal static let contentWarning = L10n.tr("Localizable", "Common.Controls.Status.ContentWarning")
|
||||
|
@ -278,12 +290,6 @@ internal enum L10n {
|
|||
internal static let profile = L10n.tr("Localizable", "Common.Controls.Tabs.Profile")
|
||||
/// Search
|
||||
internal static let search = L10n.tr("Localizable", "Common.Controls.Tabs.Search")
|
||||
internal enum Keyboard {
|
||||
/// Switch to %@
|
||||
internal static func switchToTab(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Tabs.Keyboard.SwitchToTab", String(describing: p1))
|
||||
}
|
||||
}
|
||||
}
|
||||
internal enum Timeline {
|
||||
internal enum Accessibility {
|
||||
|
@ -828,6 +834,10 @@ internal enum L10n {
|
|||
internal enum Settings {
|
||||
/// Settings
|
||||
internal static let title = L10n.tr("Localizable", "Scene.Settings.Title")
|
||||
internal enum Keyboard {
|
||||
/// Close Settings Window
|
||||
internal static let closeSettingsWindow = L10n.tr("Localizable", "Scene.Settings.Keyboard.CloseSettingsWindow")
|
||||
}
|
||||
internal enum Section {
|
||||
internal enum Appearance {
|
||||
/// Automatic
|
||||
|
|
|
@ -64,6 +64,9 @@ Please check your internet connection.";
|
|||
"Common.Controls.Firendship.UnblockUser" = "Unblock %@";
|
||||
"Common.Controls.Firendship.Unmute" = "Unmute";
|
||||
"Common.Controls.Firendship.UnmuteUser" = "Unmute %@";
|
||||
"Common.Controls.Keyboard.Common.OpenSettings" = "Open Settings";
|
||||
"Common.Controls.Keyboard.Common.ShowFavorites" = "Show Favorites";
|
||||
"Common.Controls.Keyboard.Common.SwitchToTab" = "Switch to %@";
|
||||
"Common.Controls.Status.Actions.Favorite" = "Favorite";
|
||||
"Common.Controls.Status.Actions.Menu" = "Menu";
|
||||
"Common.Controls.Status.Actions.Reblog" = "Reblog";
|
||||
|
@ -91,7 +94,6 @@ Please check your internet connection.";
|
|||
"Common.Controls.Status.UserReblogged" = "%@ reblogged";
|
||||
"Common.Controls.Status.UserRepliedTo" = "Replied to %@";
|
||||
"Common.Controls.Tabs.Home" = "Home";
|
||||
"Common.Controls.Tabs.Keyboard.SwitchToTab" = "Switch to %@";
|
||||
"Common.Controls.Tabs.Notification" = "Notification";
|
||||
"Common.Controls.Tabs.Profile" = "Profile";
|
||||
"Common.Controls.Tabs.Search" = "Search";
|
||||
|
@ -273,6 +275,7 @@ any server.";
|
|||
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";
|
||||
"Scene.ServerRules.TermsOfService" = "terms of service";
|
||||
"Scene.ServerRules.Title" = "Some ground rules.";
|
||||
"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window";
|
||||
"Scene.Settings.Section.Appearance.Automatic" = "Automatic";
|
||||
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
|
||||
"Scene.Settings.Section.Appearance.Light" = "Always Light";
|
||||
|
|
|
@ -64,6 +64,9 @@ Please check your internet connection.";
|
|||
"Common.Controls.Firendship.UnblockUser" = "Unblock %@";
|
||||
"Common.Controls.Firendship.Unmute" = "Unmute";
|
||||
"Common.Controls.Firendship.UnmuteUser" = "Unmute %@";
|
||||
"Common.Controls.Keyboard.Common.OpenSettings" = "Open Settings";
|
||||
"Common.Controls.Keyboard.Common.ShowFavorites" = "Show Favorites";
|
||||
"Common.Controls.Keyboard.Common.SwitchToTab" = "Switch to %@";
|
||||
"Common.Controls.Status.Actions.Favorite" = "Favorite";
|
||||
"Common.Controls.Status.Actions.Menu" = "Menu";
|
||||
"Common.Controls.Status.Actions.Reblog" = "Reblog";
|
||||
|
@ -91,7 +94,6 @@ Please check your internet connection.";
|
|||
"Common.Controls.Status.UserReblogged" = "%@ reblogged";
|
||||
"Common.Controls.Status.UserRepliedTo" = "Replied to %@";
|
||||
"Common.Controls.Tabs.Home" = "Home";
|
||||
"Common.Controls.Tabs.Keyboard.SwitchToTab" = "Switch to %@";
|
||||
"Common.Controls.Tabs.Notification" = "Notification";
|
||||
"Common.Controls.Tabs.Profile" = "Profile";
|
||||
"Common.Controls.Tabs.Search" = "Search";
|
||||
|
@ -273,6 +275,7 @@ any server.";
|
|||
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";
|
||||
"Scene.ServerRules.TermsOfService" = "terms of service";
|
||||
"Scene.ServerRules.Title" = "Some ground rules.";
|
||||
"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window";
|
||||
"Scene.Settings.Section.Appearance.Automatic" = "Automatic";
|
||||
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
|
||||
"Scene.Settings.Section.Appearance.Light" = "Always Light";
|
||||
|
|
|
@ -190,28 +190,126 @@ extension MainTabBarController {
|
|||
|
||||
}
|
||||
|
||||
|
||||
// HIG: keyboard UX
|
||||
// https://developer.apple.com/design/human-interface-guidelines/macos/user-interaction/keyboard/
|
||||
extension MainTabBarController {
|
||||
|
||||
override var keyCommands: [UIKeyCommand]? {
|
||||
var switchToTabKeyCommands: [UIKeyCommand] {
|
||||
var commands: [UIKeyCommand] = []
|
||||
for (i, tab) in Tab.allCases.enumerated() {
|
||||
let title = L10n.Common.Controls.Tabs.Keyboard.switchToTab(tab.title)
|
||||
let title = L10n.Common.Controls.Keyboard.Common.switchToTab(tab.title)
|
||||
let input = String(i + 1)
|
||||
let command = UIKeyCommand(title: title, image: nil, action: #selector(MainTabBarController.switchToTab(_:)), input: input, modifierFlags: .control, propertyList: tab.rawValue, alternates: [], discoverabilityTitle: nil, attributes: [], state: .off)
|
||||
let command = UIKeyCommand(
|
||||
title: title,
|
||||
image: nil,
|
||||
action: #selector(MainTabBarController.switchToTabKeyCommandHandler(_:)),
|
||||
input: input,
|
||||
modifierFlags: .command,
|
||||
propertyList: tab.rawValue,
|
||||
alternates: [],
|
||||
discoverabilityTitle: nil,
|
||||
attributes: [],
|
||||
state: .off
|
||||
)
|
||||
commands.append(command)
|
||||
|
||||
}
|
||||
return commands
|
||||
}
|
||||
|
||||
@objc private func switchToTab(_ sender: UIKeyCommand) {
|
||||
var showFavoritesKeyCommand: UIKeyCommand {
|
||||
UIKeyCommand(
|
||||
title: L10n.Common.Controls.Keyboard.Common.showFavorites,
|
||||
image: nil,
|
||||
action: #selector(MainTabBarController.showFavoritesKeyCommandHandler(_:)),
|
||||
input: "f",
|
||||
modifierFlags: .command,
|
||||
propertyList: nil,
|
||||
alternates: [],
|
||||
discoverabilityTitle: nil,
|
||||
attributes: [],
|
||||
state: .off
|
||||
)
|
||||
}
|
||||
|
||||
var openSettingsKeyCommand: UIKeyCommand {
|
||||
UIKeyCommand(
|
||||
title: L10n.Common.Controls.Keyboard.Common.openSettings,
|
||||
image: nil,
|
||||
action: #selector(MainTabBarController.openSettingsKeyCommandHandler(_:)),
|
||||
input: ",",
|
||||
modifierFlags: .command,
|
||||
propertyList: nil,
|
||||
alternates: [],
|
||||
discoverabilityTitle: nil,
|
||||
attributes: [],
|
||||
state: .off
|
||||
)
|
||||
}
|
||||
|
||||
override var keyCommands: [UIKeyCommand]? {
|
||||
guard let topMost = self.topMost else {
|
||||
return []
|
||||
}
|
||||
|
||||
var commands: [UIKeyCommand] = []
|
||||
|
||||
if topMost.isModal {
|
||||
|
||||
} else {
|
||||
// switch tabs
|
||||
commands.append(contentsOf: switchToTabKeyCommands)
|
||||
|
||||
// show favorites
|
||||
if !(self.topMost is FavoriteViewController) {
|
||||
commands.append(showFavoritesKeyCommand)
|
||||
}
|
||||
|
||||
// open settings
|
||||
if context.settingService.currentSetting.value != nil {
|
||||
commands.append(openSettingsKeyCommand)
|
||||
}
|
||||
}
|
||||
|
||||
return commands
|
||||
}
|
||||
|
||||
@objc private func switchToTabKeyCommandHandler(_ sender: UIKeyCommand) {
|
||||
guard let rawValue = sender.propertyList as? Int,
|
||||
let tab = Tab(rawValue: rawValue) else { return }
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, tab.title)
|
||||
|
||||
guard let index = Tab.allCases.firstIndex(of: tab) else { return }
|
||||
let previousTab = Tab(rawValue: selectedIndex)
|
||||
selectedIndex = index
|
||||
|
||||
if let previousTab = previousTab {
|
||||
switch (tab, previousTab) {
|
||||
case (.home, .home):
|
||||
guard let navigationController = topMost?.navigationController else { return }
|
||||
if navigationController.viewControllers.count > 1 {
|
||||
// pop to top when previous tab position already is home
|
||||
navigationController.popToRootViewController(animated: true)
|
||||
} else if let homeTimelineViewController = topMost as? HomeTimelineViewController {
|
||||
// trigger scrollToTop if topMost is home timeline
|
||||
homeTimelineViewController.scrollToTop(animated: true)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func showFavoritesKeyCommandHandler(_ sender: UIKeyCommand) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
let favoriteViewModel = FavoriteViewModel(context: context)
|
||||
coordinator.present(scene: .favorite(viewModel: favoriteViewModel), from: nil, transition: .show)
|
||||
}
|
||||
|
||||
@objc private func openSettingsKeyCommandHandler(_ sender: UIKeyCommand) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
guard let setting = context.settingService.currentSetting.value else { return }
|
||||
let settingsViewModel = SettingsViewModel(context: context, setting: setting)
|
||||
coordinator.present(scene: .settings(viewModel: settingsViewModel), from: nil, transition: .modal(animated: true, completion: nil))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -439,6 +439,41 @@ extension SettingsViewController: ActiveLabelDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - UIAdaptivePresentationControllerDelegate
|
||||
extension SettingsViewController: UIAdaptivePresentationControllerDelegate {
|
||||
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
|
||||
return .formSheet
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsViewController {
|
||||
|
||||
var closeKeyCommand: UIKeyCommand {
|
||||
UIKeyCommand(
|
||||
title: L10n.Scene.Settings.Keyboard.closeSettingsWindow,
|
||||
image: nil,
|
||||
action: #selector(SettingsViewController.closeSettingsWindowKeyCommandHandler(_:)),
|
||||
input: "w",
|
||||
modifierFlags: .command,
|
||||
propertyList: nil,
|
||||
alternates: [],
|
||||
discoverabilityTitle: nil,
|
||||
attributes: [],
|
||||
state: .off
|
||||
)
|
||||
}
|
||||
|
||||
override var keyCommands: [UIKeyCommand]? {
|
||||
return [closeKeyCommand]
|
||||
}
|
||||
|
||||
@objc private func closeSettingsWindowKeyCommandHandler(_ sender: UIKeyCommand) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if canImport(SwiftUI) && DEBUG
|
||||
import SwiftUI
|
||||
|
||||
|
|
Loading…
Reference in New Issue