WIP: add Quick Look preview groundwork

This commit is contained in:
Akshay Kolli
2026-06-30 01:43:23 -07:00
parent 3a2078c599
commit 28f50c84a6
4 changed files with 71 additions and 2 deletions

View File

@@ -182,6 +182,23 @@ final class ClipboardCacheService {
}
}
func temporaryPreviewURL(for item: ClipboardItem) -> URL? {
switch item.kind {
case .file:
let urls = FilePayload.urls(from: item.payload)
return urls.first { fileManager.fileExists(atPath: $0.path) }
case .text, .unknown:
let text = item.payload.clipboardTrimmed.isEmpty ? item.displayText : item.payload
guard !text.clipboardTrimmed.isEmpty else { return nil }
return writeTemporaryCopy(data: Data(text.utf8), id: item.id, fileExtension: "txt")
case .url:
guard let data = webLocationData(for: item.payload) else { return nil }
return writeTemporaryCopy(data: data, id: item.id, fileExtension: "webloc")
case .image, .pdf, .audio, .richText:
return temporaryReadableURL(for: item)
}
}
func encryptCachedReferencesIfNeeded(for items: [ClipboardItem]) {
queue.async { [weak self] in
guard let self else { return }
@@ -320,6 +337,16 @@ final class ClipboardCacheService {
}
}
private func webLocationData(for value: String) -> Data? {
let trimmed = value.clipboardTrimmed
guard !trimmed.isEmpty else { return nil }
return try? PropertyListSerialization.data(
fromPropertyList: ["URL": trimmed],
format: .xml,
options: 0
)
}
private func removeTemporaryPreviewFiles() {
guard fileManager.fileExists(atPath: temporaryPreviewDirectory.path) else {
return

View File

@@ -1,4 +1,5 @@
import AppKit
import QuickLook
struct ClipboardPanelAnimationProfile {
let showDuration: TimeInterval
@@ -15,10 +16,11 @@ struct ClipboardPanelReflowPlan {
enum ClipboardPanelShortcutAction: Equatable {
case copy
case open
case preview
case reveal
}
final class ClipboardPanelController: NSObject, NSWindowDelegate {
final class ClipboardPanelController: NSObject, NSWindowDelegate, QLPreviewPanelDataSource, QLPreviewPanelDelegate {
private enum Animation {
static let showDuration: TimeInterval = 0.16
static let hideDuration: TimeInterval = 0.12
@@ -44,6 +46,7 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate {
private let preferredScreenProvider: () -> NSScreen?
private let openSettings: () -> Void
private var isAnimating = false
private var quickLookURL: URL?
private var screenParametersObserver: NSObjectProtocol?
private static let collectionShortcuts: [UInt16: ClipboardSortMode] = [
18: .mostRecent,
@@ -82,7 +85,8 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate {
panelView = ClipboardPanelView(
viewModel: viewModel,
onClose: { [weak self] in self?.hide() },
onSettings: { [weak self] in self?.openSettings() }
onSettings: { [weak self] in self?.openSettings() },
onPreview: { [weak self] in self?.previewSelected() }
)
let contentSize = NSSize(width: 1200, height: 420)
@@ -333,6 +337,9 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate {
case 53:
self.hide()
return nil
case 49:
self.previewSelected()
return nil
case 36:
self.viewModel.pasteSelected()
return nil
@@ -360,11 +367,26 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate {
viewModel.copySelected()
case .open:
viewModel.openSelected()
case .preview:
previewSelected()
case .reveal:
viewModel.revealSelected()
}
}
private func previewSelected() {
guard let url = viewModel.previewURLForSelected() else { return }
quickLookURL = url
guard let previewPanel = QLPreviewPanel.shared() else {
NSWorkspace.shared.open(url)
return
}
previewPanel.dataSource = self
previewPanel.delegate = self
previewPanel.currentPreviewItemIndex = 0
previewPanel.makeKeyAndOrderFront(nil)
}
private func shouldHandlePanelKeyEvent(_ event: NSEvent) -> Bool {
shouldHandlePanelKeyEvent(event, allowSearchFieldEditing: false)
}
@@ -399,6 +421,8 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate {
return .copy
case 31:
return .open
case 16:
return .preview
case 15:
return .reveal
default:
@@ -406,6 +430,14 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate {
}
}
func numberOfPreviewItems(in panel: QLPreviewPanel!) -> Int {
quickLookURL == nil ? 0 : 1
}
func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> QLPreviewItem! {
quickLookURL as NSURL?
}
#if DEBUG
var debugPanelFrame: NSRect {
panel.frame

View File

@@ -168,6 +168,15 @@ final class ClipboardPanelViewModel {
return pasteService.pasteboardWriters(for: visibleItems[index])
}
func previewURLForSelected() -> URL? {
guard let item = selectedItem else { return nil }
return previewURL(for: item)
}
internal func previewURL(for item: ClipboardItem) -> URL? {
cacheService.temporaryPreviewURL(for: item)
}
func openSelected() {
guard let item = selectedItem else { return }
switch item.kind {