Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
- Doubao: show Agent Plan windows alongside Coding Plan usage for Volcengine AK/SK accounts that subscribe to both products (#2517). Thanks @Astro-Han!
- Augment: store session cookies owner-only (0600), atomically publish updates, and repair permissions on legacy files (#2567).
- Ollama: direct declined Chrome Keychain access recovery to the provider card's Refresh (⌘R) action instead of the ambiguous manual-cookie path (#2072).
- Menu: switching from a tall Overview to a shorter provider now shrinks the menu instead of stretching the provider-height spacer into a large blank region.
- Menu: merged provider tabs now size to their own content when switching from Overview instead of padding every tab to the tallest provider and leaving large blank regions.
- Codex: persist and budget fork-parent discovery so missing parents quiesce between inventory changes instead of sweeping every rollout on each refresh (#2525, #2538). Thanks @xx205, and @Helmi and @kiranmagic7 for the investigation!
- Claude: Auto cold boot with Keychain disabled loads without manual refresh (#2494, fixes #2493). Thanks @gmkbenjamin!
- Menu: no more stray floating "Refresh" tooltip beside the menu when switching tabs with the cursor over the actions area.
Expand Down
8 changes: 0 additions & 8 deletions Sources/CodexBar/StatusItemController+Menu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ extension StatusItemController {
self.cancelMergedSwitcherSiblingWarmup()
}
self.resetCompactAccountMenuExpansionStateIfIdle()
self.resetStableMenuHeightSessionFloor()
}

func forgetClosedMenu(_ menu: NSMenu) {
Expand Down Expand Up @@ -233,9 +232,6 @@ extension StatusItemController {
"populateMenu",
breadcrumb: "populateMenu:\(provider?.rawValue ?? "merged")")
defer { self.endMenuOperationTrace(trace, menu: menu, provider: provider) }
// LIFO defers: warmup fills sibling caches, card heights finalize, then the
// stable-height pass equalizes provider tabs against the tallest cached tab.
defer { self.applyStableMenuHeightPadding(in: menu) }
defer { self.refreshMenuCardHeights(in: menu) }
// Re-warm sibling tab caches after every populate of the open merged menu so a
// tab switch attaches pre-rendered rows; no-ops for closed or non-merged menus.
Expand Down Expand Up @@ -772,10 +768,6 @@ extension StatusItemController {
{
menu.addItem(.separator())
}
if self.shouldMergeIcons, self.store.enabledProvidersForDisplay().count > 1 {
// Sized by `applyStableMenuHeightPadding` so provider tabs share one height.
menu.addItem(self.makeStableMenuHeightSpacerItem())
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ extension StatusItemController {
in: menu,
enabledProviders: enabledProviders)
}
// Freshly warmed tabs carry zero-height spacers; equalize provider-tab
// heights now so the first switch does not resize the menu window.
self.applyStableMenuHeightPadding(in: menu)
}

private func warmMergedSwitcherContentIfMissing(
Expand Down
171 changes: 0 additions & 171 deletions Sources/CodexBar/StatusItemController+StableMenuHeight.swift

This file was deleted.

4 changes: 0 additions & 4 deletions Sources/CodexBar/StatusItemController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,6 @@ final class StatusItemController: NSObject, NSMenuDelegate, StatusItemControllin
/// Debounced pre-build of sibling switcher tabs for flicker-free tab switches.
/// A common-modes Timer (not a Task) so it fires during NSMenu tracking.
var mergedSwitcherWarmupTimer: Timer?
/// Stable-height padding: grow-only per-session floor and last measured true
/// max, keyed by rounded menu width. See `applyStableMenuHeightPadding`.
var stableMenuHeightSessionFloor: [Int: CGFloat] = [:]
var stableMenuHeightLastContentMax: [Int: CGFloat] = [:]
/// Compact multi-account layout: accounts the user expanded to full cards this menu session.
var compactAccountExpandedIDs: Set<ProviderAccountIdentity> = []
/// Compact multi-account layout: providers whose collapsed healthy tail is revealed this menu session.
Expand Down
45 changes: 7 additions & 38 deletions Tests/CodexBarTests/StatusMenuSwitcherWarmupTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,50 +62,19 @@ final class StatusMenuSwitcherWarmupTests: XCTestCase {
}
}

func test_stableHeightPaddingEqualizesProviderTabs() {
let (controller, menu) = self.makeController()
defer { controller.releaseStatusItemsForTesting() }

controller.warmMergedSwitcherSiblingContent(in: menu)

// Overview is excluded from equalization by design; compare provider tabs only.
var totals: [CGFloat] = []
let visibleSelection = controller.lastMergedMenuContentSelection
if let visibleSelection, visibleSelection != .overview {
let contentStartIndex = controller.providerSwitcherContentStartIndex(in: menu)
let visible = controller.measureTab(items: Array(menu.items[contentStartIndex...]))
totals.append(visible.contentHeight + (visible.spacer?.view?.frame.height ?? 0))
}
let caches = controller.mergedSwitcherContentCaches[ObjectIdentifier(menu)] ?? [:]
for (selection, entry) in caches where selection != .overview {
if selection == visibleSelection {
continue
}
let tab = controller.measureTab(items: entry.items)
XCTAssertNotNil(tab.spacer, "provider tab content must carry a stable-height spacer")
totals.append(tab.contentHeight + (tab.spacer?.view?.frame.height ?? 0))
}
XCTAssertGreaterThan(totals.count, 1)
let reference = totals[0]
for total in totals {
XCTAssertEqual(total, reference, accuracy: 0.5)
}
}

func test_stableHeightPaddingPublishesSpacerHeightThroughIntrinsicSize() {
func test_warmupDoesNotAddFlexibleProviderPadding() {
let (controller, menu) = self.makeController()
defer { controller.releaseStatusItemsForTesting() }

controller.warmMergedSwitcherSiblingContent(in: menu)

let caches = controller.mergedSwitcherContentCaches[ObjectIdentifier(menu)] ?? [:]
let providerSpacers = caches.compactMap { selection, entry -> StableMenuHeightSpacerView? in
guard selection != .overview else { return nil }
return controller.measureTab(items: entry.items).spacer?.view as? StableMenuHeightSpacerView
}
XCTAssertFalse(providerSpacers.isEmpty)
for spacer in providerSpacers {
XCTAssertEqual(spacer.intrinsicContentSize.height, spacer.frame.height, accuracy: 0.5)
let providerEntries = caches.filter { $0.key != .overview }
XCTAssertFalse(providerEntries.isEmpty)
for (_, entry) in providerEntries {
XCTAssertFalse(entry.items.contains { item in
item.title.isEmpty && item.view?.frame.height == 0
}, "provider tabs must size to their content instead of carrying a flexible blank row")
}
}

Expand Down