Refactor ExtensionPoints to make them easier to create in the future.

This commit is contained in:
Maurice Parker 2020-04-14 16:47:05 -05:00
parent f5aac9516f
commit e206909237
16 changed files with 381 additions and 246 deletions

View File

@ -7,8 +7,10 @@
//
import Foundation
import Secrets
import OAuthSwift
public struct TwitterFeedProvider: FeedProvider {
public struct TwitterFeedProvider {
public var username: String
@ -17,3 +19,9 @@ public struct TwitterFeedProvider: FeedProvider {
}
}
// MARK: FeedProvider
extension TwitterFeedProvider: FeedProvider {
}

View File

@ -0,0 +1,16 @@
//
// OAuth1SwiftProvider.swift
// Secrets
//
// Created by Maurice Parker on 4/14/20.
// Copyright © 2020 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import OAuthSwift
public protocol OAuth1SwiftProvider {
static var oauth1Swift: OAuth1Swift { get }
}

View File

@ -15,6 +15,7 @@
514446ED2440030900EE752D /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514446EC2440030900EE752D /* Secrets.swift */; };
514BB43B243FFBFF0023B621 /* CredentialsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BB439243FFBFF0023B621 /* CredentialsManager.swift */; };
514BB43C243FFBFF0023B621 /* Credentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BB43A243FFBFF0023B621 /* Credentials.swift */; };
5152BEF2244633FA00138380 /* OAuth1SwiftProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5152BEF1244633FA00138380 /* OAuth1SwiftProvider.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -28,6 +29,7 @@
514BB41E243FFA640023B621 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
514BB439243FFBFF0023B621 /* CredentialsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialsManager.swift; sourceTree = "<group>"; };
514BB43A243FFBFF0023B621 /* Credentials.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Credentials.swift; sourceTree = "<group>"; };
5152BEF1244633FA00138380 /* OAuth1SwiftProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth1SwiftProvider.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -44,12 +46,13 @@
514BB410243FFA640023B621 = {
isa = PBXGroup;
children = (
514446EC2440030900EE752D /* Secrets.swift */,
514BB43A243FFBFF0023B621 /* Credentials.swift */,
514BB439243FFBFF0023B621 /* CredentialsManager.swift */,
514BB42B243FFAF50023B621 /* xcconfig */,
5152BEF1244633FA00138380 /* OAuth1SwiftProvider.swift */,
514BB41E243FFA640023B621 /* Info.plist */,
514BB41B243FFA640023B621 /* Products */,
514446EC2440030900EE752D /* Secrets.swift */,
514BB42B243FFAF50023B621 /* xcconfig */,
);
sourceTree = "<group>";
};
@ -180,6 +183,7 @@
files = (
514BB43C243FFBFF0023B621 /* Credentials.swift in Sources */,
514446ED2440030900EE752D /* Secrets.swift in Sources */,
5152BEF2244633FA00138380 /* OAuth1SwiftProvider.swift in Sources */,
514BB43B243FFBFF0023B621 /* CredentialsManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -7,21 +7,14 @@
//
import AppKit
import AuthenticationServices
import Secrets
import OAuthSwift
import FeedProvider
class ExtensionPointAddViewController: NSViewController {
@IBOutlet weak var tableView: NSTableView!
private var availableExtensionPointTypes = [ExtensionPointType]()
private var availableExtensionPointTypes = [ExtensionPoint.Type]()
private var extensionPointAddWindowController: NSWindowController?
private let callbackURL = URL(string: "vincodennw://")!
private var oauth: OAuthSwift?
init() {
super.init(nibName: "ExtensionPointAdd", bundle: nil)
}
@ -68,90 +61,19 @@ extension ExtensionPointAddViewController: NSTableViewDelegate {
}
func tableViewSelectionDidChange(_ notification: Notification) {
let selectedRow = tableView.selectedRow
guard selectedRow != -1 else {
return
}
let extensionPointType = availableExtensionPointTypes[selectedRow]
switch extensionPointType {
case .marsEdit, .microblog:
let windowController = ExtensionPointEnableBasicWindowController()
windowController.extensionPointType = extensionPointType
windowController.runSheetOnWindow(self.view.window!)
extensionPointAddWindowController = windowController
case .twitter:
let oauth = OAuth1Swift(
consumerKey: Secrets.twitterConsumerKey,
consumerSecret: Secrets.twitterConsumerSecret,
requestTokenUrl: "https://api.twitter.com/oauth/request_token",
authorizeUrl: "https://api.twitter.com/oauth/authorize",
accessTokenUrl: "https://api.twitter.com/oauth/access_token"
)
self.oauth = oauth
oauth.authorizeURLHandler = self
oauth.authorize(withCallbackURL: callbackURL) { result in
switch result {
case .success(let tokenSuccess):
// let token = tokenSuccess.credential.oauthToken
// let secret = tokenSuccess.credential.oauthTokenSecret
let screenName = tokenSuccess.parameters["screen_name"] as? String ?? ""
print("******************* \(screenName)")
case .failure(let oauthSwiftError):
NSApplication.shared.presentError(oauthSwiftError)
}
self.oauth?.cancel()
self.oauth = nil
}
}
let windowController = ExtensionPointEnableWindowController()
windowController.extensionPointType = extensionPointType
windowController.runSheetOnWindow(self.view.window!)
extensionPointAddWindowController = windowController
tableView.selectRowIndexes([], byExtendingSelection: false)
}
}
extension ExtensionPointAddViewController: 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 ExtensionPointAddViewController: ASWebAuthenticationPresentationContextProviding {
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return view.window!
}
}

View File

@ -5,7 +5,7 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ExtensionPointEnableBasicWindowController" customModule="NetNewsWire" customModuleProvider="target">
<customObject id="-2" userLabel="File's Owner" customClass="ExtensionPointEnableWindowController" customModule="NetNewsWire" customModuleProvider="target">
<connections>
<outlet property="descriptionLabel" destination="thC-ep-vXS" id="o9I-vp-z54"/>
<outlet property="imageView" destination="LSA-B8-aGZ" id="AN5-t1-d52"/>

View File

@ -7,16 +7,23 @@
//
import Cocoa
import AuthenticationServices
import OAuthSwift
import Secrets
class ExtensionPointEnableBasicWindowController: NSWindowController {
class ExtensionPointEnableWindowController: NSWindowController {
@IBOutlet weak var imageView: NSImageView!
@IBOutlet weak var titleLabel: NSTextField!
@IBOutlet weak var descriptionLabel: NSTextField!
var extensionPointType: ExtensionPointType?
private weak var hostWindow: NSWindow?
private let callbackURL = URL(string: "vincodennw://")!
private var oauth: OAuthSwift?
var extensionPointType: ExtensionPoint.Type?
convenience init() {
self.init(windowNibName: NSNib.Name("ExtensionPointEnableBasic"))
}
@ -46,16 +53,81 @@ class ExtensionPointEnableBasicWindowController: NSWindowController {
@IBAction func enable(_ sender: Any) {
guard let extensionPointType = extensionPointType else { return }
switch extensionPointType {
case .marsEdit:
ExtensionPointManager.shared.activateExtensionPoint(ExtensionPointIdentifer.marsEdit)
case .microblog:
ExtensionPointManager.shared.activateExtensionPoint(ExtensionPointIdentifer.microblog)
default:
assertionFailure("Unknown extension point.")
if let oauth1 = extensionPointType as? OAuth1SwiftProvider.Type {
enableOauth1(oauth1)
} else {
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType)
hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.OK)
}
hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.OK)
}
}
extension ExtensionPointEnableWindowController: 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 ExtensionPointEnableWindowController: ASWebAuthenticationPresentationContextProviding {
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return hostWindow!
}
}
private extension ExtensionPointEnableWindowController {
func enableOauth1(_ provider: OAuth1SwiftProvider.Type) {
let oauth1 = provider.oauth1Swift
self.oauth = oauth1
oauth1.authorizeURLHandler = self
oauth1.authorize(withCallbackURL: callbackURL) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let tokenSuccess):
// let token = tokenSuccess.credential.oauthToken
// let secret = tokenSuccess.credential.oauthTokenSecret
let screenName = tokenSuccess.parameters["screen_name"] as? String ?? ""
print("******************* \(screenName)")
self.hostWindow!.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
case .failure(let oauthSwiftError):
NSApplication.shared.presentError(oauthSwiftError)
}
self.oauth?.cancel()
self.oauth = nil
}
}
}

View File

@ -0,0 +1,133 @@
//
// ExtensionPointEnableWindowController.swift
// NetNewsWire
//
// Created by Maurice Parker on 4/8/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import Cocoa
import AuthenticationServices
import OAuthSwift
import Secrets
class ExtensionPointEnableWindowController: NSWindowController {
@IBOutlet weak var imageView: NSImageView!
@IBOutlet weak var titleLabel: NSTextField!
@IBOutlet weak var descriptionLabel: NSTextField!
private weak var hostWindow: NSWindow?
private let callbackURL = URL(string: "vincodennw://")!
private var oauth: OAuthSwift?
var extensionPointType: ExtensionPoint.Type?
convenience init() {
self.init(windowNibName: NSNib.Name("ExtensionPointEnable"))
}
override func windowDidLoad() {
super.windowDidLoad()
guard let extensionPointType = extensionPointType else { return }
imageView.image = extensionPointType.templateImage
titleLabel.stringValue = extensionPointType.title
descriptionLabel.attributedStringValue = extensionPointType.description
}
// MARK: API
func runSheetOnWindow(_ hostWindow: NSWindow) {
self.hostWindow = hostWindow
hostWindow.beginSheet(window!)
}
// MARK: Actions
@IBAction func cancel(_ sender: Any) {
hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.cancel)
}
@IBAction func enable(_ sender: Any) {
guard let extensionPointType = extensionPointType else { return }
if let oauth1 = extensionPointType as? OAuth1SwiftProvider.Type {
enableOauth1(oauth1)
} else {
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType)
hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.OK)
}
}
}
extension ExtensionPointEnableWindowController: 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 ExtensionPointEnableWindowController: ASWebAuthenticationPresentationContextProviding {
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return hostWindow!
}
}
private extension ExtensionPointEnableWindowController {
func enableOauth1(_ provider: OAuth1SwiftProvider.Type) {
let oauth1 = provider.oauth1Swift
self.oauth = oauth1
oauth1.authorizeURLHandler = self
oauth1.authorize(withCallbackURL: callbackURL) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let tokenSuccess):
// let token = tokenSuccess.credential.oauthToken
// let secret = tokenSuccess.credential.oauthTokenSecret
let screenName = tokenSuccess.parameters["screen_name"] as? String ?? ""
print("******************* \(screenName)")
self.hostWindow!.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
case .failure(let oauthSwiftError):
NSApplication.shared.presentError(oauthSwiftError)
}
self.oauth?.cancel()
self.oauth = nil
}
}
}

View File

@ -24,15 +24,12 @@ final class ExtensionPointPreferencesViewController: NSViewController {
NotificationCenter.default.addObserver(self, selector: #selector(activeExtensionPointsDidChange(_:)), name: .ActiveExtensionPointsDidChange, object: nil)
showController(ExtensionPointAddViewController())
// 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
activeExtensionPointIDs = Array(ExtensionPointManager.shared.activeExtensionPoints.keys)
tableView.reloadData()
showDefaultView()
}
@IBAction func enableExtensionPoints(_ sender: Any) {
@ -104,6 +101,10 @@ extension ExtensionPointPreferencesViewController: NSTableViewDelegate {
private extension ExtensionPointPreferencesViewController {
@objc func activeExtensionPointsDidChange(_ note: Notification) {
showDefaultView()
}
func showDefaultView() {
activeExtensionPointIDs = Array(ExtensionPointManager.shared.activeExtensionPoints.keys).sorted(by: { $0.title < $1.title })
tableView.reloadData()
showController(ExtensionPointAddViewController())

View File

@ -128,21 +128,18 @@
515A50E7243D07A90089E588 /* ExtensionPointManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A50E5243D07A90089E588 /* ExtensionPointManager.swift */; };
515A5107243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5106243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift */; };
515A5108243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5106243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift */; };
515A5148243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5147243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift */; };
515A5149243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5147243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift */; };
515A5168243E66910089E588 /* ExtensionPointEnableBasic.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A5167243E66910089E588 /* ExtensionPointEnableBasic.xib */; };
515A5169243E66910089E588 /* ExtensionPointEnableBasic.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A5167243E66910089E588 /* ExtensionPointEnableBasic.xib */; };
515A5148243E64BA0089E588 /* ExtensionPointEnableWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */; };
515A5149243E64BA0089E588 /* ExtensionPointEnableWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */; };
515A5168243E66910089E588 /* ExtensionPointEnable.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A5167243E66910089E588 /* ExtensionPointEnable.xib */; };
515A5169243E66910089E588 /* ExtensionPointEnable.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A5167243E66910089E588 /* ExtensionPointEnable.xib */; };
515A516E243E7F950089E588 /* ExtensionPointDetail.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */; };
515A516F243E7F950089E588 /* ExtensionPointDetail.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */; };
515A5171243E802B0089E588 /* ExtensionPointDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */; };
515A5172243E802B0089E588 /* ExtensionPointDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */; };
515A5174243E8FEA0089E588 /* ExtensionPointType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5173243E8FEA0089E588 /* ExtensionPointType.swift */; };
515A5175243E8FEA0089E588 /* ExtensionPointType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5173243E8FEA0089E588 /* ExtensionPointType.swift */; };
515A5177243E90200089E588 /* ExtensionPointIdentifer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5176243E90200089E588 /* ExtensionPointIdentifer.swift */; };
515A5178243E90200089E588 /* ExtensionPointIdentifer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5176243E90200089E588 /* ExtensionPointIdentifer.swift */; };
515A517B243E90260089E588 /* ExtensionPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43F6243D035C009F70C3 /* ExtensionPoint.swift */; };
515A517C243E90260089E588 /* ExtensionPointManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A50E5243D07A90089E588 /* ExtensionPointManager.swift */; };
515A517D243E90260089E588 /* ExtensionPointType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5173243E8FEA0089E588 /* ExtensionPointType.swift */; };
515A517E243E90260089E588 /* SendToMarsEditCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A1500420048DDF0046AD9A /* SendToMarsEditCommand.swift */; };
515A517F243E90260089E588 /* SendToMicroBlogCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A14FF220048CA70046AD9A /* SendToMicroBlogCommand.swift */; };
515A5180243E90260089E588 /* TwitterFeedProvider+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5106243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift */; };
@ -1453,11 +1450,10 @@
51554BFC228B6EB50055115A /* SyncDatabase.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SyncDatabase.xcodeproj; path = Frameworks/SyncDatabase/SyncDatabase.xcodeproj; sourceTree = SOURCE_ROOT; };
515A50E5243D07A90089E588 /* ExtensionPointManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointManager.swift; sourceTree = "<group>"; };
515A5106243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TwitterFeedProvider+Extensions.swift"; sourceTree = "<group>"; };
515A5147243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointEnableBasicWindowController.swift; sourceTree = "<group>"; };
515A5167243E66910089E588 /* ExtensionPointEnableBasic.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointEnableBasic.xib; sourceTree = "<group>"; };
515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointEnableWindowController.swift; sourceTree = "<group>"; };
515A5167243E66910089E588 /* ExtensionPointEnable.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointEnable.xib; sourceTree = "<group>"; };
515A516D243E7F950089E588 /* ExtensionPointDetail.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointDetail.xib; sourceTree = "<group>"; };
515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointDetailViewController.swift; sourceTree = "<group>"; };
515A5173243E8FEA0089E588 /* ExtensionPointType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointType.swift; sourceTree = "<group>"; };
515A5176243E90200089E588 /* ExtensionPointIdentifer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointIdentifer.swift; sourceTree = "<group>"; };
515D4FCB2325815A00EE1167 /* SafariExt.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SafariExt.js; sourceTree = "<group>"; };
515D4FCD2325909200EE1167 /* NetNewsWire_iOS_ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_ShareExtension.entitlements; sourceTree = "<group>"; };
@ -1940,7 +1936,6 @@
510C43F6243D035C009F70C3 /* ExtensionPoint.swift */,
515A5176243E90200089E588 /* ExtensionPointIdentifer.swift */,
515A50E5243D07A90089E588 /* ExtensionPointManager.swift */,
515A5173243E8FEA0089E588 /* ExtensionPointType.swift */,
84A1500420048DDF0046AD9A /* SendToMarsEditCommand.swift */,
84A14FF220048CA70046AD9A /* SendToMicroBlogCommand.swift */,
515A5106243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift */,
@ -1962,8 +1957,8 @@
510C43EC243C0973009F70C3 /* ExtensionPointAdd.xib */,
510C43F2243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift */,
510C43EF243C0A80009F70C3 /* ExtensionPointAddViewController.swift */,
515A5167243E66910089E588 /* ExtensionPointEnableBasic.xib */,
515A5147243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift */,
515A5167243E66910089E588 /* ExtensionPointEnable.xib */,
515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */,
51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */,
515A516D243E7F950089E588 /* ExtensionPointDetail.xib */,
515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */,
@ -3777,7 +3772,7 @@
65ED4057235DEF6C0081F399 /* AccountsDetail.xib in Resources */,
65ED4058235DEF6C0081F399 /* main.js in Resources */,
65ED40A1235DEFF00081F399 /* container-migration.plist in Resources */,
515A5169243E66910089E588 /* ExtensionPointEnableBasic.xib in Resources */,
515A5169243E66910089E588 /* ExtensionPointEnable.xib in Resources */,
65ED4059235DEF6C0081F399 /* AccountsAddLocal.xib in Resources */,
65ED405A235DEF6C0081F399 /* main_mac.js in Resources */,
65ED405B235DEF6C0081F399 /* KeyboardShortcuts.html in Resources */,
@ -3871,7 +3866,7 @@
5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */,
5142194B2353C1CF00E07E2C /* main_mac.js in Resources */,
84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */,
515A5168243E66910089E588 /* ExtensionPointEnableBasic.xib in Resources */,
515A5168243E66910089E588 /* ExtensionPointEnable.xib in Resources */,
5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */,
844B5B691FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist in Resources */,
5103A9F4242258C600410853 /* AccountsAddCloudKit.xib in Resources */,
@ -4087,7 +4082,7 @@
65ED3FC7235DEF6C0081F399 /* Reachability.swift in Sources */,
65ED3FC8235DEF6C0081F399 /* SidebarCellLayout.swift in Sources */,
65ED3FC9235DEF6C0081F399 /* SmartFeedPasteboardWriter.swift in Sources */,
515A5149243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift in Sources */,
515A5149243E64BA0089E588 /* ExtensionPointEnableWindowController.swift in Sources */,
65ED3FCA235DEF6C0081F399 /* SmartFeedsController.swift in Sources */,
515A5178243E90200089E588 /* ExtensionPointIdentifer.swift in Sources */,
65ED3FCB235DEF6C0081F399 /* SidebarViewController.swift in Sources */,
@ -4139,7 +4134,6 @@
65ED3FF7235DEF6C0081F399 /* SearchFeedDelegate.swift in Sources */,
65ED3FF8235DEF6C0081F399 /* ErrorHandler.swift in Sources */,
65ED3FF9235DEF6C0081F399 /* ActivityManager.swift in Sources */,
515A5175243E8FEA0089E588 /* ExtensionPointType.swift in Sources */,
65ED3FFA235DEF6C0081F399 /* WebFeedInspectorViewController.swift in Sources */,
65ED3FFB235DEF6C0081F399 /* AccountsReaderAPIWindowController.swift in Sources */,
65ED3FFC235DEF6C0081F399 /* AccountsAddLocalWindowController.swift in Sources */,
@ -4362,7 +4356,6 @@
514219372352510100E07E2C /* ImageScrollView.swift in Sources */,
516AE9B32371C372007DEEAA /* MasterFeedTableViewSectionHeaderLayout.swift in Sources */,
51DC370B2405BC9A0095D371 /* PreloadedWebView.swift in Sources */,
515A517D243E90260089E588 /* ExtensionPointType.swift in Sources */,
C5A6ED5223C9AF4300AB6BE2 /* TitleActivityItemSource.swift in Sources */,
51DC37092402F1470095D371 /* MasterFeedDataSourceOperation.swift in Sources */,
515A517E243E90260089E588 /* SendToMarsEditCommand.swift in Sources */,
@ -4478,7 +4471,7 @@
55E15BCC229D65A900D6602A /* AccountsReaderAPIWindowController.swift in Sources */,
5144EA382279FC6200D19003 /* AccountsAddLocalWindowController.swift in Sources */,
84AD1EAA2031617300BC20B7 /* PasteboardFolder.swift in Sources */,
515A5148243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift in Sources */,
515A5148243E64BA0089E588 /* ExtensionPointEnableWindowController.swift in Sources */,
5103A9F724225E4C00410853 /* AccountsAddCloudKitWindowController.swift in Sources */,
5144EA51227B8E4500D19003 /* AccountsFeedbinWindowController.swift in Sources */,
84AD1EBC2032AF5C00BC20B7 /* SidebarOutlineDataSource.swift in Sources */,
@ -4526,7 +4519,6 @@
510C43F0243C0A80009F70C3 /* ExtensionPointAddViewController.swift in Sources */,
849A97781ED9EC04007D329B /* TimelineCellLayout.swift in Sources */,
84E8E0EB202F693600562D8F /* DetailWebView.swift in Sources */,
515A5174243E8FEA0089E588 /* ExtensionPointType.swift in Sources */,
849A976C1ED9EBC8007D329B /* TimelineTableRowView.swift in Sources */,
849A977B1ED9EC04007D329B /* UnreadIndicatorView.swift in Sources */,
51FA73A72332BE880090D516 /* ExtractedArticle.swift in Sources */,

