NetNewsWire/Mac/Preferences/PreferencesWindowController...

205 lines
6.8 KiB
Swift
Raw Normal View History

2017-05-27 19:43:27 +02:00
//
// PreferencesWindowController.swift
2018-08-29 07:18:24 +02:00
// NetNewsWire
2017-05-27 19:43:27 +02:00
//
// Created by Brent Simmons on 8/1/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
import AppKit
2017-05-27 19:43:27 +02:00
private struct PreferencesToolbarItemSpec {
let identifier: NSToolbarItem.Identifier
2017-05-27 19:43:27 +02:00
let name: String
2020-04-07 15:06:47 +02:00
let image: NSImage?
2020-04-07 15:06:47 +02:00
init(identifierRawValue: String, name: String, image: NSImage?) {
2019-01-12 08:19:19 +01:00
self.identifier = NSToolbarItem.Identifier(identifierRawValue)
self.name = name
2020-04-07 15:06:47 +02:00
self.image = image
}
2017-05-27 19:43:27 +02:00
}
2019-01-12 08:19:19 +01:00
private struct ToolbarItemIdentifier {
static let General = "General"
2019-03-18 03:01:28 +01:00
static let Accounts = "Accounts"
2020-04-07 22:25:33 +02:00
static let Extensions = "Extensions"
2019-01-12 08:19:19 +01:00
static let Advanced = "Advanced"
}
2017-05-27 19:43:27 +02:00
class PreferencesWindowController : NSWindowController, NSToolbarDelegate {
private let windowWidth = CGFloat(512.0) // Width is constant for all views; only the height changes
2019-01-12 08:19:19 +01:00
private var viewControllers = [String: NSViewController]()
private let toolbarItemSpecs: [PreferencesToolbarItemSpec] = {
2017-05-27 19:43:27 +02:00
var specs = [PreferencesToolbarItemSpec]()
2020-04-07 15:06:47 +02:00
specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.General,
name: NSLocalizedString("General", comment: "Preferences"),
image: AppAssets.preferencesToolbarGeneralImage)]
2020-04-07 15:06:47 +02:00
specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.Accounts,
name: NSLocalizedString("Accounts", comment: "Preferences"),
image: AppAssets.preferencesToolbarAccountsImage)]
specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.Extensions,
name: NSLocalizedString("Extensions", comment: "Preferences"),
image: AppAssets.preferencesToolbarExtensionsImage)]
// Omit the Advanced Preferences for now because the Software Update related functionality is
// forbidden/non-applicable, and we can rely upon Apple to some extent for crash reports. We
// can add back the Crash Reporter preferences when we're ready to dynamically shuffle the rest
// of the content in this tab.
#if !MAC_APP_STORE
2020-04-07 15:06:47 +02:00
specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.Advanced,
name: NSLocalizedString("Advanced", comment: "Preferences"),
image: AppAssets.preferencesToolbarAdvancedImage)]
#endif
2017-05-27 19:43:27 +02:00
return specs
}()
override func windowDidLoad() {
2018-12-09 21:32:33 +01:00
let toolbar = NSToolbar(identifier: NSToolbar.Identifier("PreferencesToolbar"))
2017-05-27 19:43:27 +02:00
toolbar.delegate = self
toolbar.autosavesConfiguration = false
toolbar.allowsUserCustomization = false
toolbar.displayMode = .iconAndLabel
toolbar.selectedItemIdentifier = toolbarItemSpecs.first!.identifier
window?.showsToolbarButton = false
window?.toolbar = toolbar
switchToViewAtIndex(0)
window?.center()
2017-05-27 19:43:27 +02:00
}
// MARK: Actions
@objc func toolbarItemClicked(_ sender: Any?) {
guard let toolbarItem = sender as? NSToolbarItem else {
return
}
switchToView(identifier: toolbarItem.itemIdentifier.rawValue)
2017-05-27 19:43:27 +02:00
}
// MARK: NSToolbarDelegate
2017-09-24 21:24:44 +02:00
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
2017-05-27 19:43:27 +02:00
2017-09-27 06:43:40 +02:00
guard let toolbarItemSpec = toolbarItemSpecs.first(where: { $0.identifier.rawValue == itemIdentifier.rawValue }) else {
2017-05-27 19:43:27 +02:00
return nil
}
let toolbarItem = NSToolbarItem(itemIdentifier: toolbarItemSpec.identifier)
toolbarItem.action = #selector(toolbarItemClicked(_:))
toolbarItem.target = self
toolbarItem.label = toolbarItemSpec.name
toolbarItem.paletteLabel = toolbarItem.label
2020-04-07 15:06:47 +02:00
toolbarItem.image = toolbarItemSpec.image
2017-05-27 19:43:27 +02:00
return toolbarItem
}
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
2017-05-27 19:43:27 +02:00
return toolbarItemSpecs.map { $0.identifier }
}
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
2017-05-27 19:43:27 +02:00
return toolbarDefaultItemIdentifiers(toolbar)
}
func toolbarSelectableItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
2017-05-27 19:43:27 +02:00
return toolbarDefaultItemIdentifiers(toolbar)
}
}
private extension PreferencesWindowController {
var currentView: NSView? {
return window?.contentView?.subviews.first
2017-05-27 19:43:27 +02:00
}
func toolbarItemSpec(for identifier: String) -> PreferencesToolbarItemSpec? {
2017-10-02 22:15:07 +02:00
return toolbarItemSpecs.first(where: { $0.identifier.rawValue == identifier })
2017-05-27 19:43:27 +02:00
}
func switchToViewAtIndex(_ index: Int) {
let identifier = toolbarItemSpecs[index].identifier
2017-10-02 22:15:07 +02:00
switchToView(identifier: identifier.rawValue)
2017-05-27 19:43:27 +02:00
}
func switchToView(identifier: String) {
guard let toolbarItemSpec = toolbarItemSpec(for: identifier) else {
assertionFailure("Preferences window: no toolbarItemSpec matching \(identifier).")
return
}
guard let newViewController = viewController(identifier: identifier) else {
assertionFailure("Preferences window: no view controller matching \(identifier).")
return
}
if newViewController.view == currentView {
return
}
newViewController.view.nextResponder = newViewController
newViewController.nextResponder = window!.contentView
window!.title = toolbarItemSpec.name
resizeWindow(toFitView: newViewController.view)
if let currentView = currentView {
window!.contentView?.replaceSubview(currentView, with: newViewController.view)
}
else {
window!.contentView?.addSubview(newViewController.view)
}
window!.makeFirstResponder(newViewController.view)
}
func viewController(identifier: String) -> NSViewController? {
if let cachedViewController = viewControllers[identifier] {
return cachedViewController
}
2018-12-09 21:32:33 +01:00
let storyboard = NSStoryboard(name: NSStoryboard.Name("Preferences"), bundle: nil)
guard let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(identifier)) as? NSViewController else {
2017-05-27 19:43:27 +02:00
assertionFailure("Unknown preferences view controller: \(identifier)")
return nil
}
viewControllers[identifier] = viewController
return viewController
}
2017-05-27 19:43:27 +02:00
func resizeWindow(toFitView view: NSView) {
let viewFrame = view.frame
let windowFrame = window!.frame
let contentViewFrame = window!.contentView!.frame
let deltaHeight = NSHeight(contentViewFrame) - NSHeight(viewFrame)
let heightForWindow = NSHeight(windowFrame) - deltaHeight
let windowOriginY = NSMinY(windowFrame) + deltaHeight
2017-05-27 19:43:27 +02:00
var updatedWindowFrame = windowFrame
updatedWindowFrame.size.height = heightForWindow
updatedWindowFrame.origin.y = windowOriginY
updatedWindowFrame.size.width = windowWidth //NSWidth(viewFrame)
2017-05-27 19:43:27 +02:00
var updatedViewFrame = viewFrame
updatedViewFrame.origin = NSZeroPoint
updatedViewFrame.size.width = windowWidth
2017-05-27 19:43:27 +02:00
if viewFrame != updatedViewFrame {
view.frame = updatedViewFrame
}
if windowFrame != updatedWindowFrame {
window!.contentView?.alphaValue = 0.0
2017-05-27 19:43:27 +02:00
window!.setFrame(updatedWindowFrame, display: true, animate: true)
window!.contentView?.alphaValue = 1.0
2017-05-27 19:43:27 +02:00
}
}
}