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.
|
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.
|
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.
|
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
|
## Copy And Paste
|
||||||
|
|
||||||
|
|||||||
@@ -1370,6 +1370,14 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
|
|||||||
cardViews.first?.debugFooterDetailText ?? ""
|
cardViews.first?.debugFooterDetailText ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var debugFirstCardFooterSourceText: String {
|
||||||
|
cardViews.first?.debugFooterSourceText ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugFirstCardFooterSourceIsHidden: Bool {
|
||||||
|
cardViews.first?.debugFooterSourceIsHidden ?? true
|
||||||
|
}
|
||||||
|
|
||||||
var debugQuickPasteBadgeTexts: [String] {
|
var debugQuickPasteBadgeTexts: [String] {
|
||||||
cardViews.compactMap(\.debugQuickPasteBadgeText)
|
cardViews.compactMap(\.debugQuickPasteBadgeText)
|
||||||
}
|
}
|
||||||
@@ -2401,6 +2409,7 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
private let activeCollectionColor: NSColor?
|
private let activeCollectionColor: NSColor?
|
||||||
private let collectionNames: [String]
|
private let collectionNames: [String]
|
||||||
private let contentView = NSView()
|
private let contentView = NSView()
|
||||||
|
private let footerSourceLabel = NSTextField(labelWithString: "")
|
||||||
private let footerDetailLabel = NSTextField(labelWithString: "")
|
private let footerDetailLabel = NSTextField(labelWithString: "")
|
||||||
private let actionRail = NSStackView()
|
private let actionRail = NSStackView()
|
||||||
private var actionRailButtons: [NSButton] = []
|
private var actionRailButtons: [NSButton] = []
|
||||||
@@ -2697,6 +2706,14 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
footerDetailLabel.stringValue
|
footerDetailLabel.stringValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var debugFooterSourceText: String {
|
||||||
|
footerSourceLabel.stringValue
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugFooterSourceIsHidden: Bool {
|
||||||
|
footerSourceLabel.isHidden
|
||||||
|
}
|
||||||
|
|
||||||
var debugItemID: UUID {
|
var debugItemID: UUID {
|
||||||
itemID
|
itemID
|
||||||
}
|
}
|
||||||
@@ -3786,12 +3803,14 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
footer.layer?.backgroundColor = Palette.footerBackground
|
footer.layer?.backgroundColor = Palette.footerBackground
|
||||||
footer.heightAnchor.constraint(equalToConstant: layout.footerHeight).isActive = true
|
footer.heightAnchor.constraint(equalToConstant: layout.footerHeight).isActive = true
|
||||||
|
|
||||||
let source = NSTextField(labelWithString: sourceText(for: item))
|
let sourceText = footerSourceText(for: item)
|
||||||
source.font = .systemFont(ofSize: NSFont.smallSystemFontSize, weight: .medium)
|
footerSourceLabel.stringValue = sourceText ?? ""
|
||||||
source.textColor = .secondaryLabelColor
|
footerSourceLabel.font = .systemFont(ofSize: NSFont.smallSystemFontSize, weight: .medium)
|
||||||
source.lineBreakMode = .byTruncatingTail
|
footerSourceLabel.textColor = .secondaryLabelColor
|
||||||
source.maximumNumberOfLines = 1
|
footerSourceLabel.lineBreakMode = .byTruncatingTail
|
||||||
source.toolTip = source.stringValue
|
footerSourceLabel.maximumNumberOfLines = 1
|
||||||
|
footerSourceLabel.toolTip = footerSourceLabel.stringValue
|
||||||
|
footerSourceLabel.isHidden = sourceText == nil
|
||||||
|
|
||||||
let detailText = detailMetricText(for: item)
|
let detailText = detailMetricText(for: item)
|
||||||
if activeCollectionName == nil,
|
if activeCollectionName == nil,
|
||||||
@@ -3814,12 +3833,12 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
divider.wantsLayer = true
|
divider.wantsLayer = true
|
||||||
divider.layer?.backgroundColor = Palette.divider
|
divider.layer?.backgroundColor = Palette.divider
|
||||||
divider.translatesAutoresizingMaskIntoConstraints = false
|
divider.translatesAutoresizingMaskIntoConstraints = false
|
||||||
let stack = row([source, footerDetailLabel])
|
let stack = row([footerSourceLabel, footerDetailLabel])
|
||||||
stack.distribution = .fill
|
stack.distribution = .fill
|
||||||
stack.alignment = .centerY
|
stack.alignment = .centerY
|
||||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
source.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
footerSourceLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||||
source.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
footerSourceLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||||
footerDetailLabel.setContentHuggingPriority(.required, for: .horizontal)
|
footerDetailLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
footerDetailLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
footerDetailLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
footer.addSubview(divider)
|
footer.addSubview(divider)
|
||||||
@@ -3989,8 +4008,21 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func sourceText(for item: ClipboardItem) -> String {
|
private func footerSourceText(for item: ClipboardItem) -> String? {
|
||||||
item.sourceApp?.clipboardTrimmed.isEmpty == false ? item.sourceApp! : "Unknown"
|
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 {
|
private func linkTitle(for item: ClipboardItem) -> String {
|
||||||
|
|||||||
@@ -106,6 +106,33 @@ final class ClipboardPanelViewTests: XCTestCase {
|
|||||||
XCTAssertFalse(fixture.view.debugStatusText.contains("Enter paste"))
|
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() {
|
func testEditedTextStatusUsesActionTone() {
|
||||||
let fixture = makePanelFixture()
|
let fixture = makePanelFixture()
|
||||||
fixture.store.upsert(makeTextItem("Editable footer item", store: fixture.store))
|
fixture.store.upsert(makeTextItem("Editable footer item", store: fixture.store))
|
||||||
|
|||||||
Reference in New Issue
Block a user