2020-04-07 22:25:33 +02:00
|
|
|
//
|
|
|
|
// ExtensionPointManager.swift
|
|
|
|
// NetNewsWire
|
|
|
|
//
|
|
|
|
// Created by Maurice Parker on 4/7/20.
|
|
|
|
// Copyright © 2020 Ranchero Software. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
2020-04-16 18:15:39 +02:00
|
|
|
import Account
|
2020-04-07 22:25:33 +02:00
|
|
|
import RSCore
|
2020-04-15 05:33:05 +02:00
|
|
|
import OAuthSwift
|
2020-04-07 22:25:33 +02:00
|
|
|
|
2020-04-09 03:22:13 +02:00
|
|
|
public extension Notification.Name {
|
|
|
|
static let ActiveExtensionPointsDidChange = Notification.Name(rawValue: "ActiveExtensionPointsDidChange")
|
|
|
|
}
|
|
|
|
|
2020-05-03 20:23:36 +02:00
|
|
|
public enum ExtensionPointManagerError: LocalizedError {
|
|
|
|
case unableToCreate
|
|
|
|
|
|
|
|
public var localizedDescription: String {
|
|
|
|
switch self {
|
|
|
|
case .unableToCreate:
|
|
|
|
return NSLocalizedString("Unable to create extension.", comment: "Unable to create extension")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-16 22:06:56 +02:00
|
|
|
final class ExtensionPointManager: FeedProviderManagerDelegate {
|
2020-04-07 22:25:33 +02:00
|
|
|
|
|
|
|
static let shared = ExtensionPointManager()
|
2020-04-08 20:46:15 +02:00
|
|
|
|
|
|
|
var activeExtensionPoints = [ExtensionPointIdentifer: ExtensionPoint]()
|
2020-04-14 23:47:05 +02:00
|
|
|
let possibleExtensionPointTypes: [ExtensionPoint.Type]
|
|
|
|
var availableExtensionPointTypes: [ExtensionPoint.Type] {
|
2020-04-09 03:22:13 +02:00
|
|
|
|
2020-04-15 06:03:08 +02:00
|
|
|
let activeExtensionPointTypes = activeExtensionPoints.keys.compactMap({ ObjectIdentifier($0.extensionPointType) })
|
2020-04-14 23:47:05 +02:00
|
|
|
var available = [ExtensionPoint.Type]()
|
2020-04-09 03:22:13 +02:00
|
|
|
for possibleExtensionPointType in possibleExtensionPointTypes {
|
2020-04-22 21:16:50 +02:00
|
|
|
if !(AppDefaults.isDeveloperBuild && possibleExtensionPointType.isDeveloperBuildRestricted) {
|
|
|
|
if possibleExtensionPointType.isSinglton {
|
|
|
|
if !activeExtensionPointTypes.contains(ObjectIdentifier(possibleExtensionPointType)) {
|
|
|
|
available.append(possibleExtensionPointType)
|
|
|
|
}
|
|
|
|
} else {
|
2020-04-09 03:22:13 +02:00
|
|
|
available.append(possibleExtensionPointType)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return available
|
2020-04-17 01:19:49 +02:00
|
|
|
|
2020-04-09 03:22:13 +02:00
|
|
|
}
|
2020-04-08 20:46:15 +02:00
|
|
|
|
|
|
|
var activeSendToCommands: [SendToCommand] {
|
|
|
|
return activeExtensionPoints.values.compactMap({ return $0 as? SendToCommand })
|
|
|
|
}
|
|
|
|
|
|
|
|
var activeFeedProviders: [FeedProvider] {
|
|
|
|
return activeExtensionPoints.values.compactMap({ return $0 as? FeedProvider })
|
|
|
|
}
|
2020-04-07 22:25:33 +02:00
|
|
|
|
2020-05-03 00:21:01 +02:00
|
|
|
var isTwitterEnabled: Bool {
|
|
|
|
return activeExtensionPoints.values.contains(where: { $0 is TwitterFeedProvider })
|
|
|
|
}
|
|
|
|
|
2020-05-03 02:38:57 +02:00
|
|
|
var isRedditEnabled: Bool {
|
|
|
|
return activeExtensionPoints.values.contains(where: { $0 is RedditFeedProvider })
|
|
|
|
}
|
|
|
|
|
2020-04-07 22:25:33 +02:00
|
|
|
init() {
|
|
|
|
#if os(macOS)
|
|
|
|
#if DEBUG
|
2020-05-03 02:38:57 +02:00
|
|
|
possibleExtensionPointTypes = [SendToMarsEditCommand.self, SendToMicroBlogCommand.self, TwitterFeedProvider.self, RedditFeedProvider.self]
|
2020-04-07 22:25:33 +02:00
|
|
|
#else
|
2020-05-03 02:38:57 +02:00
|
|
|
possibleExtensionPointTypes = [SendToMarsEditCommand.self, SendToMicroBlogCommand.self, TwitterFeedProvider.self, RedditFeedProvider.self]
|
2020-04-07 22:25:33 +02:00
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#if DEBUG
|
2020-05-03 02:38:57 +02:00
|
|
|
possibleExtensionPointTypes = [TwitterFeedProvider.self, RedditFeedProvider.self]
|
2020-04-07 22:25:33 +02:00
|
|
|
#else
|
2020-05-03 02:38:57 +02:00
|
|
|
possibleExtensionPointTypes = [TwitterFeedProvider.self, RedditFeedProvider.self]
|
2020-04-07 22:25:33 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
2020-04-09 03:22:13 +02:00
|
|
|
loadExtensionPoints()
|
2020-04-08 20:46:15 +02:00
|
|
|
}
|
|
|
|
|
2020-05-03 20:23:36 +02:00
|
|
|
func activateExtensionPoint(_ extensionPointType: ExtensionPoint.Type, tokenSuccess: OAuthSwift.TokenSuccess? = nil, completion: @escaping (Result<Void, Error>) -> Void) {
|
|
|
|
self.extensionPoint(for: extensionPointType, tokenSuccess: tokenSuccess) { result in
|
|
|
|
switch result {
|
|
|
|
case .success(let extensionPoint):
|
|
|
|
self.activeExtensionPoints[extensionPoint.extensionPointID] = extensionPoint
|
|
|
|
self.saveExtensionPointIDs()
|
|
|
|
completion(.success(()))
|
|
|
|
case .failure(let error):
|
|
|
|
completion(.failure(error))
|
|
|
|
}
|
2020-04-14 23:47:05 +02:00
|
|
|
}
|
2020-04-08 20:46:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func deactivateExtensionPoint(_ extensionPointID: ExtensionPointIdentifer) {
|
|
|
|
activeExtensionPoints[extensionPointID] = nil
|
|
|
|
saveExtensionPointIDs()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private extension ExtensionPointManager {
|
|
|
|
|
2020-04-09 03:22:13 +02:00
|
|
|
func loadExtensionPoints() {
|
2020-04-08 20:46:15 +02:00
|
|
|
if let extensionPointUserInfos = AppDefaults.activeExtensionPointIDs {
|
|
|
|
for extensionPointUserInfo in extensionPointUserInfos {
|
|
|
|
if let extensionPointID = ExtensionPointIdentifer(userInfo: extensionPointUserInfo) {
|
|
|
|
activeExtensionPoints[extensionPointID] = extensionPoint(for: extensionPointID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func saveExtensionPointIDs() {
|
|
|
|
AppDefaults.activeExtensionPointIDs = activeExtensionPoints.keys.map({ $0.userInfo })
|
2020-04-09 03:22:13 +02:00
|
|
|
NotificationCenter.default.post(name: .ActiveExtensionPointsDidChange, object: nil, userInfo: nil)
|
2020-04-08 20:46:15 +02:00
|
|
|
}
|
|
|
|
|
2020-05-03 20:23:36 +02:00
|
|
|
func extensionPoint(for extensionPointType: ExtensionPoint.Type, tokenSuccess: OAuthSwift.TokenSuccess?, completion: @escaping (Result<ExtensionPoint, Error>) -> Void) {
|
2020-04-14 23:47:05 +02:00
|
|
|
switch extensionPointType {
|
2020-04-16 15:25:40 +02:00
|
|
|
#if os(macOS)
|
2020-04-14 23:47:05 +02:00
|
|
|
case is SendToMarsEditCommand.Type:
|
2020-05-03 20:23:36 +02:00
|
|
|
completion(.success(SendToMarsEditCommand()))
|
2020-04-14 23:47:05 +02:00
|
|
|
case is SendToMicroBlogCommand.Type:
|
2020-05-03 20:23:36 +02:00
|
|
|
completion(.success(SendToMicroBlogCommand()))
|
2020-04-16 15:25:40 +02:00
|
|
|
#endif
|
2020-04-15 05:33:05 +02:00
|
|
|
case is TwitterFeedProvider.Type:
|
2020-05-03 20:23:36 +02:00
|
|
|
if let tokenSuccess = tokenSuccess, let twitter = TwitterFeedProvider(tokenSuccess: tokenSuccess) {
|
|
|
|
completion(.success(twitter))
|
2020-04-15 05:33:05 +02:00
|
|
|
} else {
|
2020-05-03 20:23:36 +02:00
|
|
|
completion(.failure(ExtensionPointManagerError.unableToCreate))
|
2020-04-15 05:33:05 +02:00
|
|
|
}
|
2020-05-03 02:38:57 +02:00
|
|
|
case is RedditFeedProvider.Type:
|
|
|
|
if let tokenSuccess = tokenSuccess {
|
2020-05-03 20:23:36 +02:00
|
|
|
RedditFeedProvider.create(tokenSuccess: tokenSuccess) { result in
|
|
|
|
switch result {
|
|
|
|
case .success(let reddit):
|
|
|
|
completion(.success(reddit))
|
|
|
|
case .failure(let error):
|
|
|
|
completion(.failure(error))
|
|
|
|
}
|
|
|
|
}
|
2020-05-03 02:38:57 +02:00
|
|
|
} else {
|
2020-05-03 20:23:36 +02:00
|
|
|
completion(.failure(ExtensionPointManagerError.unableToCreate))
|
2020-05-03 02:38:57 +02:00
|
|
|
}
|
2020-04-14 23:47:05 +02:00
|
|
|
default:
|
|
|
|
assertionFailure("Unrecognized Extension Point Type.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-15 06:19:06 +02:00
|
|
|
func extensionPoint(for extensionPointID: ExtensionPointIdentifer) -> ExtensionPoint? {
|
2020-04-08 20:46:15 +02:00
|
|
|
switch extensionPointID {
|
2020-04-16 15:25:40 +02:00
|
|
|
#if os(macOS)
|
2020-04-08 20:46:15 +02:00
|
|
|
case .marsEdit:
|
|
|
|
return SendToMarsEditCommand()
|
|
|
|
case .microblog:
|
|
|
|
return SendToMicroBlogCommand()
|
2020-04-16 15:25:40 +02:00
|
|
|
#endif
|
2020-04-17 01:19:49 +02:00
|
|
|
case .twitter(let screenName):
|
|
|
|
return TwitterFeedProvider(screenName: screenName)
|
2020-05-03 02:38:57 +02:00
|
|
|
case .reddit(let username):
|
|
|
|
return RedditFeedProvider(username: username)
|
2020-04-08 20:46:15 +02:00
|
|
|
}
|
2020-04-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
2020-04-24 20:33:43 +02:00
|
|
|
func feedProviderMatching(_ offered: URLComponents, ability: FeedProviderAbility) -> FeedProvider? {
|
2020-04-15 23:35:09 +02:00
|
|
|
for extensionPoint in activeExtensionPoints.values {
|
2020-04-24 20:33:43 +02:00
|
|
|
if let feedProvider = extensionPoint as? FeedProvider, feedProvider.ability(offered) == ability {
|
2020-04-15 23:35:09 +02:00
|
|
|
return feedProvider
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-04-07 22:25:33 +02:00
|
|
|
}
|