1655 lines · 72.9 KB · Swift
RawDownload
import AppKitimport CodexBarCoreimport Observationimport QuartzCoreimport SwiftUI // MARK: - NSMenu construction extension StatusItemController {    static let menuCardBaseWidth: CGFloat = 310    private static let maxOverviewProviders = SettingsStore.mergedOverviewProviderLimit    static let overviewRowIdentifierPrefix = "overviewRow-"    static let persistentRefreshMenuItemID = "persistentRefreshAction"    private static let defaultMenuOpenRefreshDelay: Duration = .seconds(1.2)    #if DEBUG    private static var menuOpenRefreshDelayForTesting: Duration = .seconds(1.2)    static func setMenuOpenRefreshDelayForTesting(_ delay: Duration) {        self.menuOpenRefreshDelayForTesting = delay    }     static func resetMenuOpenRefreshDelayForTesting() {        self.menuOpenRefreshDelayForTesting = self.defaultMenuOpenRefreshDelay    }    #endif     private static var menuOpenRefreshDelay: Duration {        #if DEBUG        menuOpenRefreshDelayForTesting        #else        defaultMenuOpenRefreshDelay        #endif    }     static let usageBreakdownChartID = "usageBreakdownChart"    static let creditsHistoryChartID = "creditsHistoryChart"    static let costHistoryChartID = "costHistoryChart"    static let usageHistoryChartID = "usageHistoryChart"    static let storageBreakdownID = "storageBreakdown"    static let statusComponentsID = "statusComponents"     func shortcut(for action: MenuDescriptor.MenuAction) -> (key: String, modifiers: NSEvent.ModifierFlags)? {        switch action {        case .refresh:            ("r", [.command])        case .settings:            (",", [.command])        case .quit:            ("q", [.command])        default:            nil        }    }     func isPersistentRefreshItem(_ item: NSMenuItem) -> Bool {        item.representedObject as? String == Self.persistentRefreshMenuItemID    }     func makeMenu() -> NSMenu {        guard self.shouldMergeIcons else {            return self.makeMenu(for: nil)        }        return self.makeBaseMenu()    }     func menuNeedsUpdate(_ menu: NSMenu) {        guard self.shouldMergeIcons, menu === self.mergedMenu else { return }        self.refreshMenuForOpenIfNeeded(menu, provider: self.resolvedMenuProvider())    }     func menuWillOpen(_ menu: NSMenu) {        // Records interaction and may bring an adaptive timer forward; never refreshes synchronously.        self.store.noteMenuOpened()         let trace = self.beginMenuOperationTrace("menuWillOpen", breadcrumb: "menuWillOpen")        defer { self.endMenuOperationTrace(trace, menu: menu, provider: self.menuProvider(for: menu)) }         // Keep the menu drawing in the current system appearance rather than the menu bar's        // (possibly dark) vibrant appearance. Done before any early return so submenus match too.        StatusMenuAppearance.pin(menu)         self.cancelDeferredMenuInteractionRefreshTask()        self.cancelClosedMenuRebuild(menu)         // Track whether this is the root menu opening (no menus were open). Only the root open rebuilds        // all content from current data, so the readiness baseline is re-anchored only here — re-anchoring        // on a nested submenu open could mask a pending refresh for the already-open parent menu.        let menuTrackingWasIdle = self.openMenus.isEmpty         if self.isHostedSubviewMenu(menu) {            if !self.hydrateHostedSubviewMenuIfNeeded(menu) {                self.refreshHostedSubviewMenu(menu)            }            if self.isMenuRefreshEnabled, self.isOpenAIWebSubviewMenu(menu) {                self.deferOpenAIDashboardRefreshUntilMenuCloses(reason: "submenu open")            }            if self.isMenuRefreshEnabled {                // Intentionally skip open-menu tracking when refresh is disabled (tests).                // If refresh is re-enabled while this menu stays open, it will not be backfilled until next open.                self.openMenus[ObjectIdentifier(menu)] = menu                if menuTrackingWasIdle {                    self.resyncMenuAdjunctReadinessBaseline()                }            }            // Removed redundant async refresh - single pass is sufficient after initial layout            return        }         var provider: UsageProvider?        if self.shouldMergeIcons {            let resolvedProvider = self.resolvedMenuProvider()            self.lastMenuProvider = resolvedProvider ?? .codex            provider = resolvedProvider        } else {            if let menuProvider = self.menuProviders[ObjectIdentifier(menu)] {                self.lastMenuProvider = menuProvider                provider = menuProvider            } else if menu === self.fallbackMenu {                self.lastMenuProvider = self.store.enabledProvidersForDisplay().first ?? .codex                provider = nil            } else {                let resolved = self.store.enabledProvidersForDisplay().first ?? .codex                self.lastMenuProvider = resolved                provider = resolved            }        }         if self.isMenuRefreshEnabled, (provider ?? self.lastMenuProvider) == .codex {            self.deferOpenAIDashboardRefreshUntilMenuCloses(reason: "parent menu open")        }        if self.settings.providerStorageFootprintsEnabled {            self.store.refreshStorageFootprintsForOverview()        }         let menuWasFreshBeforeOpen = !self.menuNeedsRefresh(menu)        self.refreshMenuForOpenIfNeeded(menu, provider: provider)        self.scheduleCodexAccountMenuProjectionRevalidationIfNeeded(            for: self.renderedProviders(for: menu))        if self.isMenuRefreshEnabled {            // Intentionally skip open-menu tracking when refresh is disabled (tests).            // If refresh is re-enabled while this menu stays open, it will not be backfilled until next open.            self.openMenus[ObjectIdentifier(menu)] = menu            // Only re-anchor when the opened menu actually shows current data. During an in-flight provider            // refresh `refreshMenuForOpenIfNeeded` can preserve stale content; resyncing the baseline to            // live store data in that case would mask the refresh-completion update (#1351).            if menuTrackingWasIdle, !self.menuNeedsRefresh(menu) {                self.resyncMenuAdjunctReadinessBaselineForRootOpen(                    menu,                    provider: provider,                    menuWasFreshBeforeOpen: menuWasFreshBeforeOpen)            }            self.installProviderSwitcherShortcutMonitorIfNeeded(for: menu)            // Only schedule refresh after menu is registered as open - refreshNow is called async            self.scheduleOpenMenuRefresh(for: menu)        }    }     func menuDidClose(_ menu: NSMenu) {        let wasHostedSubviewMenu = self.isHostedSubviewMenu(menu)        self.forgetClosedMenu(menu)        if wasHostedSubviewMenu {            self.refreshOpenMenusAfterHostedSubviewClose()        }    }     func forgetClosedMenu(_ menu: NSMenu) {        let key = ObjectIdentifier(menu)        let wasMergedMenu = menu === self.mergedMenu         if key == self.providerSwitcherShortcutMenuID {            self.removeProviderSwitcherShortcutMonitor()        }         self.clearMergedSwitcherContentCache(for: menu)        let wasTracked = self.openMenus.removeValue(forKey: key) != nil        let menuTrackingEnded = wasTracked && self.openMenus.isEmpty        if self.openMenus.isEmpty {            self.parentMenuRebuildPendingAfterHostedSubviewClose = false        }        self.cancelMenuWork(key)        self.clearMenuHighlight(key)         let isPersistentMenu = menu === self.mergedMenu ||            menu === self.fallbackMenu ||            self.providerMenus.values.contains { $0 === menu }        if !isPersistentMenu {            self.removeMenuTrackingState(key)        } else if self.menuNeedsRefresh(menu) {            self.handleClosedPersistentMenuNeedingRefresh(menu)        }        self.menuSession.clearParentRebuildDeferral(key)        self.scheduleDeferredMenuInteractionRefreshIfNeeded()        if wasMergedMenu {            self.applyDeferredMergedIconRenderAfterTrackingIfNeeded()        }        if menuTrackingEnded {            self.prepareAttachedClosedMenusIfNeeded()        }    }     func menu(_ menu: NSMenu, willHighlight item: NSMenuItem?) {        let key = ObjectIdentifier(menu)        let previous = self.highlightedMenuItems[key]        guard previous !== item else { return }         if let previous {            (previous.view as? MenuCardHighlighting)?.setHighlighted(false)        }         if let item,           item.isEnabled,           (item.view as? MenuCardHighlighting)?.allowsMenuHighlight != false        {            self.highlightedMenuItems[key] = item            (item.view as? MenuCardHighlighting)?.setHighlighted(true)        } else {            self.highlightedMenuItems.removeValue(forKey: key)        }    }     func populateMenu(_ menu: NSMenu, provider: UsageProvider?) {        let trace = self.beginMenuOperationTrace(            "populateMenu",            breadcrumb: "populateMenu:\(provider?.rawValue ?? "merged")")        defer { self.endMenuOperationTrace(trace, menu: menu, provider: provider) }        defer { self.refreshMenuCardHeights(in: menu) }         let enabledProviders = self.store.enabledProvidersForDisplay()        let includesOverview = self.includesOverviewTab(enabledProviders: enabledProviders)        let switcherSelection = self.shouldMergeIcons && enabledProviders.count > 1            ? self.resolvedSwitcherSelection(                enabledProviders: enabledProviders,                includesOverview: includesOverview)            : nil        let isOverviewSelected = switcherSelection == .overview        let selectedProvider = if isOverviewSelected {            self.resolvedMenuProvider(enabledProviders: enabledProviders)        } else {            switcherSelection?.provider ?? provider        }        let currentProvider = selectedProvider ?? enabledProviders.first ?? .codex        let rawCodexAccountDisplay = isOverviewSelected ? nil : self.codexAccountMenuDisplay(for: currentProvider)        let codexAccountDisplay = isOverviewSelected            ? nil            : self.stableCodexAccountMenuDisplay(                rawCodexAccountDisplay,                menu: menu,                provider: currentProvider)        let tokenAccountDisplay = isOverviewSelected ? nil : self.tokenAccountMenuDisplay(for: currentProvider)        let showAllAccounts = (tokenAccountDisplay?.showAll ?? false) || (codexAccountDisplay?.showAll ?? false)        let openAIContext = self.openAIWebContext(            currentProvider: currentProvider,            showAllAccounts: showAllAccounts)        let descriptor = self.makeMenuDescriptor(            provider: selectedProvider,            includeContextualActions: !isOverviewSelected)        let menuWidth = self.menuCardWidth(            for: enabledProviders,            selectedProvider: selectedProvider,            descriptor: descriptor)         let hasTokenSwitcher = menu.items.contains { $0.view is TokenAccountSwitcherView }        let hasCodexSwitcher = menu.items.contains { $0.view is CodexAccountSwitcherView }        let switcherProvidersMatch = enabledProviders == self.lastSwitcherProviders        let switcherUsageBarsShowUsedMatch = self.settings.usageBarsShowUsed == self.lastSwitcherUsageBarsShowUsed        let switcherSelectionMatches = switcherSelection == self.lastMergedSwitcherSelection        let switcherOverviewAvailabilityMatches = includesOverview == self.lastSwitcherIncludesOverview        let menuLocalizationMatches = self.menuLocalizationSignature() == self.lastMenuLocalizationSignature        let tokenSwitcherCompatible = tokenAccountDisplay == self.lastTokenAccountMenuDisplay &&            ((tokenAccountDisplay?.showSwitcher == true && hasTokenSwitcher) ||                (tokenAccountDisplay?.showSwitcher != true && !hasTokenSwitcher))        let codexSwitcherCompatible = codexAccountDisplay == self.lastCodexAccountMenuDisplay &&            ((codexAccountDisplay?.showSwitcher == true && hasCodexSwitcher) ||                (codexAccountDisplay?.showSwitcher != true && !hasCodexSwitcher))        let reusableRowWidthsMatch = self.reusableFixedWidthRows(in: menu).allSatisfy { item in            guard let view = item.view else { return false }            return abs(view.frame.width - menuWidth) <= 0.5        }        let providerSwitcherWidthMatches = (menu.items.first?.view as? ProviderSwitcherView).map { view in            abs(view.frame.width - menuWidth) <= 0.5        } ?? false        let canSmartUpdate = self.shouldMergeIcons &&            enabledProviders.count > 1 &&            !isOverviewSelected &&            switcherProvidersMatch &&            switcherUsageBarsShowUsedMatch &&            switcherSelectionMatches &&            switcherOverviewAvailabilityMatches &&            menuLocalizationMatches &&            tokenSwitcherCompatible &&            codexSwitcherCompatible &&            reusableRowWidthsMatch &&            !menu.items.isEmpty &&            menu.items.first?.view is ProviderSwitcherView         #if DEBUG        if self.openMenus[ObjectIdentifier(menu)] != nil {            self.menuLogger.debug(                "populateMenu(open): provider=\(String(describing: provider)) " +                    "display=\(enabledProviders.map(\.rawValue)) " +                    "available=\(self.store.enabledProviders().map(\.rawValue)) " +                    "selection=\(String(describing: switcherSelection)) " +                    "last=\(String(describing: self.lastMergedSwitcherSelection)) " +                    "smart=\(canSmartUpdate)")        }        #endif         if canSmartUpdate {            self.updateMenuContentPreservingSwitcher(                menu,                context: MenuUpdateContext(                    provider: selectedProvider,                    currentProvider: currentProvider,                    switcherSelection: switcherSelection ?? .provider(currentProvider),                    menuWidth: menuWidth,                    codexAccountDisplay: codexAccountDisplay,                    tokenAccountDisplay: tokenAccountDisplay,                    openAIContext: openAIContext,                    descriptor: descriptor))            return        }         let canPreserveProviderSwitcher = self.shouldMergeIcons &&            enabledProviders.count > 1 &&            switcherProvidersMatch &&            switcherUsageBarsShowUsedMatch &&            switcherOverviewAvailabilityMatches &&            menuLocalizationMatches &&            providerSwitcherWidthMatches &&            !menu.items.isEmpty &&            menu.items.first?.view is ProviderSwitcherView         #if DEBUG        if self.openMenus[ObjectIdentifier(menu)] != nil {            self.menuLogger.debug(                "populateMenu(open): preserveSwitcher=\(canPreserveProviderSwitcher) " +                    "widthMatch=\(providerSwitcherWidthMatches)")        }        #endif         if canPreserveProviderSwitcher {            self.updateMenuContentPreservingSwitcher(                menu,                context: MenuUpdateContext(                    provider: selectedProvider,                    currentProvider: currentProvider,                    switcherSelection: switcherSelection ?? .provider(currentProvider),                    menuWidth: menuWidth,                    codexAccountDisplay: codexAccountDisplay,                    tokenAccountDisplay: tokenAccountDisplay,                    openAIContext: openAIContext,                    descriptor: descriptor))            return        }         #if DEBUG        if self.openMenus[ObjectIdentifier(menu)] != nil, menu.items.first?.view is ProviderSwitcherView {            self.menuLogger.debug("populateMenu(open): rebuilding whole menu and replacing provider switcher")        }        #endif        self.rebuildMenuContent(            menu,            context: MenuRebuildContext(                enabledProviders: enabledProviders,                includesOverview: includesOverview,                switcherSelection: switcherSelection,                currentProvider: currentProvider,                selectedProvider: selectedProvider,                menuWidth: menuWidth,                codexAccountDisplay: codexAccountDisplay,                tokenAccountDisplay: tokenAccountDisplay,                openAIContext: openAIContext,                descriptor: descriptor))    }     private func reusableFixedWidthRows(in menu: NSMenu) -> [NSMenuItem] {        guard !menu.items.isEmpty else { return [] }         var reusableRows: [NSMenuItem] = []        var index = self.providerSwitcherContentStartIndex(in: menu)        if index > 0 {            reusableRows.append(menu.items[0])        }        if menu.items.count > index,           menu.items[index].view is CodexAccountSwitcherView        {            reusableRows.append(menu.items[index])            index += 2        }        if menu.items.count > index,           menu.items[index].view is TokenAccountSwitcherView        {            reusableRows.append(menu.items[index])        }        return reusableRows    }     private func rebuildMenuContent(        _ menu: NSMenu,        context: MenuRebuildContext)    {        self.performMenuMutationWithoutAnimation {            let displacedSelection = self.lastMergedMenuContentSelection            self.lastMergedMenuContentSelection = nil            self.harvestRecyclableMenuCardViews(in: menu, fromIndex: 0, displacedSelection: displacedSelection)            defer { self.clearMenuCardViewRecyclePool() }            menu.removeAllItems()            let contentSelection = context.switcherSelection ?? .provider(context.currentProvider)            self.addProviderSwitcherIfNeeded(                to: menu,                enabledProviders: context.enabledProviders,                includesOverview: context.includesOverview,                selection: context.switcherSelection ?? .provider(context.currentProvider),                width: context.menuWidth)            // Track which providers the switcher was built with for smart update detection            if self.shouldMergeIcons, context.enabledProviders.count > 1 {                self.rememberMergedSwitcherState(                    context.enabledProviders,                    context.switcherSelection,                    context.includesOverview)            }            if self.shouldMergeIcons,               context.enabledProviders.count > 1,               self.addCachedMergedSwitcherContent(                   for: contentSelection,                   to: menu,                   menuWidth: context.menuWidth,                   codexAccountDisplay: context.codexAccountDisplay,                   tokenAccountDisplay: context.tokenAccountDisplay)            {                return            }            self.addCodexAccountSwitcherIfNeeded(                to: menu,                display: context.codexAccountDisplay,                width: context.menuWidth)            self.lastCodexAccountMenuDisplay = context.codexAccountDisplay            self.addTokenAccountSwitcherIfNeeded(                to: menu,                display: context.tokenAccountDisplay,                width: context.menuWidth)            self.lastTokenAccountMenuDisplay = context.tokenAccountDisplay            let menuContext = MenuCardContext(                currentProvider: context.currentProvider,                selectedProvider: context.selectedProvider,                menuWidth: context.menuWidth,                codexAccountDisplay: context.codexAccountDisplay,                tokenAccountDisplay: context.tokenAccountDisplay,                openAIContext: context.openAIContext)            self.addPrimaryMenuContent(                to: menu,                context: menuContext,                switcherSelection: contentSelection)            self.addActionableSections(context.descriptor.sections, to: menu, width: context.menuWidth)            self.cacheVisibleMergedSwitcherContent(                in: menu,                selection: contentSelection,                contentStartIndex: self.providerSwitcherContentStartIndex(in: menu),                menuWidth: context.menuWidth,                contentVersion: self.menuSession.contentVersion)        }    }     private func openAIWebContext(        currentProvider: UsageProvider,        showAllAccounts: Bool) -> OpenAIWebContext    {        let codexProjection = self.store.codexConsumerProjectionIfNeeded(            for: currentProvider,            surface: .liveCard)        let hasCreditsHistory = codexProjection?.hasCreditsHistory == true        let hasUsageBreakdown = codexProjection?.hasUsageBreakdown == true        let hasCostHistory = self.settings.costSummaryShowsSubmenu(for: currentProvider) &&            (self.store.tokenSnapshot(for: currentProvider)?.daily.isEmpty == false)        let canShowBuyCredits = self.settings.showOptionalCreditsAndExtraUsage &&            codexProjection?.canShowBuyCredits == true        let hasOpenAIWebMenuItems = !showAllAccounts &&            (hasCreditsHistory || hasUsageBreakdown || hasCostHistory)        return OpenAIWebContext(            hasUsageBreakdown: hasUsageBreakdown,            hasCreditsHistory: hasCreditsHistory,            hasCostHistory: hasCostHistory,            canShowBuyCredits: canShowBuyCredits,            hasOpenAIWebMenuItems: hasOpenAIWebMenuItems)    }     private func addProviderSwitcherIfNeeded(        to menu: NSMenu,        enabledProviders: [UsageProvider],        includesOverview: Bool,        selection: ProviderSwitcherSelection,        width: CGFloat)    {        guard self.shouldMergeIcons, enabledProviders.count > 1 else { return }        let switcherItem = self.makeProviderSwitcherItem(            providers: enabledProviders,            includesOverview: includesOverview,            selected: selection,            menu: menu,            width: width)        menu.addItem(switcherItem)

Lines 1–500 of 1655.