Move more navigation responsibilities into the AppCoordinator
This commit is contained in:
parent
19f8f8bc97
commit
15754684a4
|
@ -23,7 +23,12 @@ public extension Notification.Name {
|
|||
|
||||
class AppCoordinator {
|
||||
|
||||
static let fetchAndMergeArticlesQueue = CoalescingQueue(name: "Fetch and Merge Articles", interval: 0.5)
|
||||
private var rootSplitViewController: UISplitViewController!
|
||||
private var masterNavigationController: UINavigationController!
|
||||
private var masterFeedViewController: MasterFeedViewController!
|
||||
private var masterTimelineViewController: MasterTimelineViewController?
|
||||
|
||||
private let fetchAndMergeArticlesQueue = CoalescingQueue(name: "Fetch and Merge Articles", interval: 0.5)
|
||||
|
||||
private var articleRowMap = [String: Int]() // articleID: rowIndex
|
||||
|
||||
|
@ -185,6 +190,21 @@ class AppCoordinator {
|
|||
|
||||
}
|
||||
|
||||
func start() -> UIViewController {
|
||||
rootSplitViewController = (UIStoryboard.main.instantiateInitialViewController() as! UISplitViewController)
|
||||
rootSplitViewController.delegate = self
|
||||
|
||||
masterNavigationController = (rootSplitViewController.viewControllers.first as! UINavigationController)
|
||||
masterFeedViewController = UIStoryboard.main.instantiateController(ofType: MasterFeedViewController.self)
|
||||
masterFeedViewController.coordinator = self
|
||||
masterNavigationController.pushViewController(masterFeedViewController, animated: false)
|
||||
|
||||
// let detailNavigationController = (rootSplitViewController.viewControllers.last as! UINavigationController)
|
||||
// detailNavigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
|
||||
|
||||
return rootSplitViewController
|
||||
}
|
||||
|
||||
// MARK: Notifications
|
||||
|
||||
@objc func containerChildrenDidChange(_ note: Notification) {
|
||||
|
@ -226,6 +246,24 @@ class AppCoordinator {
|
|||
|
||||
// MARK: API
|
||||
|
||||
func didSelectFeed(_ indexPath: IndexPath) {
|
||||
masterTimelineViewController = UIStoryboard.main.instantiateController(ofType: MasterTimelineViewController.self)
|
||||
masterTimelineViewController!.coordinator = self
|
||||
currentMasterIndexPath = indexPath
|
||||
masterNavigationController.pushViewController(masterTimelineViewController!, animated: true)
|
||||
}
|
||||
|
||||
func didSelectArticle(_ indexPath: IndexPath) {
|
||||
let detailViewController = UIStoryboard.main.instantiateController(ofType: DetailViewController.self)
|
||||
detailViewController.coordinator = self
|
||||
detailViewController.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
|
||||
detailViewController.navigationItem.leftItemsSupplementBackButton = true
|
||||
currentArticleIndexPath = indexPath
|
||||
// rootSplitViewController.toggleMasterView()
|
||||
rootSplitViewController.showDetailViewController(detailViewController, sender: self)
|
||||
|
||||
}
|
||||
|
||||
func beginUpdates() {
|
||||
animatingChanges = true
|
||||
}
|
||||
|
@ -608,7 +646,7 @@ private extension AppCoordinator {
|
|||
}
|
||||
|
||||
func queueFetchAndMergeArticles() {
|
||||
AppCoordinator.fetchAndMergeArticlesQueue.add(self, #selector(fetchAndMergeArticles))
|
||||
fetchAndMergeArticlesQueue.add(self, #selector(fetchAndMergeArticles))
|
||||
}
|
||||
|
||||
@objc func fetchAndMergeArticles() {
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
<rect key="frame" x="0.0" y="813" width="414" height="49"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</toolbar>
|
||||
<connections>
|
||||
<segue destination="7bK-jq-Zjz" kind="relationship" relationship="rootViewController" id="tsl-Nk-0bq"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="8fS-aE-onr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
@ -36,7 +33,7 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<wkWebView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="t8d-md-Yhc">
|
||||
<rect key="frame" x="0.0" y="88" width="414" height="725"/>
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="769"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<wkWebViewConfiguration key="configuration">
|
||||
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
|
||||
|
@ -155,9 +152,6 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="414" height="208"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showDetail" id="RT3-gH-cyN"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
|
@ -206,7 +200,7 @@
|
|||
<!--Feeds-->
|
||||
<scene sceneID="smW-Zh-WAh">
|
||||
<objects>
|
||||
<tableViewController storyboardIdentifier="MasterViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="MasterFeedViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableViewController storyboardIdentifier="MasterFeedViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="MasterFeedViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="r7i-6Z-zg0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
@ -263,12 +257,8 @@
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Skn-vK-czG">
|
||||
<rect key="frame" x="0.0" y="813" width="414" height="49"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</toolbar>
|
||||
<connections>
|
||||
<segue destination="JEX-9P-axG" kind="relationship" relationship="rootViewController" id="GKi-kA-LjT"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="SLD-UC-DBI" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
@ -284,7 +274,4 @@
|
|||
<image name="square.and.arrow.up" catalog="system" width="56" height="64"/>
|
||||
<image name="star" catalog="system" width="64" height="58"/>
|
||||
</resources>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="RT3-gH-cyN"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
|
|
|
@ -23,7 +23,7 @@ class DetailViewController: UIViewController {
|
|||
@IBOutlet weak var browserBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var webView: WKWebView!
|
||||
|
||||
weak var coordinator: AppCoordinator?
|
||||
weak var coordinator: AppCoordinator!
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
|
@ -47,14 +47,14 @@ class DetailViewController: UIViewController {
|
|||
}
|
||||
|
||||
func markAsRead() {
|
||||
if let article = coordinator?.currentArticle {
|
||||
if let article = coordinator.currentArticle {
|
||||
markArticles(Set([article]), statusKey: .read, flag: true)
|
||||
}
|
||||
}
|
||||
|
||||
func updateUI() {
|
||||
|
||||
guard let article = coordinator?.currentArticle else {
|
||||
guard let article = coordinator.currentArticle else {
|
||||
nextUnreadBarButtonItem.isEnabled = false
|
||||
prevArticleBarButtonItem.isEnabled = false
|
||||
nextArticleBarButtonItem.isEnabled = false
|
||||
|
@ -65,9 +65,9 @@ class DetailViewController: UIViewController {
|
|||
return
|
||||
}
|
||||
|
||||
nextUnreadBarButtonItem.isEnabled = coordinator?.isAnyUnreadAvailable ?? false
|
||||
prevArticleBarButtonItem.isEnabled = coordinator?.isPrevArticleAvailable ?? false
|
||||
nextArticleBarButtonItem.isEnabled = coordinator?.isNextArticleAvailable ?? false
|
||||
nextUnreadBarButtonItem.isEnabled = coordinator.isAnyUnreadAvailable
|
||||
prevArticleBarButtonItem.isEnabled = coordinator.isPrevArticleAvailable
|
||||
nextArticleBarButtonItem.isEnabled = coordinator.isNextArticleAvailable
|
||||
|
||||
readBarButtonItem.isEnabled = true
|
||||
starBarButtonItem.isEnabled = true
|
||||
|
@ -80,7 +80,7 @@ class DetailViewController: UIViewController {
|
|||
let starImage = article.status.starred ? AppAssets.starClosedImage : AppAssets.starOpenImage
|
||||
starBarButtonItem.image = starImage
|
||||
|
||||
if let timelineName = coordinator?.timelineName {
|
||||
if let timelineName = coordinator.timelineName {
|
||||
if navigationController?.navigationItem.backBarButtonItem?.title != timelineName {
|
||||
let backItem = UIBarButtonItem(title: timelineName, style: .plain, target: nil, action: nil)
|
||||
navigationController?.navigationItem.backBarButtonItem = backItem
|
||||
|
@ -91,7 +91,7 @@ class DetailViewController: UIViewController {
|
|||
|
||||
func reloadHTML() {
|
||||
|
||||
guard let article = coordinator?.currentArticle, let webView = webView else {
|
||||
guard let article = coordinator.currentArticle, let webView = webView else {
|
||||
return
|
||||
}
|
||||
let style = ArticleStylesManager.shared.currentStyle
|
||||
|
@ -110,7 +110,7 @@ class DetailViewController: UIViewController {
|
|||
guard let articles = note.userInfo?[Account.UserInfoKey.articles] as? Set<Article> else {
|
||||
return
|
||||
}
|
||||
if articles.count == 1 && articles.first?.articleID == coordinator?.currentArticle?.articleID {
|
||||
if articles.count == 1 && articles.first?.articleID == coordinator.currentArticle?.articleID {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
@ -132,41 +132,41 @@ class DetailViewController: UIViewController {
|
|||
// MARK: Actions
|
||||
|
||||
@IBAction func nextUnread(_ sender: Any) {
|
||||
coordinator?.selectNextUnread()
|
||||
coordinator.selectNextUnread()
|
||||
}
|
||||
|
||||
@IBAction func prevArticle(_ sender: Any) {
|
||||
coordinator?.currentArticleIndexPath = coordinator?.prevArticleIndexPath
|
||||
coordinator.currentArticleIndexPath = coordinator.prevArticleIndexPath
|
||||
}
|
||||
|
||||
@IBAction func nextArticle(_ sender: Any) {
|
||||
coordinator?.currentArticleIndexPath = coordinator?.nextArticleIndexPath
|
||||
coordinator.currentArticleIndexPath = coordinator.nextArticleIndexPath
|
||||
}
|
||||
|
||||
@IBAction func toggleRead(_ sender: Any) {
|
||||
if let article = coordinator?.currentArticle {
|
||||
if let article = coordinator.currentArticle {
|
||||
markArticles(Set([article]), statusKey: .read, flag: !article.status.read)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func toggleStar(_ sender: Any) {
|
||||
if let article = coordinator?.currentArticle {
|
||||
if let article = coordinator.currentArticle {
|
||||
markArticles(Set([article]), statusKey: .starred, flag: !article.status.starred)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func openBrowser(_ sender: Any) {
|
||||
guard let preferredLink = coordinator?.currentArticle?.preferredLink, let url = URL(string: preferredLink) else {
|
||||
guard let preferredLink = coordinator.currentArticle?.preferredLink, let url = URL(string: preferredLink) else {
|
||||
return
|
||||
}
|
||||
UIApplication.shared.open(url, options: [:])
|
||||
}
|
||||
|
||||
@IBAction func showActivityDialog(_ sender: Any) {
|
||||
guard let preferredLink = coordinator?.currentArticle?.preferredLink, let url = URL(string: preferredLink) else {
|
||||
guard let preferredLink = coordinator.currentArticle?.preferredLink, let url = URL(string: preferredLink) else {
|
||||
return
|
||||
}
|
||||
let itemSource = ArticleActivityItemSource(url: url, subject: coordinator?.currentArticle?.title)
|
||||
let itemSource = ArticleActivityItemSource(url: url, subject: coordinator.currentArticle?.title)
|
||||
let activityViewController = UIActivityViewController(activityItems: [itemSource], applicationActivities: nil)
|
||||
activityViewController.popoverPresentationController?.barButtonItem = self.actionBarButtonItem
|
||||
|
||||
|
|
|
@ -276,12 +276,7 @@ class MasterFeedViewController: ProgressTableViewController, UndoableCommandRunn
|
|||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
||||
let timeline = UIStoryboard.main.instantiateController(ofType: MasterTimelineViewController.self)
|
||||
timeline.coordinator = coordinator
|
||||
coordinator.currentMasterIndexPath = indexPath
|
||||
self.navigationController?.pushViewController(timeline, animated: true)
|
||||
|
||||
coordinator.didSelectFeed(indexPath)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
|
||||
|
|
|
@ -63,16 +63,6 @@ class MasterTimelineViewController: ProgressTableViewController, UndoableCommand
|
|||
resignFirstResponder()
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "showDetail" {
|
||||
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
|
||||
controller.coordinator = coordinator
|
||||
controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
|
||||
controller.navigationItem.leftItemsSupplementBackButton = true
|
||||
splitViewController?.toggleMasterView()
|
||||
}
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
|
@ -185,7 +175,7 @@ class MasterTimelineViewController: ProgressTableViewController, UndoableCommand
|
|||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
coordinator.currentArticleIndexPath = indexPath
|
||||
coordinator.didSelectArticle(indexPath)
|
||||
}
|
||||
|
||||
// MARK: Notifications
|
||||
|
|
|
@ -19,19 +19,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
|
||||
window!.tintColor = AppAssets.netNewsWireBlueColor
|
||||
window!.rootViewController = coordinator.start()
|
||||
|
||||
let splitViewController = UIStoryboard.main.instantiateInitialViewController() as! UISplitViewController
|
||||
splitViewController.delegate = coordinator
|
||||
window!.rootViewController = splitViewController
|
||||
|
||||
let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
|
||||
let masterFeedViewController = masterNavigationController.topViewController as! MasterFeedViewController
|
||||
masterFeedViewController.coordinator = coordinator
|
||||
|
||||
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
|
||||
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
|
||||
|
||||
|
||||
// if let userActivity = connectionOptions.userActivities.first ?? session.stateRestorationActivity {
|
||||
// if !configure(window: window, with: userActivity) {
|
||||
// print("Failed to restore from \(userActivity)")
|
||||
|
|
Loading…
Reference in New Issue