import QuickLook import SwiftUI // 预览项包装:URL 本身不是 Identifiable,sheet(item:) 需要它。 struct PreviewItem: Identifiable { let id = UUID() let url: URL } // 文件预览 sheet:QuickLookView 外套 NavigationStack + toolbar「完成」按钮,供「收到的 // 文件」与传输详情两处共用。@Environment(\.dismiss) 关闭 sheet 即清空外层 item 绑定。 struct FilePreviewSheet: View { @Environment(\.dismiss) private var dismiss let item: PreviewItem var body: some View { NavigationStack { QuickLookView(url: item.url) .ignoresSafeArea() .navigationTitle(item.url.lastPathComponent) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button(t("ios.files.done")) { dismiss() } } } } } } // QLPreviewController 的纯 SwiftUI 包装(无内建关闭入口)。关闭交给外层 SwiftUI // NavigationStack 的 toolbar「完成」按钮——QL 自身的轻点切换 chrome 只影响它自己的工具 // 栏,不动外层导航栏,故 Done 始终可达(上轮用 UINavigationController 内建 Done 不可靠: // QL 全屏时把它一起藏了)。 struct QuickLookView: UIViewControllerRepresentable { let url: URL func makeUIViewController(context: Context) -> QLPreviewController { let controller = QLPreviewController() controller.dataSource = context.coordinator return controller } func updateUIViewController(_ controller: QLPreviewController, context: Context) { controller.reloadData() } func makeCoordinator() -> Coordinator { Coordinator(url: url) } final class Coordinator: NSObject, QLPreviewControllerDataSource { let url: URL init(url: URL) { self.url = url } func numberOfPreviewItems(in controller: QLPreviewController) -> Int { 1 } func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { return url as NSURL } } }