diff --git a/AppKitExtras/Sources/AppKitExtras/UserApp.swift b/AppKitExtras/Sources/AppKitExtras/UserApp.swift index 9bc67df3d..39de0624b 100644 --- a/AppKitExtras/Sources/AppKitExtras/UserApp.swift +++ b/AppKitExtras/Sources/AppKitExtras/UserApp.swift @@ -63,19 +63,17 @@ public final class UserApp { path = bundleURL.path } else { - path = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleID) + path = NSWorkspace.shared.urlForApplication(withBundleIdentifier: bundleID)?.path } - if icon == nil, let path = path { + if icon == nil, let path { icon = NSWorkspace.shared.icon(forFile: path) } return } - path = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleID) - if let path = path { - if icon == nil { - icon = NSWorkspace.shared.icon(forFile: path) - } + path = NSWorkspace.shared.urlForApplication(withBundleIdentifier: bundleID)?.path + if icon == nil, let path { + icon = NSWorkspace.shared.icon(forFile: path) existsOnDisk = true } else { @@ -84,7 +82,7 @@ public final class UserApp { } } - public func launchIfNeeded() -> Bool { + public func launchIfNeeded() async -> Bool { // Return true if already running. // Return true if not running and successfully gets launched. @@ -99,20 +97,29 @@ public final class UserApp { } let url = URL(fileURLWithPath: path) - if let app = try? NSWorkspace.shared.launchApplication(at: url, options: [.withErrorPresentation], configuration: [:]) { - runningApplication = app - if app.isFinishedLaunching { - return true - } - Thread.sleep(forTimeInterval: 1.0) // Give the app time to launch. This is ugly. - if app.isFinishedLaunching { - return true - } - Thread.sleep(forTimeInterval: 1.0) // Give it some *more* time. - return true - } - return false + do { + let configuration = NSWorkspace.OpenConfiguration() + configuration.promptsUserIfNeeded = true + + let app = try await NSWorkspace.shared.openApplication(at: url, configuration: configuration) + runningApplication = app + + if app.isFinishedLaunching { + return true + } + + try? await Task.sleep(for: .seconds(1)) // Give the app time to launch. This is ugly. + if app.isFinishedLaunching { + return true + } + + try? await Task.sleep(for: .seconds(1)) // Give it some *more* time. + return true + + } catch { + return false + } } public func bringToFront() -> Bool { diff --git a/Core/Sources/Core/SendToCommand.swift b/Core/Sources/Core/SendToCommand.swift index ff83c5f4a..c60c6027d 100644 --- a/Core/Sources/Core/SendToCommand.swift +++ b/Core/Sources/Core/SendToCommand.swift @@ -44,6 +44,6 @@ public protocol SendToCommand { /// - Parameters: /// - object: The object whose data to send. /// - selectedText: The currently selected text. - func sendObject(_ object: Any?, selectedText: String?) + @MainActor func sendObject(_ object: Any?, selectedText: String?) } diff --git a/Shared/ExtensionPoints/SendToMarsEditCommand.swift b/Shared/ExtensionPoints/SendToMarsEditCommand.swift index fb2533f80..61752583c 100644 --- a/Shared/ExtensionPoints/SendToMarsEditCommand.swift +++ b/Shared/ExtensionPoints/SendToMarsEditCommand.swift @@ -30,11 +30,17 @@ final class SendToMarsEditCommand: SendToCommand { guard let article = (object as? ArticlePasteboardWriter)?.article else { return } - guard let app = appToUse(), app.launchIfNeeded(), app.bringToFront() else { + guard let app = appToUse() else { return } - send(article, to: app) + Task { @MainActor in + guard await app.launchIfNeeded(), app.bringToFront() else { + return + } + + send(article, to: app) + } } } diff --git a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift index 897e00959..4de3e8447 100644 --- a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift +++ b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift @@ -38,24 +38,27 @@ final class SendToMicroBlogCommand: SendToCommand { guard let article = (object as? ArticlePasteboardWriter)?.article else { return } - guard microBlogApp.launchIfNeeded(), microBlogApp.bringToFront() else { - return + + Task { @MainActor in + guard await microBlogApp.launchIfNeeded(), microBlogApp.bringToFront() else { + return + } + + // TODO: get text from contentHTML or contentText if no title and no selectedText. + // TODO: consider selectedText. + + let s = article.attributionString + article.linkString + + let urlQueryDictionary = ["text": s] + guard let urlQueryString = urlQueryDictionary.urlQueryString else { + return + } + guard let url = URL(string: "microblog://post?" + urlQueryString) else { + return + } + + NSWorkspace.shared.open(url) } - - // TODO: get text from contentHTML or contentText if no title and no selectedText. - // TODO: consider selectedText. - - let s = article.attributionString + article.linkString - - let urlQueryDictionary = ["text": s] - guard let urlQueryString = urlQueryDictionary.urlQueryString else { - return - } - guard let url = URL(string: "microblog://post?" + urlQueryString) else { - return - } - - NSWorkspace.shared.open(url) } }