import UIKit @MainActor final class AppContext { let core = GotchaCore() private let window: UIWindow private(set) var tabs = UITabBarController() private(set) var navigationControllers: [UINavigationController] = [] init(window: UIWindow) { self.window = window applyAppearance() } func makeRootController() -> UIViewController { let roots: [UIViewController] = [ HomeViewController(context: self), repositoryRoot(mode: .issues), repositoryRoot(mode: .commits), PullsViewController(context: self), repositoryRoot(mode: .milestones), ] let items = [ ("Home", "house", "house.fill"), ("Issues", "exclamationmark.circle", "exclamationmark.circle.fill"), ("Repos", "books.vertical", "books.vertical.fill"), ("PRs", "arrow.triangle.pull", "arrow.triangle.pull"), ("Milestones", "flag", "flag.fill"), ] navigationControllers = zip(roots, items).map { root, item in let navigation = UINavigationController(rootViewController: root) navigation.tabBarItem = UITabBarItem( title: item.0, image: UIImage(systemName: item.1), selectedImage: UIImage(systemName: item.2) ) return navigation } tabs.viewControllers = navigationControllers return tabs } func showStartupErrorIfNeeded() { guard let message = core.startupError() else { return } tabs.present(errorAlert(message), animated: true) } func selectServer(index: UInt32) throws { try core.selectServer(index: index) let replacements: [(Int, UIViewController)] = [ (0, HomeViewController(context: self)), (1, RepositoriesViewController(context: self, mode: .issues)), (2, RepositoriesViewController(context: self, mode: .commits)), (3, PullsViewController(context: self)), (4, RepositoriesViewController(context: self, mode: .milestones)), ] for (index, root) in replacements { navigationControllers[index].setViewControllers([root], animated: false) } } func didAddServer(index: UInt32) throws { try selectServer(index: index) } func applyAppearance() { switch core.settings().appearance { case 1: window.overrideUserInterfaceStyle = .light case 2: window.overrideUserInterfaceStyle = .dark default: window.overrideUserInterfaceStyle = .unspecified } } func route(_ activity: ActivityRow) { switch activity.target { case "repository": tabs.selectedIndex = 1 navigationControllers[1].pushViewController( IssuesViewController( context: self, owner: activity.owner, repository: activity.repository ), animated: true ) case "issue": tabs.selectedIndex = 1 navigationControllers[1].pushViewController( IssueViewController( context: self, owner: activity.owner, repository: activity.repository, number: activity.number ), animated: true ) case "pull": tabs.selectedIndex = 3 navigationControllers[3].pushViewController( PullViewController( context: self, owner: activity.owner, repository: activity.repository, number: activity.number ), animated: true ) case "commit": tabs.selectedIndex = 2 navigationControllers[2].pushViewController( FilesViewController( context: self, owner: activity.owner, repository: activity.repository, sha: activity.sha ), animated: true ) default: break } } func symbol(_ name: String) -> UIImage? { UIImage(systemName: name) } private func repositoryRoot(mode: RepositoryMode) -> UIViewController { if core.activeServerIndex() == nil { return ServersViewController(context: self, destination: mode) } return RepositoriesViewController(context: self, mode: mode) } }