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.
|
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.
|
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.
|
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
|
## Copy And Paste
|
||||||
|
|
||||||
|
|||||||
@@ -1338,6 +1338,14 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
|
|||||||
cardViews.map(\.debugPreviewSummary)
|
cardViews.map(\.debugPreviewSummary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var debugCardTextPreviewTitles: [String] {
|
||||||
|
cardViews.map(\.debugTextPreviewTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugCardTextPreviewBodies: [String] {
|
||||||
|
cardViews.map(\.debugTextPreviewBody)
|
||||||
|
}
|
||||||
|
|
||||||
var debugCardPreviewStyles: [String] {
|
var debugCardPreviewStyles: [String] {
|
||||||
cardViews.map(\.debugPreviewStyle)
|
cardViews.map(\.debugPreviewStyle)
|
||||||
}
|
}
|
||||||
@@ -2680,6 +2688,8 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
private(set) var debugHeaderTitle = ""
|
private(set) var debugHeaderTitle = ""
|
||||||
private(set) var debugHeaderSubtitle = ""
|
private(set) var debugHeaderSubtitle = ""
|
||||||
private(set) var debugHeaderColorHex = ""
|
private(set) var debugHeaderColorHex = ""
|
||||||
|
private(set) var debugTextPreviewTitle = ""
|
||||||
|
private(set) var debugTextPreviewBody = ""
|
||||||
|
|
||||||
var debugMenuTitles: [String] {
|
var debugMenuTitles: [String] {
|
||||||
contextMenu().items.map { $0.isSeparatorItem ? "-" : $0.title }
|
contextMenu().items.map { $0.isSeparatorItem ? "-" : $0.title }
|
||||||
@@ -3517,28 +3527,39 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
|
|
||||||
let titleString = titleText(for: item)
|
let titleString = titleText(for: item)
|
||||||
let bodyString = previewBodyText(for: item, title: titleString)
|
let bodyString = previewBodyText(for: item, title: titleString)
|
||||||
|
#if DEBUG
|
||||||
|
debugTextPreviewTitle = titleString
|
||||||
|
debugTextPreviewBody = bodyString ?? ""
|
||||||
|
#endif
|
||||||
let title = NSTextField(wrappingLabelWithString: titleString)
|
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.textColor = .labelColor
|
||||||
title.maximumNumberOfLines = 1
|
title.maximumNumberOfLines = bodyString == nil ? 5 : 1
|
||||||
title.lineBreakMode = .byTruncatingTail
|
title.lineBreakMode = .byTruncatingTail
|
||||||
title.toolTip = title.stringValue
|
title.toolTip = title.stringValue
|
||||||
|
|
||||||
|
var textViews: [NSView] = [title]
|
||||||
|
if let bodyString {
|
||||||
let detail = NSTextField(wrappingLabelWithString: bodyString)
|
let detail = NSTextField(wrappingLabelWithString: bodyString)
|
||||||
detail.font = .systemFont(ofSize: item.kind == .richText ? 15 : 14)
|
detail.font = .systemFont(ofSize: item.kind == .richText ? 15 : 14)
|
||||||
detail.textColor = .secondaryLabelColor
|
detail.textColor = .secondaryLabelColor
|
||||||
detail.maximumNumberOfLines = 5
|
detail.maximumNumberOfLines = 5
|
||||||
detail.lineBreakMode = .byTruncatingTail
|
detail.lineBreakMode = .byTruncatingTail
|
||||||
detail.toolTip = detail.stringValue
|
detail.toolTip = detail.stringValue
|
||||||
|
textViews.append(detail)
|
||||||
|
}
|
||||||
|
|
||||||
let stack = NSStackView(views: [title, detail])
|
let stack = NSStackView(views: textViews)
|
||||||
stack.orientation = .vertical
|
stack.orientation = .vertical
|
||||||
stack.alignment = .leading
|
stack.alignment = .leading
|
||||||
stack.spacing = 10
|
stack.spacing = bodyString == nil ? 0 : 10
|
||||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
container.addSubview(stack)
|
container.addSubview(stack)
|
||||||
title.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
|
for view in textViews {
|
||||||
detail.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
|
view.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
|
||||||
|
}
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
stack.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: layout.inset),
|
stack.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: layout.inset),
|
||||||
stack.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -layout.inset),
|
stack.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -layout.inset),
|
||||||
@@ -3846,11 +3867,11 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
return label
|
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 preview = previewText(for: item)
|
||||||
let normalizedTitle = normalized(title)
|
let normalizedTitle = normalized(title)
|
||||||
if preview == normalizedTitle {
|
if preview == normalizedTitle {
|
||||||
return preview
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix = normalizedTitle + " "
|
let prefix = normalizedTitle + " "
|
||||||
@@ -3859,6 +3880,7 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
|
|||||||
if !remainder.isEmpty {
|
if !remainder.isEmpty {
|
||||||
return remainder
|
return remainder
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return preview
|
return preview
|
||||||
|
|||||||
@@ -65,6 +65,26 @@ final class ClipboardPanelViewTests: XCTestCase {
|
|||||||
XCTAssertEqual(fixture.view.debugCardRailOverflowFadeVisibility, [false, false])
|
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() {
|
func testCompactCardsFitTwoItemsOnNarrowDockShelf() {
|
||||||
let fixture = makePanelFixture()
|
let fixture = makePanelFixture()
|
||||||
fixture.window.setFrame(NSRect(x: 0, y: 0, width: 620, height: 520), display: true)
|
fixture.window.setFrame(NSRect(x: 0, y: 0, width: 620, height: 520), display: true)
|
||||||
|
|||||||
Reference in New Issue
Block a user