Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Shared/Sources/Document/Documents/ImageSaveService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ import Foundation

class ImageSaveService {
func load(from path: URL) throws -> Image? {
let imageURL = path.appendingPathComponent("screen.png")
let imageURL = imagePath(documentURL: path)
let data = try Data(contentsOf: imageURL)
return Image(data: data)
}

func imagePath(documentURL: URL) -> URL {
documentURL.appendingPathComponent("screen.png")
}
}

#if os(iOS)
Expand Down
36 changes: 35 additions & 1 deletion Shared/Sources/Document/Documents/VODesignDocument+AppKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import os

public let vodesign = "vodesign"
public let uti = "com.akaDuality.vodesign"
import QuickLookThumbnailing

public class VODesignDocument: Document, VODesignDocumentProtocol {

Expand Down Expand Up @@ -85,10 +86,35 @@ public class VODesignDocument: Document, VODesignDocumentProtocol {
return true
}

public static func image(from url: URL) -> Image? {
public static func image(from url: URL) async -> Image? {
try? ImageSaveService().load(from: url)
}

private var thumbnailCache: Image?
public func thumbnail(size: CGSize, scale: CGFloat) async -> Image? {
guard let fileURL else {
return nil
}

if let thumbnailCache {
// TODO: Invalidate cache if other size is requested
return thumbnailCache
}

let imagePath = ImageSaveService().imagePath(documentURL: fileURL)
let request = QLThumbnailGenerator.Request(
fileAt: imagePath,
size: size,
scale: scale,
representationTypes: .thumbnail)

let previewGenerator = QLThumbnailGenerator()
let thumbnail = try? await previewGenerator.generateBestRepresentation(for: request)

thumbnailCache = thumbnail?.nsImage
return thumbnail?.nsImage
}

public override class var readableTypes: [String] {
[uti]
}
Expand Down Expand Up @@ -141,3 +167,11 @@ extension VODesignDocument {
}
}
#endif

import Foundation
import QuickLookThumbnailing
public extension URL {
var fileName: String {
deletingPathExtension().lastPathComponent
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,19 @@ class RecentCollectionViewItem: NSCollectionViewItem {
view = projectCellView
}

func configure(image: NSImage?, fileName: String) {
projectCellView.thumbnail.image = image
func configure(fileName: String) {
projectCellView.fileNameTextField.stringValue = fileName
projectCellView.layoutSubtreeIfNeeded()
}


var image: NSImage? {
didSet {
projectCellView.thumbnail.image = image
}
}

var expectedImageSize: CGSize {
CGSize(width: 125,
height: 220)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public class RecentViewController: NSViewController {
let storyboard = NSStoryboard(name: "RecentViewController", bundle: .module)
return storyboard.instantiateInitialController() as! RecentViewController
}

lazy var backingScaleFactor: CGFloat = {
view.window?.backingScaleFactor ?? NSScreen.main?.backingScaleFactor ?? 1
}()
}

extension RecentViewController: DragNDropDelegate {
Expand Down Expand Up @@ -96,9 +100,18 @@ extension RecentViewController : NSCollectionViewDataSource {
case .document(let url):
let item = RecentCollectionViewItem()
item.configure(
image: VODesignDocument.image(from: url),
fileName: url.deletingPathExtension().lastPathComponent
fileName: url.fileName
)

Task {
let image = await VODesignDocument(file: url)
.thumbnail(size: item.expectedImageSize,
scale: backingScaleFactor)

item.image = image
// No need to check that item is changed because there is no reuse
}

return item
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,19 @@ class ProjectCollectionViewItemTests: XCTestCase {

func testConfiguringCollectionViewCell_WithSampleImageAndText() throws {
let sut = makeSUT()
let testImageA11yDescription = "TestA11yDescription"
let testImage = NSImage(systemSymbolName: "plus", accessibilityDescription: testImageA11yDescription)
let fileName = "TestFileName"

sut.configure(image: testImage, fileName: fileName)
sut.configure(fileName: fileName)

XCTAssertEqual(sut.projectCellView.fileNameTextField.stringValue, fileName)
XCTAssertEqual(sut.projectCellView.thumbnail.image, testImage)
XCTAssertEqual(sut.projectCellView.thumbnail.image?.accessibilityDescription, testImageA11yDescription)
}

func testConfiguringCollectionViewCell_WithNilImageAndText() throws {
let sut = makeSUT()
let fileName = "TestFileName"

sut.configure(image: nil, fileName: fileName)
sut.configure(fileName: fileName)

XCTAssertEqual(sut.projectCellView.fileNameTextField.stringValue, fileName)
XCTAssertNil(sut.projectCellView.thumbnail.image)
}

}