WIP: keep selected clip visible in shelf
This commit is contained in:
@@ -566,11 +566,32 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateSelection() {
|
private func updateSelection() {
|
||||||
|
var selectedCard: ClipboardItemCardView?
|
||||||
for (index, card) in cardViews.enumerated() {
|
for (index, card) in cardViews.enumerated() {
|
||||||
card.setSelected(index == viewModel.selectedIndex)
|
let selected = index == viewModel.selectedIndex
|
||||||
|
card.setSelected(selected)
|
||||||
|
if selected {
|
||||||
|
selectedCard = card
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let selectedCard {
|
||||||
|
scrollCardIntoView(selectedCard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func scrollCardIntoView(_ card: NSView) {
|
||||||
|
guard scrollView.documentView === itemsStack else { return }
|
||||||
|
guard card.window != nil else { return }
|
||||||
|
scrollView.layoutSubtreeIfNeeded()
|
||||||
|
itemsStack.layoutSubtreeIfNeeded()
|
||||||
|
|
||||||
|
let frame = card.convert(card.bounds, to: itemsStack)
|
||||||
|
let paddedFrame = frame.insetBy(dx: -Metrics.cardSpacing, dy: 0)
|
||||||
|
itemsStack.scrollToVisible(paddedFrame)
|
||||||
|
scrollView.reflectScrolledClipView(scrollView.contentView)
|
||||||
|
}
|
||||||
|
|
||||||
private func updateStatus(_ message: String) {
|
private func updateStatus(_ message: String) {
|
||||||
let text: String
|
let text: String
|
||||||
if !message.isEmpty {
|
if !message.isEmpty {
|
||||||
@@ -846,6 +867,18 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
|
|||||||
cardViews.map(\.debugHeaderBadgeSymbol)
|
cardViews.map(\.debugHeaderBadgeSymbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var debugSelectedCardFrameInDocument: NSRect {
|
||||||
|
guard viewModel.selectedIndex >= 0, viewModel.selectedIndex < cardViews.count else {
|
||||||
|
return .zero
|
||||||
|
}
|
||||||
|
let card = cardViews[viewModel.selectedIndex]
|
||||||
|
return card.convert(card.bounds, to: itemsStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugCardRailVisibleRect: NSRect {
|
||||||
|
scrollView.contentView.bounds
|
||||||
|
}
|
||||||
|
|
||||||
var debugFirstCardMenuTitles: [String] {
|
var debugFirstCardMenuTitles: [String] {
|
||||||
cardViews.first?.debugMenuTitles ?? []
|
cardViews.first?.debugMenuTitles ?? []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,6 +243,38 @@ final class ClipboardPanelViewTests: XCTestCase {
|
|||||||
XCTAssertTrue(fixture.view.debugCustomCollectionTitles.contains("Product References"))
|
XCTAssertTrue(fixture.view.debugCustomCollectionTitles.contains("Product References"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testSelectionScrollsCardRailToKeepSelectedCardVisible() {
|
||||||
|
let fixture = makePanelFixture()
|
||||||
|
fixture.window.setFrame(NSRect(x: 0, y: 0, width: 620, height: 520), display: true)
|
||||||
|
|
||||||
|
for index in 0..<8 {
|
||||||
|
fixture.store.upsert(makeTextItem("Scrollable clipboard item \(index)", store: fixture.store))
|
||||||
|
drainMainQueue()
|
||||||
|
}
|
||||||
|
fixture.window.contentView?.layoutSubtreeIfNeeded()
|
||||||
|
|
||||||
|
fixture.viewModel.selectFirstItem()
|
||||||
|
drainMainQueue()
|
||||||
|
fixture.window.contentView?.layoutSubtreeIfNeeded()
|
||||||
|
XCTAssertLessThanOrEqual(fixture.view.debugCardRailVisibleRect.minX, 1)
|
||||||
|
|
||||||
|
fixture.viewModel.selectItem(at: fixture.viewModel.visibleItems.count - 1)
|
||||||
|
drainMainQueue()
|
||||||
|
fixture.window.contentView?.layoutSubtreeIfNeeded()
|
||||||
|
|
||||||
|
let visibleRect = fixture.view.debugCardRailVisibleRect
|
||||||
|
let selectedFrame = fixture.view.debugSelectedCardFrameInDocument
|
||||||
|
XCTAssertGreaterThan(visibleRect.minX, 0)
|
||||||
|
XCTAssertLessThanOrEqual(selectedFrame.minX, visibleRect.maxX)
|
||||||
|
XCTAssertGreaterThanOrEqual(visibleRect.maxX + 1, selectedFrame.maxX)
|
||||||
|
|
||||||
|
fixture.viewModel.selectItem(at: 0)
|
||||||
|
drainMainQueue()
|
||||||
|
fixture.window.contentView?.layoutSubtreeIfNeeded()
|
||||||
|
|
||||||
|
XCTAssertLessThanOrEqual(fixture.view.debugCardRailVisibleRect.minX, 1)
|
||||||
|
}
|
||||||
|
|
||||||
func testFilteredEmptyStateNamesCurrentCollection() {
|
func testFilteredEmptyStateNamesCurrentCollection() {
|
||||||
let fixture = makePanelFixture()
|
let fixture = makePanelFixture()
|
||||||
fixture.store.upsert(makeTextItem("Only text exists", store: fixture.store))
|
fixture.store.upsert(makeTextItem("Only text exists", store: fixture.store))
|
||||||
|
|||||||
Reference in New Issue
Block a user