mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-25 09:25:50 +00:00
154 lines
4.4 KiB
Swift
154 lines
4.4 KiB
Swift
import Foundation
|
|
import QuickLook
|
|
import SwiftUI
|
|
|
|
@MainActor
|
|
class QuickLookManager: NSObject, ObservableObject {
|
|
static let shared = QuickLookManager()
|
|
|
|
@Published var isPresenting = false
|
|
@Published var downloadProgress: Double = 0
|
|
@Published var isDownloading = false
|
|
|
|
private var previewItems: [QLPreviewItem] = []
|
|
private var currentFile: FileEntry?
|
|
private let temporaryDirectory: URL
|
|
|
|
override init() {
|
|
// Create a temporary directory for downloaded files
|
|
let tempDir = FileManager.default.temporaryDirectory.appendingPathComponent("QuickLookCache", isDirectory: true)
|
|
try? FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
|
|
self.temporaryDirectory = tempDir
|
|
super.init()
|
|
|
|
// Clean up old files on init
|
|
cleanupTemporaryFiles()
|
|
}
|
|
|
|
func previewFile(_ file: FileEntry, apiClient: APIClient) async throws {
|
|
guard !file.isDir else {
|
|
throw QuickLookError.isDirectory
|
|
}
|
|
|
|
currentFile = file
|
|
isDownloading = true
|
|
downloadProgress = 0
|
|
|
|
do {
|
|
let localURL = try await downloadFileForPreview(file: file, apiClient: apiClient)
|
|
|
|
// Create preview item
|
|
let previewItem = PreviewItem(url: localURL, title: file.name)
|
|
previewItems = [previewItem]
|
|
|
|
isDownloading = false
|
|
isPresenting = true
|
|
} catch {
|
|
isDownloading = false
|
|
throw error
|
|
}
|
|
}
|
|
|
|
private func downloadFileForPreview(file: FileEntry, apiClient: APIClient) async throws -> URL {
|
|
// Check if file is already cached
|
|
let cachedURL = temporaryDirectory.appendingPathComponent(file.name)
|
|
|
|
// For now, always download fresh (could implement proper caching later)
|
|
if FileManager.default.fileExists(atPath: cachedURL.path) {
|
|
try FileManager.default.removeItem(at: cachedURL)
|
|
}
|
|
|
|
// Download the file
|
|
let data = try await apiClient.downloadFile(path: file.path) { progress in
|
|
Task { @MainActor in
|
|
self.downloadProgress = progress
|
|
}
|
|
}
|
|
|
|
// Save to temporary location
|
|
try data.write(to: cachedURL)
|
|
|
|
return cachedURL
|
|
}
|
|
|
|
func cleanupTemporaryFiles() {
|
|
// Remove files older than 1 hour
|
|
let oneHourAgo = Date().addingTimeInterval(-3_600)
|
|
|
|
guard let files = try? FileManager.default.contentsOfDirectory(
|
|
at: temporaryDirectory,
|
|
includingPropertiesForKeys: [.creationDateKey]
|
|
) else {
|
|
return
|
|
}
|
|
|
|
for file in files {
|
|
if let creationDate = try? file.resourceValues(forKeys: [.creationDateKey]).creationDate,
|
|
creationDate < oneHourAgo {
|
|
try? FileManager.default.removeItem(at: file)
|
|
}
|
|
}
|
|
}
|
|
|
|
func makePreviewController() -> QLPreviewController {
|
|
let controller = QLPreviewController()
|
|
controller.dataSource = self
|
|
controller.delegate = self
|
|
return controller
|
|
}
|
|
}
|
|
|
|
// MARK: - QLPreviewControllerDataSource
|
|
|
|
extension QuickLookManager: QLPreviewControllerDataSource {
|
|
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
|
|
previewItems.count
|
|
}
|
|
|
|
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
|
|
previewItems[index]
|
|
}
|
|
}
|
|
|
|
// MARK: - QLPreviewControllerDelegate
|
|
|
|
extension QuickLookManager: QLPreviewControllerDelegate {
|
|
nonisolated func previewControllerDidDismiss(_ controller: QLPreviewController) {
|
|
Task { @MainActor in
|
|
isPresenting = false
|
|
previewItems = []
|
|
currentFile = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Preview Item
|
|
|
|
private class PreviewItem: NSObject, QLPreviewItem {
|
|
let previewItemURL: URL?
|
|
let previewItemTitle: String?
|
|
|
|
init(url: URL, title: String) {
|
|
self.previewItemURL = url
|
|
self.previewItemTitle = title
|
|
}
|
|
}
|
|
|
|
// MARK: - Errors
|
|
|
|
enum QuickLookError: LocalizedError {
|
|
case isDirectory
|
|
case downloadFailed
|
|
case unsupportedFileType
|
|
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .isDirectory:
|
|
"Cannot preview directories"
|
|
case .downloadFailed:
|
|
"Failed to download file"
|
|
case .unsupportedFileType:
|
|
"This file type cannot be previewed"
|
|
}
|
|
}
|
|
}
|