WIP: avoid duplicated text card body
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user