Merge pull request #549 from danielpunkass/state-restoration-improvements

Switch to standard state restoration mechanism
This commit is contained in:
Brent Simmons 2019-02-15 10:40:41 -08:00 committed by GitHub
commit a8924bf337
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 34 deletions

View File

@ -53,7 +53,6 @@ struct AppDefaults {
static let timelineSortDirection = "timelineSortDirection" static let timelineSortDirection = "timelineSortDirection"
static let detailFontSize = "detailFontSize" static let detailFontSize = "detailFontSize"
static let openInBrowserInBackground = "openInBrowserInBackground" static let openInBrowserInBackground = "openInBrowserInBackground"
static let mainWindowWidths = "mainWindowWidths"
static let refreshInterval = "refreshInterval" static let refreshInterval = "refreshInterval"
// Hidden prefs // Hidden prefs
@ -120,15 +119,6 @@ struct AppDefaults {
} }
} }
static var mainWindowWidths: [Int]? {
get {
return UserDefaults.standard.object(forKey: Key.mainWindowWidths) as? [Int]
}
set {
UserDefaults.standard.set(newValue, forKey: Key.mainWindowWidths)
}
}
static var refreshInterval: RefreshInterval { static var refreshInterval: RefreshInterval {
get { get {
let rawValue = UserDefaults.standard.integer(forKey: Key.refreshInterval) let rawValue = UserDefaults.standard.integer(forKey: Key.refreshInterval)

View File

@ -576,7 +576,6 @@ private extension AppDelegate {
func saveState() { func saveState() {
inspectorWindowController?.saveState() inspectorWindowController?.saveState()
mainWindowController?.saveState()
} }
func updateSortMenuItems() { func updateSortMenuItems() {

View File

@ -11,12 +11,11 @@ import Articles
import Account import Account
import RSCore import RSCore
class MainWindowController : NSWindowController, NSUserInterfaceValidations { class MainWindowController : NSWindowController, NSUserInterfaceValidations, NSWindowDelegate {
@IBOutlet var toolbarDelegate: MainWindowToolbarDelegate? @IBOutlet var toolbarDelegate: MainWindowToolbarDelegate?
private var sharingServicePickerDelegate: NSSharingServicePickerDelegate? private var sharingServicePickerDelegate: NSSharingServicePickerDelegate?
private let windowAutosaveName = NSWindow.FrameAutosaveName("MainWindow")
static var didPositionWindowOnFirstRun = false static var didPositionWindowOnFirstRun = false
private var currentFeedOrFolder: AnyObject? = nil { private var currentFeedOrFolder: AnyObject? = nil {
@ -43,7 +42,6 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
window?.titleVisibility = .hidden window?.titleVisibility = .hidden
} }
window?.setFrameUsingName(windowAutosaveName, force: true)
if AppDefaults.isFirstRun && !MainWindowController.didPositionWindowOnFirstRun { if AppDefaults.isFirstRun && !MainWindowController.didPositionWindowOnFirstRun {
if let window = window { if let window = window {
@ -56,9 +54,6 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
} }
detailSplitViewItem?.minimumThickness = CGFloat(MainWindowController.detailViewMinimumThickness) detailSplitViewItem?.minimumThickness = CGFloat(MainWindowController.detailViewMinimumThickness)
restoreSplitViewState()
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillTerminate(_:)), name: NSApplication.willTerminateNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(refreshProgressDidChange(_:)), name: .AccountRefreshDidBegin, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(refreshProgressDidChange(_:)), name: .AccountRefreshDidBegin, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(refreshProgressDidChange(_:)), name: .AccountRefreshDidFinish, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(refreshProgressDidChange(_:)), name: .AccountRefreshDidFinish, object: nil)
@ -75,12 +70,6 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
// MARK: - API // MARK: - API
func saveState() {
saveSplitViewState()
}
func selectedObjectsInSidebar() -> [AnyObject]? { func selectedObjectsInSidebar() -> [AnyObject]? {
return sidebarViewController?.selectedObjects return sidebarViewController?.selectedObjects
@ -88,10 +77,18 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
// MARK: - Notifications // MARK: - Notifications
@objc func applicationWillTerminate(_ note: Notification) { func window(_ window: NSWindow, willEncodeRestorableState state: NSCoder) {
saveState() saveSplitViewState(to: state)
window?.saveFrame(usingName: windowAutosaveName) }
func window(_ window: NSWindow, didDecodeRestorableState state: NSCoder) {
restoreSplitViewState(from: state)
// Make sure the timeline view is first responder if possible, to start out viewing
// whatever preserved selection might have been restored
makeTimelineViewFirstResponder()
} }
@objc func refreshProgressDidChange(_ note: Notification) { @objc func refreshProgressDidChange(_ note: Notification) {
@ -396,7 +393,9 @@ extension MainWindowController : ScriptingMainWindowController {
// MARK: - Private // MARK: - Private
private extension MainWindowController { private extension MainWindowController {
private static let mainWindowWidthsStateKey = "mainWindowWidths"
var splitViewController: NSSplitViewController? { var splitViewController: NSSplitViewController? {
guard let viewController = contentViewController else { guard let viewController = contentViewController else {
return nil return nil
@ -583,7 +582,7 @@ private extension MainWindowController {
} }
func saveSplitViewState() { func saveSplitViewState(to coder: NSCoder) {
// TODO: Update this for multiple windows. // TODO: Update this for multiple windows.
@ -592,16 +591,25 @@ private extension MainWindowController {
} }
let widths = splitView.arrangedSubviews.map{ Int(floor($0.frame.width)) } let widths = splitView.arrangedSubviews.map{ Int(floor($0.frame.width)) }
if AppDefaults.mainWindowWidths != widths { coder.encode(widths, forKey: MainWindowController.mainWindowWidthsStateKey)
AppDefaults.mainWindowWidths = widths
}
} }
func restoreSplitViewState() { func arrayOfIntFromCoder(_ coder: NSCoder, withKey: String) -> [Int]? {
let decodedFloats: [Int]?
do {
decodedFloats = try coder.decodeTopLevelObject(forKey: MainWindowController.mainWindowWidthsStateKey) as? [Int]? ?? nil
}
catch {
decodedFloats = nil
}
return decodedFloats
}
func restoreSplitViewState(from coder: NSCoder) {
// TODO: Update this for multiple windows. // TODO: Update this for multiple windows.
guard let splitView = splitViewController?.splitView, let widths = arrayOfIntFromCoder(coder, withKey: MainWindowController.mainWindowWidthsStateKey), widths.count == 3, let window = window else {
guard let splitView = splitViewController?.splitView, let widths = AppDefaults.mainWindowWidths, widths.count == 3, let window = window else {
return return
} }

View File

@ -70,6 +70,26 @@ import RSCore
} }
} }
// MARK: State Restoration
private static let stateRestorationSelectedRowIndexes = "selectedRowIndexes"
override func encodeRestorableState(with coder: NSCoder) {
super.encodeRestorableState(with: coder)
coder.encode(outlineView.selectedRowIndexes, forKey: SidebarViewController.stateRestorationSelectedRowIndexes)
}
override func restoreState(with coder: NSCoder) {
super.restoreState(with: coder)
if let restoredRowIndexes = coder.decodeObject(of: [NSIndexSet.self], forKey: SidebarViewController.stateRestorationSelectedRowIndexes) as? IndexSet {
outlineView.selectRowIndexes(restoredRowIndexes, byExtendingSelection: false)
}
}
// MARK: - Notifications // MARK: - Notifications
@objc func unreadCountDidChange(_ note: Notification) { @objc func unreadCountDidChange(_ note: Notification) {
@ -278,6 +298,8 @@ import RSCore
func outlineViewSelectionDidChange(_ notification: Notification) { func outlineViewSelectionDidChange(_ notification: Notification) {
postSidebarSelectionDidChangeNotification(selectedObjects.isEmpty ? nil : selectedObjects) postSidebarSelectionDidChangeNotification(selectedObjects.isEmpty ? nil : selectedObjects)
self.invalidateRestorableState()
} }
//MARK: - Node Manipulation //MARK: - Node Manipulation

View File

@ -143,6 +143,26 @@ class TimelineViewController: NSViewController, UndoableCommandRunner {
sharingServiceDelegate = SharingServiceDelegate(self.view.window) sharingServiceDelegate = SharingServiceDelegate(self.view.window)
} }
// MARK: State Restoration
private static let stateRestorationSelectedArticles = "selectedArticles"
override func encodeRestorableState(with coder: NSCoder) {
super.encodeRestorableState(with: coder)
coder.encode(self.selectedArticleIDs(), forKey: TimelineViewController.stateRestorationSelectedArticles)
}
override func restoreState(with coder: NSCoder) {
super.restoreState(with: coder)
if let restoredArticleIDs = (try? coder.decodeTopLevelObject(forKey: TimelineViewController.stateRestorationSelectedArticles)) as? [String] {
self.restoreSelection(restoredArticleIDs)
}
}
// MARK: Appearance Change // MARK: Appearance Change
private func fontSizeDidChange() { private func fontSizeDidChange() {
@ -618,6 +638,8 @@ extension TimelineViewController: NSTableViewDelegate {
} }
postTimelineSelectionDidChangeNotification(selectedArticles) postTimelineSelectionDidChangeNotification(selectedArticles)
self.invalidateRestorableState()
} }
private func postTimelineSelectionDidChangeNotification(_ selectedArticles: ArticleArray?) { private func postTimelineSelectionDidChangeNotification(_ selectedArticles: ArticleArray?) {