2020-04-07 04:06:42 +02:00
|
|
|
|
//
|
2020-04-07 22:25:33 +02:00
|
|
|
|
// ExtensionsPreferencesViewController.swift
|
2020-04-07 04:06:42 +02:00
|
|
|
|
// NetNewsWire
|
|
|
|
|
//
|
|
|
|
|
// Created by Maurice Parker on 4/6/20.
|
|
|
|
|
// Copyright © 2020 Ranchero Software. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import AppKit
|
2020-10-30 20:43:42 +01:00
|
|
|
|
import SwiftUI
|
|
|
|
|
import AuthenticationServices
|
|
|
|
|
import OAuthSwift
|
|
|
|
|
import Secrets
|
|
|
|
|
|
|
|
|
|
protocol ExtensionPointPreferencesEnabler: class {
|
|
|
|
|
func enable(_ extensionPointType: ExtensionPoint.Type)
|
|
|
|
|
}
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
2020-04-07 22:25:33 +02:00
|
|
|
|
final class ExtensionPointPreferencesViewController: NSViewController {
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
|
|
|
|
@IBOutlet weak var tableView: NSTableView!
|
|
|
|
|
@IBOutlet weak var detailView: NSView!
|
|
|
|
|
@IBOutlet weak var deleteButton: NSButton!
|
|
|
|
|
|
2020-04-15 05:33:05 +02:00
|
|
|
|
private var activeExtensionPoints = [ExtensionPoint]()
|
2020-10-30 20:43:42 +01:00
|
|
|
|
private var callbackURL: URL? = nil
|
|
|
|
|
private var oauth: OAuthSwift?
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
|
|
|
|
override func viewDidLoad() {
|
|
|
|
|
super.viewDidLoad()
|
|
|
|
|
|
|
|
|
|
tableView.delegate = self
|
|
|
|
|
tableView.dataSource = self
|
2020-04-09 03:22:13 +02:00
|
|
|
|
|
|
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(activeExtensionPointsDidChange(_:)), name: .ActiveExtensionPointsDidChange, object: nil)
|
|
|
|
|
|
2020-04-07 04:06:42 +02:00
|
|
|
|
// Fix tableView frame — for some reason IB wants it 1pt wider than the clip view. This leads to unwanted horizontal scrolling.
|
|
|
|
|
var rTable = tableView.frame
|
|
|
|
|
rTable.size.width = tableView.superview!.frame.size.width
|
|
|
|
|
tableView.frame = rTable
|
2020-04-09 03:22:13 +02:00
|
|
|
|
|
2020-04-14 23:47:05 +02:00
|
|
|
|
showDefaultView()
|
2020-10-30 20:43:42 +01:00
|
|
|
|
|
2020-11-04 03:35:53 +01:00
|
|
|
|
|
2020-04-07 04:06:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-09 03:22:13 +02:00
|
|
|
|
@IBAction func enableExtensionPoints(_ sender: Any) {
|
2020-11-06 12:07:28 +01:00
|
|
|
|
let controller = NSHostingController(rootView: EnableExtensionPointView(enabler: self, selectedType: nil))
|
|
|
|
|
controller.rootView.parent = controller
|
|
|
|
|
presentAsSheet(controller)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func enableExtensionPointFromSelection(_ selection: ExtensionPoint.Type) {
|
|
|
|
|
let controller = NSHostingController(rootView: EnableExtensionPointView(enabler: self, selectedType: selection))
|
2020-10-30 20:43:42 +01:00
|
|
|
|
controller.rootView.parent = controller
|
|
|
|
|
presentAsSheet(controller)
|
2020-04-09 03:22:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@IBAction func disableExtensionPoint(_ sender: Any) {
|
|
|
|
|
guard tableView.selectedRow != -1 else {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 05:33:05 +02:00
|
|
|
|
let extensionPoint = activeExtensionPoints[tableView.selectedRow]
|
|
|
|
|
ExtensionPointManager.shared.deactivateExtensionPoint(extensionPoint.extensionPointID)
|
2020-10-30 20:43:42 +01:00
|
|
|
|
hideController()
|
2020-04-09 03:22:13 +02:00
|
|
|
|
}
|
2020-04-07 04:06:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - NSTableViewDataSource
|
|
|
|
|
|
2020-04-07 22:25:33 +02:00
|
|
|
|
extension ExtensionPointPreferencesViewController: NSTableViewDataSource {
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
|
|
|
|
func numberOfRows(in tableView: NSTableView) -> Int {
|
2020-04-15 05:33:05 +02:00
|
|
|
|
return activeExtensionPoints.count
|
2020-04-07 04:06:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
|
2020-04-15 05:33:05 +02:00
|
|
|
|
return activeExtensionPoints[row]
|
2020-04-07 04:06:42 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - NSTableViewDelegate
|
|
|
|
|
|
2020-04-07 22:25:33 +02:00
|
|
|
|
extension ExtensionPointPreferencesViewController: NSTableViewDelegate {
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
|
|
|
|
private static let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "AccountCell")
|
|
|
|
|
|
|
|
|
|
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
|
|
|
|
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: nil) as? NSTableCellView {
|
2020-04-15 05:33:05 +02:00
|
|
|
|
let extensionPoint = activeExtensionPoints[row]
|
|
|
|
|
cell.textField?.stringValue = extensionPoint.title
|
2020-10-30 21:42:45 +01:00
|
|
|
|
cell.imageView?.image = extensionPoint.image
|
2020-04-07 04:06:42 +02:00
|
|
|
|
return cell
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func tableViewSelectionDidChange(_ notification: Notification) {
|
|
|
|
|
|
2020-04-09 03:22:13 +02:00
|
|
|
|
let selectedRow = tableView.selectedRow
|
|
|
|
|
if tableView.selectedRow == -1 {
|
|
|
|
|
deleteButton.isEnabled = false
|
2020-10-30 20:43:42 +01:00
|
|
|
|
hideController()
|
2020-04-09 03:22:13 +02:00
|
|
|
|
return
|
|
|
|
|
} else {
|
|
|
|
|
deleteButton.isEnabled = true
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 05:33:05 +02:00
|
|
|
|
let extensionPoint = activeExtensionPoints[selectedRow]
|
|
|
|
|
let controller = ExtensionPointDetailViewController(extensionPoint: extensionPoint)
|
2020-04-09 03:22:13 +02:00
|
|
|
|
showController(controller)
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 20:43:42 +01:00
|
|
|
|
// MARK: ExtensionPointPreferencesViewController
|
|
|
|
|
|
|
|
|
|
extension ExtensionPointPreferencesViewController: ExtensionPointPreferencesEnabler {
|
|
|
|
|
|
|
|
|
|
func enable(_ extensionPointType: ExtensionPoint.Type) {
|
|
|
|
|
if let oauth1 = extensionPointType as? OAuth1SwiftProvider.Type {
|
|
|
|
|
enableOauth1(oauth1, extensionPointType: extensionPointType)
|
|
|
|
|
} else if let oauth2 = extensionPointType as? OAuth2SwiftProvider.Type {
|
|
|
|
|
enableOauth2(oauth2, extensionPointType: extensionPointType)
|
|
|
|
|
} else {
|
|
|
|
|
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType) { result in
|
|
|
|
|
if case .failure(let error) = result {
|
|
|
|
|
self.presentError(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension ExtensionPointPreferencesViewController: OAuthSwiftURLHandlerType {
|
|
|
|
|
|
|
|
|
|
public func handle(_ url: URL) {
|
|
|
|
|
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL!.scheme, completionHandler: { (url, error) in
|
|
|
|
|
if let callbackedURL = url {
|
|
|
|
|
OAuth1Swift.handle(url: callbackedURL)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guard let error = error else { return }
|
|
|
|
|
|
|
|
|
|
self.oauth?.cancel()
|
|
|
|
|
self.oauth = nil
|
|
|
|
|
|
|
|
|
|
if case ASWebAuthenticationSessionError.canceledLogin = error {
|
|
|
|
|
print("Login cancelled.")
|
|
|
|
|
} else {
|
|
|
|
|
NSApplication.shared.presentError(error)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
session.presentationContextProvider = self
|
|
|
|
|
if !session.start() {
|
|
|
|
|
print("Session failed to start!!!")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension ExtensionPointPreferencesViewController: ASWebAuthenticationPresentationContextProviding {
|
|
|
|
|
|
|
|
|
|
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
|
|
|
|
|
return view.window!
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-07 04:06:42 +02:00
|
|
|
|
// MARK: - Private
|
|
|
|
|
|
2020-04-07 22:25:33 +02:00
|
|
|
|
private extension ExtensionPointPreferencesViewController {
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
2020-04-09 03:22:13 +02:00
|
|
|
|
@objc func activeExtensionPointsDidChange(_ note: Notification) {
|
2020-04-14 23:47:05 +02:00
|
|
|
|
showDefaultView()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func showDefaultView() {
|
2020-04-15 05:33:05 +02:00
|
|
|
|
activeExtensionPoints = Array(ExtensionPointManager.shared.activeExtensionPoints.values).sorted(by: { $0.title < $1.title })
|
2020-04-09 03:22:13 +02:00
|
|
|
|
tableView.reloadData()
|
2020-11-02 04:08:54 +01:00
|
|
|
|
|
|
|
|
|
if tableView.selectedRow == -1 {
|
|
|
|
|
var helpText = ""
|
2020-11-06 12:07:28 +01:00
|
|
|
|
if ExtensionPointManager.shared.availableExtensionPointTypes.count == 0 {
|
|
|
|
|
helpText = NSLocalizedString("You've added all available extension points.", comment: "Extension Explainer")
|
|
|
|
|
}
|
|
|
|
|
else if activeExtensionPoints.count == 0 {
|
2020-11-04 03:35:53 +01:00
|
|
|
|
helpText = NSLocalizedString("Add an extension by clicking the + button.", comment: "Extension Explainer")
|
2020-11-02 04:08:54 +01:00
|
|
|
|
} else {
|
2020-11-04 03:35:53 +01:00
|
|
|
|
helpText = NSLocalizedString("Select an extension or add a new extension point by clicking the + button.", comment: "Extension Explainer")
|
2020-11-02 04:08:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-03 02:58:46 +01:00
|
|
|
|
if let controller = children.first {
|
|
|
|
|
children.removeAll()
|
|
|
|
|
controller.view.removeFromSuperview()
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 03:35:53 +01:00
|
|
|
|
let textHostingController = NSHostingController(rootView: EnableExtensionPointHelpView(helpText: helpText, preferencesController: self))
|
2020-11-02 04:08:54 +01:00
|
|
|
|
addChild(textHostingController)
|
|
|
|
|
textHostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
detailView.addSubview(textHostingController.view)
|
2020-11-03 02:41:34 +01:00
|
|
|
|
detailView.addConstraints([
|
|
|
|
|
NSLayoutConstraint(item: textHostingController.view, attribute: .top, relatedBy: .equal, toItem: detailView, attribute: .top, multiplier: 1, constant: 1),
|
|
|
|
|
NSLayoutConstraint(item: textHostingController.view, attribute: .bottom, relatedBy: .equal, toItem: detailView, attribute: .bottom, multiplier: 1, constant: -deleteButton.frame.height),
|
|
|
|
|
NSLayoutConstraint(item: textHostingController.view, attribute: .width, relatedBy: .equal, toItem: detailView, attribute: .width, multiplier: 1, constant: 1)
|
|
|
|
|
])
|
2020-11-02 04:08:54 +01:00
|
|
|
|
}
|
2020-04-09 03:22:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-07 04:06:42 +02:00
|
|
|
|
func showController(_ controller: NSViewController) {
|
2020-10-30 20:43:42 +01:00
|
|
|
|
hideController()
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
2020-10-30 20:43:42 +01:00
|
|
|
|
addChild(controller)
|
|
|
|
|
controller.view.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
detailView.addSubview(controller.view)
|
|
|
|
|
detailView.addFullSizeConstraints(forSubview: controller.view)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func hideController() {
|
2020-04-07 04:06:42 +02:00
|
|
|
|
if let controller = children.first {
|
|
|
|
|
children.removeAll()
|
|
|
|
|
controller.view.removeFromSuperview()
|
|
|
|
|
}
|
2020-11-02 04:08:54 +01:00
|
|
|
|
|
|
|
|
|
if tableView.selectedRow == -1 {
|
|
|
|
|
var helpText = ""
|
2020-11-06 12:07:28 +01:00
|
|
|
|
if ExtensionPointManager.shared.availableExtensionPointTypes.count == 0 {
|
|
|
|
|
helpText = NSLocalizedString("You've added all available extension points.", comment: "Extension Explainer")
|
|
|
|
|
}
|
|
|
|
|
else if activeExtensionPoints.count == 0 {
|
2020-11-04 03:35:53 +01:00
|
|
|
|
helpText = NSLocalizedString("Add an extension by clicking the + button.", comment: "Extension Explainer")
|
2020-11-02 04:08:54 +01:00
|
|
|
|
} else {
|
2020-11-04 03:35:53 +01:00
|
|
|
|
helpText = NSLocalizedString("Select an extension or add a new extension point by clicking the + button.", comment: "Extension Explainer")
|
2020-11-02 04:08:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 03:35:53 +01:00
|
|
|
|
let textHostingController = NSHostingController(rootView: EnableExtensionPointHelpView(helpText: helpText, preferencesController: self))
|
2020-11-02 04:08:54 +01:00
|
|
|
|
addChild(textHostingController)
|
|
|
|
|
textHostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
detailView.addSubview(textHostingController.view)
|
2020-11-03 02:58:46 +01:00
|
|
|
|
detailView.addConstraints([
|
|
|
|
|
NSLayoutConstraint(item: textHostingController.view, attribute: .top, relatedBy: .equal, toItem: detailView, attribute: .top, multiplier: 1, constant: 1),
|
|
|
|
|
NSLayoutConstraint(item: textHostingController.view, attribute: .bottom, relatedBy: .equal, toItem: detailView, attribute: .bottom, multiplier: 1, constant: -deleteButton.frame.height),
|
|
|
|
|
NSLayoutConstraint(item: textHostingController.view, attribute: .width, relatedBy: .equal, toItem: detailView, attribute: .width, multiplier: 1, constant: 1)
|
|
|
|
|
])
|
2020-11-02 04:08:54 +01:00
|
|
|
|
}
|
2020-10-30 20:43:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func enableOauth1(_ provider: OAuth1SwiftProvider.Type, extensionPointType: ExtensionPoint.Type) {
|
|
|
|
|
callbackURL = provider.callbackURL
|
|
|
|
|
|
|
|
|
|
let oauth1 = provider.oauth1Swift
|
|
|
|
|
self.oauth = oauth1
|
|
|
|
|
oauth1.authorizeURLHandler = self
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
2020-10-30 20:43:42 +01:00
|
|
|
|
oauth1.authorize(withCallbackURL: callbackURL!) { [weak self] result in
|
|
|
|
|
guard let self = self else { return }
|
|
|
|
|
|
|
|
|
|
switch result {
|
|
|
|
|
case .success(let tokenSuccess):
|
|
|
|
|
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in
|
|
|
|
|
if case .failure(let error) = result {
|
|
|
|
|
self.presentError(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case .failure(let oauthSwiftError):
|
|
|
|
|
self.presentError(oauthSwiftError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.oauth?.cancel()
|
|
|
|
|
self.oauth = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func enableOauth2(_ provider: OAuth2SwiftProvider.Type, extensionPointType: ExtensionPoint.Type) {
|
|
|
|
|
callbackURL = provider.callbackURL
|
|
|
|
|
|
|
|
|
|
let oauth2 = provider.oauth2Swift
|
|
|
|
|
self.oauth = oauth2
|
|
|
|
|
oauth2.authorizeURLHandler = self
|
|
|
|
|
|
|
|
|
|
let oauth2Vars = provider.oauth2Vars
|
|
|
|
|
|
|
|
|
|
oauth2.authorize(withCallbackURL: callbackURL!, scope: oauth2Vars.scope, state: oauth2Vars.state, parameters: oauth2Vars.params) { [weak self] result in
|
|
|
|
|
guard let self = self else { return }
|
|
|
|
|
|
|
|
|
|
switch result {
|
|
|
|
|
case .success(let tokenSuccess):
|
|
|
|
|
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in
|
|
|
|
|
if case .failure(let error) = result {
|
|
|
|
|
self.presentError(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case .failure(let oauthSwiftError):
|
|
|
|
|
self.presentError(oauthSwiftError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.oauth?.cancel()
|
|
|
|
|
self.oauth = nil
|
|
|
|
|
}
|
2020-04-07 04:06:42 +02:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2020-11-04 03:35:53 +01:00
|
|
|
|
|
|
|
|
|
|