import AppKit import SwiftUI @MainActor final class MenuBarController: NSObject { static let shared = MenuBarController() private var statusItem: NSStatusItem? private var popover: NSPopover? private var labelHostingView: NSHostingView? private let settings = AppSettings.shared private let refreshService = UsageRefreshService.shared func install() { guard statusItem == nil else { return } let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) statusItem = item guard let button = item.button else { return } button.image = nil button.title = "" button.imagePosition = .noImage let labelView = MenuBarLabelView(refreshService: refreshService, settings: settings) let hostingView = NSHostingView(rootView: labelView) hostingView.translatesAutoresizingMaskIntoConstraints = false labelHostingView = hostingView button.addSubview(hostingView) NSLayoutConstraint.activate([ hostingView.leadingAnchor.constraint(equalTo: button.leadingAnchor, constant: 2), hostingView.trailingAnchor.constraint(equalTo: button.trailingAnchor, constant: -2), hostingView.topAnchor.constraint(equalTo: button.topAnchor), hostingView.bottomAnchor.constraint(equalTo: button.bottomAnchor), ]) hostingView.layoutSubtreeIfNeeded() button.target = self button.action = #selector(statusItemClicked(_:)) button.sendAction(on: [.leftMouseUp, .rightMouseUp]) let popover = NSPopover() popover.behavior = .transient popover.contentViewController = NSHostingController( rootView: PopoverView(refreshService: refreshService, settings: settings) ) self.popover = popover } @objc private func statusItemClicked(_ sender: NSStatusBarButton) { guard let event = NSApp.currentEvent else { return } if event.type == .rightMouseUp { showContextMenu(on: sender) return } togglePopover(on: sender) } private func togglePopover(on button: NSStatusBarButton) { guard let popover else { return } if popover.isShown { popover.performClose(nil) return } popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY) popover.contentViewController?.view.window?.makeKey() } private func showContextMenu(on button: NSStatusBarButton) { let menu = NSMenu() menu.addItem( withTitle: "Settings…", action: #selector(openSettings), keyEquivalent: "," ) menu.addItem(.separator()) menu.addItem( withTitle: "Quit AI Menubar Usage", action: #selector(quitApp), keyEquivalent: "q" ) menu.items.forEach { $0.target = self } statusItem?.menu = menu button.performClick(nil) statusItem?.menu = nil } @objc private func openSettings() { popover?.performClose(nil) NSApp.activate(ignoringOtherApps: true) NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil) } @objc private func quitApp() { NSApplication.shared.terminate(nil) } } final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { MenuBarController.shared.install() } func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { false } }