From e206909237c60e08d90104a8a3414296db048136 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 14 Apr 2020 16:47:05 -0500 Subject: [PATCH] Refactor ExtensionPoints to make them easier to create in the future. --- .../Twitter/TwitterFeedProvider.swift | 10 +- Frameworks/Secrets/OAuth1SwiftProvider.swift | 16 +++ .../Secrets/Secrets.xcodeproj/project.pbxproj | 8 +- .../ExtensionPointAddViewController.swift | 88 +----------- ...ableBasic.xib => ExtensionPointEnable.xib} | 2 +- ...sionPointEnableBasicWindowController.swift | 94 +++++++++++-- ...ExtensionPointEnableWindowController.swift | 133 ++++++++++++++++++ ...ensionPointPreferencesViewController.swift | 9 +- NetNewsWire.xcodeproj/project.pbxproj | 32 ++--- Shared/ExtensionPoints/ExtensionPoint.swift | 19 ++- .../ExtensionPointIdentifer.swift | 18 +-- .../ExtensionPointManager.swift | 40 ++++-- .../ExtensionPoints/ExtensionPointType.swift | 95 ------------- .../SendToMarsEditCommand.swift | 15 +- .../SendToMicroBlogCommand.swift | 15 +- .../TwitterFeedProvider+Extensions.swift | 33 ++++- 16 files changed, 381 insertions(+), 246 deletions(-) create mode 100644 Frameworks/Secrets/OAuth1SwiftProvider.swift rename Mac/Preferences/ExtensionPoints/{ExtensionPointEnableBasic.xib => ExtensionPointEnable.xib} (98%) create mode 100644 Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift delete mode 100644 Shared/ExtensionPoints/ExtensionPointType.swift diff --git a/Frameworks/FeedProvider/Twitter/TwitterFeedProvider.swift b/Frameworks/FeedProvider/Twitter/TwitterFeedProvider.swift index 125e47b3c..b82f05b41 100644 --- a/Frameworks/FeedProvider/Twitter/TwitterFeedProvider.swift +++ b/Frameworks/FeedProvider/Twitter/TwitterFeedProvider.swift @@ -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 { + +} diff --git a/Frameworks/Secrets/OAuth1SwiftProvider.swift b/Frameworks/Secrets/OAuth1SwiftProvider.swift new file mode 100644 index 000000000..327aa34d7 --- /dev/null +++ b/Frameworks/Secrets/OAuth1SwiftProvider.swift @@ -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 } + +} diff --git a/Frameworks/Secrets/Secrets.xcodeproj/project.pbxproj b/Frameworks/Secrets/Secrets.xcodeproj/project.pbxproj index e31b78c2a..114bf499b 100644 --- a/Frameworks/Secrets/Secrets.xcodeproj/project.pbxproj +++ b/Frameworks/Secrets/Secrets.xcodeproj/project.pbxproj @@ -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 = ""; }; 514BB439243FFBFF0023B621 /* CredentialsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialsManager.swift; sourceTree = ""; }; 514BB43A243FFBFF0023B621 /* Credentials.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Credentials.swift; sourceTree = ""; }; + 5152BEF1244633FA00138380 /* OAuth1SwiftProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth1SwiftProvider.swift; sourceTree = ""; }; /* 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 = ""; }; @@ -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; diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift index 00b2e2282..d1c9f70e6 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift @@ -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! } } diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableBasic.xib b/Mac/Preferences/ExtensionPoints/ExtensionPointEnable.xib similarity index 98% rename from Mac/Preferences/ExtensionPoints/ExtensionPointEnableBasic.xib rename to Mac/Preferences/ExtensionPoints/ExtensionPointEnable.xib index 93c57f61e..197a8aeec 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableBasic.xib +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointEnable.xib @@ -5,7 +5,7 @@ - + diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableBasicWindowController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableBasicWindowController.swift index 48ab3ea44..5354fa1cb 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableBasicWindowController.swift +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableBasicWindowController.swift @@ -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 + } + + } + +} diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift new file mode 100644 index 000000000..38cebbf0c --- /dev/null +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift @@ -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 + } + + } + +} diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift index 79219ed4a..8445a2ddc 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift @@ -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()) diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index cf56e2c9b..24f795736 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -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 = ""; }; 515A5106243D0CCD0089E588 /* TwitterFeedProvider+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TwitterFeedProvider+Extensions.swift"; sourceTree = ""; }; - 515A5147243E64BA0089E588 /* ExtensionPointEnableBasicWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointEnableBasicWindowController.swift; sourceTree = ""; }; - 515A5167243E66910089E588 /* ExtensionPointEnableBasic.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointEnableBasic.xib; sourceTree = ""; }; + 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointEnableWindowController.swift; sourceTree = ""; }; + 515A5167243E66910089E588 /* ExtensionPointEnable.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointEnable.xib; sourceTree = ""; }; 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointDetail.xib; sourceTree = ""; }; 515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointDetailViewController.swift; sourceTree = ""; }; - 515A5173243E8FEA0089E588 /* ExtensionPointType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointType.swift; sourceTree = ""; }; 515A5176243E90200089E588 /* ExtensionPointIdentifer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointIdentifer.swift; sourceTree = ""; }; 515D4FCB2325815A00EE1167 /* SafariExt.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SafariExt.js; sourceTree = ""; }; 515D4FCD2325909200EE1167 /* NetNewsWire_iOS_ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_ShareExtension.entitlements; sourceTree = ""; }; @@ -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 */, diff --git a/Shared/ExtensionPoints/ExtensionPoint.swift b/Shared/ExtensionPoints/ExtensionPoint.swift index 9ba8e27be..44d5deb9f 100644 --- a/Shared/ExtensionPoints/ExtensionPoint.swift +++ b/Shared/ExtensionPoints/ExtensionPoint.swift @@ -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) + } } diff --git a/Shared/ExtensionPoints/ExtensionPointIdentifer.swift b/Shared/ExtensionPoints/ExtensionPointIdentifer.swift index eb00609e4..87cc5deac 100644 --- a/Shared/ExtensionPoints/ExtensionPointIdentifer.swift +++ b/Shared/ExtensionPoints/ExtensionPointIdentifer.swift @@ -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 } } diff --git a/Shared/ExtensionPoints/ExtensionPointManager.swift b/Shared/ExtensionPoints/ExtensionPointManager.swift index eb8cc5993..d0dd4453a 100644 --- a/Shared/ExtensionPoints/ExtensionPointManager.swift +++ b/Shared/ExtensionPoints/ExtensionPointManager.swift @@ -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: diff --git a/Shared/ExtensionPoints/ExtensionPointType.swift b/Shared/ExtensionPoints/ExtensionPointType.swift deleted file mode 100644 index 470759449..000000000 --- a/Shared/ExtensionPoints/ExtensionPointType.swift +++ /dev/null @@ -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) - } - -} diff --git a/Shared/ExtensionPoints/SendToMarsEditCommand.swift b/Shared/ExtensionPoints/SendToMarsEditCommand.swift index 25b094e82..a53811de9 100644 --- a/Shared/ExtensionPoints/SendToMarsEditCommand.swift +++ b/Shared/ExtensionPoints/SendToMarsEditCommand.swift @@ -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 { diff --git a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift index e304d26d3..739554615 100644 --- a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift +++ b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift @@ -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? { diff --git a/Shared/ExtensionPoints/TwitterFeedProvider+Extensions.swift b/Shared/ExtensionPoints/TwitterFeedProvider+Extensions.swift index 57ea02595..cebcca7e8 100644 --- a/Shared/ExtensionPoints/TwitterFeedProvider+Extensions.swift +++ b/Shared/ExtensionPoints/TwitterFeedProvider+Extensions.swift @@ -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" + ) + } + +}