Make the send-to-Micro.blog command work. Need some tweaking, but it mostly does the job.
This commit is contained in:
parent
811084c106
commit
c3bcf82713
|
@ -12,15 +12,54 @@ import Cocoa
|
||||||
|
|
||||||
protocol SendToCommand {
|
protocol SendToCommand {
|
||||||
|
|
||||||
|
var title: String { get }
|
||||||
|
var image: NSImage? { get }
|
||||||
|
|
||||||
func canSendObject(_ object: Any?, selectedText: String?) -> Bool
|
func canSendObject(_ object: Any?, selectedText: String?) -> Bool
|
||||||
func sendObject(_ object: Any?, selectedText: String?)
|
func sendObject(_ object: Any?, selectedText: String?)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SendToCommand {
|
|
||||||
|
|
||||||
func appExistsOnDisk(_ bundleIdentifier: String) -> Bool {
|
final class ApplicationSpecifier {
|
||||||
|
|
||||||
if let _ = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleIdentifier) {
|
let bundleID: String
|
||||||
|
var icon: NSImage? = nil
|
||||||
|
var existsOnDisk = false
|
||||||
|
var path: String? = nil
|
||||||
|
|
||||||
|
init(bundleID: String) {
|
||||||
|
|
||||||
|
self.bundleID = bundleID
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
|
func update() {
|
||||||
|
|
||||||
|
path = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleID)
|
||||||
|
if let path = path {
|
||||||
|
if icon == nil {
|
||||||
|
icon = NSWorkspace.shared.icon(forFile: path)
|
||||||
|
}
|
||||||
|
existsOnDisk = true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existsOnDisk = false
|
||||||
|
icon = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func launch() -> Bool {
|
||||||
|
|
||||||
|
guard existsOnDisk, let path = path else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = URL(fileURLWithPath: path)
|
||||||
|
if let runningApplication = try? NSWorkspace.shared.launchApplication(at: url, options: [.withErrorPresentation], configuration: [:]) {
|
||||||
|
if runningApplication.isFinishedLaunching {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
sleep(3) // Give the app time to launch. This is ugly.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -6,16 +6,45 @@
|
||||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Cocoa
|
||||||
|
|
||||||
final class SendToMarsEditCommand: SendToCommand {
|
final class SendToMarsEditCommand: SendToCommand {
|
||||||
|
|
||||||
|
let title = NSLocalizedString("Send to MarsEdit", comment: "Send to command")
|
||||||
|
|
||||||
|
var image: NSImage? {
|
||||||
|
return appSpecifierToUse()?.icon ?? nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private let marsEditApps = [ApplicationSpecifier(bundleID: "com.red-sweater.marsedit4"), ApplicationSpecifier(bundleID: "com.red-sweater.marsedit")]
|
||||||
|
|
||||||
func canSendObject(_ object: Any?, selectedText: String?) -> Bool {
|
func canSendObject(_ object: Any?, selectedText: String?) -> Bool {
|
||||||
|
|
||||||
|
if let _ = appSpecifierToUse() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendObject(_ object: Any?, selectedText: String?) {
|
func sendObject(_ object: Any?, selectedText: String?) {
|
||||||
|
|
||||||
|
if !canSendObject(object, selectedText: selectedText) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension SendToMarsEditCommand {
|
||||||
|
|
||||||
|
func appSpecifierToUse() -> ApplicationSpecifier? {
|
||||||
|
|
||||||
|
for specifier in marsEditApps {
|
||||||
|
specifier.update()
|
||||||
|
if specifier.existsOnDisk {
|
||||||
|
return specifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,18 +13,18 @@ import Data
|
||||||
|
|
||||||
final class SendToMicroBlogCommand: SendToCommand {
|
final class SendToMicroBlogCommand: SendToCommand {
|
||||||
|
|
||||||
private let bundleID = "blog.micro.mac"
|
let title = NSLocalizedString("Send to Micro.blog", comment: "Send to command")
|
||||||
private var appExists = false
|
|
||||||
|
|
||||||
init() {
|
var image: NSImage? {
|
||||||
|
return microBlogApp.icon
|
||||||
self.appExists = appExistsOnDisk(bundleID)
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive(_:)), name: NSApplication.didBecomeActiveNotification, object: nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let microBlogApp = ApplicationSpecifier(bundleID: "blog.micro.mac")
|
||||||
|
|
||||||
func canSendObject(_ object: Any?, selectedText: String?) -> Bool {
|
func canSendObject(_ object: Any?, selectedText: String?) -> Bool {
|
||||||
|
|
||||||
guard appExists, let article = object as? Article, let _ = article.preferredLink else {
|
microBlogApp.update()
|
||||||
|
guard microBlogApp.existsOnDisk, let article = (object as? ArticlePasteboardWriter)?.article, let _ = article.preferredLink else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,10 @@ final class SendToMicroBlogCommand: SendToCommand {
|
||||||
guard canSendObject(object, selectedText: selectedText) else {
|
guard canSendObject(object, selectedText: selectedText) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let article = object as? Article else {
|
guard let article = (object as? ArticlePasteboardWriter)?.article else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard microBlogApp.existsOnDisk, microBlogApp.launch() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,11 +70,6 @@ final class SendToMicroBlogCommand: SendToCommand {
|
||||||
|
|
||||||
let _ = try? NSWorkspace.shared.open(url, options: [], configuration: [:])
|
let _ = try? NSWorkspace.shared.open(url, options: [], configuration: [:])
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func appDidBecomeActive(_ note: Notification) {
|
|
||||||
|
|
||||||
self.appExists = appExistsOnDisk(bundleID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -479,6 +479,7 @@
|
||||||
846E77161F6EF5D000A165E2 /* Database.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Database.xcodeproj; path = Frameworks/Database/Database.xcodeproj; sourceTree = "<group>"; };
|
846E77161F6EF5D000A165E2 /* Database.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Database.xcodeproj; path = Frameworks/Database/Database.xcodeproj; sourceTree = "<group>"; };
|
||||||
846E77301F6EF5D600A165E2 /* Account.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Account.xcodeproj; path = Frameworks/Account/Account.xcodeproj; sourceTree = "<group>"; };
|
846E77301F6EF5D600A165E2 /* Account.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Account.xcodeproj; path = Frameworks/Account/Account.xcodeproj; sourceTree = "<group>"; };
|
||||||
84702AA31FA27AC0006B8943 /* MarkReadOrUnreadCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkReadOrUnreadCommand.swift; sourceTree = "<group>"; };
|
84702AA31FA27AC0006B8943 /* MarkReadOrUnreadCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkReadOrUnreadCommand.swift; sourceTree = "<group>"; };
|
||||||
|
847752FE2008879500D93690 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
|
||||||
848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconDownloader.swift; sourceTree = "<group>"; };
|
848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconDownloader.swift; sourceTree = "<group>"; };
|
||||||
849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderWindowController.swift; sourceTree = "<group>"; };
|
849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderWindowController.swift; sourceTree = "<group>"; };
|
||||||
849A97511ED9EAC0007D329B /* AddFeedController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFeedController.swift; path = AddFeed/AddFeedController.swift; sourceTree = "<group>"; };
|
849A97511ED9EAC0007D329B /* AddFeedController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFeedController.swift; path = AddFeed/AddFeedController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1094,6 +1095,7 @@
|
||||||
84FB9A2C1EDCD6A4003D53B9 /* Frameworks */ = {
|
84FB9A2C1EDCD6A4003D53B9 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
847752FE2008879500D93690 /* CoreServices.framework */,
|
||||||
84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */,
|
84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
|
|
|
@ -33,6 +33,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
|
||||||
return image
|
return image
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
lazy var sendToCommands: [SendToCommand] = {
|
||||||
|
return [SendToMicroBlogCommand()] //, SendToMarsEditCommand()]
|
||||||
|
}()
|
||||||
|
|
||||||
var unreadCount = 0 {
|
var unreadCount = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
if unreadCount != oldValue {
|
if unreadCount != oldValue {
|
||||||
|
|
|
@ -287,6 +287,7 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
|
||||||
|
|
||||||
let items = selectedArticles.map { ArticlePasteboardWriter(article: $0) }
|
let items = selectedArticles.map { ArticlePasteboardWriter(article: $0) }
|
||||||
let sharingServicePicker = NSSharingServicePicker(items: items)
|
let sharingServicePicker = NSSharingServicePicker(items: items)
|
||||||
|
sharingServicePicker.delegate = self
|
||||||
sharingServicePicker.show(relativeTo: view.bounds, of: view, preferredEdge: .minY)
|
sharingServicePicker.show(relativeTo: view.bounds, of: view, preferredEdge: .minY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,6 +300,30 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - NSSharingServicePickerDelegate
|
||||||
|
|
||||||
|
extension MainWindowController: NSSharingServicePickerDelegate {
|
||||||
|
|
||||||
|
func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, sharingServicesForItems items: [Any], proposedSharingServices proposedServices: [NSSharingService]) -> [NSSharingService] {
|
||||||
|
|
||||||
|
let sendToServices = appDelegate.sendToCommands.flatMap { (sendToCommand) -> NSSharingService? in
|
||||||
|
|
||||||
|
guard let object = items.first else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
guard sendToCommand.canSendObject(object, selectedText: nil) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let image = sendToCommand.image ?? appDelegate.genericFeedImage ?? NSImage()
|
||||||
|
return NSSharingService(title: sendToCommand.title, image: image, alternateImage: nil) {
|
||||||
|
sendToCommand.sendObject(object, selectedText: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proposedServices + sendToServices
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - NSToolbarDelegate
|
// MARK: - NSToolbarDelegate
|
||||||
|
|
||||||
extension NSToolbarItem.Identifier {
|
extension NSToolbarItem.Identifier {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import Data
|
||||||
|
|
||||||
@objc final class ArticlePasteboardWriter: NSObject, NSPasteboardWriting {
|
@objc final class ArticlePasteboardWriter: NSObject, NSPasteboardWriting {
|
||||||
|
|
||||||
private let article: Article
|
let article: Article
|
||||||
static let articleUTI = "com.ranchero.article"
|
static let articleUTI = "com.ranchero.article"
|
||||||
static let articleUTIType = NSPasteboard.PasteboardType(rawValue: articleUTI)
|
static let articleUTIType = NSPasteboard.PasteboardType(rawValue: articleUTI)
|
||||||
static let articleUTIInternal = "com.ranchero.evergreen.internal.article"
|
static let articleUTIInternal = "com.ranchero.evergreen.internal.article"
|
||||||
|
|
Loading…
Reference in New Issue