diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 706d1c1a..0486c58a 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -236,6 +236,7 @@ D6B053AC23BD2F1400A066FA /* AssetCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6B053AA23BD2F1400A066FA /* AssetCollectionViewCell.xib */; }; D6B053AE23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053AD23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift */; }; D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */; }; + D6B22A0F2560D52D004D82EF /* TabbedPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */; }; D6B30E09254BAF63009CAEE5 /* ImageGrayscalifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */; }; D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */; }; D6B81F3C2560365300F6E31D /* RefreshableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B81F3B2560365300F6E31D /* RefreshableViewController.swift */; }; @@ -585,6 +586,7 @@ D6B053AA23BD2F1400A066FA /* AssetCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AssetCollectionViewCell.xib; sourceTree = ""; }; D6B053AD23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetPickerSheetContainerViewController.swift; sourceTree = ""; }; D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OppositeCollapseKeywordsView.swift; sourceTree = ""; }; + D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbedPageViewController.swift; sourceTree = ""; }; D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGrayscalifier.swift; sourceTree = ""; }; D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDisplayNameLabel.swift; sourceTree = ""; }; D6B81F3B2560365300F6E31D /* RefreshableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshableViewController.swift; sourceTree = ""; }; @@ -1362,6 +1364,7 @@ D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */, D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */, D6BC8747219738E1006163F1 /* EnhancedTableViewController.swift */, + D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */, D68FEC4E232C5BC300C84F23 /* SegmentedPageViewController.swift */, D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */, D693DE5823FE24300061E07D /* InteractivePushTransition.swift */, @@ -1858,6 +1861,7 @@ D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */, D6D3FDE224F46A8D00FF50A5 /* ComposeUIState.swift in Sources */, D6C99FC724FACFAB005C74D3 /* ActivityIndicatorView.swift in Sources */, + D6B22A0F2560D52D004D82EF /* TabbedPageViewController.swift in Sources */, D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */, 0411610022B442870030A9B7 /* LoadingLargeImageViewController.swift in Sources */, D6A4DCE525537C7A00D9DE31 /* FastSwitchingAccountView.swift in Sources */, diff --git a/Tusker/Controllers/MenuController.swift b/Tusker/Controllers/MenuController.swift index 9bf78f37..9a26a094 100644 --- a/Tusker/Controllers/MenuController.swift +++ b/Tusker/Controllers/MenuController.swift @@ -57,9 +57,18 @@ struct MenuController { ] } + static func nextSubTabCommand() -> UIKeyCommand { + return UIKeyCommand(title: "Next Sub Tab", action: #selector(TabbedPageViewController.selectNextPage), input: "]", modifierFlags: [.command, .shift]) + } + + static func prevSubTabCommand() -> UIKeyCommand { + return UIKeyCommand(title: "Previous Sub Tab", action: #selector(TabbedPageViewController.selectPrevPage), input: "[", modifierFlags: [.command, .shift]) + } + static func buildMainMenu(builder: UIMenuBuilder) { builder.insertChild(buildFileMenu(), atStartOfMenu: .file) - builder.insertChild(buildViewMenu(), atStartOfMenu: .view) + builder.insertChild(buildSubTabMenu(), atStartOfMenu: .view) + builder.insertChild(buildSidebarShortcuts(), atStartOfMenu: .view) } private static func buildFileMenu() -> UIMenu { @@ -75,7 +84,20 @@ struct MenuController { ) } - private static func buildViewMenu() -> UIMenu { + private static func buildSubTabMenu() -> UIMenu { + return UIMenu( + title: "", + image: nil, + identifier: nil, + options: .displayInline, + children: [ + prevSubTabCommand(), + nextSubTabCommand(), + ] + ) + } + + private static func buildSidebarShortcuts() -> UIMenu { let children: [UIMenuElement] if #available(iOS 14.0, *) { children = sidebarItemKeyCommands() diff --git a/Tusker/Screens/Profile/ProfileViewController.swift b/Tusker/Screens/Profile/ProfileViewController.swift index d0f59b4d..0d5f417f 100644 --- a/Tusker/Screens/Profile/ProfileViewController.swift +++ b/Tusker/Screens/Profile/ProfileViewController.swift @@ -89,6 +89,9 @@ class ProfileViewController: UIPageViewController { headerView.widthAnchor.constraint(equalTo: view.widthAnchor), ]) + addKeyCommand(MenuController.prevSubTabCommand()) + addKeyCommand(MenuController.nextSubTabCommand()) + accountUpdater = mastodonController.persistentContainer.accountSubject .filter { [weak self] in $0 == self?.accountID } .receive(on: DispatchQueue.main) @@ -145,6 +148,8 @@ class ProfileViewController: UIPageViewController { let direction: UIPageViewController.NavigationDirection = currentIndex == nil || index - currentIndex > 0 ? .forward : .reverse currentIndex = index + headerView.pagesSegmentedControl.selectedSegmentIndex = index + guard let old = viewControllers?.first as? ProfileStatusesViewController else { // if old doesn't exist, we're selecting the initial view controller, so moving the header around isn't necessary // since it will be added in viewDidLoad @@ -273,3 +278,15 @@ extension ProfileViewController: TabBarScrollableViewController { pageControllers[currentIndex].tabBarScrollToTop() } } + +extension ProfileViewController: TabbedPageViewController { + func selectNextPage() { + guard currentIndex < pageControllers.count - 1 else { return } + selectPage(at: currentIndex + 1, animated: true) + } + + func selectPrevPage() { + guard currentIndex > 0 else { return } + selectPage(at: currentIndex - 1, animated: true) + } +} diff --git a/Tusker/Screens/Utilities/SegmentedPageViewController.swift b/Tusker/Screens/Utilities/SegmentedPageViewController.swift index 6b1f2993..0fd2ce03 100644 --- a/Tusker/Screens/Utilities/SegmentedPageViewController.swift +++ b/Tusker/Screens/Utilities/SegmentedPageViewController.swift @@ -41,6 +41,9 @@ class SegmentedPageViewController: UIPageViewController, UIPageViewControllerDel segmentedControl.selectedSegmentIndex = 0 selectPage(at: 0, animated: false) + + addKeyCommand(MenuController.prevSubTabCommand()) + addKeyCommand(MenuController.nextSubTabCommand()) } func selectPage(at index: Int, animated: Bool) { @@ -48,6 +51,7 @@ class SegmentedPageViewController: UIPageViewController, UIPageViewControllerDel setViewControllers([pageControllers[index]], direction: direction, animated: animated) navigationItem.title = pageControllers[index].title currentIndex = index + segmentedControl.selectedSegmentIndex = index } @objc func segmentedControlChanged() { @@ -72,6 +76,18 @@ extension SegmentedPageViewController: TabBarScrollableViewController { } } +extension SegmentedPageViewController: TabbedPageViewController { + func selectNextPage() { + guard currentIndex < pageControllers.count - 1 else { return } + selectPage(at: currentIndex + 1, animated: true) + } + + func selectPrevPage() { + guard currentIndex > 0 else { return } + selectPage(at: currentIndex - 1, animated: true) + } +} + extension SegmentedPageViewController: BackgroundableViewController { func sceneDidEnterBackground() { if let current = pageControllers[currentIndex] as? BackgroundableViewController { diff --git a/Tusker/Screens/Utilities/TabbedPageViewController.swift b/Tusker/Screens/Utilities/TabbedPageViewController.swift new file mode 100644 index 00000000..c1da3d08 --- /dev/null +++ b/Tusker/Screens/Utilities/TabbedPageViewController.swift @@ -0,0 +1,14 @@ +// +// TabbedPageViewController.swift +// Tusker +// +// Created by Shadowfacts on 11/14/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import UIKit + +@objc protocol TabbedPageViewController { + func selectNextPage() + func selectPrevPage() +}