From 50e8ed36936f10b014581fd74294f9c1ebe0c7bd Mon Sep 17 00:00:00 2001 From: Ryan Nystrom Date: Sun, 7 Oct 2018 23:24:29 -0400 Subject: [PATCH] new routing library and refactor shortcuts --- Classes/Search/SearchViewController.swift | 4 + Classes/Systems/AppDelegate.swift | 7 +- .../AppRouter/AppController+SetupRoutes.swift | 19 +++++ Classes/Systems/AppRouter/AppController.swift | 35 ++++++--- .../AppRouter/AppSplitViewController.swift | 8 +- .../AppRouter/BookmarkShortcutRoute.swift | 28 +++++++ Classes/Systems/AppRouter/Routable.swift | 19 +++++ .../Systems/AppRouter/RoutePerformable.swift | 18 +++++ .../AppRouter/SearchShortcutRoute.swift | 31 ++++++++ .../SwitchAccountShortcutRoute.swift | 38 +++++++++ Classes/Systems/Route.swift | 23 ------ Classes/Systems/ShortcutHandler.swift | 77 +++++++++++-------- .../View Controllers/TabBarController.swift | 22 ------ .../UITabBarController+SelectType.swift | 34 ++++++++ Freetime.xcodeproj/project.pbxproj | 36 +++++++-- Resources/Base.lproj/Main.storyboard | 4 +- 16 files changed, 295 insertions(+), 108 deletions(-) create mode 100644 Classes/Systems/AppRouter/AppController+SetupRoutes.swift create mode 100644 Classes/Systems/AppRouter/BookmarkShortcutRoute.swift create mode 100644 Classes/Systems/AppRouter/Routable.swift create mode 100644 Classes/Systems/AppRouter/RoutePerformable.swift create mode 100644 Classes/Systems/AppRouter/SearchShortcutRoute.swift create mode 100644 Classes/Systems/AppRouter/SwitchAccountShortcutRoute.swift delete mode 100644 Classes/Systems/Route.swift delete mode 100644 Classes/View Controllers/TabBarController.swift create mode 100644 Classes/View Controllers/UITabBarController+SelectType.swift diff --git a/Classes/Search/SearchViewController.swift b/Classes/Search/SearchViewController.swift index d0d0f8315..99edff1d3 100644 --- a/Classes/Search/SearchViewController.swift +++ b/Classes/Search/SearchViewController.swift @@ -104,6 +104,10 @@ SearchResultSectionControllerDelegate { } } + func searchBarBecomeFirstResponder() { + searchBar.becomeFirstResponder() + } + // MARK: Data Loading/Paging private func update(animated: Bool) { diff --git a/Classes/Systems/AppDelegate.swift b/Classes/Systems/AppDelegate.swift index 17f6c2e7c..2734e4a00 100644 --- a/Classes/Systems/AppDelegate.swift +++ b/Classes/Systems/AppDelegate.swift @@ -23,6 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { appController.appDidFinishLaunching(with: window) + appController.setupRoutes() // setup fabric Fabric.with([Crashlytics.self]) @@ -49,11 +50,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { - guard let route = Route(shortcutItem: shortcutItem) else { - completionHandler(false) - return - } - completionHandler(appController.handle(route: route)) + appController.handle(path: shortcutItem.type, params: shortcutItem.params) } func applicationDidBecomeActive(_ application: UIApplication) { diff --git a/Classes/Systems/AppRouter/AppController+SetupRoutes.swift b/Classes/Systems/AppRouter/AppController+SetupRoutes.swift new file mode 100644 index 000000000..af715f5be --- /dev/null +++ b/Classes/Systems/AppRouter/AppController+SetupRoutes.swift @@ -0,0 +1,19 @@ +// +// AppController+SetupRoutes.swift +// Freetime +// +// Created by Ryan Nystrom on 10/7/18. +// Copyright © 2018 Ryan Nystrom. All rights reserved. +// + +import Foundation + +extension AppController { + + func setupRoutes() { + register(route: BookmarkShortcutRoute.self) + register(route: SwitchAccountShortcutRoute.self) + register(route: SearchShortcutRoute.self) + } + +} diff --git a/Classes/Systems/AppRouter/AppController.swift b/Classes/Systems/AppRouter/AppController.swift index 802115464..23986c0cc 100644 --- a/Classes/Systems/AppRouter/AppController.swift +++ b/Classes/Systems/AppRouter/AppController.swift @@ -18,6 +18,7 @@ final class AppController: LoginSplashViewControllerDelegate, GitHubSessionListe private var appClient: GithubClient? private var settingsNavigationController: UINavigationController? private var watchAppSync: WatchAppUserSessionSync? + private var routes = [String: (Routable & RoutePerformable).Type]() init() { sessionManager.addListener(listener: self) @@ -51,18 +52,30 @@ final class AppController: LoginSplashViewControllerDelegate, GitHubSessionListe appClient?.badge.fetch(application: application, handler: completion) } - func handle(route: Route) -> Bool { - switch route { - case .tab(let tab): - splitViewController.select(tabAt: tab.rawValue) - return true - case .switchAccount(let sessionIndex): - if let index = sessionIndex { - let session = sessionManager.userSessions[index] - sessionManager.focus(session, dismiss: false) - } - return true + @discardableResult + func handle(url: URL) -> Bool { + guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) + else { return false } + var params = [String: String]() + for item in components.queryItems ?? [] { + params[item.name] = item.value } + return handle(path: url.path, params: params) + } + + @discardableResult + func handle(path: String, params: [String: String]) -> Bool { + guard let routeType = routes[path], + let route = routeType.from(params: params) + else { return false } + return route.perform( + sessionManager: sessionManager, + splitViewController: splitViewController + ) + } + + func register(route: T.Type) { + routes[T.path] = T.self } private func resetWatchSync(userSession: GitHubUserSession) { diff --git a/Classes/Systems/AppRouter/AppSplitViewController.swift b/Classes/Systems/AppRouter/AppSplitViewController.swift index cfe268252..e2bad7684 100644 --- a/Classes/Systems/AppRouter/AppSplitViewController.swift +++ b/Classes/Systems/AppRouter/AppSplitViewController.swift @@ -20,18 +20,14 @@ final class AppSplitViewController: UISplitViewController { preferredDisplayMode = .allVisible } - private var detailNavigationController: UINavigationController? { + var detailNavigationController: UINavigationController? { return viewControllers.last as? UINavigationController } - private var masterTabBarController: UITabBarController? { + var masterTabBarController: UITabBarController? { return viewControllers.first as? UITabBarController } - func select(tabAt index: Int) { - masterTabBarController?.selectedIndex = index - } - func resetEmpty() { let controller = UIViewController() controller.view.backgroundColor = Styles.Colors.background diff --git a/Classes/Systems/AppRouter/BookmarkShortcutRoute.swift b/Classes/Systems/AppRouter/BookmarkShortcutRoute.swift new file mode 100644 index 000000000..1033f084e --- /dev/null +++ b/Classes/Systems/AppRouter/BookmarkShortcutRoute.swift @@ -0,0 +1,28 @@ +// +// BookmarkShortcutRoute.swift +// Freetime +// +// Created by Ryan Nystrom on 10/7/18. +// Copyright © 2018 Ryan Nystrom. All rights reserved. +// + +import Foundation +import GitHubSession + +struct BookmarkShortcutRoute: Routable { + static func from(params: [String : String]) -> BookmarkShortcutRoute? { + return BookmarkShortcutRoute() + } + static var path: String { + return "com.githawk.shortcut.bookmark" + } +} + +extension BookmarkShortcutRoute: RoutePerformable { + func perform( + sessionManager: GitHubSessionManager, + splitViewController: AppSplitViewController + ) -> Bool { + return splitViewController.masterTabBarController?.selectTab(of: BookmarkViewController.self) != nil + } +} diff --git a/Classes/Systems/AppRouter/Routable.swift b/Classes/Systems/AppRouter/Routable.swift new file mode 100644 index 000000000..a770982b3 --- /dev/null +++ b/Classes/Systems/AppRouter/Routable.swift @@ -0,0 +1,19 @@ +// +// Routable.swift +// Freetime +// +// Created by Ryan Nystrom on 10/7/18. +// Copyright © 2018 Ryan Nystrom. All rights reserved. +// + +import Foundation + +protocol Routable { + static func from(params: [String: String]) -> Self? + var encoded: [String: String] { get } + static var path: String { get } +} + +extension Routable { + var encoded: [String: String] { return [:] } +} diff --git a/Classes/Systems/AppRouter/RoutePerformable.swift b/Classes/Systems/AppRouter/RoutePerformable.swift new file mode 100644 index 000000000..30902cf7c --- /dev/null +++ b/Classes/Systems/AppRouter/RoutePerformable.swift @@ -0,0 +1,18 @@ +// +// RoutePerformable.swift +// Freetime +// +// Created by Ryan Nystrom on 10/7/18. +// Copyright © 2018 Ryan Nystrom. All rights reserved. +// + +import Foundation +import GitHubSession + +protocol RoutePerformable { + @discardableResult + func perform( + sessionManager: GitHubSessionManager, + splitViewController: AppSplitViewController + ) -> Bool +} diff --git a/Classes/Systems/AppRouter/SearchShortcutRoute.swift b/Classes/Systems/AppRouter/SearchShortcutRoute.swift new file mode 100644 index 000000000..d3501a328 --- /dev/null +++ b/Classes/Systems/AppRouter/SearchShortcutRoute.swift @@ -0,0 +1,31 @@ +// +// SearchShortcutRoute.swift +// Freetime +// +// Created by Ryan Nystrom on 10/7/18. +// Copyright © 2018 Ryan Nystrom. All rights reserved. +// + +import UIKit +import GitHubSession + +struct SearchShortcutRoute: Routable { + static func from(params: [String : String]) -> SearchShortcutRoute? { + return SearchShortcutRoute() + } + static var path: String { + return "com.githawk.shortcut.search" + } +} + +extension SearchShortcutRoute: RoutePerformable { + func perform( + sessionManager: GitHubSessionManager, + splitViewController: AppSplitViewController + ) -> Bool { + guard let controller = splitViewController.masterTabBarController?.selectTab(of: SearchViewController.self) + else { return false } + controller.searchBarBecomeFirstResponder() + return true + } +} diff --git a/Classes/Systems/AppRouter/SwitchAccountShortcutRoute.swift b/Classes/Systems/AppRouter/SwitchAccountShortcutRoute.swift new file mode 100644 index 000000000..35394c84c --- /dev/null +++ b/Classes/Systems/AppRouter/SwitchAccountShortcutRoute.swift @@ -0,0 +1,38 @@ +// +// SwitchAccountShortcutRoute.swift +// Freetime +// +// Created by Ryan Nystrom on 10/7/18. +// Copyright © 2018 Ryan Nystrom. All rights reserved. +// + +import Foundation +import GitHubSession + +struct SwitchAccountShortcutRoute: Routable { + let username: String + static func from(params: [String : String]) -> SwitchAccountShortcutRoute? { + guard let username = params["username"] else { return nil } + return SwitchAccountShortcutRoute(username: username) + } + var encoded: [String : String] { + return ["username": username] + } + static var path: String { + return "com.githawk.shortcut.switch" + } +} + +extension SwitchAccountShortcutRoute: RoutePerformable { + func perform( + sessionManager: GitHubSessionManager, + splitViewController: AppSplitViewController + ) -> Bool { + let userSessions = sessionManager.userSessions + guard let needle = userSessions.first(where: { username == $0.username }) + else { return false } + sessionManager.focus(needle, dismiss: false) + splitViewController.masterTabBarController?.selectTab(of: NotificationsViewController.self) + return true + } +} diff --git a/Classes/Systems/Route.swift b/Classes/Systems/Route.swift deleted file mode 100644 index 2e158e9be..000000000 --- a/Classes/Systems/Route.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Navigation.swift -// Freetime -// -// Created by Rizwan on 26/02/18. -// Copyright © 2018 Ryan Nystrom. All rights reserved. -// - -import Foundation - -enum Route { - case tab(TabBarController.Tab) - case switchAccount(sessionIndex: Int?) - - init?(shortcutItem: UIApplicationShortcutItem) { - guard let itemType = ShortcutHandler.Items(rawValue: shortcutItem.type) else { return nil } - switch itemType { - case .search: self = .tab(.search) - case .bookmarks: self = .tab(.bookmarks) - case .switchAccount: self = .switchAccount(sessionIndex: shortcutItem.userInfo?["sessionIndex"] as? Int) - } - } -} diff --git a/Classes/Systems/ShortcutHandler.swift b/Classes/Systems/ShortcutHandler.swift index c5b8665e7..fec1d7102 100644 --- a/Classes/Systems/ShortcutHandler.swift +++ b/Classes/Systems/ShortcutHandler.swift @@ -9,52 +9,67 @@ import Foundation import GitHubSession -struct ShortcutHandler { +extension UIApplicationShortcutItem { + + var params: [String: String] { + var params = [String: String]() + userInfo?.forEach { + if let value = $1 as? String { + params[$0] = value + } + } + return params + } - enum Items: String { - case search - case bookmarks - case switchAccount + static func from( + route: T, + localizedTitle: String, + localizedSubtitle: String? = nil, + icon: UIApplicationShortcutIcon? = nil + ) -> UIApplicationShortcutItem { + return UIApplicationShortcutItem( + type: T.path, + localizedTitle: localizedTitle, + localizedSubtitle: localizedSubtitle, + icon: icon, + userInfo: route.encoded + ) } +} + +struct ShortcutHandler { + static func configure(sessionUsernames: [String]) { UIApplication.shared.shortcutItems = generateItems(sessionUsernames: sessionUsernames) } private static func generateItems(sessionUsernames: [String]) -> [UIApplicationShortcutItem] { - var items: [UIApplicationShortcutItem] = [] - - // Search - let searchIcon = UIApplicationShortcutIcon(templateImageName: Items.search.rawValue) - let searchItem = UIApplicationShortcutItem(type: Items.search.rawValue, - localizedTitle: Constants.Strings.search, - localizedSubtitle: nil, - icon: searchIcon) - items.append(searchItem) - - // Bookmarks - let bookmarkIcon = UIApplicationShortcutIcon(templateImageName: "bookmark") - let bookmarkItem = UIApplicationShortcutItem(type: Items.bookmarks.rawValue, - localizedTitle: Constants.Strings.bookmarks, - localizedSubtitle: nil, - icon: bookmarkIcon) - items.append(bookmarkItem) - - // Switchuser + var items = [ + UIApplicationShortcutItem.from( + route: SearchShortcutRoute(), + localizedTitle: Constants.Strings.search, + icon: UIApplicationShortcutIcon(templateImageName: "search") + ), + UIApplicationShortcutItem.from( + route: BookmarkShortcutRoute(), + localizedTitle: Constants.Strings.bookmarks, + icon: UIApplicationShortcutIcon(templateImageName: "bookmark") + ) + ] + if sessionUsernames.count > 1 { let username = sessionUsernames[1] - let userIcon = UIApplicationShortcutIcon(templateImageName: "organization") - let userItem = UIApplicationShortcutItem( - type: Items.switchAccount.rawValue, + items.append(UIApplicationShortcutItem.from( + route: SwitchAccountShortcutRoute(username: username), localizedTitle: NSLocalizedString("Switch Account", comment: ""), localizedSubtitle: username, - icon: userIcon, - userInfo: ["sessionIndex": 1] - ) - items.append(userItem) + icon: UIApplicationShortcutIcon(templateImageName: "organization") + )) } return items } } + diff --git a/Classes/View Controllers/TabBarController.swift b/Classes/View Controllers/TabBarController.swift deleted file mode 100644 index 451a21e2d..000000000 --- a/Classes/View Controllers/TabBarController.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// TabBarController.swift -// Freetime -// -// Created by Rizwan on 26/02/18. -// Copyright © 2018 Ryan Nystrom. All rights reserved. -// - -import Foundation - -final class TabBarController: UITabBarController { - enum Tab: Int { - case inbox = 0 - case search = 1 - case bookmarks = 2 - case settings = 3 - } - - func showTab(_ tab: Tab) { - selectedIndex = tab.rawValue - } -} diff --git a/Classes/View Controllers/UITabBarController+SelectType.swift b/Classes/View Controllers/UITabBarController+SelectType.swift new file mode 100644 index 000000000..2e197d638 --- /dev/null +++ b/Classes/View Controllers/UITabBarController+SelectType.swift @@ -0,0 +1,34 @@ +// +// UITabBarController+SelectType.swift +// Freetime +// +// Created by Ryan Nystrom on 10/7/18. +// Copyright © 2018 Ryan Nystrom. All rights reserved. +// + +import UIKit + +extension UITabBarController { + + @discardableResult + func selectTab(of type: T.Type) -> T? { + for viewController in viewControllers ?? [] { + let checkController: T? + let selectController: UIViewController + if let navigationController = viewController as? UINavigationController, + let topController = navigationController.topViewController { + checkController = topController as? T + selectController = navigationController + } else { + checkController = viewController as? T + selectController = viewController + } + if checkController != nil { + selectedViewController = selectController + return checkController + } + } + return nil + } + +} diff --git a/Freetime.xcodeproj/project.pbxproj b/Freetime.xcodeproj/project.pbxproj index 2bd2244c0..4210f975a 100644 --- a/Freetime.xcodeproj/project.pbxproj +++ b/Freetime.xcodeproj/project.pbxproj @@ -25,6 +25,13 @@ 290CA7642169799600DE04F8 /* AppController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA7632169799600DE04F8 /* AppController.swift */; }; 290CA76621697A7900DE04F8 /* AppSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA76521697A7900DE04F8 /* AppSplitViewController.swift */; }; 290CA768216984F000DE04F8 /* Client+GithubUserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA767216984F000DE04F8 /* Client+GithubUserSession.swift */; }; + 290CA76A216AC82700DE04F8 /* SearchShortcutRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA769216AC82700DE04F8 /* SearchShortcutRoute.swift */; }; + 290CA76E216AE8FA00DE04F8 /* Routable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA76D216AE8FA00DE04F8 /* Routable.swift */; }; + 290CA770216AE91300DE04F8 /* UITabBarController+SelectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA76F216AE91300DE04F8 /* UITabBarController+SelectType.swift */; }; + 290CA772216AE93E00DE04F8 /* SwitchAccountShortcutRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA771216AE93E00DE04F8 /* SwitchAccountShortcutRoute.swift */; }; + 290CA774216AE94D00DE04F8 /* BookmarkShortcutRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA773216AE94D00DE04F8 /* BookmarkShortcutRoute.swift */; }; + 290CA778216AFAE600DE04F8 /* RoutePerformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA777216AFAE600DE04F8 /* RoutePerformable.swift */; }; + 290CA77A216AFC1300DE04F8 /* AppController+SetupRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290CA779216AFC1300DE04F8 /* AppController+SetupRoutes.swift */; }; 290D2A3D1F044CB20082E6CC /* UIViewController+SmartDeselection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290D2A3C1F044CB20082E6CC /* UIViewController+SmartDeselection.swift */; }; 290D2A421F04D3470082E6CC /* IssueStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290D2A411F04D3470082E6CC /* IssueStatus.swift */; }; 290EF56A1F06A821006A2160 /* Notification+NotificationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290EF5691F06A7E1006A2160 /* Notification+NotificationViewModel.swift */; }; @@ -401,8 +408,6 @@ 49FFF4341F9FC83200335568 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FFF4331F9FC83200335568 /* HapticFeedback.swift */; }; 54AD5E8E1F24D953004A4BD6 /* FeedSelectionProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AD5E8D1F24D953004A4BD6 /* FeedSelectionProviding.swift */; }; 5DB4DD471FC5C10000DF7ABF /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB4DD461FC5C10000DF7ABF /* Accessibility.swift */; }; - 65A315292044369D0074E3B6 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A315282044369D0074E3B6 /* TabBarController.swift */; }; - 65A3152B2044376D0074E3B6 /* Route.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A3152A2044376D0074E3B6 /* Route.swift */; }; 7509865A2048959D00D1E37A /* RepositoryWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750986592048959D00D1E37A /* RepositoryWebViewController.swift */; }; 754488B11F7ADF8D0032D08C /* UIAlertController+Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754488B01F7ADF8D0032D08C /* UIAlertController+Action.swift */; }; 75468F7A1F7AFBC800F2BC19 /* AlertActionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75468F791F7AFBC800F2BC19 /* AlertActionBuilder.swift */; }; @@ -548,6 +553,13 @@ 290CA7632169799600DE04F8 /* AppController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppController.swift; sourceTree = ""; }; 290CA76521697A7900DE04F8 /* AppSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSplitViewController.swift; sourceTree = ""; }; 290CA767216984F000DE04F8 /* Client+GithubUserSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+GithubUserSession.swift"; sourceTree = ""; }; + 290CA769216AC82700DE04F8 /* SearchShortcutRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchShortcutRoute.swift; sourceTree = ""; }; + 290CA76D216AE8FA00DE04F8 /* Routable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Routable.swift; sourceTree = ""; }; + 290CA76F216AE91300DE04F8 /* UITabBarController+SelectType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITabBarController+SelectType.swift"; sourceTree = ""; }; + 290CA771216AE93E00DE04F8 /* SwitchAccountShortcutRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchAccountShortcutRoute.swift; sourceTree = ""; }; + 290CA773216AE94D00DE04F8 /* BookmarkShortcutRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkShortcutRoute.swift; sourceTree = ""; }; + 290CA777216AFAE600DE04F8 /* RoutePerformable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutePerformable.swift; sourceTree = ""; }; + 290CA779216AFC1300DE04F8 /* AppController+SetupRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppController+SetupRoutes.swift"; sourceTree = ""; }; 290D2A3C1F044CB20082E6CC /* UIViewController+SmartDeselection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+SmartDeselection.swift"; sourceTree = ""; }; 290D2A411F04D3470082E6CC /* IssueStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueStatus.swift; sourceTree = ""; }; 290EF5691F06A7E1006A2160 /* Notification+NotificationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+NotificationViewModel.swift"; sourceTree = ""; }; @@ -939,8 +951,6 @@ 54AD5E8D1F24D953004A4BD6 /* FeedSelectionProviding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedSelectionProviding.swift; sourceTree = ""; }; 5DB4DD461FC5C10000DF7ABF /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = ""; }; 63A98647141C04CBCFCA7923 /* Pods-Freetime.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Freetime.release.xcconfig"; path = "Pods/Target Support Files/Pods-Freetime/Pods-Freetime.release.xcconfig"; sourceTree = ""; }; - 65A315282044369D0074E3B6 /* TabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; }; - 65A3152A2044376D0074E3B6 /* Route.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Route.swift; sourceTree = ""; }; 750986592048959D00D1E37A /* RepositoryWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepositoryWebViewController.swift; sourceTree = ""; }; 754488B01F7ADF8D0032D08C /* UIAlertController+Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Action.swift"; sourceTree = ""; }; 75468F791F7AFBC800F2BC19 /* AlertActionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertActionBuilder.swift; sourceTree = ""; }; @@ -1087,6 +1097,12 @@ children = ( 290CA7632169799600DE04F8 /* AppController.swift */, 290CA76521697A7900DE04F8 /* AppSplitViewController.swift */, + 290CA773216AE94D00DE04F8 /* BookmarkShortcutRoute.swift */, + 290CA76D216AE8FA00DE04F8 /* Routable.swift */, + 290CA779216AFC1300DE04F8 /* AppController+SetupRoutes.swift */, + 290CA777216AFAE600DE04F8 /* RoutePerformable.swift */, + 290CA769216AC82700DE04F8 /* SearchShortcutRoute.swift */, + 290CA771216AE93E00DE04F8 /* SwitchAccountShortcutRoute.swift */, ); path = AppRouter; sourceTree = ""; @@ -1678,7 +1694,6 @@ 292CD3D31F0DC12100D3D57B /* PhotoViewHandler.swift */, 2980033A1F51E82400BE90F4 /* Rating */, 293189271F5391F700EF0911 /* Result.swift */, - 65A3152A2044376D0074E3B6 /* Route.swift */, 294A3D751FB29843000E81A4 /* ScrollViewKeyboardAdjuster.swift */, 9870B9021FC73EE70009719C /* Secrets.swift */, 3E79A2FE1F8A7DA700E1126B /* ShortcutHandler.swift */, @@ -1703,7 +1718,6 @@ 29316DBE1ECC95DB007CAE3F /* RootViewControllers.swift */, 29C33FDA1F127DBB00EC8D40 /* SplitPlaceholderViewController.swift */, 29AC90E41F00A7C8000B80E4 /* SplitViewControllerDelegate.swift */, - 65A315282044369D0074E3B6 /* TabBarController.swift */, 294B111F1F7B07DD00E04F2D /* TabBarControllerDelegate.swift */, 294B111D1F7B07BB00E04F2D /* TabNavRootViewControllerType.swift */, 29D548CA1FA27FE900F8E46F /* UINavigationItem+TitleSubtitle.swift */, @@ -1721,6 +1735,7 @@ 290D2A3C1F044CB20082E6CC /* UIViewController+SmartDeselection.swift */, 299F63E3205E1CAB0015D901 /* UIViewController+StyledTextViewCellDelegate.swift */, 4920F1A71F72E27200131E9D /* UIViewController+UserActivity.swift */, + 290CA76F216AE91300DE04F8 /* UITabBarController+SelectType.swift */, ); path = "View Controllers"; sourceTree = ""; @@ -2759,6 +2774,7 @@ 29F3A18620CBF99E00645CB7 /* NotificationModelController.swift in Sources */, 29EB1EEF1F425E5100A200B4 /* ForegroundHandler.swift in Sources */, 29C167741ECA0DBB00439D62 /* GithubAPIDateFormatter.swift in Sources */, + 290CA770216AE91300DE04F8 /* UITabBarController+SelectType.swift in Sources */, 294434E11FB1F2DA00050C06 /* BookmarkNavigationController.swift in Sources */, 29BCA7FE212137E100753A3C /* IssueTargetBranchModel.swift in Sources */, 29EE44461F19D5C100B05ED3 /* GithubClient+Issues.swift in Sources */, @@ -2875,6 +2891,7 @@ DCA5ED141FAEE8030072F074 /* Bookmark.swift in Sources */, 299F4A89204CEDDC004BA4F0 /* Client+AccessToken.swift in Sources */, 2931892F1F539C0E00EF0911 /* IssueMilestoneSectionController.swift in Sources */, + 290CA77A216AFC1300DE04F8 /* AppController+SetupRoutes.swift in Sources */, 29BBD82920CAC7D5004D62FE /* NotificationViewModel.swift in Sources */, 299F63E2205DE1470015D901 /* UIView+DateDetails.swift in Sources */, 9870B9031FC73EE70009719C /* Secrets.swift in Sources */, @@ -2903,6 +2920,7 @@ 2928C78C1F15D80E0000D06D /* IssueRenamedSectionController.swift in Sources */, 2928C78E1F15DF1B0000D06D /* IssueRenamedString.swift in Sources */, 297A372E1F17018F0081C04E /* IssueRequestCell.swift in Sources */, + 290CA774216AE94D00DE04F8 /* BookmarkShortcutRoute.swift in Sources */, 297A372C1F1700BC0081C04E /* IssueRequestModel.swift in Sources */, 297A37301F1704C10081C04E /* IssueRequestSectionController.swift in Sources */, 29F7F05C1F2A751B00F6075D /* IssueResult.swift in Sources */, @@ -2923,7 +2941,6 @@ DCA5ED101FAEDF290072F074 /* BookmarkStore.swift in Sources */, 295C31CD1F0AA55400521CED /* IssueStatusEvent.swift in Sources */, 295840671EE89FE4007723C6 /* IssueStatusEventCell.swift in Sources */, - 65A315292044369D0074E3B6 /* TabBarController.swift in Sources */, 295840651EE89F28007723C6 /* IssueStatusEventModel.swift in Sources */, 295840691EE8A328007723C6 /* IssueStatusEventSectionController.swift in Sources */, 29F3A18C20CD790F00645CB7 /* UIViewController+CommonActionItems.swift in Sources */, @@ -2967,6 +2984,7 @@ 29D548CB1FA27FE900F8E46F /* UINavigationItem+TitleSubtitle.swift in Sources */, 299A04A11FAE86B0003C2450 /* IssueReviewViewCommentsCell.swift in Sources */, 7BF2239D1F91056C006CC9A2 /* File+Filename.swift in Sources */, + 290CA76E216AE8FA00DE04F8 /* Routable.swift in Sources */, 2924C18120D5B29800FCFCFF /* MilestonesViewController.swift in Sources */, 29A1950A1EC78B4800C3E289 /* NotificationType+Icon.swift in Sources */, 29A1950C1EC7901400C3E289 /* NotificationType.swift in Sources */, @@ -3018,10 +3036,13 @@ 2905AFAF1F7357FA0015AE32 /* RepositoryViewController.swift in Sources */, 2963A9341EE2118E0066509C /* ResponderButton.swift in Sources */, BDB6AA69215FBC35009BB73C /* RepositoryBranchesViewController.swift in Sources */, + 290CA772216AE93E00DE04F8 /* SwitchAccountShortcutRoute.swift in Sources */, 293189281F5391F700EF0911 /* Result.swift in Sources */, + 290CA778216AFAE600DE04F8 /* RoutePerformable.swift in Sources */, 295B51421FC26B8100C3993B /* PeopleCell.swift in Sources */, 29316DBF1ECC95DB007CAE3F /* RootViewControllers.swift in Sources */, 29DA1E791F5DEE8F0050C64B /* SearchLoadingView.swift in Sources */, + 290CA76A216AC82700DE04F8 /* SearchShortcutRoute.swift in Sources */, 986B872D1F2C846700AAB55C /* SearchNoResultsCell.swift in Sources */, DC60C6DC1F99414E00241271 /* IsCancellationError.swift in Sources */, 29CC29311FF421DC006B6DE7 /* PullRequestReviewCommentsViewController.swift in Sources */, @@ -3087,7 +3108,6 @@ 2924C18320D5B2BF00FCFCFF /* MilestoneCell.swift in Sources */, 29C8F9AB208BF64D0075931C /* BaseListViewController2.swift in Sources */, 29AC90E51F00A7C8000B80E4 /* SplitViewControllerDelegate.swift in Sources */, - 65A3152B2044376D0074E3B6 /* Route.swift in Sources */, 2977788A20B306F200F2AFC2 /* LabelLayoutManager.swift in Sources */, 29DB264A1FCA10A800C3D0C9 /* GithubHighlighting.swift in Sources */, 2950AB1D2083B1E400C6F19A /* EmptyLoadingView.swift in Sources */, diff --git a/Resources/Base.lproj/Main.storyboard b/Resources/Base.lproj/Main.storyboard index bd7706501..4bcc5779f 100644 --- a/Resources/Base.lproj/Main.storyboard +++ b/Resources/Base.lproj/Main.storyboard @@ -12,7 +12,6 @@ - @@ -27,6 +26,7 @@ + @@ -109,7 +109,7 @@ - +