Skip to main content

Overview

QuickLookCoordinator manages the system Quick Look panel, allowing users to preview files directly from R2 storage without downloading them first. It streams files using presigned URLs and integrates with macOS’s native Quick Look functionality (spacebar preview).
Located at: Fiaxe/Services/QuickLookCoordinator.swift:18

Type Definition

@MainActor
final class QuickLookCoordinator: NSObject, QLPreviewPanelDataSource, QLPreviewPanelDelegate
Main actor-isolated singleton that implements Quick Look protocols for preview functionality.

Singleton Instance

static let shared = QuickLookCoordinator()
Access the shared coordinator instance from the main actor.

Methods

preview()

Displays the Quick Look panel for a specific R2 object.
func preview(_ object: R2Object, credentials: R2Credentials)
object
R2Object
required
The R2 object to preview. Must contain a valid key and name.
credentials
R2Credentials
required
R2 credentials used to generate a presigned URL for secure access.

Implementation Details

// Example from QuickLookCoordinator.swift:27-45
func preview(_ object: R2Object, credentials: R2Credentials) {
    let panel = QLPreviewPanel.shared()!

    // Toggle: if already visible for same coordinator, close it
    if panel.isVisible && panel.dataSource === self {
        panel.close()
        return
    }

    // Generate a presigned URL and pass it directly to Quick Look — no download needed.
    // previewItemTitle supplies the filename so QL picks the right previewer plugin.
    guard let presignedURL = AWSV4Signer.presignedURL(for: object.key, credentials: credentials) else { return }
    previewItem = PreviewItem(url: presignedURL, title: object.name)

    panel.dataSource = self
    panel.delegate  = self
    panel.makeKeyAndOrderFront(nil)
    panel.reloadData()
}
The method:
  1. Gets the shared Quick Look panel
  2. Toggles panel visibility if already open for the same coordinator
  3. Generates a presigned URL for streaming the file directly from R2
  4. Wraps the URL in a PreviewItem with the filename for proper format detection
  5. Sets itself as the data source and delegate
  6. Shows the panel and loads the preview
No Download RequiredQuick Look streams the file directly from the presigned URL without downloading to disk first. This provides instant previews for files of any size.

Preview Item Wrapper

The coordinator uses a private PreviewItem class to wrap URLs for Quick Look:
private final class PreviewItem: NSObject, QLPreviewItem {
    let previewItemURL: URL?
    let previewItemTitle: String?

    init(url: URL, title: String) {
        self.previewItemURL = url
        self.previewItemTitle = title
    }
}
previewItemURL
URL?
The presigned URL pointing to the R2 object.
previewItemTitle
String?
The original filename. Quick Look uses this to determine the correct previewer plugin based on file extension.
Why Wrap the URL?URL is a struct and can’t directly conform to the QLPreviewItem protocol which requires NSObject. The wrapper class provides this conformance.

Protocol Conformance

QLPreviewPanelDataSource

Provides preview items to the Quick Look panel.

numberOfPreviewItems()

func numberOfPreviewItems(in panel: QLPreviewPanel!) -> Int {
    previewItem != nil ? 1 : 0
}
Returns 1 if a preview item is available, 0 otherwise.

previewPanel(_:previewItemAt:)

func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> (any QLPreviewItem)! {
    previewItem
}
Returns the current preview item at the specified index.

QLPreviewPanelDelegate

Handles Quick Look panel events.

previewPanel(_:handle:)

func previewPanel(_ panel: QLPreviewPanel!, handle event: NSEvent!) -> Bool {
    false
}
Returns false to use default event handling. Could be customized for keyboard shortcuts or gestures.

Presigned URL Generation

The coordinator relies on AWSV4Signer to generate time-limited presigned URLs:
guard let presignedURL = AWSV4Signer.presignedURL(
    for: object.key,
    credentials: credentials
) else { return }
Presigned URLs:
  • Grant temporary read access to private R2 objects
  • Expire after a set duration (typically 1 hour)
  • Allow streaming without exposing credentials
  • Work with any HTTP client (including Quick Look)

Supported File Types

Quick Look supports previews for many file types:

Images

JPEG, PNG, GIF, HEIC, SVG, etc.

Videos

MP4, MOV, M4V, etc.

Documents

PDF, Pages, Word, Excel, etc.

Code

Swift, Python, JavaScript, etc.

Archives

ZIP, TAR, etc. (shows contents)

Audio

MP3, M4A, FLAC, etc.

Usage Example

import SwiftUI

struct FileRowView: View {
    let object: R2Object
    let credentials: R2Credentials
    
    var body: some View {
        HStack {
            Image(systemName: "doc")
            Text(object.name)
        }
        .onTapGesture(count: 2) {
            // Double-click to preview
            QuickLookCoordinator.shared.preview(object, credentials: credentials)
        }
        .onKeyPress(.space) {
            // Spacebar to preview
            QuickLookCoordinator.shared.preview(object, credentials: credentials)
            return .handled
        }
    }
}

Toggle Behavior

The coordinator implements smart toggle behavior:
// If panel is already visible for this coordinator, close it
if panel.isVisible && panel.dataSource === self {
    panel.close()
    return
}
This allows users to:
  • Press spacebar to open preview
  • Press spacebar again to close preview
  • Switch between different files seamlessly

Integration with r2Vault

In the main browser view, Quick Look is triggered via:
List(browserObjects) { object in
    FileRow(object: object)
        .onKeyPress(.space) {
            QuickLookCoordinator.shared.preview(object, credentials: credentials)
            return .handled
        }
}
Users can:
  • Select a file and press spacebar
  • Double-click a file (if implemented)
  • See instant previews without downloading

Performance Characteristics

Files are streamed directly from R2 via presigned URLs. Quick Look handles buffering and caching automatically.
Previews don’t write to disk (unless Quick Look caches internally). Large files can be previewed without filling up storage.
Preview quality depends on network speed. Slow connections may show loading indicators.

Limitations

Quick Look Limitations
  • Some file types may not be supported
  • Very large files (multi-GB) may timeout or be slow to load
  • Network interruptions will break the preview
  • Presigned URLs expire after their validity period
  • Private R2 buckets require valid credentials

Security Considerations

Presigned URL SecurityPresigned URLs are temporary and scoped to a single object:
  • URLs expire after a set duration (typically 1 hour)
  • Each URL is signed with credentials
  • URLs grant read-only access to one specific file
  • No credentials are exposed to Quick Look or the user
  • URLs can’t be used to access other files
This is secure for personal use cases where you control the R2 bucket.