2020-04-07 04:06:42 +02:00
//
2020-04-07 22:25:33 +02:00
// E x t e n s i o n s P r e f e r e n c e s V i e w C o n t r o l l e r . s w i f t
2020-04-07 04:06:42 +02:00
// N e t N e w s W i r e
//
// C r e a t e d b y M a u r i c e P a r k e r o n 4 / 6 / 2 0 .
// C o p y r i g h t © 2 0 2 0 R a n c h e r o S o f t w a r e . A l l r i g h t s r e s e r v e d .
//
import AppKit
2020-10-30 20:43:42 +01:00
import SwiftUI
import AuthenticationServices
import OAuthSwift
import Secrets
2021-02-06 00:06:45 +01:00
protocol ExtensionPointPreferencesEnabler : AnyObject {
2020-10-30 20:43:42 +01:00
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
// F i x t a b l e V i e w f r a m e — f o r s o m e r e a s o n I B w a n t s i t 1 p t w i d e r t h a n t h e c l i p v i e w . T h i s l e a d s t o u n w a n t e d h o r i z o n t a l s c r o l l i n g .
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-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 ]
2020-12-08 23:54:34 +01:00
let alert = NSAlert ( )
alert . alertStyle = . warning
let prompt = NSLocalizedString ( " Deactivate " , comment : " Deactivate " )
alert . messageText = " \( prompt ) “ \( extensionPoint . title ) ”? "
let extensionPointTypeTitle = extensionPoint . extensionPointID . extensionPointType . title
alert . informativeText = NSLocalizedString ( " Are you sure you want to deactivate the \( extensionPointTypeTitle ) extension “ \( extensionPoint . title ) ”? " , comment : " Deactivate text " )
alert . addButton ( withTitle : NSLocalizedString ( " Deactivate " , comment : " Deactivate Extension " ) )
alert . addButton ( withTitle : NSLocalizedString ( " Cancel " , comment : " Cancel Deactivate Extension " ) )
alert . beginSheetModal ( for : view . window ! ) { [ weak self ] result in
if result = = NSApplication . ModalResponse . alertFirstButtonReturn {
ExtensionPointManager . shared . deactivateExtensionPoint ( extensionPoint . extensionPointID )
self ? . hideController ( )
}
}
2020-04-09 03:22:13 +02:00
}
2020-04-07 04:06:42 +02:00
}
// MARK: - N S T a b l e V i e w D a t a S o u r c e
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: - N S T a b l e V i e w D e l e g a t e
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: E x t e n s i o n P o i n t P r e f e r e n c e s V i e w C o n t r o l l e r
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: - P r i v a t e
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 {
2020-12-06 07:35:17 +01:00
helpText = NSLocalizedString ( " You've added all available extensions. " , comment : " Extension Explainer " )
2020-11-06 12:07:28 +01:00
}
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-12-06 07:35:17 +01:00
helpText = NSLocalizedString ( " Select an extension or add a new extension 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 {
2020-12-06 07:35:17 +01:00
helpText = NSLocalizedString ( " You've added all available extensions. " , comment : " Extension Explainer " )
2020-11-06 12:07:28 +01:00
}
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-12-06 07:35:17 +01:00
helpText = NSLocalizedString ( " Select an extension or add a new extension 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