diff --git a/iOS/KeyboardManager.swift b/iOS/KeyboardManager.swift index ece86d0b9..2644d4404 100644 --- a/iOS/KeyboardManager.swift +++ b/iOS/KeyboardManager.swift @@ -17,45 +17,52 @@ enum KeyboardType: String { class KeyboardManager { - private(set) var keyCommands: [UIKeyCommand]? - + private(set) var keyCommands: [UIKeyCommand] + init(type: KeyboardType) { + keyCommands = KeyboardManager.globalAuxilaryKeyCommands() + + switch type { + case .sidebar: + keyCommands.append(contentsOf: KeyboardManager.hardcodeFeedKeyCommands()) + case .timeline, .detail: + keyCommands.append(contentsOf: KeyboardManager.hardcodeArticleKeyCommands()) + default: + break + } + let globalFile = Bundle.main.path(forResource: KeyboardType.global.rawValue, ofType: "plist")! let globalEntries = NSArray(contentsOfFile: globalFile)! as! [[String: Any]] - keyCommands = globalEntries.compactMap { createKeyCommand(keyEntry: $0) } - keyCommands!.append(contentsOf: globalAuxilaryKeyCommands()) + let globalCommands = globalEntries.compactMap { KeyboardManager.createKeyCommand(keyEntry: $0) } + keyCommands.append(contentsOf: globalCommands) let specificFile = Bundle.main.path(forResource: type.rawValue, ofType: "plist")! let specificEntries = NSArray(contentsOfFile: specificFile)! as! [[String: Any]] - keyCommands!.append(contentsOf: specificEntries.compactMap { createKeyCommand(keyEntry: $0) } ) - - if type == .sidebar { - keyCommands!.append(contentsOf: sidebarAuxilaryKeyCommands()) - } + keyCommands.append(contentsOf: specificEntries.compactMap { KeyboardManager.createKeyCommand(keyEntry: $0) } ) + } + + static func createKeyCommand(title: String, action: String, input: String, modifiers: UIKeyModifierFlags) -> UIKeyCommand { + let selector = NSSelectorFromString(action) + return UIKeyCommand(title: title, image: nil, action: selector, input: input, modifierFlags: modifiers, propertyList: nil, alternates: [], discoverabilityTitle: nil, attributes: [], state: .on) } } private extension KeyboardManager { - func createKeyCommand(keyEntry: [String: Any]) -> UIKeyCommand? { + static func createKeyCommand(keyEntry: [String: Any]) -> UIKeyCommand? { guard let input = createKeyCommandInput(keyEntry: keyEntry) else { return nil } let modifiers = createKeyModifierFlags(keyEntry: keyEntry) let action = keyEntry["action"] as! String if let title = keyEntry["title"] as? String { - return createKeyCommand(title: title, action: action, input: input, modifiers: modifiers) + return KeyboardManager.createKeyCommand(title: title, action: action, input: input, modifiers: modifiers) } else { return UIKeyCommand(input: input, modifierFlags: modifiers, action: NSSelectorFromString(action)) } } - - func createKeyCommand(title: String, action: String, input: String, modifiers: UIKeyModifierFlags) -> UIKeyCommand { - let selector = NSSelectorFromString(action) - return UIKeyCommand(title: title, image: nil, action: selector, input: input, modifierFlags: modifiers, propertyList: nil, alternates: [], discoverabilityTitle: nil, attributes: [], state: .on) - } - - func createKeyCommandInput(keyEntry: [String: Any]) -> String? { + + static func createKeyCommandInput(keyEntry: [String: Any]) -> String? { guard let key = keyEntry["key"] as? String else { return nil } switch(key) { @@ -85,7 +92,7 @@ private extension KeyboardManager { } - func createKeyModifierFlags(keyEntry: [String: Any]) -> UIKeyModifierFlags { + static func createKeyModifierFlags(keyEntry: [String: Any]) -> UIKeyModifierFlags { var flags = UIKeyModifierFlags() if keyEntry["shiftModifier"] as? Bool ?? false { @@ -107,59 +114,65 @@ private extension KeyboardManager { return flags } - func globalAuxilaryKeyCommands() -> [UIKeyCommand] { + static func globalAuxilaryKeyCommands() -> [UIKeyCommand] { var keys = [UIKeyCommand]() let addNewFeedTitle = NSLocalizedString("New Feed", comment: "New Feed") - keys.append(createKeyCommand(title: addNewFeedTitle, action: "addNewFeed:", input: "n", modifiers: [.command])) + keys.append(KeyboardManager.createKeyCommand(title: addNewFeedTitle, action: "addNewFeed:", input: "n", modifiers: [.command])) let addNewFolderTitle = NSLocalizedString("New Folder", comment: "New Folder") - keys.append(createKeyCommand(title: addNewFolderTitle, action: "addNewFolder:", input: "n", modifiers: [.command, .shift])) + keys.append(KeyboardManager.createKeyCommand(title: addNewFolderTitle, action: "addNewFolder:", input: "n", modifiers: [.command, .shift])) let refreshTitle = NSLocalizedString("Refresh", comment: "Refresh") - keys.append(createKeyCommand(title: refreshTitle, action: "refresh:", input: "r", modifiers: [.command])) + keys.append(KeyboardManager.createKeyCommand(title: refreshTitle, action: "refresh:", input: "r", modifiers: [.command])) let nextUnreadTitle = NSLocalizedString("Next Unread", comment: "Next Unread") - keys.append(createKeyCommand(title: nextUnreadTitle, action: "nextUnread:", input: "/", modifiers: [.command])) + keys.append(KeyboardManager.createKeyCommand(title: nextUnreadTitle, action: "nextUnread:", input: "/", modifiers: [.command])) let goToTodayTitle = NSLocalizedString("Go To Today", comment: "Go To Today") - keys.append(createKeyCommand(title: goToTodayTitle, action: "goToToday:", input: "1", modifiers: [.command])) + keys.append(KeyboardManager.createKeyCommand(title: goToTodayTitle, action: "goToToday:", input: "1", modifiers: [.command])) let goToAllUnreadTitle = NSLocalizedString("Go To All Unread", comment: "Go To All Unread") - keys.append(createKeyCommand(title: goToAllUnreadTitle, action: "goToAllUnread:", input: "2", modifiers: [.command])) + keys.append(KeyboardManager.createKeyCommand(title: goToAllUnreadTitle, action: "goToAllUnread:", input: "2", modifiers: [.command])) let goToStarredTitle = NSLocalizedString("Go To Starred", comment: "Go To Starred") - keys.append(createKeyCommand(title: goToStarredTitle, action: "goToStarred:", input: "3", modifiers: [.command])) - - let toggleReadTitle = NSLocalizedString("Toggle Read Status", comment: "Toggle Read Status") - keys.append(createKeyCommand(title: toggleReadTitle, action: "toggleRead:", input: "U", modifiers: [.command, .shift])) - - let markAllAsReadTitle = NSLocalizedString("Mark All as Read", comment: "Mark All as Read") - keys.append(createKeyCommand(title: markAllAsReadTitle, action: "markAllAsRead:", input: "k", modifiers: [.command])) - - let markOlderAsReadTitle = NSLocalizedString("Mark Older as Read", comment: "Mark Older as Read") - keys.append(createKeyCommand(title: markOlderAsReadTitle, action: "markOlderArticlesAsRead:", input: "k", modifiers: [.command, .shift])) - - let toggleStarredTitle = NSLocalizedString("Toggle Starred Status", comment: "Toggle Starred Status") - keys.append(createKeyCommand(title: toggleStarredTitle, action: "toggleStarred:", input: "l", modifiers: [.command, .shift])) - - let openInBrowserTitle = NSLocalizedString("Open In Browser", comment: "Open In Browser") - keys.append(createKeyCommand(title: openInBrowserTitle, action: "openInBrowser:", input: UIKeyCommand.inputRightArrow, modifiers: [.command])) + keys.append(KeyboardManager.createKeyCommand(title: goToStarredTitle, action: "goToStarred:", input: "3", modifiers: [.command])) let articleSearchTitle = NSLocalizedString("Article Search", comment: "Article Search") - keys.append(createKeyCommand(title: articleSearchTitle, action: "articleSearch:", input: "f", modifiers: [.command, .shift])) + keys.append(KeyboardManager.createKeyCommand(title: articleSearchTitle, action: "articleSearch:", input: "f", modifiers: [.command, .shift])) + + let markAllAsReadTitle = NSLocalizedString("Mark All as Read", comment: "Mark All as Read") + keys.append(KeyboardManager.createKeyCommand(title: markAllAsReadTitle, action: "markAllAsRead:", input: "k", modifiers: [.command])) return keys } - func sidebarAuxilaryKeyCommands() -> [UIKeyCommand] { + static func hardcodeFeedKeyCommands() -> [UIKeyCommand] { var keys = [UIKeyCommand]() - + let nextUpTitle = NSLocalizedString("Select Next Up", comment: "Select Next Up") - keys.append(createKeyCommand(title: nextUpTitle, action: "selectNextUp:", input: UIKeyCommand.inputUpArrow, modifiers: [])) + keys.append(KeyboardManager.createKeyCommand(title: nextUpTitle, action: "selectNextUp:", input: UIKeyCommand.inputUpArrow, modifiers: [])) let nextDownTitle = NSLocalizedString("Select Next Down", comment: "Select Next Down") - keys.append(createKeyCommand(title: nextDownTitle, action: "selectNextDown:", input: UIKeyCommand.inputDownArrow, modifiers: [])) + keys.append(KeyboardManager.createKeyCommand(title: nextDownTitle, action: "selectNextDown:", input: UIKeyCommand.inputDownArrow, modifiers: [])) + + return keys + } + + static func hardcodeArticleKeyCommands() -> [UIKeyCommand] { + var keys = [UIKeyCommand]() + + let openInBrowserTitle = NSLocalizedString("Open In Browser", comment: "Open In Browser") + keys.append(KeyboardManager.createKeyCommand(title: openInBrowserTitle, action: "openInBrowser:", input: UIKeyCommand.inputRightArrow, modifiers: [.command])) + + let toggleReadTitle = NSLocalizedString("Toggle Read Status", comment: "Toggle Read Status") + keys.append(KeyboardManager.createKeyCommand(title: toggleReadTitle, action: "toggleRead:", input: "u", modifiers: [.command, .shift])) + + let markOlderAsReadTitle = NSLocalizedString("Mark Older as Read", comment: "Mark Older as Read") + keys.append(KeyboardManager.createKeyCommand(title: markOlderAsReadTitle, action: "markOlderArticlesAsRead:", input: "k", modifiers: [.command, .shift])) + + let toggleStarredTitle = NSLocalizedString("Toggle Starred Status", comment: "Toggle Starred Status") + keys.append(KeyboardManager.createKeyCommand(title: toggleStarredTitle, action: "toggleStarred:", input: "l", modifiers: [.command, .shift])) return keys } diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 8db81d157..84eb4d66f 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -523,8 +523,10 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { } func expandFolder(_ indexPath: IndexPath) { - let expandNode = shadowTable[indexPath.section][indexPath.row] - guard !expandedNodes.contains(expandNode) else { return } + guard let expandNode = nodeFor(indexPath), !expandedNodes.contains(expandNode) && expandNode.representedObject is Folder else { + return + } + expandedNodes.append(expandNode) animatingChanges = true @@ -566,10 +568,12 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { } func collapseFolder(_ indexPath: IndexPath) { + guard let collapseNode = nodeFor(indexPath), expandedNodes.contains(collapseNode) && collapseNode.representedObject is Folder else { + return + } + animatingChanges = true - let collapseNode = shadowTable[indexPath.section][indexPath.row] - guard expandedNodes.contains(collapseNode) else { return } if let removeNode = expandedNodes.firstIndex(of: collapseNode) { expandedNodes.remove(at: removeNode) }