import UIKit import SwiftUI import UniformTypeIdentifiers final class ShareViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .clear Task { await loadAttachment() } } private func loadAttachment() async { guard let item = (extensionContext?.inputItems as? [NSExtensionItem])?.first, let provider = item.attachments?.first(where: { $0.hasItemConformingToTypeIdentifier(UTType.image.identifier) }) else { present(host: ShareSheetView(image: nil, onClose: { [weak self] in self?.complete() })) return } do { let data = try await loadImageData(from: provider) await MainActor.run { let image = data.flatMap { UIImage(data: $0) } let host = ShareSheetView( image: image, imageData: data, onClose: { [weak self] in self?.complete() } ) self.present(host: host) } } catch { await MainActor.run { present(host: ShareSheetView(image: nil, errorMessage: error.localizedDescription, onClose: { [weak self] in self?.complete() })) } } } private func loadImageData(from provider: NSItemProvider) async throws -> Data? { try await withCheckedThrowingContinuation { continuation in provider.loadItem(forTypeIdentifier: UTType.image.identifier, options: nil) { item, error in if let error { continuation.resume(throwing: error); return } if let data = item as? Data { continuation.resume(returning: data); return } if let url = item as? URL, let data = try? Data(contentsOf: url) { continuation.resume(returning: data); return } if let image = item as? UIImage, let data = image.pngData() { continuation.resume(returning: data); return } continuation.resume(returning: nil) } } } private func present(host: ShareSheetView) { let controller = UIHostingController(rootView: host) controller.modalPresentationStyle = .formSheet addChild(controller) controller.view.frame = view.bounds controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(controller.view) controller.didMove(toParent: self) } fileprivate func complete() { extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) } fileprivate func cancel() { extensionContext?.cancelRequest(withError: NSError(domain: "GiteaIssueShare", code: 0)) } }