WIP: quiet card footer metadata
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user