156 lines
4.9 KiB
Swift
156 lines
4.9 KiB
Swift
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)
|
|
}
|
|
}
|
|
} |