mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Change to new iOS 3 panel UISplitViewController
This commit is contained in:
@@ -271,7 +271,6 @@
|
||||
518C3193237B00D9004D740F /* DetailIconSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7552374A2890013FF27 /* DetailIconSchemeHandler.swift */; };
|
||||
518C3194237B00DA004D740F /* DetailIconSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7552374A2890013FF27 /* DetailIconSchemeHandler.swift */; };
|
||||
518ED21D23D0F26000E0A862 /* UIViewController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518ED21C23D0F26000E0A862 /* UIViewController-Extensions.swift */; };
|
||||
51934CCB230F599B006127BE /* InteractiveNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CC1230F5963006127BE /* InteractiveNavigationController.swift */; };
|
||||
51934CCE2310792F006127BE /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; };
|
||||
51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
||||
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
||||
@@ -1268,7 +1267,6 @@
|
||||
518B2ED22351B3DD00400001 /* NetNewsWire-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "NetNewsWire-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
518B2EE92351B4C200400001 /* NetNewsWire_iOSTests_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSTests_target.xcconfig; sourceTree = "<group>"; };
|
||||
518ED21C23D0F26000E0A862 /* UIViewController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController-Extensions.swift"; sourceTree = "<group>"; };
|
||||
51934CC1230F5963006127BE /* InteractiveNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveNavigationController.swift; sourceTree = "<group>"; };
|
||||
51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = "<group>"; };
|
||||
51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = "<group>"; };
|
||||
5193CD57245E44A90092735E /* RedditFeedProvider-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RedditFeedProvider-Extensions.swift"; sourceTree = "<group>"; };
|
||||
@@ -2027,7 +2025,6 @@
|
||||
51627A92238A3836007B3B4B /* CroppingPreviewParameters.swift */,
|
||||
512AF9C1236ED52C0066F8BE /* ImageHeaderView.swift */,
|
||||
512AF9DC236F05230066F8BE /* InteractiveLabel.swift */,
|
||||
51934CC1230F5963006127BE /* InteractiveNavigationController.swift */,
|
||||
51A9A5F42380F6A60033AADF /* ModalNavigationController.swift */,
|
||||
51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */,
|
||||
5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */,
|
||||
@@ -4201,7 +4198,6 @@
|
||||
51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */,
|
||||
51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */,
|
||||
51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */,
|
||||
51934CCB230F599B006127BE /* InteractiveNavigationController.swift in Sources */,
|
||||
769F2ED513DA03EE75B993A8 /* NewsBlurAccountViewController.swift in Sources */,
|
||||
51BC4B01247277E0000A6ED8 /* URL-Extensions.swift in Sources */,
|
||||
);
|
||||
|
||||
@@ -45,6 +45,8 @@ class ArticleViewController: UIViewController {
|
||||
|
||||
weak var coordinator: SceneCoordinator!
|
||||
|
||||
private let poppableDelegate = PoppableGestureRecognizerDelegate()
|
||||
|
||||
var article: Article? {
|
||||
didSet {
|
||||
if let controller = currentWebViewController, controller.article != article {
|
||||
@@ -101,6 +103,11 @@ class ArticleViewController: UIViewController {
|
||||
articleExtractorButton.addTarget(self, action: #selector(toggleArticleExtractor(_:)), for: .touchUpInside)
|
||||
toolbarItems?.insert(UIBarButtonItem(customView: articleExtractorButton), at: 6)
|
||||
|
||||
if let parentNavController = navigationController?.parent as? UINavigationController {
|
||||
poppableDelegate.navigationController = parentNavController
|
||||
parentNavController.interactivePopGestureRecognizer?.delegate = poppableDelegate
|
||||
}
|
||||
|
||||
pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
|
||||
pageViewController.delegate = self
|
||||
pageViewController.dataSource = self
|
||||
@@ -154,6 +161,11 @@ class ArticleViewController: UIViewController {
|
||||
|
||||
updateUI()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
navigationController?.isToolbarHidden = false
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(true)
|
||||
@@ -161,6 +173,7 @@ class ArticleViewController: UIViewController {
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
if searchBar != nil && !searchBar.isHidden {
|
||||
endFind()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="AJQ-jq-uMa">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
@@ -17,7 +17,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h1Q-FS-jlg" customClass="ArticleSearchBar" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<view hidden="YES" contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="h1Q-FS-jlg" customClass="ArticleSearchBar" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="782" width="414" height="31"/>
|
||||
<color key="backgroundColor" name="barBackgroundColor"/>
|
||||
</view>
|
||||
@@ -107,7 +107,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2318.840579710145" y="-759.375"/>
|
||||
<point key="canvasLocation" x="451" y="-431"/>
|
||||
</scene>
|
||||
<!--Timeline-->
|
||||
<scene sceneID="fag-XH-avP">
|
||||
@@ -153,7 +153,21 @@
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="nzm-Gf-Xce" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1620" y="-759"/>
|
||||
<point key="canvasLocation" x="451" y="-1124"/>
|
||||
</scene>
|
||||
<!--Root Split View Controller-->
|
||||
<scene sceneID="FfI-oe-67h">
|
||||
<objects>
|
||||
<splitViewController storyboardIdentifier="RootSplitViewController" allowDoubleColumnStyle="YES" id="AJQ-jq-uMa" customClass="RootSplitViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<connections>
|
||||
<segue destination="Kyk-vK-QRX" kind="relationship" relationship="supplementaryViewController" id="FW6-KM-3C4"/>
|
||||
<segue destination="JEX-9P-axG" kind="relationship" relationship="detailViewController" id="JbU-kn-u7r"/>
|
||||
<segue destination="7bK-jq-Zjz" kind="relationship" relationship="masterViewController" id="rFx-mT-r7a"/>
|
||||
</connections>
|
||||
</splitViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="9SW-km-PuE" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1320" y="-1123"/>
|
||||
</scene>
|
||||
<!--Feeds-->
|
||||
<scene sceneID="smW-Zh-WAh">
|
||||
@@ -216,7 +230,7 @@
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Rux-fX-hf1" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="900" y="-759"/>
|
||||
<point key="canvasLocation" x="452" y="-1794"/>
|
||||
</scene>
|
||||
<!--Image View Controller-->
|
||||
<scene sceneID="TT4-oA-DBw">
|
||||
|
||||
@@ -78,6 +78,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
navigationController?.isToolbarHidden = false
|
||||
updateUI()
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
@@ -109,10 +109,14 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
self.navigationController?.isToolbarHidden = false
|
||||
|
||||
// If the nav bar is hidden, fade it in to avoid it showing stuff as it is getting laid out
|
||||
if navigationController?.navigationBar.isHidden ?? false {
|
||||
navigationController?.navigationBar.alpha = 0
|
||||
}
|
||||
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
@@ -603,9 +607,8 @@ extension MasterTimelineViewController: UISearchBarDelegate {
|
||||
|
||||
private extension MasterTimelineViewController {
|
||||
|
||||
func configureToolbar() {
|
||||
|
||||
guard !coordinator.isThreePanelMode else {
|
||||
func configureToolbar() {
|
||||
guard !(splitViewController?.isCollapsed ?? true) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,6 @@ class RootSplitViewController: UISplitViewController {
|
||||
coordinator.resetFocus()
|
||||
}
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
self.coordinator.configurePanelMode(for: size)
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
}
|
||||
|
||||
// MARK: Keyboard Shortcuts
|
||||
|
||||
@objc func scrollOrGoToNextUnread(_ sender: Any?) {
|
||||
|
||||
@@ -14,12 +14,6 @@ import RSCore
|
||||
import RSTree
|
||||
import SafariServices
|
||||
|
||||
enum PanelMode {
|
||||
case unset
|
||||
case three
|
||||
case standard
|
||||
}
|
||||
|
||||
enum SearchScope: Int {
|
||||
case timeline = 0
|
||||
case global = 1
|
||||
@@ -54,33 +48,13 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
|
||||
lazy var webViewProvider = WebViewProvider(coordinator: self)
|
||||
|
||||
private var panelMode: PanelMode = .unset
|
||||
|
||||
private var activityManager = ActivityManager()
|
||||
|
||||
private var rootSplitViewController: RootSplitViewController!
|
||||
private var masterNavigationController: UINavigationController!
|
||||
|
||||
private var masterFeedViewController: MasterFeedViewController!
|
||||
private var masterTimelineViewController: MasterTimelineViewController?
|
||||
private var subSplitViewController: UISplitViewController?
|
||||
|
||||
private var articleViewController: ArticleViewController? {
|
||||
if let detail = masterNavigationController.viewControllers.last as? ArticleViewController {
|
||||
return detail
|
||||
}
|
||||
if let subSplit = subSplitViewController {
|
||||
if let navController = subSplit.viewControllers.last as? UINavigationController {
|
||||
return navController.topViewController as? ArticleViewController
|
||||
}
|
||||
} else {
|
||||
if let navController = rootSplitViewController.viewControllers.last as? UINavigationController {
|
||||
return navController.topViewController as? ArticleViewController
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private var wasRootSplitViewControllerCollapsed = false
|
||||
private var articleViewController: ArticleViewController?
|
||||
|
||||
private let fetchAndMergeArticlesQueue = CoalescingQueue(name: "Fetch and Merge Articles", interval: 0.5)
|
||||
private let rebuildBackingStoresQueue = CoalescingQueue(name: "Rebuild The Backing Stores", interval: 0.5)
|
||||
@@ -140,10 +114,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
return rootSplitViewController.isCollapsed
|
||||
}
|
||||
|
||||
var isThreePanelMode: Bool {
|
||||
return panelMode == .three
|
||||
}
|
||||
|
||||
var isReadFeedsFiltered: Bool {
|
||||
return treeControllerDelegate.isReadFiltered
|
||||
}
|
||||
@@ -294,11 +264,24 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
|
||||
var timelineUnreadCount: Int = 0
|
||||
|
||||
override init() {
|
||||
treeController = TreeController(delegate: treeControllerDelegate)
|
||||
init(rootSplitViewController: RootSplitViewController) {
|
||||
self.rootSplitViewController = rootSplitViewController
|
||||
self.treeController = TreeController(delegate: treeControllerDelegate)
|
||||
|
||||
super.init()
|
||||
|
||||
|
||||
self.masterFeedViewController = rootSplitViewController.viewController(for: .primary) as? MasterFeedViewController
|
||||
self.masterFeedViewController.coordinator = self
|
||||
self.masterFeedViewController?.navigationController?.delegate = self
|
||||
|
||||
self.masterTimelineViewController = rootSplitViewController.viewController(for: .supplementary) as? MasterTimelineViewController
|
||||
self.masterTimelineViewController?.coordinator = self
|
||||
self.masterTimelineViewController?.navigationController?.delegate = self
|
||||
|
||||
self.articleViewController = rootSplitViewController.viewController(for: .secondary) as? ArticleViewController
|
||||
self.articleViewController?.coordinator = self
|
||||
self.articleViewController?.navigationController?.delegate = self
|
||||
|
||||
for sectionNode in treeController.rootNode.childNodes {
|
||||
markExpanded(sectionNode)
|
||||
shadowTable.append((sectionID: "", feedNodes: [FeedNode]()))
|
||||
@@ -321,30 +304,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themeDownloadDidFail(_:)), name: .didFailToImportThemeWithError, object: nil)
|
||||
}
|
||||
|
||||
func start(for size: CGSize) -> UIViewController {
|
||||
rootSplitViewController = RootSplitViewController()
|
||||
rootSplitViewController.coordinator = self
|
||||
rootSplitViewController.preferredDisplayMode = .oneBesideSecondary
|
||||
rootSplitViewController.viewControllers = [InteractiveNavigationController.template()]
|
||||
rootSplitViewController.delegate = self
|
||||
|
||||
masterNavigationController = (rootSplitViewController.viewControllers.first as! UINavigationController)
|
||||
masterNavigationController.delegate = self
|
||||
|
||||
masterFeedViewController = UIStoryboard.main.instantiateController(ofType: MasterFeedViewController.self)
|
||||
masterFeedViewController.coordinator = self
|
||||
masterNavigationController.pushViewController(masterFeedViewController, animated: false)
|
||||
|
||||
let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
|
||||
articleViewController.coordinator = self
|
||||
let detailNavigationController = addNavControllerIfNecessary(articleViewController, showButton: true)
|
||||
rootSplitViewController.showDetailViewController(detailNavigationController, sender: self)
|
||||
|
||||
configurePanelMode(for: size)
|
||||
|
||||
return rootSplitViewController
|
||||
}
|
||||
|
||||
func restoreWindowState(_ activity: NSUserActivity?) {
|
||||
if let activity = activity, let windowState = activity.userInfo?[UserInfoKey.windowState] as? [AnyHashable: Any] {
|
||||
|
||||
@@ -399,26 +358,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
handleReadArticle(userInfo)
|
||||
}
|
||||
|
||||
func configurePanelMode(for size: CGSize) {
|
||||
guard rootSplitViewController.traitCollection.userInterfaceIdiom == .pad else {
|
||||
return
|
||||
}
|
||||
|
||||
if (size.width / size.height) > 1.2 {
|
||||
if panelMode == .unset || panelMode == .standard {
|
||||
panelMode = .three
|
||||
configureThreePanelMode()
|
||||
}
|
||||
} else {
|
||||
if panelMode == .unset || panelMode == .three {
|
||||
panelMode = .standard
|
||||
configureStandardPanelMode()
|
||||
}
|
||||
}
|
||||
|
||||
wasRootSplitViewControllerCollapsed = rootSplitViewController.isCollapsed
|
||||
}
|
||||
|
||||
func resetFocus() {
|
||||
if currentArticle != nil {
|
||||
masterTimelineViewController?.focus()
|
||||
@@ -438,7 +377,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
|
||||
func showSearch() {
|
||||
selectFeed(indexPath: nil) {
|
||||
self.installTimelineControllerIfNecessary(animated: false)
|
||||
self.rootSplitViewController.show(.supplementary)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()) {
|
||||
self.masterTimelineViewController!.showSearchAll()
|
||||
}
|
||||
@@ -793,7 +732,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
if let ip = indexPath, let node = nodeFor(ip), let feed = node.representedObject as? Feed {
|
||||
|
||||
self.activityManager.selecting(feed: feed)
|
||||
self.installTimelineControllerIfNecessary(animated: animations.contains(.navigation))
|
||||
self.rootSplitViewController.show(.supplementary)
|
||||
setTimelineFeed(feed, animated: false) {
|
||||
if self.isReadFeedsFiltered {
|
||||
self.rebuildBackingStores()
|
||||
@@ -808,9 +747,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
self.rebuildBackingStores()
|
||||
}
|
||||
self.activityManager.invalidateSelecting()
|
||||
if self.rootSplitViewController.isCollapsed && self.navControllerForTimeline().viewControllers.last is MasterTimelineViewController {
|
||||
self.navControllerForTimeline().popViewController(animated: animations.contains(.navigation))
|
||||
}
|
||||
self.rootSplitViewController.show(.primary)
|
||||
completion?()
|
||||
}
|
||||
|
||||
@@ -858,31 +795,20 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
activityManager.reading(feed: timelineFeed, article: article)
|
||||
|
||||
if article == nil {
|
||||
if rootSplitViewController.isCollapsed {
|
||||
if masterNavigationController.children.last is ArticleViewController {
|
||||
masterNavigationController.popViewController(animated: animations.contains(.navigation))
|
||||
}
|
||||
} else {
|
||||
articleViewController?.article = nil
|
||||
}
|
||||
rootSplitViewController.show(.supplementary)
|
||||
masterTimelineViewController?.updateArticleSelection(animations: animations)
|
||||
return
|
||||
}
|
||||
|
||||
let currentArticleViewController: ArticleViewController
|
||||
if articleViewController == nil {
|
||||
currentArticleViewController = installArticleController(animated: animations.contains(.navigation))
|
||||
} else {
|
||||
currentArticleViewController = articleViewController!
|
||||
}
|
||||
rootSplitViewController.show(.secondary)
|
||||
|
||||
// Mark article as read before navigating to it, so the read status does not flash unread/read on display
|
||||
markArticles(Set([article!]), statusKey: .read, flag: true)
|
||||
|
||||
masterTimelineViewController?.updateArticleSelection(animations: animations)
|
||||
currentArticleViewController.article = article
|
||||
articleViewController?.article = article
|
||||
if let isShowingExtractedArticle = isShowingExtractedArticle, let articleWindowScrollY = articleWindowScrollY {
|
||||
currentArticleViewController.restoreScrollPosition = (isShowingExtractedArticle, articleWindowScrollY)
|
||||
articleViewController?.restoreScrollPosition = (isShowingExtractedArticle, articleWindowScrollY)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1029,7 +955,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
|
||||
func markAllAsReadInTimeline(completion: (() -> Void)? = nil) {
|
||||
markAllAsRead(articles) {
|
||||
self.masterNavigationController.popViewController(animated: true)
|
||||
self.rootSplitViewController.show(.primary)
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
@@ -1339,45 +1265,28 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
// MARK: UISplitViewControllerDelegate
|
||||
|
||||
extension SceneCoordinator: UISplitViewControllerDelegate {
|
||||
|
||||
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
|
||||
masterTimelineViewController?.updateUI()
|
||||
|
||||
guard !isThreePanelMode else {
|
||||
return true
|
||||
}
|
||||
|
||||
if let articleViewController = (secondaryViewController as? UINavigationController)?.topViewController as? ArticleViewController {
|
||||
if currentArticle != nil {
|
||||
masterNavigationController.pushViewController(articleViewController, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
|
||||
masterTimelineViewController?.updateUI()
|
||||
|
||||
guard !isThreePanelMode else {
|
||||
return subSplitViewController
|
||||
func splitViewController(_ svc: UISplitViewController, topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
|
||||
switch proposedTopColumn {
|
||||
case .supplementary:
|
||||
if currentFeedIndexPath != nil {
|
||||
return .supplementary
|
||||
} else {
|
||||
return .primary
|
||||
}
|
||||
case .secondary:
|
||||
if currentArticle != nil {
|
||||
return .secondary
|
||||
} else {
|
||||
if currentFeedIndexPath != nil {
|
||||
return .supplementary
|
||||
} else {
|
||||
return .primary
|
||||
}
|
||||
}
|
||||
default:
|
||||
return .primary
|
||||
}
|
||||
|
||||
if let articleViewController = masterNavigationController.viewControllers.last as? ArticleViewController {
|
||||
articleViewController.showBars(self)
|
||||
masterNavigationController.popViewController(animated: false)
|
||||
let controller = addNavControllerIfNecessary(articleViewController, showButton: true)
|
||||
return controller
|
||||
}
|
||||
|
||||
if currentArticle == nil {
|
||||
let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
|
||||
articleViewController.coordinator = self
|
||||
let controller = addNavControllerIfNecessary(articleViewController, showButton: true)
|
||||
return controller
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1387,13 +1296,16 @@ extension SceneCoordinator: UISplitViewControllerDelegate {
|
||||
extension SceneCoordinator: UINavigationControllerDelegate {
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
|
||||
guard UIApplication.shared.applicationState != .background else {
|
||||
return
|
||||
}
|
||||
|
||||
if UIApplication.shared.applicationState == .background {
|
||||
guard rootSplitViewController.isCollapsed else {
|
||||
return
|
||||
}
|
||||
|
||||
// If we are showing the Feeds and only the feeds start clearing stuff
|
||||
if viewController === masterFeedViewController && !isThreePanelMode && !isTimelineViewControllerPending {
|
||||
if viewController === masterFeedViewController && !isTimelineViewControllerPending {
|
||||
activityManager.invalidateCurrentActivities()
|
||||
selectFeed(nil, animations: [.scroll, .select, .navigation])
|
||||
return
|
||||
@@ -1403,7 +1315,7 @@ extension SceneCoordinator: UINavigationControllerDelegate {
|
||||
// Don't clear it if we have pushed an ArticleViewController, but don't yet see it on the navigation stack.
|
||||
// This happens when we are going to the next unread and we need to grab another timeline to continue. The
|
||||
// ArticleViewController will be pushed, but we will briefly show the Timeline. Don't clear things out when that happens.
|
||||
if viewController === masterTimelineViewController && !isThreePanelMode && rootSplitViewController.isCollapsed && !isArticleViewControllerPending {
|
||||
if viewController === masterTimelineViewController && rootSplitViewController.isCollapsed && !isArticleViewControllerPending {
|
||||
currentArticle = nil
|
||||
masterTimelineViewController?.updateArticleSelection(animations: [.scroll, .select, .navigation])
|
||||
activityManager.invalidateReading()
|
||||
@@ -1414,9 +1326,8 @@ extension SceneCoordinator: UINavigationControllerDelegate {
|
||||
navigationController.setToolbarHidden(false, animated: true)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
@@ -2077,134 +1988,6 @@ private extension SceneCoordinator {
|
||||
|
||||
}
|
||||
|
||||
// MARK: Three Panel Mode
|
||||
|
||||
func installTimelineControllerIfNecessary(animated: Bool) {
|
||||
if navControllerForTimeline().viewControllers.filter({ $0 is MasterTimelineViewController }).count < 1 {
|
||||
isTimelineViewControllerPending = true
|
||||
masterTimelineViewController = UIStoryboard.main.instantiateController(ofType: MasterTimelineViewController.self)
|
||||
masterTimelineViewController!.coordinator = self
|
||||
navControllerForTimeline().pushViewController(masterTimelineViewController!, animated: animated)
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func installArticleController(state: ArticleViewController.State? = nil, animated: Bool) -> ArticleViewController {
|
||||
|
||||
isArticleViewControllerPending = true
|
||||
|
||||
let articleController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
|
||||
articleController.coordinator = self
|
||||
articleController.article = currentArticle
|
||||
articleController.restoreState = state
|
||||
|
||||
if let subSplit = subSplitViewController {
|
||||
let controller = addNavControllerIfNecessary(articleController, showButton: false)
|
||||
subSplit.showDetailViewController(controller, sender: self)
|
||||
} else if rootSplitViewController.isCollapsed || wasRootSplitViewControllerCollapsed {
|
||||
masterNavigationController.pushViewController(articleController, animated: animated)
|
||||
} else {
|
||||
let controller = addNavControllerIfNecessary(articleController, showButton: true)
|
||||
rootSplitViewController.showDetailViewController(controller, sender: self)
|
||||
}
|
||||
|
||||
return articleController
|
||||
|
||||
}
|
||||
|
||||
func addNavControllerIfNecessary(_ controller: UIViewController, showButton: Bool) -> UIViewController {
|
||||
|
||||
// You will sometimes get a compact horizontal size class while in three panel mode. Dunno why it lies.
|
||||
if rootSplitViewController.traitCollection.horizontalSizeClass == .compact && !isThreePanelMode {
|
||||
|
||||
return controller
|
||||
|
||||
} else {
|
||||
|
||||
let navController = InteractiveNavigationController.template(rootViewController: controller)
|
||||
navController.isToolbarHidden = false
|
||||
|
||||
if showButton {
|
||||
controller.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
|
||||
controller.navigationItem.leftItemsSupplementBackButton = true
|
||||
} else {
|
||||
controller.navigationItem.leftBarButtonItem = nil
|
||||
controller.navigationItem.leftItemsSupplementBackButton = false
|
||||
}
|
||||
|
||||
return navController
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func installSubSplit() {
|
||||
rootSplitViewController.preferredPrimaryColumnWidthFraction = 0.30
|
||||
|
||||
subSplitViewController = UISplitViewController()
|
||||
subSplitViewController!.preferredDisplayMode = .oneBesideSecondary
|
||||
subSplitViewController!.viewControllers = [InteractiveNavigationController.template()]
|
||||
subSplitViewController!.preferredPrimaryColumnWidthFraction = 0.4285
|
||||
|
||||
rootSplitViewController.showDetailViewController(subSplitViewController!, sender: self)
|
||||
rootSplitViewController.setOverrideTraitCollection(UITraitCollection(horizontalSizeClass: .regular), forChild: subSplitViewController!)
|
||||
}
|
||||
|
||||
func navControllerForTimeline() -> UINavigationController {
|
||||
if let subSplit = subSplitViewController {
|
||||
return subSplit.viewControllers.first as! UINavigationController
|
||||
} else {
|
||||
return masterNavigationController
|
||||
}
|
||||
}
|
||||
|
||||
func configureThreePanelMode() {
|
||||
articleViewController?.stopArticleExtractorIfProcessing()
|
||||
let articleViewControllerState = articleViewController?.currentState
|
||||
defer {
|
||||
masterNavigationController.viewControllers = [masterFeedViewController]
|
||||
}
|
||||
|
||||
if rootSplitViewController.viewControllers.last is InteractiveNavigationController {
|
||||
_ = rootSplitViewController.viewControllers.popLast()
|
||||
}
|
||||
|
||||
installSubSplit()
|
||||
installTimelineControllerIfNecessary(animated: false)
|
||||
masterTimelineViewController?.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
|
||||
masterTimelineViewController?.navigationItem.leftItemsSupplementBackButton = true
|
||||
|
||||
installArticleController(state: articleViewControllerState, animated: false)
|
||||
|
||||
masterFeedViewController.restoreSelectionIfNecessary(adjustScroll: true)
|
||||
masterTimelineViewController!.restoreSelectionIfNecessary(adjustScroll: false)
|
||||
}
|
||||
|
||||
func configureStandardPanelMode() {
|
||||
articleViewController?.stopArticleExtractorIfProcessing()
|
||||
let articleViewControllerState = articleViewController?.currentState
|
||||
rootSplitViewController.preferredPrimaryColumnWidthFraction = UISplitViewController.automaticDimension
|
||||
|
||||
// Set the is Pending flags early to prevent the navigation controller delegate from thinking that we
|
||||
// swiping around in the user interface
|
||||
isTimelineViewControllerPending = true
|
||||
isArticleViewControllerPending = true
|
||||
|
||||
masterNavigationController.viewControllers = [masterFeedViewController]
|
||||
if rootSplitViewController.viewControllers.last is UISplitViewController {
|
||||
subSplitViewController = nil
|
||||
_ = rootSplitViewController.viewControllers.popLast()
|
||||
}
|
||||
|
||||
if currentFeedIndexPath != nil {
|
||||
masterTimelineViewController = UIStoryboard.main.instantiateController(ofType: MasterTimelineViewController.self)
|
||||
masterTimelineViewController!.coordinator = self
|
||||
masterNavigationController.pushViewController(masterTimelineViewController!, animated: false)
|
||||
}
|
||||
|
||||
installArticleController(state: articleViewControllerState, animated: false)
|
||||
}
|
||||
|
||||
// MARK: NSUserActivity
|
||||
|
||||
func windowState() -> [AnyHashable: Any] {
|
||||
|
||||
@@ -14,35 +14,36 @@ import Zip
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
var coordinator = SceneCoordinator()
|
||||
var coordinator: SceneCoordinator!
|
||||
|
||||
// UIWindowScene delegate
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
|
||||
window = UIWindow(windowScene: scene as! UIWindowScene)
|
||||
window!.tintColor = AppAssets.primaryAccentColor
|
||||
updateUserInterfaceStyle()
|
||||
window!.rootViewController = coordinator.start(for: window!.frame.size)
|
||||
UINavigationBar.appearance().scrollEdgeAppearance = UINavigationBarAppearance()
|
||||
|
||||
let rootViewController = window!.rootViewController as! RootSplitViewController
|
||||
coordinator = SceneCoordinator(rootSplitViewController: rootViewController)
|
||||
rootViewController.coordinator = coordinator
|
||||
rootViewController.delegate = coordinator
|
||||
|
||||
coordinator.restoreWindowState(session.stateRestorationActivity)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange), name: UserDefaults.didChangeNotification, object: nil)
|
||||
|
||||
if let _ = connectionOptions.urlContexts.first?.url {
|
||||
window?.makeKeyAndVisible()
|
||||
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
|
||||
return
|
||||
}
|
||||
|
||||
if let shortcutItem = connectionOptions.shortcutItem {
|
||||
window!.makeKeyAndVisible()
|
||||
handleShortcutItem(shortcutItem)
|
||||
return
|
||||
}
|
||||
|
||||
if let notificationResponse = connectionOptions.notificationResponse {
|
||||
window!.makeKeyAndVisible()
|
||||
coordinator.handle(notificationResponse)
|
||||
return
|
||||
}
|
||||
@@ -50,8 +51,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
if let userActivity = connectionOptions.userActivities.first ?? session.stateRestorationActivity {
|
||||
coordinator.handle(userActivity)
|
||||
}
|
||||
|
||||
window!.makeKeyAndVisible()
|
||||
|
||||
}
|
||||
|
||||
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||
@@ -74,7 +74,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
func sceneWillEnterForeground(_ scene: UIScene) {
|
||||
appDelegate.resumeDatabaseProcessingIfNecessary()
|
||||
appDelegate.prepareAccountsForForeground()
|
||||
coordinator.configurePanelMode(for: window!.frame.size)
|
||||
coordinator.resetFocus()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
//
|
||||
// InteractiveNavigationController.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 8/22/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class InteractiveNavigationController: UINavigationController {
|
||||
|
||||
private let poppableDelegate = PoppableGestureRecognizerDelegate()
|
||||
|
||||
static func template() -> UINavigationController {
|
||||
let navController = InteractiveNavigationController()
|
||||
navController.configure()
|
||||
return navController
|
||||
}
|
||||
|
||||
static func template(rootViewController: UIViewController) -> UINavigationController {
|
||||
let navController = InteractiveNavigationController(rootViewController: rootViewController)
|
||||
navController.configure()
|
||||
return navController
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
poppableDelegate.navigationController = self
|
||||
interactivePopGestureRecognizer?.delegate = poppableDelegate
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
|
||||
configure()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private extension InteractiveNavigationController {
|
||||
|
||||
func configure() {
|
||||
isToolbarHidden = false
|
||||
|
||||
// Standard appearance with system background
|
||||
let standardAppearance = UINavigationBarAppearance()
|
||||
standardAppearance.backgroundColor = .clear
|
||||
standardAppearance.shadowColor = nil
|
||||
|
||||
let scrollEdgeAppearance = UINavigationBarAppearance()
|
||||
scrollEdgeAppearance.backgroundColor = .systemBackground
|
||||
scrollEdgeAppearance.shadowColor = nil
|
||||
|
||||
navigationBar.standardAppearance = standardAppearance
|
||||
navigationBar.scrollEdgeAppearance = scrollEdgeAppearance
|
||||
navigationBar.compactAppearance = standardAppearance
|
||||
navigationBar.compactScrollEdgeAppearance = scrollEdgeAppearance
|
||||
|
||||
|
||||
let toolbarAppearance = UIToolbarAppearance()
|
||||
toolbarAppearance.shadowColor = nil
|
||||
toolbar.standardAppearance = toolbarAppearance
|
||||
toolbar.compactAppearance = nil
|
||||
toolbar.scrollEdgeAppearance = nil
|
||||
toolbar.tintColor = AppAssets.primaryAccentColor
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user