import UIKit import SwiftUI import UniformTypeIdentifiers @objc(ShareViewController) class ShareViewController: UIViewController { private let supportedTypeIdentifiers = [ UTType.url.identifier, UTType.html.identifier, UTType.rtf.identifier, UTType.plainText.identifier, UTType.text.identifier ] override func viewDidLoad() { super.viewDidLoad() let blur = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) blur.frame = view.bounds blur.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(blur) extractPayload() } private func extractPayload() { guard let item = extensionContext?.inputItems.first as? NSExtensionItem, let attachments = item.attachments else { present(payload: nil) return } let candidates = attachments.flatMap { attachment in supportedTypeIdentifiers .filter { attachment.hasItemConformingToTypeIdentifier($0) } .map { (attachment, $0) } } loadNext(candidates, index: 0) } private func loadNext(_ candidates: [(NSItemProvider, String)], index: Int) { guard index < candidates.count else { present(payload: nil) return } let (attachment, typeIdentifier) = candidates[index] attachment.loadItem(forTypeIdentifier: typeIdentifier, options: nil) { [weak self] item, _ in guard let self else { return } if let payload = IngestPayloadParser.parse(item: item, typeIdentifier: typeIdentifier) { DispatchQueue.main.async { self.present(payload: payload) } } else { DispatchQueue.main.async { self.loadNext(candidates, index: index + 1) } } } } /// Hosts the SwiftUI save card. A nil URL surfaces an error state in the card. private func present(payload: IngestPayload?) { let root = ShareView( url: payload?.url ?? "", initialTitle: payload?.title, initialNotes: payload?.notes ?? "" ) { [weak self] _ in self?.close() } let host = UIHostingController(rootView: root) host.view.backgroundColor = .clear addChild(host) host.view.frame = view.bounds host.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(host.view) host.didMove(toParent: self) if payload == nil { // No URL to work with — let the card render its failure state briefly. DispatchQueue.main.asyncAfter(deadline: .now() + 1.6) { [weak self] in self?.close() } } } private func close() { extensionContext?.completeRequest(returningItems: [], completionHandler: nil) } }