WIP: add color clip support
This commit is contained in:
@@ -187,6 +187,35 @@ final class ClipboardMonitorServiceTests: XCTestCase {
|
||||
XCTAssertEqual(NSPasteboard.general.data(forType: .sound), audioData)
|
||||
}
|
||||
|
||||
func testPollNowCapturesColorAsRestorableSwatch() throws {
|
||||
let settings = SettingsModel(defaults: makeTestDefaults())
|
||||
let (store, cacheService) = makeStoreAndCache(settings: settings)
|
||||
let monitor = ClipboardMonitorService(store: store, cacheService: cacheService, settings: settings)
|
||||
let color = NSColor(deviceRed: 10 / 255, green: 132 / 255, blue: 255 / 255, alpha: 1)
|
||||
let captured = expectation(description: "color captured")
|
||||
|
||||
store.observeItems { items in
|
||||
if items.contains(where: { $0.kind == .color && $0.payload == "#0A84FF" }) {
|
||||
captured.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
let pasteboard = NSPasteboard.general
|
||||
pasteboard.clearContents()
|
||||
XCTAssertTrue(pasteboard.writeObjects([color]))
|
||||
|
||||
monitor.pollNowAndWait()
|
||||
wait(for: [captured], timeout: 1.0)
|
||||
|
||||
let item = try XCTUnwrap(store.items.first(where: { $0.kind == .color }))
|
||||
XCTAssertEqual(item.displayText, "#0A84FF")
|
||||
XCTAssertEqual(item.payload, "#0A84FF")
|
||||
XCTAssertEqual(PasteActionService(cacheService: cacheService).copy(item), .copied)
|
||||
let restored = try XCTUnwrap(NSColor(from: NSPasteboard.general))
|
||||
XCTAssertEqual(ColorPayload.hexString(from: restored), "#0A84FF")
|
||||
XCTAssertEqual(NSPasteboard.general.string(forType: .string), "#0A84FF")
|
||||
}
|
||||
|
||||
func testPollNowCapturesFileReference() throws {
|
||||
let settings = SettingsModel(defaults: makeTestDefaults())
|
||||
let (store, cacheService) = makeStoreAndCache(settings: settings)
|
||||
@@ -592,6 +621,24 @@ final class ClipboardMonitorServiceTests: XCTestCase {
|
||||
XCTAssertTrue(try imageCacheFileURLs(in: baseURL).isEmpty)
|
||||
}
|
||||
|
||||
func testIgnoredColorKindDoesNotCaptureSwatch() throws {
|
||||
let settings = SettingsModel(defaults: makeTestDefaults())
|
||||
settings.ignoredItemKindsRaw = [ClipboardItemKind.color.rawValue]
|
||||
let (store, cacheService, _) = makeStoreCacheAndBaseURL(settings: settings)
|
||||
let monitor = ClipboardMonitorService(store: store, cacheService: cacheService, settings: settings)
|
||||
let color = NSColor(deviceRed: 10 / 255, green: 132 / 255, blue: 255 / 255, alpha: 1)
|
||||
|
||||
let pasteboard = NSPasteboard.general
|
||||
pasteboard.clearContents()
|
||||
XCTAssertTrue(pasteboard.writeObjects([color]))
|
||||
|
||||
monitor.pollNowAndWait()
|
||||
RunLoop.main.run(until: Date().addingTimeInterval(0.05))
|
||||
|
||||
XCTAssertTrue(store.items.isEmpty)
|
||||
XCTAssertEqual(settings.captureStatusMessage, "Skipped: Color items are ignored in capture settings.")
|
||||
}
|
||||
|
||||
func testIgnoredPDFKindDoesNotWriteAttachmentFiles() throws {
|
||||
let settings = SettingsModel(defaults: makeTestDefaults())
|
||||
settings.ignoredItemKindsRaw = [ClipboardItemKind.pdf.rawValue]
|
||||
|
||||
@@ -156,6 +156,7 @@ final class ClipboardPanelControllerTests: XCTestCase {
|
||||
XCTAssertEqual(ClipboardPanelController.collectionShortcutMode(forKeyCode: 22, modifiers: [.command, .option]), .files)
|
||||
XCTAssertEqual(ClipboardPanelController.collectionShortcutMode(forKeyCode: 26, modifiers: [.command, .option]), .pinned)
|
||||
XCTAssertEqual(ClipboardPanelController.collectionShortcutMode(forKeyCode: 28, modifiers: [.command, .option]), .audio)
|
||||
XCTAssertEqual(ClipboardPanelController.collectionShortcutMode(forKeyCode: 25, modifiers: [.command, .option]), .colors)
|
||||
}
|
||||
|
||||
func testCollectionShortcutsRequireCommandOptionSoQuickPasteKeepsCommandNumbers() {
|
||||
|
||||
@@ -39,6 +39,51 @@ final class ClipboardPanelViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(pinnedOnly.map(\.payload), ["four", "one"])
|
||||
}
|
||||
|
||||
func testComputeVisibleItemsFiltersColorClipsAndStructuredType() {
|
||||
let settings = makeSettings()
|
||||
let store = makeStore(settings: settings)
|
||||
let viewModel = ClipboardPanelViewModel(store: store, settings: settings, cacheService: ClipboardCacheService())
|
||||
let color = ClipboardItem(
|
||||
id: UUID(),
|
||||
kind: .color,
|
||||
displayText: "#0A84FF",
|
||||
payload: "#0A84FF",
|
||||
payloadHash: hash("#0A84FF"),
|
||||
createdAt: Date(timeIntervalSince1970: 100),
|
||||
lastUsedAt: Date(timeIntervalSince1970: 100),
|
||||
useCount: 0,
|
||||
sourceApp: "Design Tool",
|
||||
imagePath: nil,
|
||||
thumbnailPath: nil
|
||||
)
|
||||
let text = ClipboardItem(
|
||||
id: UUID(),
|
||||
kind: .text,
|
||||
displayText: "Color note",
|
||||
payload: "Color note",
|
||||
payloadHash: hash("Color note"),
|
||||
createdAt: Date(timeIntervalSince1970: 200),
|
||||
lastUsedAt: Date(timeIntervalSince1970: 200),
|
||||
useCount: 0,
|
||||
sourceApp: "Notes",
|
||||
imagePath: nil,
|
||||
thumbnailPath: nil
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
viewModel.computeVisibleItems(from: [text, color], query: "", sortMode: .colors).map(\.payload),
|
||||
["#0A84FF"]
|
||||
)
|
||||
XCTAssertEqual(
|
||||
viewModel.computeVisibleItems(from: [text, color], query: "type:swatch", sortMode: .mostRecent).map(\.payload),
|
||||
["#0A84FF"]
|
||||
)
|
||||
XCTAssertEqual(
|
||||
viewModel.computeVisibleItems(from: [text, color], query: "hex 0a84ff", sortMode: .mostRecent).map(\.payload),
|
||||
["#0A84FF"]
|
||||
)
|
||||
}
|
||||
|
||||
func testSearchMatchesIndependentTokensCaseInsensitively() {
|
||||
let settings = makeSettings()
|
||||
let store = makeStore(settings: settings)
|
||||
|
||||
@@ -246,11 +246,11 @@ final class ClipboardPanelViewTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(
|
||||
fixture.view.debugCollectionTitles,
|
||||
["Clipboard", "Frequent", "Text", "Links", "Images", "Audio", "Files", "Pinned"]
|
||||
["Clipboard", "Frequent", "Text", "Links", "Images", "Colors", "Audio", "Files", "Pinned"]
|
||||
)
|
||||
XCTAssertEqual(
|
||||
fixture.view.debugCollectionLeadingSymbols,
|
||||
["doc.on.clipboard", "chart.bar.fill", "text.alignleft", "link", "photo", "music.note", "doc.fill", "pin.fill"]
|
||||
["doc.on.clipboard", "chart.bar.fill", "text.alignleft", "link", "photo", "paintpalette", "music.note", "doc.fill", "pin.fill"]
|
||||
)
|
||||
XCTAssertEqual(fixture.view.debugSelectedCollectionTitle, "Clipboard")
|
||||
|
||||
@@ -678,17 +678,18 @@ final class ClipboardPanelViewTests: XCTestCase {
|
||||
let rich = makeItem(kind: .richText, text: "Rich note", store: fixture.store)
|
||||
let link = makeItem(kind: .url, text: "https://example.com/releases", store: fixture.store)
|
||||
let image = makeItem(kind: .image, text: "image payload", store: fixture.store)
|
||||
let color = makeItem(kind: .color, displayText: "#0A84FF", payload: "#0A84FF", store: fixture.store)
|
||||
let audio = makeItem(kind: .audio, text: "audio payload", store: fixture.store)
|
||||
let file = makeItem(kind: .file, text: "/tmp/report.pdf", store: fixture.store)
|
||||
|
||||
[pinned, rich, link, image, audio, file].forEach {
|
||||
[pinned, rich, link, image, color, audio, file].forEach {
|
||||
fixture.store.upsert($0)
|
||||
drainMainQueue()
|
||||
}
|
||||
|
||||
XCTAssertEqual(fixture.viewModel.visibleItems.count, 6)
|
||||
XCTAssertEqual(ClipboardSortMode.allCases.map { fixture.viewModel.collectionCount(for: $0) }, [6, 6, 2, 1, 1, 1, 1, 1])
|
||||
XCTAssertEqual(fixture.view.debugCollectionCounts, [6, 6, 2, 1, 1, 1, 1, 1])
|
||||
XCTAssertEqual(fixture.viewModel.visibleItems.count, 7)
|
||||
XCTAssertEqual(ClipboardSortMode.allCases.map { fixture.viewModel.collectionCount(for: $0) }, [7, 7, 2, 1, 1, 1, 1, 1, 1])
|
||||
XCTAssertEqual(fixture.view.debugCollectionCounts, [7, 7, 2, 1, 1, 1, 1, 1, 1])
|
||||
XCTAssertEqual(fixture.view.debugCollectionCountLabelHiddenStates, Array(repeating: false, count: ClipboardSortMode.allCases.count))
|
||||
}
|
||||
|
||||
@@ -1296,6 +1297,25 @@ final class ClipboardPanelViewTests: XCTestCase {
|
||||
XCTAssertEqual(fixture.view.debugCardPreviewStyles, ["audio-preview"])
|
||||
}
|
||||
|
||||
func testColorCardsUseSwatchPreview() {
|
||||
let fixture = makePanelFixture()
|
||||
let item = makeItem(
|
||||
kind: .color,
|
||||
displayText: "#0A84FF",
|
||||
payload: "#0A84FF",
|
||||
store: fixture.store
|
||||
)
|
||||
|
||||
fixture.store.upsert(item)
|
||||
fixture.viewModel.sortMode = .colors
|
||||
drainMainQueue()
|
||||
fixture.window.contentView?.layoutSubtreeIfNeeded()
|
||||
|
||||
XCTAssertEqual(fixture.view.debugCardAccessibilityLabels, ["Color: #0A84FF"])
|
||||
XCTAssertEqual(fixture.view.debugCardPreviewSummaries, ["#0A84FF|RGB 10 132 255|Color"])
|
||||
XCTAssertEqual(fixture.view.debugCardPreviewStyles, ["color-preview"])
|
||||
}
|
||||
|
||||
private func makePanelWithPanelView() -> (NSWindow, ClipboardPanelView) {
|
||||
let fixture = makePanelFixture()
|
||||
return (fixture.window, fixture.view)
|
||||
|
||||
@@ -83,6 +83,30 @@ final class PasteActionServiceTests: XCTestCase {
|
||||
)
|
||||
}
|
||||
|
||||
func testCopyWritesColorToPasteboardWithHexFallback() throws {
|
||||
let service = PasteActionService()
|
||||
let item = ClipboardItem(
|
||||
id: UUID(),
|
||||
kind: .color,
|
||||
displayText: "#0A84FF",
|
||||
payload: "#0A84FF",
|
||||
payloadHash: "hash",
|
||||
createdAt: Date(),
|
||||
lastUsedAt: Date(),
|
||||
useCount: 0,
|
||||
sourceApp: nil,
|
||||
imagePath: nil,
|
||||
thumbnailPath: nil
|
||||
)
|
||||
|
||||
XCTAssertEqual(service.copy(item), .copied)
|
||||
let restored = try XCTUnwrap(NSColor(from: NSPasteboard.general))
|
||||
XCTAssertEqual(ColorPayload.hexString(from: restored), "#0A84FF")
|
||||
XCTAssertEqual(NSPasteboard.general.string(forType: .string), "#0A84FF")
|
||||
XCTAssertEqual(service.copyPlainText(item), .copiedPlainText)
|
||||
XCTAssertEqual(NSPasteboard.general.string(forType: .string), "#0A84FF")
|
||||
}
|
||||
|
||||
func testPasteWithoutTargetCopiesWithoutRequestingAutomaticPaste() {
|
||||
let service = PasteActionService()
|
||||
let item = ClipboardItem(
|
||||
|
||||
Reference in New Issue
Block a user