253 lines · 7.7 KB · Swift
RawDownload
import CodexBarCoreimport Foundation enum PercentWindow: String, CaseIterable, Codable, Hashable, Sendable {    case session    case weekly    case automatic} enum MenuBarLayoutToken: Codable, Hashable, Sendable {    case icon    case providerName    case accountLabel    case percent(window: PercentWindow)    case usageBar    case resetCountdown    case resetAbsolute    case runsOut    case costToday    case cost30d    case separatorDot    case space} enum MenuBarLayoutSemanticWindowResolver {    static func windows(        provider: UsageProvider,        snapshot: UsageSnapshot?)        -> (session: RateWindow?, weekly: RateWindow?)    {        guard let snapshot else { return (nil, nil) }        let candidates = [            snapshot.primary,            snapshot.secondary,            snapshot.tertiary,        ] + (snapshot.extraRateWindows ?? []).map(\.window)        let usable = candidates.compactMap { window -> RateWindow? in            guard let window, !window.isSyntheticPlaceholder else { return nil }            return window        }        let session = usable.first { window in            guard let minutes = window.windowMinutes else { return false }            return (60...(12 * 60)).contains(minutes)        }        let cadenceWeekly = usable.first { $0.windowMinutes == 7 * 24 * 60 }        let kimiWeekly = snapshot.primary.flatMap { $0.isSyntheticPlaceholder ? nil : $0 }        let weekly = provider == .kimi ? kimiWeekly ?? cadenceWeekly : cadenceWeekly        return (session, weekly)    }} enum MenuBarLayoutCostResolver {    static func todayCostUSD(        snapshot: CostUsageTokenSnapshot?,        now: Date,        calendar: Calendar = .current)        -> Double?    {        guard let snapshot else { return nil }        return CostUsageTokenSnapshot.entry(            in: snapshot.daily,            forLocalDayContaining: now,            calendar: calendar)?.costUSD    }} struct MenuBarLayout: Codable, Hashable, Sendable {    static let defaultLayout = MenuBarLayout(lines: [[.icon, .percent(window: .automatic)]])     let lines: [[MenuBarLayoutToken]]     init(lines: [[MenuBarLayoutToken]]) {        self.lines = Self.normalizedLines(lines)    }     private enum CodingKeys: String, CodingKey {        case lines    }     init(from decoder: Decoder) throws {        let container = try decoder.container(keyedBy: CodingKeys.self)        try self.init(lines: container.decode([[MenuBarLayoutToken]].self, forKey: .lines))    }     func encode(to encoder: Encoder) throws {        var container = encoder.container(keyedBy: CodingKeys.self)        try container.encode(self.lines, forKey: .lines)    }     private static func normalizedLines(_ lines: [[MenuBarLayoutToken]]) -> [[MenuBarLayoutToken]] {        guard let firstContentLine = lines.firstIndex(where: { !$0.isEmpty }) else {            return self.defaultLayout.lines        }        return Array(lines[firstContentLine...].prefix(2))    }} enum MenuBarLayoutPreset: String, CaseIterable, Identifiable, Sendable {    case iconAndPercent    case iconOnly    case percentAndReset    case compactStacked    case custom     var id: String {        self.rawValue    }     var layout: MenuBarLayout? {        switch self {        case .iconAndPercent:            MenuBarLayout(lines: [[.icon, .percent(window: .automatic)]])        case .iconOnly:            MenuBarLayout(lines: [[.icon]])        case .percentAndReset:            MenuBarLayout(lines: [[                .icon,                .percent(window: .automatic),                .separatorDot,                .resetCountdown,            ]])        case .compactStacked:            MenuBarLayout(lines: [                [.percent(window: .session)],                [.percent(window: .weekly)],            ])        case .custom:            nil        }    }     static func matching(_ layout: MenuBarLayout) -> Self {        allCases.first { $0.layout == layout } ?? .custom    }} enum MenuBarLayoutSize: String, CaseIterable, Identifiable, Sendable {    case small    case regular     var id: String {        self.rawValue    }} enum MenuBarLayoutGap: String, CaseIterable, Identifiable, Sendable {    case tight    case regular     var id: String {        self.rawValue    }} struct MenuBarLayoutResolution: Equatable {    struct LegacySettings: Equatable {        let iconStyle: MenuBarIconStyle        let displayMode: MenuBarDisplayMode        let metricPreference: MenuBarMetricPreference        let resetTimeDisplayStyle: ResetTimeDisplayStyle    }     let layout: MenuBarLayout    let legacySettings: LegacySettings?     var usesLegacyRendering: Bool {        self.legacySettings != nil    }     static func stored(_ layout: MenuBarLayout) -> Self {        Self(layout: layout, legacySettings: nil)    }     static func legacy(        iconStyle: MenuBarIconStyle,        displayMode: MenuBarDisplayMode,        metricPreference: MenuBarMetricPreference,        resetTimeDisplayStyle: ResetTimeDisplayStyle,        provider: UsageProvider? = nil)        -> Self    {        Self(            layout: MenuBarLayout.migrated(                iconStyle: iconStyle,                displayMode: displayMode,                metricPreference: metricPreference,                resetTimeDisplayStyle: resetTimeDisplayStyle,                provider: provider),            legacySettings: LegacySettings(                iconStyle: iconStyle,                displayMode: displayMode,                metricPreference: metricPreference,                resetTimeDisplayStyle: resetTimeDisplayStyle))    }} extension MenuBarLayout {    static func migrated(        iconStyle: MenuBarIconStyle,        displayMode: MenuBarDisplayMode,        metricPreference: MenuBarMetricPreference,        resetTimeDisplayStyle: ResetTimeDisplayStyle,        provider: UsageProvider? = nil)        -> MenuBarLayout    {        _ = iconStyle // Critters and bars keep rendering through their unchanged legacy path.        let icon: MenuBarLayoutToken = .icon        switch displayMode {        case .percent:            if metricPreference == .primaryAndSecondary {                return MenuBarLayout(lines: [[                    icon,                    .percent(window: Self.percentWindow(for: .primary, provider: provider)),                    .separatorDot,                    .percent(window: Self.percentWindow(for: .secondary, provider: provider)),                ]])            }            return MenuBarLayout(lines: [[                icon,                .percent(window: Self.percentWindow(for: metricPreference, provider: provider)),            ]])        case .pace:            return MenuBarLayout(lines: [[icon, .runsOut]])        case .both:            return MenuBarLayout(lines: [[                icon,                .percent(window: Self.percentWindow(for: metricPreference, provider: provider)),                .separatorDot,                .runsOut,            ]])        case .resetTime:            let resetItem = resetTimeDisplayStyle == .absolute                ? MenuBarLayoutToken.resetAbsolute                : MenuBarLayoutToken.resetCountdown            return MenuBarLayout(lines: [[icon, resetItem]])        }    }     private static func percentWindow(        for preference: MenuBarMetricPreference,        provider: UsageProvider?)        -> PercentWindow    {        switch preference {        case .primary:            provider == .kimi ? .weekly : .session        case .secondary:            provider == .kimi ? .session : .weekly        case .automatic, .primaryAndSecondary, .tertiary, .extraUsage, .average, .monthlyPlan:            .automatic        }    }}