WIP: avoid duplicated text card body

This commit is contained in:
Akshay Kolli
2026-06-30 10:44:11 -07:00
parent 40da0200c6
commit 890b500647
3 changed files with 57 additions and 14 deletions

View File

@@ -59,6 +59,7 @@ Use this checklist before a release or after changes to panel, pasteboard, setti
26. 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.
27. Confirm card headers use readable relative ages such as `3 minutes ago` or `2 hours ago`, including when viewing a named collection.
28. Confirm the selected card shows a green corner Stack control, the action rail does not duplicate Stack, and clips added to Stack keep a visible corner indicator when selection moves away.
29. Confirm single-line text cards do not repeat the same text in both title and body, while multi-line text cards show the remaining lines below the first line.
## Copy And Paste

View File

@@ -1338,6 +1338,14 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
cardViews.map(\.debugPreviewSummary)
}
var debugCardTextPreviewTitles: [String] {
cardViews.map(\.debugTextPreviewTitle)
}
var debugCardTextPreviewBodies: [String] {
cardViews.map(\.debugTextPreviewBody)
}
var debugCardPreviewStyles: [String] {
cardViews.map(\.debugPreviewStyle)
}
@@ -2680,6 +2688,8 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
private(set) var debugHeaderTitle = ""
private(set) var debugHeaderSubtitle = ""
private(set) var debugHeaderColorHex = ""
private(set) var debugTextPreviewTitle = ""
private(set) var debugTextPreviewBody = ""
var debugMenuTitles: [String] {
contextMenu().items.map { $0.isSeparatorItem ? "-" : $0.title }
@@ -3517,28 +3527,39 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
let titleString = titleText(for: item)
let bodyString = previewBodyText(for: item, title: titleString)
#if DEBUG
debugTextPreviewTitle = titleString
debugTextPreviewBody = bodyString ?? ""
#endif
let title = NSTextField(wrappingLabelWithString: titleString)
title.font = .systemFont(ofSize: 13, weight: .semibold)
title.font = bodyString == nil
? .systemFont(ofSize: item.kind == .richText ? 15 : 14, weight: .regular)
: .systemFont(ofSize: 13, weight: .semibold)
title.textColor = .labelColor
title.maximumNumberOfLines = 1
title.maximumNumberOfLines = bodyString == nil ? 5 : 1
title.lineBreakMode = .byTruncatingTail
title.toolTip = title.stringValue
let detail = NSTextField(wrappingLabelWithString: bodyString)
detail.font = .systemFont(ofSize: item.kind == .richText ? 15 : 14)
detail.textColor = .secondaryLabelColor
detail.maximumNumberOfLines = 5
detail.lineBreakMode = .byTruncatingTail
detail.toolTip = detail.stringValue
var textViews: [NSView] = [title]
if let bodyString {
let detail = NSTextField(wrappingLabelWithString: bodyString)
detail.font = .systemFont(ofSize: item.kind == .richText ? 15 : 14)
detail.textColor = .secondaryLabelColor
detail.maximumNumberOfLines = 5
detail.lineBreakMode = .byTruncatingTail
detail.toolTip = detail.stringValue
textViews.append(detail)
}
let stack = NSStackView(views: [title, detail])
let stack = NSStackView(views: textViews)
stack.orientation = .vertical
stack.alignment = .leading
stack.spacing = 10
stack.spacing = bodyString == nil ? 0 : 10
stack.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(stack)
title.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
detail.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
for view in textViews {
view.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
}
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: layout.inset),
stack.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -layout.inset),
@@ -3846,11 +3867,11 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
return label
}
private func previewBodyText(for item: ClipboardItem, title: String) -> String {
private func previewBodyText(for item: ClipboardItem, title: String) -> String? {
let preview = previewText(for: item)
let normalizedTitle = normalized(title)
if preview == normalizedTitle {
return preview
return nil
}
let prefix = normalizedTitle + " "
@@ -3859,6 +3880,7 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
if !remainder.isEmpty {
return remainder
}
return nil
}
return preview

View File

@@ -65,6 +65,26 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.view.debugCardRailOverflowFadeVisibility, [false, false])
}
func testSingleLineTextCardsDoNotDuplicateTitleInBody() {
let fixture = makePanelFixture()
fixture.store.upsert(makeTextItem("Client follow-up note", store: fixture.store))
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertEqual(fixture.view.debugCardTextPreviewTitles, ["Client follow-up note"])
XCTAssertEqual(fixture.view.debugCardTextPreviewBodies, [""])
}
func testMultiLineTextCardsShowRemainderBelowTitle() {
let fixture = makePanelFixture()
fixture.store.upsert(makeTextItem("Address:\n399 The Embarcadero\nSan Francisco", store: fixture.store))
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertEqual(fixture.view.debugCardTextPreviewTitles, ["Address:"])
XCTAssertEqual(fixture.view.debugCardTextPreviewBodies, ["399 The Embarcadero San Francisco"])
}
func testCompactCardsFitTwoItemsOnNarrowDockShelf() {
let fixture = makePanelFixture()
fixture.window.setFrame(NSRect(x: 0, y: 0, width: 620, height: 520), display: true)