From 4d677b20558686a09fcee0039d78379c1b8210bf Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sun, 24 Sep 2017 12:24:44 -0700 Subject: [PATCH] Fix a bunch of build errors. --- Evergreen.xcodeproj/project.pbxproj | 20 +-- Evergreen/AppDefaults.swift | 23 +-- Evergreen/AppDelegate.swift | 13 +- Evergreen/AppNotifications.swift | 48 ++++-- Evergreen/Data/DefaultFeedsImporter.swift | 2 +- .../AddFeed/AddFeedController.swift | 4 +- .../FolderTreeControllerDelegate.swift | 3 +- .../AddFolder/AddFolderWindowController.swift | 2 +- .../Detail/DetailViewController.swift | 7 +- .../MainWindow/MainWindowController.swift | 4 +- .../Sidebar/SidebarOutlineView.swift | 6 +- .../SidebarTreeControllerDelegate.swift | 3 +- .../Sidebar/SidebarViewController.swift | 10 +- .../MainWindow/Sidebar/UnreadCountView.swift | 4 +- .../MainWindow/StatusBar/StatusBarView.swift | 9 +- .../Cell/TimelineCellAppearance.swift | 4 +- .../Timeline/Cell/TimelineCellData.swift | 7 +- .../Timeline/TimelineViewController.swift | 163 +++++++++--------- .../PreferencesWindowController.swift | 10 +- Frameworks/Account/AccountManager.swift | 4 +- 20 files changed, 182 insertions(+), 164 deletions(-) diff --git a/Evergreen.xcodeproj/project.pbxproj b/Evergreen.xcodeproj/project.pbxproj index 5c98b3da0..7a1e61038 100644 --- a/Evergreen.xcodeproj/project.pbxproj +++ b/Evergreen.xcodeproj/project.pbxproj @@ -1147,25 +1147,29 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 842E45CE1ED8C308000A8B52 /* AppNotifications.swift in Sources */, 849C64641ED37A5D003D8FC0 /* AppDelegate.swift in Sources */, + 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */, + 842E45CE1ED8C308000A8B52 /* AppNotifications.swift in Sources */, 842E45DD1ED8C54B000A8B52 /* Browser.swift in Sources */, + 842E45E31ED8C681000A8B52 /* KeyboardDelegateProtocol.swift in Sources */, + 849A975E1ED9EB72007D329B /* MainWindowController.swift in Sources */, + 842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */, + 849A97661ED9EB96007D329B /* SidebarViewController.swift in Sources */, + 849A97641ED9EB96007D329B /* SidebarOutlineView.swift in Sources */, + 849A979F1ED9F130007D329B /* SidebarCell.swift in Sources */, + 849A97651ED9EB96007D329B /* SidebarTreeControllerDelegate.swift in Sources */, + 849A97671ED9EB96007D329B /* UnreadCountView.swift in Sources */, 849A975B1ED9EB0D007D329B /* ArticleUtilities.swift in Sources */, 849A97891ED9ECEF007D329B /* ArticleStyle.swift in Sources */, 849A978A1ED9ECEF007D329B /* ArticleStylesManager.swift in Sources */, 849A97791ED9EC04007D329B /* TimelineStringUtilities.swift in Sources */, - 849A979F1ED9F130007D329B /* SidebarCell.swift in Sources */, 849A97981ED9EFAA007D329B /* Node-Extensions.swift in Sources */, 849A97531ED9EAC0007D329B /* AddFeedController.swift in Sources */, 849A97831ED9EC63007D329B /* StatusBarView.swift in Sources */, 849A97431ED9EAA9007D329B /* AddFolderWindowController.swift in Sources */, 849A97921ED9EF65007D329B /* IndeterminateProgressWindowController.swift in Sources */, 849A97801ED9EC42007D329B /* DetailViewController.swift in Sources */, - 849A975E1ED9EB72007D329B /* MainWindowController.swift in Sources */, - 849A97661ED9EB96007D329B /* SidebarViewController.swift in Sources */, - 842E45E31ED8C681000A8B52 /* KeyboardDelegateProtocol.swift in Sources */, 849A976E1ED9EBC8007D329B /* TimelineViewController.swift in Sources */, - 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */, 849A978D1ED9EE4D007D329B /* FeedListWindowController.swift in Sources */, 849A97771ED9EC04007D329B /* TimelineCellData.swift in Sources */, 849A975C1ED9EB0D007D329B /* DefaultFeedsImporter.swift in Sources */, @@ -1173,16 +1177,12 @@ 849A976C1ED9EBC8007D329B /* TimelineTableRowView.swift in Sources */, 849A977B1ED9EC04007D329B /* UnreadIndicatorView.swift in Sources */, 849A97541ED9EAC0007D329B /* AddFeedWindowController.swift in Sources */, - 842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */, 849A976D1ED9EBC8007D329B /* TimelineTableView.swift in Sources */, 849A97A31ED9F180007D329B /* FolderTreeControllerDelegate.swift in Sources */, - 849A97671ED9EB96007D329B /* UnreadCountView.swift in Sources */, 849A97851ED9ECCD007D329B /* PreferencesWindowController.swift in Sources */, 849A977A1ED9EC04007D329B /* TimelineTableCellView.swift in Sources */, - 849A97641ED9EB96007D329B /* SidebarOutlineView.swift in Sources */, 849A97761ED9EC04007D329B /* TimelineCellAppearance.swift in Sources */, 849A97A21ED9F180007D329B /* FeedTitleDownloader.swift in Sources */, - 849A97651ED9EB96007D329B /* SidebarTreeControllerDelegate.swift in Sources */, 849A977F1ED9EC42007D329B /* ArticleRenderer.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Evergreen/AppDefaults.swift b/Evergreen/AppDefaults.swift index 362fccd4c..2abb73117 100644 --- a/Evergreen/AppDefaults.swift +++ b/Evergreen/AppDefaults.swift @@ -19,7 +19,7 @@ final class AppDefaults { static let shared = AppDefaults() - private struct Key { + struct Key { static let firstRunDate = "firstRunDate" static let sidebarFontSize = "sidebarFontSize" static let timelineFontSize = "timelineFontSize" @@ -27,6 +27,9 @@ final class AppDefaults { static let openInBrowserInBackground = "openInBrowserInBackground" } + private let smallestFontSizeRawValue = FontSize.small.rawValue + private let largestFontSizeRawValue = FontSize.veryLarge.rawValue + let isFirstRun: Bool var openInBrowserInBackground: Bool { @@ -65,11 +68,12 @@ final class AppDefaults { } } - init() { + private init() { - registerDefaults() - - if self.firstRunDate == nil { + AppDefaults.registerDefaults() + + let firstRunDate = UserDefaults.standard.object(forKey: Key.firstRunDate) as? Date + if firstRunDate == nil { self.isFirstRun = true self.firstRunDate = Date() } @@ -86,11 +90,11 @@ private extension AppDefaults { return date(for: Key.firstRunDate) } set { - setDate(for: key.firstRunDate, date) + setDate(for: Key.firstRunDate, newValue) } } - func registerDefaults() { + static func registerDefaults() { let defaults = [Key.sidebarFontSize: FontSize.medium.rawValue, Key.timelineFontSize: FontSize.medium.rawValue, Key.detailFontSize: FontSize.medium.rawValue] @@ -98,9 +102,6 @@ private extension AppDefaults { } func fontSize(for key: String) -> FontSize { - - static let smallestFontSizeRawValue = FontSize.small.rawValue - static let largestFontSizeRawValue = FontSize.veryLarge.rawValue var rawFontSize = int(for: key) if rawFontSize < smallestFontSizeRawValue { @@ -136,7 +137,7 @@ private extension AppDefaults { return UserDefaults.standard.object(forKey: key) as? Date } - func setDate(for key: String, _ date: Date) { + func setDate(for key: String, _ date: Date?) { UserDefaults.standard.set(date, forKey: key) } } diff --git a/Evergreen/AppDelegate.swift b/Evergreen/AppDelegate.swift index 0b8ddfc6a..f453f8bd1 100644 --- a/Evergreen/AppDelegate.swift +++ b/Evergreen/AppDelegate.swift @@ -47,12 +47,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations { func applicationDidFinishLaunching(_ note: Notification) { let isFirstRun = AppDefaults.shared.isFirstRun + let localAccount = AccountManager.shared.localAccount + importDefaultFeedsIfNeeded(isFirstRun, account: localAccount) currentTheme = themeLoader.defaultTheme - - let _ = AccountManager.sharedInstance - - importDefaultFeedsIfNeeded(isFirstRun, account: AccountManager.shared.localAccount) + createAndShowMainWindow() #if RELEASE @@ -180,7 +179,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations { @IBAction func refreshAll(_ sender: AnyObject) { - AccountManager.sharedInstance.refreshAll() + AccountManager.shared.refreshAll() } @IBAction func showAddFeedWindow(_ sender: AnyObject) { @@ -219,7 +218,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations { let result = panel.runModal() if result == NSApplication.ModalResponse.OK, let url = panel.url { DispatchQueue.main.async { - self.parseAndImportOPML(url, AccountManager.sharedInstance.localAccount) + self.parseAndImportOPML(url, AccountManager.shared.localAccount) } } } @@ -243,7 +242,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations { let result = panel.runModal() if result.rawValue == NSFileHandlingPanelOKButton, let url = panel.url { DispatchQueue.main.async { - let opmlString = AccountManager.sharedInstance.localAccount.OPMLString(indentLevel: 0) + let opmlString = AccountManager.shared.localAccount.OPMLString(indentLevel: 0) do { try opmlString.write(to: url, atomically: true, encoding: String.Encoding.utf8) } diff --git a/Evergreen/AppNotifications.swift b/Evergreen/AppNotifications.swift index b0cef4c6a..4070429ec 100644 --- a/Evergreen/AppNotifications.swift +++ b/Evergreen/AppNotifications.swift @@ -6,7 +6,8 @@ // Copyright © 2015 Ranchero Software, LLC. All rights reserved. // -import Foundation +import Cocoa +import Data extension Notification.Name { @@ -16,16 +17,41 @@ extension Notification.Name { static let AppNavigationKeyPressed = Notification.Name("AppNavigationKeyPressedNotification") } -struct AppUserInfoKey { - - static let view = "view" - static let node = "node" - static let objects = "objects" - static let article = "article" - static let articles = "articles" - static let articleStatus = "status" - static let appNavigation = "key" +extension Notification { + + var appInfo: AppInfo? { + get { + return AppInfo.pullFromUserInfo(userInfo) + } + } +} + +typealias UserInfoDictionary = [AnyHashable: Any] + +final class AppInfo { + + // These are things commonly passed around in Evergreen notifications. + // Rather than setting these things using strings, we have a single AppInfo class + // that the userInfo dictionary may contain. + + var view: NSView? + var article: Article? + var articles: Set
? + var navigationKey: Int? + var objects: [AnyObject]? + + static let appInfoKey = "appInfo" + + var userInfo: UserInfoDictionary { + get { + return [AppInfo.appInfoKey: self] as UserInfoDictionary + } + } + + static func pullFromUserInfo(_ userInfo: UserInfoDictionary?) -> AppInfo? { + + return userInfo?[appInfoKey] as? AppInfo + } } - diff --git a/Evergreen/Data/DefaultFeedsImporter.swift b/Evergreen/Data/DefaultFeedsImporter.swift index ec725b4cc..b26571178 100644 --- a/Evergreen/Data/DefaultFeedsImporter.swift +++ b/Evergreen/Data/DefaultFeedsImporter.swift @@ -16,7 +16,7 @@ private func shouldImportDefaultFeeds(_ isFirstRun: Bool) -> Bool { return false } - for oneAccount in AccountManager.sharedInstance.accounts { + for oneAccount in AccountManager.shared.accounts { if oneAccount.hasAtLeastOneFeed { return false } diff --git a/Evergreen/MainWindow/AddFeed/AddFeedController.swift b/Evergreen/MainWindow/AddFeed/AddFeedController.swift index 1dcaf9b0c..5cde2612f 100644 --- a/Evergreen/MainWindow/AddFeed/AddFeedController.swift +++ b/Evergreen/MainWindow/AddFeed/AddFeedController.swift @@ -46,7 +46,7 @@ class AddFeedController: AddFeedWindowControllerDelegate, FeedFinderDelegate { let folderTreeControllerDelegate = FolderTreeControllerDelegate() - let rootNode = Node(representedObject: AccountManager.sharedInstance.localAccount, parent: nil) + let rootNode = Node(representedObject: AccountManager.shared.localAccount, parent: nil) rootNode.canHaveChildNodes = true let folderTreeController = TreeController(delegate: folderTreeControllerDelegate, rootNode: rootNode) @@ -61,7 +61,7 @@ class AddFeedController: AddFeedWindowControllerDelegate, FeedFinderDelegate { closeAddFeedSheet(NSApplication.ModalResponse.OK) assert(folder.account != nil, "Folder must have an account.") - let account = folder.account ?? AccountManager.sharedInstance.localAccount + let account = folder.account ?? AccountManager.shared.localAccount if account.hasFeed(withURL: url.absoluteString) { showAlreadySubscribedError(url.absoluteString, folder) diff --git a/Evergreen/MainWindow/AddFeed/FolderTreeControllerDelegate.swift b/Evergreen/MainWindow/AddFeed/FolderTreeControllerDelegate.swift index e083682c4..3beadca78 100644 --- a/Evergreen/MainWindow/AddFeed/FolderTreeControllerDelegate.swift +++ b/Evergreen/MainWindow/AddFeed/FolderTreeControllerDelegate.swift @@ -10,6 +10,7 @@ import Foundation import RSCore import RSTree import Data +import Account final class FolderTreeControllerDelegate: TreeControllerDelegate { @@ -28,7 +29,7 @@ private extension FolderTreeControllerDelegate { var folderNodes = [Node]() - let _ = AccountManager.sharedInstance.localAccount.visitChildren { (oneRepresentedObject) in + let _ = AccountManager.shared.localAccount.visitChildren { (oneRepresentedObject) in if let folder = oneRepresentedObject as? Folder { folderNodes += [createNode(folder, parent: node)] diff --git a/Evergreen/MainWindow/AddFolder/AddFolderWindowController.swift b/Evergreen/MainWindow/AddFolder/AddFolderWindowController.swift index 09f720301..bafe63423 100644 --- a/Evergreen/MainWindow/AddFolder/AddFolderWindowController.swift +++ b/Evergreen/MainWindow/AddFolder/AddFolderWindowController.swift @@ -45,7 +45,7 @@ class AddFolderWindowController : NSWindowController { accountPopupButton.removeAllItems() let menu = NSMenu() - for oneAccount in AccountManager.sharedInstance.sortedAccounts { + for oneAccount in AccountManager.shared.sortedAccounts { let oneMenuItem = NSMenuItem() oneMenuItem.title = oneAccount.nameForDisplay oneMenuItem.representedObject = oneAccount diff --git a/Evergreen/MainWindow/Detail/DetailViewController.swift b/Evergreen/MainWindow/Detail/DetailViewController.swift index 2835eebb2..281d72028 100644 --- a/Evergreen/MainWindow/Detail/DetailViewController.swift +++ b/Evergreen/MainWindow/Detail/DetailViewController.swift @@ -50,10 +50,9 @@ class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDelegate @objc func timelineSelectionDidChange(_ note: Notification) { - let timelineView = note.userInfo?[viewKey] as! NSView - - if timelineView.window! === self.view.window { - article = note.userInfo?[articleKey] as? Article + let timelineView = note.appInfo?.view + if timelineView?.window === self.view.window { + article = note.appInfo?.article } } diff --git a/Evergreen/MainWindow/MainWindowController.swift b/Evergreen/MainWindow/MainWindowController.swift index ed1f10a84..37aeeb449 100644 --- a/Evergreen/MainWindow/MainWindowController.swift +++ b/Evergreen/MainWindow/MainWindowController.swift @@ -40,14 +40,14 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { @objc func appNavigationKeyPressed(_ note: Notification) { - guard let key = note.userInfo?[AppKey.appNavigation] as? Int else { + guard let navigationKey = note.appInfo?.navigationKey else { return } guard let contentView = window?.contentView, let view = note.object as? NSView, view.isDescendant(of: contentView) else { return } - print(key) + print(navigationKey) } @objc func refreshProgressDidChange(_ note: Notification) { diff --git a/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift b/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift index b1d74a8ce..04f0b6706 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift @@ -38,13 +38,13 @@ class SidebarOutlineView : NSOutlineView { default: keyHandled = false - } if keyHandled { - NotificationCenter.default.post(name: .AppNavigationKeyPressed, object: self, userInfo: [appNavigationKey: ch]) + let appInfo = AppInfo() + appInfo.navigationKey = ch + NotificationCenter.default.post(name: .AppNavigationKeyPressed, object: self, userInfo: appInfo.userInfo) } - else { super.keyDown(with: event) } diff --git a/Evergreen/MainWindow/Sidebar/SidebarTreeControllerDelegate.swift b/Evergreen/MainWindow/Sidebar/SidebarTreeControllerDelegate.swift index aa6abd6e0..4c02e6f65 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarTreeControllerDelegate.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarTreeControllerDelegate.swift @@ -9,6 +9,7 @@ import Foundation import RSTree import Data +import Account final class SidebarTreeControllerDelegate: TreeControllerDelegate { @@ -34,7 +35,7 @@ private extension SidebarTreeControllerDelegate { var updatedChildNodes = [Node]() - let _ = AccountManager.sharedInstance.localAccount.visitChildren { (oneRepresentedObject) in + let _ = AccountManager.shared.localAccount.visitChildren { (oneRepresentedObject) in if let existingNode = node.childNodeRepresentingObject(oneRepresentedObject as AnyObject) { // Reuse nodes. diff --git a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift index 3e6ca4e87..6677575bd 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift @@ -174,14 +174,14 @@ private extension SidebarViewController { } func postSidebarSelectionDidChangeNotification(_ selectedObjects: NSArray?) { - - var userInfo = [AnyHashable: Any]() + + let appInfo = AppInfo() if let selectedObjects = selectedObjects { - userInfo[AppKey.objects] = selectedObjects + appInfo.objects = selectedObjects } - userInfo[AppKey.view] = self.outlineView + appInfo.view = outlineView - NotificationCenter.default.post(name: .SidebarSelectionDidChange, object: self, userInfo: userInfo) + NotificationCenter.default.post(name: .SidebarSelectionDidChange, object: self, userInfo: appInfo.userInfo) } func nodeForItem(_ item: AnyObject?) -> Node { diff --git a/Evergreen/MainWindow/Sidebar/UnreadCountView.swift b/Evergreen/MainWindow/Sidebar/UnreadCountView.swift index a9b99b38f..4d5aac8cb 100644 --- a/Evergreen/MainWindow/Sidebar/UnreadCountView.swift +++ b/Evergreen/MainWindow/Sidebar/UnreadCountView.swift @@ -14,8 +14,8 @@ private let cornerRadius = currentTheme.float(forKey: "MainWindow.SourceList.unr private let backgroundColor = currentTheme.colorWithAlpha(forKey: "MainWindow.SourceList.unreadCount.backgroundColor") private let textColor = currentTheme.colorWithAlpha(forKey: "MainWindow.SourceList.unreadCount.color") private let textSize = currentTheme.float(forKey: "MainWindow.SourceList.unreadCount.fontSize") -private let textFont = NSFont.systemFont(ofSize: textSize, weight: NSFontWeightSemibold) -private var textAttributes: [String: AnyObject] = [NSForegroundColorAttributeName: textColor, NSFontAttributeName: textFont, NSKernAttributeName: NSNull()] +private let textFont = NSFont.systemFont(ofSize: textSize, weight: NSFont.Weight.semibold) +private var textAttributes: [NSAttributedStringKey: AnyObject] = [NSAttributedStringKey.foregroundColor: textColor, NSAttributedStringKey.font: textFont, NSAttributedStringKey.kern: NSNull()] private var textSizeCache = [Int: NSSize]() class UnreadCountView : NSView { diff --git a/Evergreen/MainWindow/StatusBar/StatusBarView.swift b/Evergreen/MainWindow/StatusBar/StatusBarView.swift index ffd31a83e..696aab462 100644 --- a/Evergreen/MainWindow/StatusBar/StatusBarView.swift +++ b/Evergreen/MainWindow/StatusBar/StatusBarView.swift @@ -55,11 +55,10 @@ final class StatusBarView: NSView { // MARK: Notifications @objc dynamic func timelineSelectionDidChange(_ note: Notification) { - - let timelineView = note.userInfo?[AppKey.view] as! NSView - - if timelineView.window! === self.window { - article = note.userInfo?[AppKey.article] as? Article + + let timelineView = note.appInfo?.view + if timelineView?.window === self.window { + article = note.appInfo?.article } } diff --git a/Evergreen/MainWindow/Timeline/Cell/TimelineCellAppearance.swift b/Evergreen/MainWindow/Timeline/Cell/TimelineCellAppearance.swift index d0045ef92..c77d9afeb 100644 --- a/Evergreen/MainWindow/Timeline/Cell/TimelineCellAppearance.swift +++ b/Evergreen/MainWindow/Timeline/Cell/TimelineCellAppearance.swift @@ -53,7 +53,7 @@ struct TimelineCellAppearance { dateMarginLeft = theme.float(forKey: "MainWindow.Timeline.cell.dateMarginLeft") titleColor = theme.color(forKey: "MainWindow.Timeline.cell.titleColor") - titleFont = NSFont.systemFont(ofSize: actualFontSize, weight: NSFontWeightBold) + titleFont = NSFont.systemFont(ofSize: actualFontSize, weight: NSFont.Weight.bold) titleBottomMargin = theme.float(forKey: "MainWindow.Timeline.cell.titleMarginBottom") textColor = theme.color(forKey: "MainWindow.Timeline.cell.textColor") @@ -69,7 +69,7 @@ struct TimelineCellAppearance { } } -private let smallFontSize = NSFont.systemFontSize() +private let smallFontSize = NSFont.systemFontSize private let mediumFontSize = smallFontSize + 1.0 private let largeFontSize = mediumFontSize + 4.0 private let veryLargeFontSize = largeFontSize + 8.0 diff --git a/Evergreen/MainWindow/Timeline/Cell/TimelineCellData.swift b/Evergreen/MainWindow/Timeline/Cell/TimelineCellData.swift index 42517ae43..ced5867fe 100644 --- a/Evergreen/MainWindow/Timeline/Cell/TimelineCellData.swift +++ b/Evergreen/MainWindow/Timeline/Cell/TimelineCellData.swift @@ -66,12 +66,7 @@ struct TimelineCellData { self.showFeedName = showFeedName self.favicon = nil - if let status = article.status { - self.read = status.read - } - else { - self.read = false - } + self.read = article.status.read } init() { //Empty diff --git a/Evergreen/MainWindow/Timeline/TimelineViewController.swift b/Evergreen/MainWindow/Timeline/TimelineViewController.swift index 9a566c9bd..409d36b3e 100644 --- a/Evergreen/MainWindow/Timeline/TimelineViewController.swift +++ b/Evergreen/MainWindow/Timeline/TimelineViewController.swift @@ -13,13 +13,11 @@ import RSTree import Data import Account -let timelineFontSizeKVOKey = "values." + TimelineFontSizeKey - class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource, KeyboardDelegate { @IBOutlet var tableView: TimelineTableView! var didRegisterForNotifications = false - var fontSize: FontSize = timelineFontSize() { + var fontSize: FontSize = AppDefaults.shared.timelineFontSize { didSet { fontSizeDidChange() } @@ -53,7 +51,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView var selectedArticles: [Article] { get { - return articlesForIndexes(tableView.selectedRowIndexes) + return Array(articlesForIndexes(tableView.selectedRowIndexes)) } } @@ -63,6 +61,8 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView } } + private let timelineFontSizeKVOKey = "values.{AppDefaults.Key.timelineFontSize}" + override func viewDidLoad() { cellAppearance = TimelineCellAppearance(theme: currentTheme, fontSize: fontSize) @@ -78,7 +78,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView NotificationCenter.default.addObserver(self, selector: #selector(sidebarSelectionDidChange(_:)), name: .SidebarSelectionDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(articleStatusesDidChange(_:)), name: .ArticleStatusesDidChange, object: nil) - NSUserDefaultsController.shared.addObserver(self, forKeyPath:timelineFontSizeKVOKey, options: NSKeyValueObservingOptions(rawValue: 0), context: nil) + NSUserDefaultsController.shared.addObserver(self, forKeyPath: timelineFontSizeKVOKey, options: NSKeyValueObservingOptions(rawValue: 0), context: nil) didRegisterForNotifications = true } @@ -144,12 +144,8 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView return } let articles = selectedArticles - var markAsRead = true - if let status = articles.first!.status { - if status.read { - markAsRead = false - } - } + let status = articles.first!.status + let markAsRead = !status.read markArticles(Set(articles), statusKey: ArticleStatusKey.read.rawValue, flag: markAsRead) } @@ -187,7 +183,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView func canMarkAllAsRead() -> Bool { for article in articles { - if !article.read { + if !article.status.read { return true } } @@ -209,7 +205,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView break } let article = articleAtRow(ix)! - if !article.read { + if !article.status.read { return ix } } @@ -221,20 +217,19 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView @objc func sidebarSelectionDidChange(_ note: Notification) { - let sidebarView = note.userInfo?[viewKey] as! NSView + let sidebarView = note.appInfo?.view - if sidebarView.window! === tableView.window { - representedObjects = note.userInfo?[objectsKey] as? [AnyObject] + if sidebarView?.window === tableView.window { + representedObjects = note.appInfo?.objects } } @objc func articleStatusesDidChange(_ note: Notification) { - - guard let articles = note.userInfo?[articlesKey] as? NSSet else { + + guard let articles = note.appInfo?.articles else { return } - - reloadCellsForArticles(articles.allObjects as! [Article]) + reloadCellsForArticles(articles) } func fontSizeInDefaultsDidChange() { @@ -243,7 +238,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView RSSingleLineRenderer.emptyCache() RSMultiLineRenderer.emptyCache() - let updatedFontSize = timelineFontSize() + let updatedFontSize = AppDefaults.shared.timelineFontSize if updatedFontSize != self.fontSize { self.fontSize = updatedFontSize } @@ -318,7 +313,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView return nil } - private func reloadCellsForArticles(_ articles: [Article]) { + private func reloadCellsForArticles(_ articles: Set
) { let indexes = indexesForArticles(articles) tableView.reloadData(forRowIndexes: indexes, columnIndexes: NSIndexSet(index: 0) as IndexSet) @@ -326,7 +321,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView // MARK: Articles - private func indexesForArticles(_ articles: [Article]) -> IndexSet { + private func indexesForArticles(_ articles: Set
) -> IndexSet { var indexes = IndexSet() @@ -340,11 +335,11 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView return indexes } - private func articlesForIndexes(_ indexes: IndexSet) -> [Article] { + private func articlesForIndexes(_ indexes: IndexSet) -> Set
{ - return indexes.flatMap{ (oneIndex) -> Article? in + return Set(indexes.flatMap{ (oneIndex) -> Article? in return articleAtRow(oneIndex) - } + }) } private func articleAtRow(_ row: Int) -> Article? { @@ -380,57 +375,57 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView private func fetchArticles() { - guard let representedObjects = representedObjects else { - if !articles.isEmpty { - articles = [Article]() - } - return - } - - var accountsDictionary = [String: [AnyObject]]() - - func addToAccountArray(accountID: String, object: AnyObject) { - - if let accountArray = accountsDictionary[accountID] { - if !accountArray.contains(where: { $0 === object }) { - accountsDictionary[accountID] = accountArray + [object] - } - } - else { - accountsDictionary[accountID] = [object] - } - } - - for oneObject in representedObjects { - - if let oneFeed = oneObject as? Feed { - addToAccountArray(accountID: oneFeed.account.accountID, object: oneFeed) - } - else if let oneFolder = oneObject as? Folder, let accountID = oneFolder.account?.accountID { - addToAccountArray(accountID: accountID, object: oneFolder) - } - } - - var fetchedArticles = [Article]() - for (accountID, objects) in accountsDictionary { - - guard let oneAccount = accountWithID(accountID) else { - continue - } - - let oneFetchedArticles = oneAccount.fetchArticles(for: objects) - for oneFetchedArticle in oneFetchedArticles { - if !fetchedArticles.contains(where: { $0 === oneFetchedArticle }) { - fetchedArticles += [oneFetchedArticle] - } - } - } - - fetchedArticles.sort(by: articleComparator) - - if !articleArraysAreIdentical(array1: articles, array2: fetchedArticles) { - articles = fetchedArticles - } +// guard let representedObjects = representedObjects else { +// if !articles.isEmpty { +// articles = [Article]() +// } +// return +// } +// +// var accountsDictionary = [String: [AnyObject]]() +// +// func addToAccountArray(accountID: String, object: AnyObject) { +// +// if let accountArray = accountsDictionary[accountID] { +// if !accountArray.contains(where: { $0 === object }) { +// accountsDictionary[accountID] = accountArray + [object] +// } +// } +// else { +// accountsDictionary[accountID] = [object] +// } +// } +// +// for oneObject in representedObjects { +// +// if let oneFeed = oneObject as? Feed { +// addToAccountArray(accountID: oneFeed.account.accountID, object: oneFeed) +// } +// else if let oneFolder = oneObject as? Folder, let accountID = oneFolder.account?.accountID { +// addToAccountArray(accountID: accountID, object: oneFolder) +// } +// } +// +// var fetchedArticles = [Article]() +// for (accountID, objects) in accountsDictionary { +// +// guard let oneAccount = accountWithID(accountID) else { +// continue +// } +// +// let oneFetchedArticles = oneAccount.fetchArticles(for: objects) +// for oneFetchedArticle in oneFetchedArticles { +// if !fetchedArticles.contains(where: { $0 === oneFetchedArticle }) { +// fetchedArticles += [oneFetchedArticle] +// } +// } +// } +// +// fetchedArticles.sort(by: articleComparator) +// +// if articles != fetchedArticles { +// articles = fetchedArticles +// } } // MARK: Cell Configuring @@ -438,7 +433,9 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView private func calculateRowHeight() -> CGFloat { let longTitle = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?" - let prototypeArticle = Article(accountID: "prototype", articleID: "prototype", feedID: "prototype", uniqueID: "prototype", title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, tags: nil, attachments: nil) + let prototypeID = "prototype" + let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date()) + let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, tags: nil, attachments: nil, status: status) let prototypeCellData = TimelineCellData(article: prototypeArticle, appearance: cellAppearance, showFeedName: false) let height = timelineCellHeight(100, cellData: prototypeCellData, appearance: cellAppearance) @@ -495,13 +492,13 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView private func postTimelineSelectionDidChangeNotification(_ selectedArticle: Article?) { - var userInfo = [String: AnyObject]() + let appInfo = AppInfo() if let article = selectedArticle { - userInfo[articleKey] = article as AnyObject + appInfo.article = article } - userInfo[viewKey] = self.tableView + appInfo.view = tableView - NotificationCenter.default.post(name: .TimelineSelectionDidChange, object: self, userInfo: userInfo) + NotificationCenter.default.post(name: .TimelineSelectionDidChange, object: self, userInfo: appInfo.userInfo) } func tableViewSelectionDidChange(_ notification: Notification) { @@ -516,7 +513,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView } if let selectedArticle = articleAtRow(selectedRow) { - if (!selectedArticle.read) { + if (!selectedArticle.status.read) { markArticles(Set([selectedArticle]), statusKey: ArticleStatusKey.read.rawValue, flag: true) } postTimelineSelectionDidChangeNotification(selectedArticle) diff --git a/Evergreen/Preferences/PreferencesWindowController.swift b/Evergreen/Preferences/PreferencesWindowController.swift index 76825e6d3..3ec51ca65 100644 --- a/Evergreen/Preferences/PreferencesWindowController.swift +++ b/Evergreen/Preferences/PreferencesWindowController.swift @@ -47,23 +47,23 @@ class PreferencesWindowController : NSWindowController, NSToolbarDelegate { window?.showsToolbarButton = false window?.toolbar = toolbar - window?.setFrameAutosaveName(windowFrameName) + window?.setFrameAutosaveName(NSWindow.FrameAutosaveName(rawValue: windowFrameName)) switchToViewAtIndex(0) } // MARK: Actions - func toolbarItemClicked(_ sender: AnyObject) { + @objc func toolbarItemClicked(_ sender: AnyObject) { } // MARK: NSToolbarDelegate - func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: String, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { + func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { - guard let toolbarItemSpec = toolbarItemSpecs.first(where: { $0.identifier == itemIdentifier }) else { + guard let toolbarItemSpec = toolbarItemSpecs.first(where: { $0.identifier.rawValue == itemIdentifier }) else { return nil } @@ -151,7 +151,7 @@ private extension PreferencesWindowController { return cachedViewController } - let storyboard = NSStoryboard(name: "Preferences", bundle: nil) + let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Preferences"), bundle: nil) guard let viewController = storyboard.instantiateController(withIdentifier: identifier) as? NSViewController else { assertionFailure("Unknown preferences view controller: \(identifier)") return nil diff --git a/Frameworks/Account/AccountManager.swift b/Frameworks/Account/AccountManager.swift index d7b9c3c98..91b185ecc 100644 --- a/Frameworks/Account/AccountManager.swift +++ b/Frameworks/Account/AccountManager.swift @@ -28,7 +28,7 @@ public final class AccountManager: UnreadCountProvider { } } - var accounts: [Account] { + public var accounts: [Account] { get { return Array(accountsDictionary.values) } @@ -194,7 +194,7 @@ private func accountFilePathWithFolder(_ folderPath: String) -> String { public func accountWithID(_ accountID: String) -> Account? { // Shortcut. - return AccountManager.sharedInstance.existingAccount(with: accountID) + return AccountManager.shared.existingAccount(with: accountID) } private struct AccountSpecifier {