Laying out my vision for a more unified architecture for app navigation and view-controller isolation.
Routables. e.g. within a view controller:func onTap() {
let route = RepoRoute(owner: "GitHawkApp", name: "GitHawk")
self.router.handle(route)
}
Router to all view controllersRoutePerformable extensions atmRouter does the attaching when VCs tell it to handle a routenavigationController.pushViewController(...) or showDetailViewController(...)Router communicates RoutePerformables to its delegate (AppController) which can then inject shared app state & objects into view controllersClient renamed to NetworkClientGitHubClient renamed to AppSessionNetworkClientMilestoneViewController would take:protocol MilestoneViewControllerNetworkClient {
fetch(owner: String, repo: String, completion: @escaping (Result<Something>) -> Void)
}
The router + client protocol design enables us to _use and test_ the VC in isolation by removing dependencies that need to be daisy-chained to other VCs.
XCUITests on individual view controller's w/ _individually_ stubbed client protocolsviewController?.view.endEditing(false) to resign keyboardHopefully this makes sense. It will take some grinding to get there, but I think we'll have a really solid app architecture design in the end.
Related: there's been a lot of chatter of making other "hawk-like" apps. It would be really cool to create all of this shared app architecture and infra can be shared (maybe even a template base app) to create more apps.
@heshamsalman this plan likely conflicts w/ #2368

