Files
busylight-buddy/macos/Runner/AppDelegate.swift

156 lines
4.9 KiB
Swift
Raw Permalink Normal View History

2026-03-21 01:34:22 +01:00
import Cocoa
import FlutterMacOS
import ServiceManagement
@main
class AppDelegate: FlutterAppDelegate {
var statusItem: NSStatusItem?
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
override func applicationDidFinishLaunching(_ notification: Notification) {
let controller = mainFlutterWindow?.contentViewController as! FlutterViewController
let channel = FlutterMethodChannel(
name: "com.igox.busylight_buddy/autostart",
binaryMessenger: controller.engine.binaryMessenger
)
channel.setMethodCallHandler { [weak self] call, result in
switch call.method {
case "isEnabled":
if #available(macOS 13.0, *) {
result(SMAppService.mainApp.status == .enabled)
} else {
let plist = self?.launchAgentURL()
result(FileManager.default.fileExists(atPath: plist?.path ?? ""))
}
case "setEnabled":
guard let args = call.arguments as? [String: Any],
let enabled = args["enabled"] as? Bool else {
result(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
return
}
// Register/unregister autostart
if #available(macOS 13.0, *) {
do {
if enabled {
try SMAppService.mainApp.register()
} else {
try SMAppService.mainApp.unregister()
}
} catch {
result(FlutterError(code: "AUTOSTART_ERROR", message: error.localizedDescription, details: nil))
return
}
} else {
self?.setLaunchAgentLegacy(enabled: enabled)
}
// Toggle dock icon and menu bar extra
if enabled {
self?.setupMenuBarExtra()
NSApp.setActivationPolicy(.accessory) // hide from dock
} else {
self?.removeMenuBarExtra()
NSApp.setActivationPolicy(.regular) // show in dock
}
result(nil)
default:
result(FlutterMethodNotImplemented)
}
}
super.applicationDidFinishLaunching(notification)
// Restore menu bar extra on launch if autostart was previously enabled
let isAutostart: Bool
if #available(macOS 13.0, *) {
isAutostart = SMAppService.mainApp.status == .enabled
} else {
isAutostart = FileManager.default.fileExists(atPath: launchAgentURL().path)
}
if isAutostart {
setupMenuBarExtra()
NSApp.setActivationPolicy(.accessory)
}
}
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
// When in menu bar mode, closing the window should not quit the app
return statusItem == nil
}
// Menu bar extra
func setupMenuBarExtra() {
guard statusItem == nil else { return }
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
if let button = statusItem?.button {
// Use the app icon scaled to menu bar size
button.image = NSImage(named: NSImage.Name("AppIcon"))
button.image?.size = NSSize(width: 18, height: 18)
button.image?.isTemplate = false
button.action = #selector(statusItemClicked)
button.target = self
}
// Right-click menu
let menu = NSMenu()
menu.addItem(NSMenuItem(title: "Show BusyLight Buddy", action: #selector(showApp), keyEquivalent: ""))
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApp), keyEquivalent: "q"))
statusItem?.menu = menu
}
func removeMenuBarExtra() {
if let item = statusItem {
NSStatusBar.system.removeStatusItem(item)
statusItem = nil
}
}
@objc func statusItemClicked() {
showApp()
}
@objc func showApp() {
NSApp.activate(ignoringOtherApps: true)
mainFlutterWindow?.makeKeyAndOrderFront(nil)
}
@objc func quitApp() {
removeMenuBarExtra()
NSApp.terminate(nil)
}
// Legacy LaunchAgent fallback (macOS < 13)
private func launchAgentURL() -> URL {
let home = FileManager.default.homeDirectoryForCurrentUser
return home
.appendingPathComponent("Library/LaunchAgents")
.appendingPathComponent("com.igox.busylight_buddy.plist")
}
private func setLaunchAgentLegacy(enabled: Bool) {
let url = launchAgentURL()
if enabled {
let execURL = Bundle.main.executableURL!.path
let plist: [String: Any] = [
"Label": "com.igox.busylight_buddy",
"ProgramArguments": [execURL],
"RunAtLoad": true,
"KeepAlive": false,
]
try? (plist as NSDictionary).write(to: url)
} else {
try? FileManager.default.removeItem(at: url)
}
}
}