WIP: quiet card footer metadata

This commit is contained in:
Akshay Kolli
2026-06-30 10:14:25 -07:00
parent ac285aed89
commit 241596acb3
3 changed files with 71 additions and 11 deletions

View File

@@ -55,6 +55,7 @@ Use this checklist before a release or after changes to panel, pasteboard, setti
22. Drag an unassigned card onto the renamed collection chip and confirm the chip count increases and the card appears when that collection is selected.
23. Resize or test on a narrow display and confirm the bottom shelf switches to compact cards that still show two recent clips cleanly.
24. Select a file, rich text, or URL card and confirm the selected-card rail exposes `Paste Plain Text`, the corner source/kind badge remains visible, and on a narrow shelf secondary actions collapse behind `More` instead of overflowing the card.
25. Confirm card footers do not show `Unknown` for clips without a source app, and confirm used clips show their usage count beside the source app.
## Copy And Paste

View File

@@ -1370,6 +1370,14 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
cardViews.first?.debugFooterDetailText ?? ""
}
var debugFirstCardFooterSourceText: String {
cardViews.first?.debugFooterSourceText ?? ""
}
var debugFirstCardFooterSourceIsHidden: Bool {
cardViews.first?.debugFooterSourceIsHidden ?? true
}
var debugQuickPasteBadgeTexts: [String] {
cardViews.compactMap(\.debugQuickPasteBadgeText)
}
@@ -2401,6 +2409,7 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
private let activeCollectionColor: NSColor?
private let collectionNames: [String]
private let contentView = NSView()
private let footerSourceLabel = NSTextField(labelWithString: "")
private let footerDetailLabel = NSTextField(labelWithString: "")
private let actionRail = NSStackView()
private var actionRailButtons: [NSButton] = []
@@ -2697,6 +2706,14 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
footerDetailLabel.stringValue
}
var debugFooterSourceText: String {
footerSourceLabel.stringValue
}
var debugFooterSourceIsHidden: Bool {
footerSourceLabel.isHidden
}
var debugItemID: UUID {
itemID
}
@@ -3786,12 +3803,14 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
footer.layer?.backgroundColor = Palette.footerBackground
footer.heightAnchor.constraint(equalToConstant: layout.footerHeight).isActive = true
let source = NSTextField(labelWithString: sourceText(for: item))
source.font = .systemFont(ofSize: NSFont.smallSystemFontSize, weight: .medium)
source.textColor = .secondaryLabelColor
source.lineBreakMode = .byTruncatingTail
source.maximumNumberOfLines = 1
source.toolTip = source.stringValue
let sourceText = footerSourceText(for: item)
footerSourceLabel.stringValue = sourceText ?? ""
footerSourceLabel.font = .systemFont(ofSize: NSFont.smallSystemFontSize, weight: .medium)
footerSourceLabel.textColor = .secondaryLabelColor
footerSourceLabel.lineBreakMode = .byTruncatingTail
footerSourceLabel.maximumNumberOfLines = 1
footerSourceLabel.toolTip = footerSourceLabel.stringValue
footerSourceLabel.isHidden = sourceText == nil
let detailText = detailMetricText(for: item)
if activeCollectionName == nil,
@@ -3814,12 +3833,12 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
divider.wantsLayer = true
divider.layer?.backgroundColor = Palette.divider
divider.translatesAutoresizingMaskIntoConstraints = false
let stack = row([source, footerDetailLabel])
let stack = row([footerSourceLabel, footerDetailLabel])
stack.distribution = .fill
stack.alignment = .centerY
stack.translatesAutoresizingMaskIntoConstraints = false
source.setContentHuggingPriority(.defaultLow, for: .horizontal)
source.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
footerSourceLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
footerSourceLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
footerDetailLabel.setContentHuggingPriority(.required, for: .horizontal)
footerDetailLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
footer.addSubview(divider)
@@ -3989,8 +4008,21 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
}
}
private func sourceText(for item: ClipboardItem) -> String {
item.sourceApp?.clipboardTrimmed.isEmpty == false ? item.sourceApp! : "Unknown"
private func footerSourceText(for item: ClipboardItem) -> String? {
let source = item.sourceApp?.clipboardTrimmed
let usage = usageText(for: item.useCount)
if let source, !source.isEmpty, let usage {
return "\(source) - \(usage)"
}
if let source, !source.isEmpty {
return source
}
return usage
}
private func usageText(for useCount: Int) -> String? {
guard useCount > 0 else { return nil }
return useCount == 1 ? "Used once" : "Used \(useCount) times"
}
private func linkTitle(for item: ClipboardItem) -> String {

View File

@@ -106,6 +106,33 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertFalse(fixture.view.debugStatusText.contains("Enter paste"))
}
func testCardFooterHidesMissingSourceInsteadOfShowingUnknown() {
let fixture = makePanelFixture()
var item = makeTextItem("No source noise", store: fixture.store)
item.sourceApp = nil
fixture.store.upsert(item)
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertTrue(fixture.view.debugFirstCardFooterSourceIsHidden)
XCTAssertEqual(fixture.view.debugFirstCardFooterSourceText, "")
XCTAssertEqual(fixture.view.debugFirstCardFooterDetailText, "15 characters")
}
func testCardFooterShowsSourceAndUsageWhenUsed() {
let fixture = makePanelFixture()
var item = makeTextItem("Frequently pasted", store: fixture.store)
item.useCount = 3
fixture.store.upsert(item)
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertFalse(fixture.view.debugFirstCardFooterSourceIsHidden)
XCTAssertEqual(fixture.view.debugFirstCardFooterSourceText, "Ghostty - Used 3 times")
}
func testEditedTextStatusUsesActionTone() {
let fixture = makePanelFixture()
fixture.store.upsert(makeTextItem("Editable footer item", store: fixture.store))