Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.

New routing library and refactor Shortcuts #2241

Merged
merged 1 commit into from
Oct 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Classes/Search/SearchViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ SearchResultSectionControllerDelegate {
}
}

func searchBarBecomeFirstResponder() {
searchBar.becomeFirstResponder()
}

// MARK: Data Loading/Paging

private func update(animated: Bool) {
Expand Down
7 changes: 2 additions & 5 deletions Classes/Systems/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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) {
Expand Down
19 changes: 19 additions & 0 deletions Classes/Systems/AppRouter/AppController+SetupRoutes.swift
Original file line number Diff line number Diff line change
@@ -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)
}

}
35 changes: 24 additions & 11 deletions Classes/Systems/AppRouter/AppController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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<T: Routable & RoutePerformable>(route: T.Type) {
routes[T.path] = T.self
}

private func resetWatchSync(userSession: GitHubUserSession) {
Expand Down
8 changes: 2 additions & 6 deletions Classes/Systems/AppRouter/AppSplitViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 28 additions & 0 deletions Classes/Systems/AppRouter/BookmarkShortcutRoute.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
19 changes: 19 additions & 0 deletions Classes/Systems/AppRouter/Routable.swift
Original file line number Diff line number Diff line change
@@ -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 [:] }
}
18 changes: 18 additions & 0 deletions Classes/Systems/AppRouter/RoutePerformable.swift
Original file line number Diff line number Diff line change
@@ -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
}
31 changes: 31 additions & 0 deletions Classes/Systems/AppRouter/SearchShortcutRoute.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
38 changes: 38 additions & 0 deletions Classes/Systems/AppRouter/SwitchAccountShortcutRoute.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
23 changes: 0 additions & 23 deletions Classes/Systems/Route.swift

This file was deleted.

77 changes: 46 additions & 31 deletions Classes/Systems/ShortcutHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: Routable>(
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
}

}

Loading