Last active
March 19, 2024 16:49
-
-
Save banjun/2fb2619a4f2355ec6e677260e6ab1621 to your computer and use it in GitHub Desktop.
Open new window on drop UserActivity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
// prerequisites in Info.plist: NSUserActivityTypes contains type, UIApplicationSceneManifest/UIApplicationSupportsMultipleScenes = YES | |
// accepts NSUserActivity.targetContentIdentifier = type | |
// see also: https://developer.apple.com/documentation/swiftui/scene/handlesexternalevents(matching:) | |
struct UserActivityWindowGroup<Content: View, Payload: Codable>: Scene { | |
var type: String | |
@ViewBuilder var content: (Payload) -> Content | |
init(type: String, payloadType: Payload.Type, @ViewBuilder content: @escaping (Payload) -> Content) { | |
self.type = type | |
self.content = content | |
} | |
var body: some Scene { | |
WindowGroup { | |
WrapperView(type: type, content: content) | |
} | |
.handlesExternalEvents(matching: [type]) | |
} | |
struct WrapperView: View { | |
var type: String | |
@ViewBuilder var content: (Payload) -> Content | |
@State private var payload: Result<Payload, Error>? | |
@Environment(\.dismissWindow) private var dismissWindow | |
var body: some View { | |
switch payload { | |
case nil: | |
ProgressView().onContinueUserActivity(type) { | |
do { | |
self.payload = .success(try $0.typedPayload(Payload.self)) | |
} catch { | |
self.payload = .failure(error) | |
} | |
} | |
case .success(let payload): | |
content(payload) | |
case .failure(let error): | |
Text(error.localizedDescription) | |
Button("Dismiss") { | |
dismissWindow() | |
} | |
} | |
} | |
} | |
} | |
// MARK: - helper extensions | |
protocol CustomUserActivityType: Codable { | |
static var type: String { get } | |
} | |
extension NSUserActivity { | |
convenience init(_ activity: CustomUserActivityType) throws { | |
self.init(activityType: type(of: activity).type) | |
targetContentIdentifier = type(of: activity).type | |
try setTypedPayload(activity) | |
} | |
} | |
extension NSItemProvider { | |
convenience init(_ activty: CustomUserActivityType) throws { | |
self.init(object: try NSUserActivity(activty)) | |
} | |
} | |
extension View { | |
func onDragActivity(_ activity: CustomUserActivityType) -> some View { | |
onDrag { | |
do { | |
return try NSItemProvider(activity) | |
} catch { | |
NSLog("%@", "error on NSItemProvider(\(activity)), error = \(String(describing: error))") | |
return NSItemProvider() | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment