Fix main-thread blocking I/O
This commit is contained in:
@@ -35,22 +35,23 @@ public struct ProfileShareButton<Label>: View where Label: View {
|
||||
|
||||
private var bodyCompat: some View {
|
||||
ShareButtonCompat(alert, label: label) {
|
||||
try profile.toContent().generateShareFile()
|
||||
try await profile.generateShareFileAsync()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ShareButtonCompat<Label>: View where Label: View {
|
||||
private let label: () -> Label
|
||||
private let itemURL: () throws -> URL
|
||||
private let itemURL: () async throws -> URL
|
||||
|
||||
@Binding private var alert: AlertState?
|
||||
|
||||
#if os(macOS)
|
||||
@State private var sharePresented = false
|
||||
@State private var shareItemURL: URL?
|
||||
#endif
|
||||
|
||||
public init(_ alert: Binding<AlertState?>, @ViewBuilder label: @escaping () -> Label, itemURL: @escaping () throws -> URL) {
|
||||
public init(_ alert: Binding<AlertState?>, @ViewBuilder label: @escaping () -> Label, itemURL: @escaping () async throws -> URL) {
|
||||
_alert = alert
|
||||
self.label = label
|
||||
self.itemURL = itemURL
|
||||
@@ -60,7 +61,7 @@ public struct ShareButtonCompat<Label>: View where Label: View {
|
||||
Button(action: shareItem, label: label)
|
||||
.buttonStyle(.plain)
|
||||
#if os(macOS)
|
||||
.background(SharingServicePicker($sharePresented, $alert, itemURL))
|
||||
.background(SharingServicePicker($sharePresented, $alert, $shareItemURL))
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -70,7 +71,9 @@ public struct ShareButtonCompat<Label>: View where Label: View {
|
||||
await shareItemAsync()
|
||||
}
|
||||
#elseif os(macOS)
|
||||
sharePresented = true
|
||||
Task {
|
||||
await shareItemAsync()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -103,6 +106,21 @@ public struct ShareButtonCompat<Label>: View where Label: View {
|
||||
animated: true
|
||||
)
|
||||
}
|
||||
|
||||
#elseif os(macOS)
|
||||
private nonisolated func shareItemAsync() async {
|
||||
do {
|
||||
let shareItem = try await itemURL()
|
||||
await MainActor.run {
|
||||
shareItemURL = shareItem
|
||||
sharePresented = true
|
||||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
alert = AlertState(error: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -110,12 +128,12 @@ public struct ShareButtonCompat<Label>: View where Label: View {
|
||||
private struct SharingServicePicker: NSViewRepresentable {
|
||||
@Binding private var isPresented: Bool
|
||||
@Binding private var alert: AlertState?
|
||||
private let item: () throws -> URL
|
||||
@Binding private var item: URL?
|
||||
|
||||
init(_ isPresented: Binding<Bool>, _ alert: Binding<AlertState?>, _ item: @escaping () throws -> URL) {
|
||||
init(_ isPresented: Binding<Bool>, _ alert: Binding<AlertState?>, _ item: Binding<URL?>) {
|
||||
_isPresented = isPresented
|
||||
_alert = alert
|
||||
self.item = item
|
||||
_item = item
|
||||
}
|
||||
|
||||
func makeNSView(context _: Context) -> NSView {
|
||||
@@ -125,14 +143,15 @@ public struct ShareButtonCompat<Label>: View where Label: View {
|
||||
|
||||
func updateNSView(_ nsView: NSView, context: Context) {
|
||||
if isPresented {
|
||||
do {
|
||||
let picker = try NSSharingServicePicker(items: [item()])
|
||||
picker.delegate = context.coordinator
|
||||
DispatchQueue.main.async {
|
||||
picker.show(relativeTo: .zero, of: nsView, preferredEdge: .minY)
|
||||
}
|
||||
} catch {
|
||||
alert = AlertState(error: error)
|
||||
guard let item else {
|
||||
return
|
||||
}
|
||||
let picker = NSSharingServicePicker(items: [item])
|
||||
picker.delegate = context.coordinator
|
||||
picker.show(relativeTo: .zero, of: nsView, preferredEdge: .minY)
|
||||
DispatchQueue.main.async {
|
||||
isPresented = false
|
||||
self.item = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user