More hawks in the store! Sounds exciting.
Sent with GitHawk
This would solve my block in #2247. That would be an easy, low-stakes issue to test this out on - intercept a regex pattern with owner/repo info and route to the Repo in-app.
Router from NSObjectHistory/UIViewController+HistoryAction.swift:
self?.navigationController?.pushViewController(
Issues/Review/IssueReviewSectionController.swift:
viewController?.navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
Notifications/NotificationsViewController.swift:
navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
Notifications/NotificationsViewController.swift:
navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
Repository/RepositoryCodeDirectoryViewController.swift:
navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
Repository/RepositoryCodeDirectoryViewController.swift:
navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
Repository/RepositorySummarySectionController.swift:
self.viewController?.navigationController?.pushViewController(
Systems/AppRouter/Router.swift:
from.navigationController?.pushViewController(
View Controllers/UIViewController+PresentLabels.swift:
navigationController?.pushViewController(
Views/IssueTextActionsView+Markdown.swift:
viewController?.navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
Views/TextActionsController.swift:
picker.pushViewController(uploadController, animated: trueUnlessReduceMotionEnabled)
Issues/Files/IssueFilesSectionController.swift:
self?.viewController?.show(controller, sender: nil)
Issues/Files/IssueViewFilesSectionController.swift:
viewController?.show(controller, sender: nil)
Issues/Referenced/IssueReferencedSectionController.swift:
viewController?.show(controller, sender: nil)
Issues/Review/IssueReviewSectionController.swift:
viewController?.show(IssuesViewController(client: client, model: issue), sender: nil)
Repository/RepositoryViewController.swift:
show(issuesViewController, sender: self)
View Controllers/SplitViewControllerDelegate.swift:
tab.selectedViewController?.show(first, sender: sender)
View Controllers/SplitViewControllerDelegate.swift:
tab.selectedViewController?.show(vc, sender: sender)
Bookmark/BookmarkViewController.swift:
showDetailViewController(navigation, sender: nil)
Issues/IssuesViewController.swift:
showDetailViewController(controller, sender: nil)
Notifications/NotificationSectionController.swift:
viewController?.showDetailViewController(navigation, sender: nil)
Search/SearchResultSectionController.swift:
viewController?.showDetailViewController(navigation, sender: nil)
Search/SearchViewController.swift:
showDetailViewController(navigation, sender: nil)
Settings/SettingsViewController.swift:
self.navigationController?.showDetailViewController(navigationController, sender: self)
Settings/SettingsViewController.swift:
showDetailViewController(navController, sender: self)
Settings/SettingsViewController.swift:
showDetailViewController(navController, sender: self)
Settings/SettingsViewController.swift:
showDetailViewController(navigation, sender: nil)
Systems/AppRouter/IssueRoute+RoutePerformable.swift:
splitViewController.showDetailViewController(controller, sender: nil)
Systems/AppRouter/RepoRoute+RoutePerformable.swift:
splitViewController.showDetailViewController(controller, sender: nil)
Bookmark/BookmarkViewController.swift:
present(alert, animated: true)
Image Upload/ImageUploadTableViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Image Upload/ImageUploadTableViewController.swift:
present(previewViewController, animated: trueUnlessReduceMotionEnabled)
Issues/Comments/IssueCommentSectionController.swift:
self?.viewController?.present(alert, animated: trueUnlessReduceMotionEnabled)
Issues/Comments/IssueCommentSectionController.swift:
self?.viewController?.present(nav, animated: trueUnlessReduceMotionEnabled)
Issues/Comments/IssueCommentSectionController.swift:
self?.viewController?.present(
Issues/Comments/IssueCommentSectionController.swift:
viewController?.present(alert, animated: trueUnlessReduceMotionEnabled)
Issues/EditComment/EditCommentViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Issues/IssuesViewController.swift:
present(activityController, animated: trueUnlessReduceMotionEnabled)
Issues/IssuesViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Issues/Managing/IssueManagingSectionController.swift: func present(controller: UIViewController, from cell: UICollectionViewCell) {
Issues/Managing/IssueManagingSectionController.swift:
present(controller: newLabelsController(), from: cell)
Issues/Managing/IssueManagingSectionController.swift:
present(controller: controller, from: cell)
Issues/Managing/IssueManagingSectionController.swift:
present(controller: controller, from: cell)
Issues/Managing/IssueManagingSectionController.swift:
present(controller: controller, from: cell)
Issues/Merge/IssueMergeSectionController.swift:
viewController?.present(alert, animated: trueUnlessReduceMotionEnabled)
Issues/Merge/IssueMergeSectionController.swift:
viewController?.present(alert, animated: trueUnlessReduceMotionEnabled)
Login/LoginSplashViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Login/LoginSplashViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Notifications/NotificationSectionController.swift:
viewController?.present(alert, animated: trueUnlessReduceMotionEnabled)
Notifications/NotificationsViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Notifications/NotificationsViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Repository/RepositoryCodeBlobViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Repository/RepositoryCodeDirectoryViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Repository/RepositoryViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Repository/RepositoryViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Search/SearchViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Settings/SettingsAccountsViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Settings/SettingsAccountsViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Settings/SettingsViewController.swift:
present(navController, animated: trueUnlessReduceMotionEnabled)
Settings/SettingsViewController.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
Systems/AppRouter/AppController.swift:
self.splitViewController.present(controller, animated: animated)
Systems/AppRouter/AppController.swift:
present()
Systems/PhotoViewHandler.swift:
viewController?.present(photosViewController, animated: trueUnlessReduceMotionEnabled)
Systems/PhotoViewHandler.swift:
self?.viewController?.present(photosViewController, animated: trueUnlessReduceMotionEnabled)
Utility/AlertAction.swift:
self.rootViewController?.present(activityController, animated: trueUnlessReduceMotionEnabled)
Utility/AlertAction.swift:
self.rootViewController?.present(nav, animated: trueUnlessReduceMotionEnabled)
View Controllers/UIViewController+Alerts.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
View Controllers/UIViewController+CancelAction.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
View Controllers/UIViewController+FilePathTitle.swift:
present(alert, animated: trueUnlessReduceMotionEnabled)
View Controllers/UIViewController+Safari.swift: present(safariViewController, animated: trueUnlessReduceMotionEnabled)
View Controllers/UIViewController+Safari.swift:
present(controller, animated: trueUnlessReduceMotionEnabled)
Views/MarkdownStyledTextView.swift:
.present(activityController, animated: trueUnlessReduceMotionEnabled)
Views/TextActionsController.swift:
viewController?.present(imagePicker, animated: trueUnlessReduceMotionEnabled)
Next up is building routes for all navigation! Exciting b/c this will start to remove all VC dependencies and get us a step towards launching/testing VCs in isolation. Onward!
Most helpful comment
Next up is building routes for all navigation! Exciting b/c this will start to remove all VC dependencies and get us a step towards launching/testing VCs in isolation. Onward!