1207 lines · 48.7 KB · Swift
RawDownload
import AppKitimport CodexBarCoreimport QuartzCore extension StatusItemController {    private static let loadingPercentEpsilon = 0.0001    private static let blinkActiveTickInterval: Duration = .milliseconds(75)    private static let blinkIdleFallbackInterval: Duration = .seconds(1)    static let loadingAnimationFPS: Double = 30.0    static let loadingAnimationPhaseIncrement: Double =        2.7 / StatusItemController.loadingAnimationFPS    private static let loadingAnimationMaxContinuousDuration: TimeInterval = 30.0    func needsMenuBarIconAnimation() -> Bool {        if self.shouldMergeIcons {            let primaryProvider = self.primaryProviderForUnifiedIcon()            return self.shouldAnimate(provider: primaryProvider)        }        return UsageProvider.allCases.contains { self.shouldAnimate(provider: $0) }    }     func updateBlinkingState() {        #if DEBUG        guard !self.isReleasedForTesting else { return }        #endif        // During the loading animation, blink ticks can overwrite the animated menu bar icon and cause flicker.        if self.needsMenuBarIconAnimation() {            self.stopBlinking()            return        }         let blinkingEnabled = self.isBlinkingAllowed()        // Use display list so merged-mode visibility stays consistent with shouldMergeIcons.        let displayProviders = self.store.enabledProvidersForDisplay()        let anyEnabled = !displayProviders.isEmpty || self.store.debugForceAnimation        let anyVisible = UsageProvider.allCases.contains { self.isVisible($0) }        let mergeIcons = self.shouldMergeIcons        let shouldBlink = mergeIcons ? anyEnabled : anyVisible        if blinkingEnabled, shouldBlink {            if self.blinkTask == nil {                self.seedBlinkStatesIfNeeded()                self.blinkTask = Task { [weak self] in                    while !Task.isCancelled {                        let delay = await MainActor.run {                            self?.blinkTickSleepDuration(now: Date())                                ?? Self.blinkIdleFallbackInterval                        }                        try? await Task.sleep(for: delay)                        await MainActor.run { self?.tickBlink() }                    }                }            }        } else {            self.stopBlinking()        }    }     private func seedBlinkStatesIfNeeded() {        let now = Date()        for provider in UsageProvider.allCases where self.blinkStates[provider] == nil {            self.blinkStates[provider] = BlinkState(                nextBlink: now.addingTimeInterval(BlinkState.randomDelay()))        }    }     private func stopBlinking() {        self.blinkTask?.cancel()        self.blinkTask = nil        self.blinkAmounts.removeAll()        let phase: Double? = self.needsMenuBarIconAnimation() ? self.animationPhase : nil        if self.shouldMergeIcons {            self.applyIcon(phase: phase)        } else {            for provider in UsageProvider.allCases {                self.applyIcon(for: provider, phase: phase)            }        }    }     private func blinkTickSleepDuration(now: Date) -> Duration {        let mergeIcons = self.shouldMergeIcons        var nextWakeAt: Date?         for provider in UsageProvider.allCases {            let shouldRender = mergeIcons ? self.isEnabled(provider) : self.isVisible(provider)            guard shouldRender, !self.shouldAnimate(provider: provider, mergeIcons: mergeIcons)            else { continue }             let state =                self                    .blinkStates[provider]                    ?? BlinkState(nextBlink: now.addingTimeInterval(BlinkState.randomDelay()))            if state.blinkStart != nil {                return Self.blinkActiveTickInterval            }             let candidate: Date = state.pendingSecondStart ?? state.nextBlink            if let current = nextWakeAt {                if candidate < current {                    nextWakeAt = candidate                }            } else {                nextWakeAt = candidate            }        }         guard let nextWakeAt else { return Self.blinkIdleFallbackInterval }        let delay = nextWakeAt.timeIntervalSince(now)        if delay <= 0 { return Self.blinkActiveTickInterval }        return .seconds(delay)    }     private func tickBlink(now: Date = .init()) {        guard self.isBlinkingAllowed(at: now) else {            self.stopBlinking()            return        }         let blinkDuration: TimeInterval = 0.36        let doubleBlinkChance = 0.18        let doubleDelayRange: ClosedRange<TimeInterval> = 0.22...0.34        // Cache merge state once per tick to avoid repeated enabled-provider lookups.        let mergeIcons = self.shouldMergeIcons         for provider in UsageProvider.allCases {            let shouldRender = mergeIcons ? self.isEnabled(provider) : self.isVisible(provider)            guard shouldRender, !self.shouldAnimate(provider: provider, mergeIcons: mergeIcons)            else {                self.clearMotion(for: provider)                continue            }             var state =                self                    .blinkStates[provider]                    ?? BlinkState(nextBlink: now.addingTimeInterval(BlinkState.randomDelay()))             if let pendingSecond = state.pendingSecondStart, now >= pendingSecond {                state.blinkStart = now                state.pendingSecondStart = nil            }             if let start = state.blinkStart {                let elapsed = now.timeIntervalSince(start)                if elapsed >= blinkDuration {                    state.blinkStart = nil                    if let pending = state.pendingSecondStart, now < pending {                        // Wait for the planned double-blink.                    } else {                        state.pendingSecondStart = nil                        state.nextBlink = now.addingTimeInterval(BlinkState.randomDelay())                    }                    self.clearMotion(for: provider)                } else {                    let progress = max(0, min(elapsed / blinkDuration, 1))                    let symmetric = progress < 0.5 ? progress * 2 : (1 - progress) * 2                    let eased = pow(symmetric, 2.2) // slightly punchier than smoothstep                    self.assignMotion(amount: CGFloat(eased), for: provider, effect: state.effect)                }            } else if now >= state.nextBlink {                state.blinkStart = now                state.effect = self.randomEffect(for: provider)                if state.effect == .blink, Double.random(in: 0...1) < doubleBlinkChance {                    state.pendingSecondStart = now.addingTimeInterval(                        Double.random(in: doubleDelayRange))                }                self.clearMotion(for: provider)            } else {                self.clearMotion(for: provider)            }             self.blinkStates[provider] = state            if !mergeIcons {                self.applyIcon(for: provider, phase: nil)            }        }        if mergeIcons {            self.applyIcon(phase: nil)        }    }     private func blinkAmount(for provider: UsageProvider) -> CGFloat {        guard self.isBlinkingAllowed() else { return 0 }        return self.blinkAmounts[provider] ?? 0    }     private func wiggleAmount(for provider: UsageProvider) -> CGFloat {        guard self.isBlinkingAllowed() else { return 0 }        return self.wiggleAmounts[provider] ?? 0    }     private func tiltAmount(for provider: UsageProvider) -> CGFloat {        guard self.isBlinkingAllowed() else { return 0 }        return self.tiltAmounts[provider] ?? 0    }     private func assignMotion(amount: CGFloat, for provider: UsageProvider, effect: MotionEffect) {        switch effect {        case .blink:            self.blinkAmounts[provider] = amount            self.wiggleAmounts[provider] = 0            self.tiltAmounts[provider] = 0        case .wiggle:            self.wiggleAmounts[provider] = amount            self.blinkAmounts[provider] = 0            self.tiltAmounts[provider] = 0        case .tilt:            self.tiltAmounts[provider] = amount            self.blinkAmounts[provider] = 0            self.wiggleAmounts[provider] = 0        }    }     private func clearMotion(for provider: UsageProvider) {        self.blinkAmounts[provider] = 0        self.wiggleAmounts[provider] = 0        self.tiltAmounts[provider] = 0    }     private func randomEffect(for provider: UsageProvider) -> MotionEffect {        if provider == .claude {            Bool.random() ? .blink : .wiggle        } else {            Bool.random() ? .blink : .tilt        }    }     private func isBlinkingAllowed(at date: Date = .init()) -> Bool {        if self.settings.randomBlinkEnabled { return true }        if let until = self.blinkForceUntil, until > date { return true }        self.blinkForceUntil = nil        return false    }     @discardableResult    func applyIcon(        phase: Double?,        bypassMergedMenuTrackingDeferral: Bool = false) -> Bool    {        guard let button = self.statusItem.button else { return false }        if !bypassMergedMenuTrackingDeferral,           self.deferMergedIconRenderDuringMenuTrackingIfNeeded() { return true }         let style = self.store.iconStyle        let showUsed = self.settings.usageBarsShowUsed        let showBrandPercent = self.settings.menuBarShowsBrandIconWithPercent        let primaryProvider = self.primaryProviderForUnifiedIcon()        let resolverStyle = self.store.style(for: primaryProvider)        let snapshot = self.store.snapshot(for: primaryProvider)        let warningFlash = self.quotaWarningFlashActive(provider: primaryProvider)         // IconRenderer treats these values as a left-to-right "progress fill" percentage; depending on the        // user setting we pass either "percent left" or "percent used".        let resolved = snapshot.map {            IconRemainingResolver.resolvedPercents(                snapshot: $0,                style: resolverStyle,                showUsed: showUsed,                renderingStyle: style,                secondaryOverrideWindowID: self.settings.copilotIconSecondaryWindowOverrideID(snapshot: $0))        }        var primary = resolved?.primary        var weekly = resolved?.secondary        var credits = self.menuBarCreditsRemainingForIcon(provider: primaryProvider, snapshot: snapshot)        var stale = self.store.isStale(provider: primaryProvider)        var morphProgress: Double?         let needsAnimation = self.needsMenuBarIconAnimation()        if let phase, needsAnimation {            var pattern = self.animationPattern            if style == .combined, pattern == .unbraid {                pattern = .cylon            }            if pattern == .unbraid {                morphProgress = pattern.value(phase: phase) / 100                primary = nil                weekly = nil                credits = nil                stale = false            } else {                // Keep loading animation layout stable: IconRenderer uses `weeklyRemaining > 0` to switch layouts,                // so hitting an exact 0 would flip between "normal" and "weekly exhausted" rendering.                primary = max(pattern.value(phase: phase), Self.loadingPercentEpsilon)                weekly = max(                    pattern.value(phase: phase + pattern.secondaryOffset),                    Self.loadingPercentEpsilon)                credits = nil                stale = false            }        }         let blink: CGFloat = style == .combined ? 0 : self.blinkAmount(for: primaryProvider)        let wiggle: CGFloat = style == .combined ? 0 : self.wiggleAmount(for: primaryProvider)        let tilt: CGFloat =            style == .combined ? 0 : self.tiltAmount(for: primaryProvider) * .pi / 28         let statusIndicator = self.store.statusIndicator(for: primaryProvider)        if showBrandPercent,           let brand = ProviderBrandIcon.image(for: primaryProvider)        {            let displayText = self.menuBarDisplayText(for: primaryProvider, snapshot: snapshot)            let signature = [                "mode=brandPercent",                "provider=\(primaryProvider.rawValue)",                "style=\(String(describing: style))",                "primary=\(Self.iconSignatureValue(primary))",                "weekly=\(Self.iconSignatureValue(weekly))",                "credits=\(Self.iconSignatureValue(credits))",                "stale=\(stale ? "1" : "0")",                "status=\(statusIndicator.rawValue)",                "text=\(displayText ?? "nil")",                "warningFlash=\(warningFlash ? "1" : "0")",                "anim=\(needsAnimation ? "1" : "0")",                "hideCritters=\(self.settings.menuBarHidesCritters ? "1" : "0")",            ].joined(separator: "|")            if self.shouldSkipMergedIconRender(signature) {                // AppKit can lose button title/image-position state independently of the cached render signature.                // Keep the cheap title path self-healing even when the icon image itself can be skipped.                self.setButtonTitle(displayText, for: button)                self.noteIconPerfRender(skipped: true)                return true            }            self.setButtonImage(                warningFlash ? Self.quotaWarningFlashImage(base: brand) : brand, for: button)            self.setButtonTitle(displayText, for: button)            self.noteIconPerfRender(skipped: false)            return false        }         self.setButtonTitle(nil, for: button)        if let morphProgress {            let signature = [                "mode=morph",                "provider=\(primaryProvider.rawValue)",                "style=\(String(describing: style))",                "morph=\(Self.iconSignatureValue(morphProgress))",                "status=\(statusIndicator.rawValue)",                "warningFlash=\(warningFlash ? "1" : "0")",                "anim=\(needsAnimation ? "1" : "0")",                "hideCritters=\(self.settings.menuBarHidesCritters ? "1" : "0")",            ].joined(separator: "|")            if self.shouldSkipMergedIconRender(signature) {                self.noteIconPerfRender(skipped: true)                return true            }            let image = IconRenderer.makeMorphIcon(                progress: morphProgress,                style: style,                hideCritters: self.settings.menuBarHidesCritters)            self.setButtonImage(                warningFlash ? Self.quotaWarningFlashImage(base: image) : image, for: button)        } else {            let signature = [                "mode=icon",                "provider=\(primaryProvider.rawValue)",                "style=\(String(describing: style))",                "primary=\(Self.iconSignatureValue(primary))",                "weekly=\(Self.iconSignatureValue(weekly))",                "credits=\(Self.iconSignatureValue(credits))",                "stale=\(stale ? "1" : "0")",                "status=\(statusIndicator.rawValue)",                "blink=\(Self.iconSignatureValue(Double(blink)))",                "wiggle=\(Self.iconSignatureValue(Double(wiggle)))",                "tilt=\(Self.iconSignatureValue(Double(tilt)))",                "warningFlash=\(warningFlash ? "1" : "0")",                "anim=\(needsAnimation ? "1" : "0")",                "hideCritters=\(self.settings.menuBarHidesCritters ? "1" : "0")",            ].joined(separator: "|")            if self.shouldSkipMergedIconRender(signature) {                self.noteIconPerfRender(skipped: true)                return true            }            let image = IconRenderer.makeIcon(                primaryRemaining: primary,                weeklyRemaining: weekly,                creditsRemaining: credits,                stale: stale,                style: style,                blink: blink,                wiggle: wiggle,                tilt: tilt,                statusIndicator: statusIndicator,                hideCritters: self.settings.menuBarHidesCritters)            self.setButtonImage(                warningFlash ? Self.quotaWarningFlashImage(base: image) : image, for: button)        }        self.noteIconPerfRender(skipped: false)        return false    }     private func deferMergedIconRenderDuringMenuTrackingIfNeeded() -> Bool {        guard self.shouldMergeIcons, self.isMergedMenuOpen else { return false }        self.deferredMergedIconRenderAfterTracking = true        self.noteIconPerfRender(skipped: true)        return true    }     func applyDeferredMergedIconRenderAfterTrackingIfNeeded() {        guard self.deferredMergedIconRenderAfterTracking else { return }        guard self.shouldMergeIcons else {            self.deferredMergedIconRenderAfterTracking = false            return        }        guard !self.isMergedMenuOpen else { return }        self.deferredMergedIconRenderAfterTracking = false        let phase: Double? = self.animationDriver == nil ? nil : self.animationPhase        self.applyIcon(phase: phase)    }     private func shouldSkipMergedIconRender(_ signature: String) -> Bool {        guard self.shouldMergeIcons else {            self.lastAppliedMergedIconRenderSignature = signature            return false        }        if self.lastAppliedMergedIconRenderSignature == signature {            return true        }        self.lastAppliedMergedIconRenderSignature = signature        return false    }     private func shouldSkipProviderIconRender(provider: UsageProvider, signature: String) -> Bool {        if self.lastAppliedProviderIconRenderSignatures[provider] == signature {            return true        }        self.lastAppliedProviderIconRenderSignatures[provider] = signature        return false    }     @discardableResult    func applyIcon(for provider: UsageProvider, phase: Double?) -> Bool {        guard let button = self.statusItems[provider]?.button else { return false }        let snapshot = self.store.snapshot(for: provider)        // IconRenderer treats these values as a left-to-right "progress fill" percentage; depending on the        // user setting we pass either "percent left" or "percent used".        let showUsed = self.settings.usageBarsShowUsed        let showBrandPercent = self.settings.menuBarShowsBrandIconWithPercent        let style: IconStyle = self.store.style(for: provider)        let warningFlash = self.quotaWarningFlashActive(provider: provider)         if showBrandPercent,           let brand = ProviderBrandIcon.image(for: provider)        {            let displayText = self.menuBarDisplayText(for: provider, snapshot: snapshot)            let signature = [                "mode=brandPercent",                "provider=\(provider.rawValue)",                "style=\(String(describing: style))",                "text=\(displayText ?? "nil")",                "warningFlash=\(warningFlash ? "1" : "0")",            ].joined(separator: "|")            if self.shouldSkipProviderIconRender(provider: provider, signature: signature) {                self.noteIconPerfRender(skipped: true)                return true            }            self.setButtonImage(                warningFlash ? Self.quotaWarningFlashImage(base: brand) : brand, for: button)            self.setButtonTitle(displayText, for: button)            self.noteIconPerfRender(skipped: false)            return false        }         self.setButtonTitle(nil, for: button)         // OpenRouter always gets a meter here — the brand-logo fallback was removed on purpose.        let resolved = snapshot.map {            IconRemainingResolver.resolvedPercents(                snapshot: $0,                style: style,                showUsed: showUsed,                secondaryOverrideWindowID: self.settings.copilotIconSecondaryWindowOverrideID(snapshot: $0))        }        var primary = resolved?.primary        var weekly = resolved?.secondary        var credits = self.menuBarCreditsRemainingForIcon(provider: provider, snapshot: snapshot)        var stale = self.store.isStale(provider: provider)        var morphProgress: Double?         if let phase, self.shouldAnimate(provider: provider) {            var pattern = self.animationPattern            if provider == .claude, pattern == .unbraid {                pattern = .cylon            }            if pattern == .unbraid {                morphProgress = pattern.value(phase: phase) / 100                primary = nil                weekly = nil                credits = nil                stale = false            } else {                // Keep loading animation layout stable: IconRenderer switches layouts at `weeklyRemaining == 0`.                primary = max(pattern.value(phase: phase), Self.loadingPercentEpsilon)                weekly = max(                    pattern.value(phase: phase + pattern.secondaryOffset),                    Self.loadingPercentEpsilon)                credits = nil                stale = false            }        }         let isLoading = phase != nil && self.shouldAnimate(provider: provider)

Lines 1–500 of 1207.