View File

@ -11,7 +11,11 @@ import RSCore
protocol ExtensionPoint {
var extensionPointType: ExtensionPointType { get }
static var isSinglton: Bool { get }
static var title: String { get }
static var templateImage: RSImage { get }
static var description: NSAttributedString { get }
var extensionPointID: ExtensionPointIdentifer { get }
}
@ -21,5 +25,18 @@ extension ExtensionPoint {
var title: String {
return extensionPointID.title
}
static func makeAttrString(_ text: String) -> NSMutableAttributedString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attrs = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: NSFont.systemFont(ofSize: NSFont.systemFontSize),
NSAttributedString.Key.foregroundColor: NSColor.textColor
]
return NSMutableAttributedString(string: text, attributes: attrs)
}
}

View File

@ -7,8 +7,10 @@
//
import Foundation
import FeedProvider
import RSCore
enum ExtensionPointIdentifer: Hashable {
case marsEdit
case microblog
@ -16,12 +18,10 @@ enum ExtensionPointIdentifer: Hashable {
var title: String {
switch self {
case .marsEdit:
return ExtensionPointType.marsEdit.title
case .microblog:
return ExtensionPointType.microblog.title
case .twitter(let username):
return "\(ExtensionPointType.microblog.title) (\(username))"
return "\(type.title) (\(username)"
default:
return type.title
}
}
@ -33,14 +33,14 @@ enum ExtensionPointIdentifer: Hashable {
return type.description
}
var type: ExtensionPointType {
var type: ExtensionPoint.Type {
switch self {
case .marsEdit:
return ExtensionPointType.marsEdit
return SendToMarsEditCommand.self
case .microblog:
return ExtensionPointType.microblog
return SendToMicroBlogCommand.self
case .twitter:
return ExtensionPointType.twitter
return TwitterFeedProvider.self
}
}

View File

@ -19,14 +19,14 @@ final class ExtensionPointManager {
static let shared = ExtensionPointManager()
var activeExtensionPoints = [ExtensionPointIdentifer: ExtensionPoint]()
let possibleExtensionPointTypes: [ExtensionPointType]
var availableExtensionPointTypes: [ExtensionPointType] {
let possibleExtensionPointTypes: [ExtensionPoint.Type]
var availableExtensionPointTypes: [ExtensionPoint.Type] {
let activeExtensionPointTypes = Set(activeExtensionPoints.keys.compactMap({ $0.type }))
var available = [ExtensionPointType]()
let activeExtensionPointTypes = activeExtensionPoints.keys.compactMap({ ObjectIdentifier($0.type) })
var available = [ExtensionPoint.Type]()
for possibleExtensionPointType in possibleExtensionPointTypes {
if possibleExtensionPointType.isSinglton {
if !activeExtensionPointTypes.contains(possibleExtensionPointType) {
if !activeExtensionPointTypes.contains(ObjectIdentifier(possibleExtensionPointType)) {
available.append(possibleExtensionPointType)
}
} else {
@ -48,23 +48,25 @@ final class ExtensionPointManager {
init() {
#if os(macOS)
#if DEBUG
possibleExtensionPointTypes = [.marsEdit, .microblog, .twitter]
possibleExtensionPointTypes = [SendToMarsEditCommand.self, SendToMicroBlogCommand.self, TwitterFeedProvider.self]
#else
possibleExtensionPointTypes = [.marsEdit, .microblog, .twitter]
possibleExtensionPointTypes = [SendToMarsEditCommand.self, SendToMicroBlogCommand.self, TwitterFeedProvider.self]
#endif
#else
#if DEBUG
possibleExtensionPointTypes = [.twitter]
possibleExtensionPointTypes = [TwitterFeedProvider.self]
#else
possibleExtensionPointTypes = [.twitter]
possibleExtensionPointTypes = [TwitterFeedProvider.self]
#endif
#endif
loadExtensionPoints()
}
func activateExtensionPoint(_ extensionPointID: ExtensionPointIdentifer) {
activeExtensionPoints[extensionPointID] = extensionPoint(for: extensionPointID)
saveExtensionPointIDs()
func activateExtensionPoint(_ extensionPointType: ExtensionPoint.Type) {
if let extensionPoint = self.extensionPoint(for: extensionPointType) {
activeExtensionPoints[extensionPoint.extensionPointID] = extensionPoint
saveExtensionPointIDs()
}
}
func deactivateExtensionPoint(_ extensionPointID: ExtensionPointIdentifer) {
@ -91,6 +93,20 @@ private extension ExtensionPointManager {
NotificationCenter.default.post(name: .ActiveExtensionPointsDidChange, object: nil, userInfo: nil)
}
func extensionPoint(for extensionPointType: ExtensionPoint.Type) -> ExtensionPoint? {
switch extensionPointType {
case is SendToMarsEditCommand.Type:
return SendToMarsEditCommand()
case is SendToMicroBlogCommand.Type:
return SendToMicroBlogCommand()
// case is TwitterFeedProvider.Type:
// return TwitterFeedProvider(username: username)
default:
assertionFailure("Unrecognized Extension Point Type.")
}
return nil
}
func extensionPoint(for extensionPointID: ExtensionPointIdentifer) -> ExtensionPoint {
switch extensionPointID {
case .marsEdit:

View File

@ -1,95 +0,0 @@
//
// ExtensionPointType.swift
// NetNewsWire
//
// Created by Maurice Parker on 4/8/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import Foundation
import RSCore
enum ExtensionPointType {
case marsEdit
case microblog
case twitter
var isSinglton: Bool {
switch self {
case .marsEdit, .microblog:
return true
default:
return false
}
}
var title: String {
switch self {
case .marsEdit:
return NSLocalizedString("MarsEdit", comment: "MarsEdit")
case .microblog:
return NSLocalizedString("Micro.blog", comment: "Micro.blog")
case .twitter:
return NSLocalizedString("Twitter", comment: "Twitter")
}
}
var templateImage: RSImage {
switch self {
case .marsEdit:
return AppAssets.extensionPointMarsEdit
case .microblog:
return AppAssets.extensionPointMicroblog
case .twitter:
return AppAssets.extensionPointTwitter
}
}
var description: NSAttributedString {
switch self {
case .marsEdit:
let attrString = makeAttrString("This extension enables share menu functionality to send selected article text to MarsEdit. You need the MarsEdit application for this to work.")
let range = NSRange(location: 81, length: 8)
attrString.beginEditing()
attrString.addAttribute(NSAttributedString.Key.link, value: "https://red-sweater.com/marsedit/", range: range)
attrString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.systemBlue, range: range)
attrString.endEditing()
return attrString
case .microblog:
let attrString = makeAttrString("This extension enables share menu functionality to send selected article text to Micro.blog. You need the Micro.blog application for this to work.")
let range = NSRange(location: 81, length: 10)
attrString.beginEditing()
attrString.addAttribute(NSAttributedString.Key.link, value: "https://micro.blog", range: range)
attrString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.systemBlue, range: range)
attrString.endEditing()
return attrString
case .twitter:
let attrString = makeAttrString("This extension enables you to subscribe to Twitter URL's as if they were RSS feeds.")
let range = NSRange(location: 43, length: 7)
attrString.beginEditing()
attrString.addAttribute(NSAttributedString.Key.link, value: "https://twitter.com", range: range)
attrString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.systemBlue, range: range)
attrString.endEditing()
return attrString
}
}
}
private extension ExtensionPointType {
func makeAttrString(_ text: String) -> NSMutableAttributedString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attrs = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: NSFont.systemFont(ofSize: NSFont.systemFontSize),
NSAttributedString.Key.foregroundColor: NSColor.textColor
]
return NSMutableAttributedString(string: text, attributes: attrs)
}
}

View File

@ -12,14 +12,25 @@ import Articles
final class SendToMarsEditCommand: ExtensionPoint, SendToCommand {
let extensionPointType = ExtensionPointType.marsEdit
static var isSinglton = true
static var title = NSLocalizedString("MarsEdit", comment: "MarsEdit")
static var templateImage = AppAssets.extensionPointMarsEdit
static var description: NSAttributedString = {
let attrString = SendToMarsEditCommand.makeAttrString("This extension enables share menu functionality to send selected article text to MarsEdit. You need the MarsEdit application for this to work.")
let range = NSRange(location: 81, length: 8)
attrString.beginEditing()
attrString.addAttribute(NSAttributedString.Key.link, value: "https://red-sweater.com/marsedit/", range: range)
attrString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.systemBlue, range: range)
attrString.endEditing()
return attrString
}()
let extensionPointID = ExtensionPointIdentifer.marsEdit
var image: NSImage? {
return appToUse()?.icon ?? nil
}
private let marsEditApps = [UserApp(bundleID: "com.red-sweater.marsedit4"), UserApp(bundleID: "com.red-sweater.marsedit")]
func canSendObject(_ object: Any?, selectedText: String?) -> Bool {

View File

@ -14,7 +14,20 @@ import RSCore
final class SendToMicroBlogCommand: ExtensionPoint, SendToCommand {
let extensionPointType = ExtensionPointType.microblog
static var isSinglton: Bool = true
static var title: String = NSLocalizedString("Micro.blog", comment: "Micro.blog")
static var templateImage = AppAssets.extensionPointMicroblog
static var description: NSAttributedString = {
let attrString = SendToMicroBlogCommand.makeAttrString("This extension enables share menu functionality to send selected article text to Micro.blog. You need the Micro.blog application for this to work.")
let range = NSRange(location: 81, length: 10)
attrString.beginEditing()
attrString.addAttribute(NSAttributedString.Key.link, value: "https://micro.blog", range: range)
attrString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.systemBlue, range: range)
attrString.endEditing()
return attrString
}()
let extensionPointID = ExtensionPointIdentifer.microblog
var image: NSImage? {

View File

@ -9,15 +9,40 @@
import Foundation
import FeedProvider
import RSCore
import OAuthSwift
import Secrets
extension TwitterFeedProvider: ExtensionPoint {
var extensionPointType: ExtensionPointType {
return ExtensionPointType.twitter
}
static var isSinglton = false
static var title = NSLocalizedString("Twitter", comment: "Twitter")
static var templateImage = AppAssets.extensionPointTwitter
static var description: NSAttributedString = {
let attrString = TwitterFeedProvider.makeAttrString("This extension enables you to subscribe to Twitter URL's as if they were RSS feeds.")
let range = NSRange(location: 43, length: 7)
attrString.beginEditing()
attrString.addAttribute(NSAttributedString.Key.link, value: "https://twitter.com", range: range)
attrString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.systemBlue, range: range)
attrString.endEditing()
return attrString
}()
var extensionPointID: ExtensionPointIdentifer {
return ExtensionPointIdentifer.twitter(username)
}
}
extension TwitterFeedProvider: OAuth1SwiftProvider {
public static var oauth1Swift: OAuth1Swift {
return OAuth1Swift(
consumerKey: Secrets.twitterConsumerKey,
consumerSecret: Secrets.twitterConsumerSecret,
requestTokenUrl: "https://api.twitter.com/oauth/request_token",
authorizeUrl: "https://api.twitter.com/oauth/authorize",
accessTokenUrl: "https://api.twitter.com/oauth/access_token"
)
}
}