Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions MacEasySymbol/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,20 @@ extension AppDelegate: StatusBarManagerDelegate {
showWhitelistSettingsWindow()
}

func statusBarManagerDidRequestToggleLoginItem(_ manager: StatusBarManager) {
let currentStatus = LoginItemManager.shared.getCurrentStatus()
let newStatus = !currentStatus

let success = LoginItemManager.shared.setLoginItemEnabled(newStatus)

if success {
statusBarManager?.updateLoginItemStatus(newStatus)
DebugLogger.log("🔄 开机自启已\(newStatus ? "启用" : "禁用")")
} else {
DebugLogger.logError("❌ 开机自启设置失败")
}
}

func statusBarManagerDidRequestQuit(_ manager: StatusBarManager) {
// 确保在退出前完整清理资源
cleanupResources()
Expand Down
116 changes: 116 additions & 0 deletions MacEasySymbol/LoginItemManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import Cocoa
import ServiceManagement

class LoginItemManager {

static let shared = LoginItemManager()

private let launchAgentFileName = "com.rivermao.maceasysymbol.MacEasySymbol.plist"
private let userDefaultsKey = "LoginItemEnabled"

private init() {}

var isEnabled: Bool {
get {
return UserDefaults.standard.bool(forKey: userDefaultsKey)
}
set {
UserDefaults.standard.set(newValue, forKey: userDefaultsKey)
}
}

func setLoginItemEnabled(_ enabled: Bool) -> Bool {
if #available(macOS 13.0, *) {
return setLoginItemEnabledModern(enabled)
} else {
return setLoginItemEnabledLegacy(enabled)
}
}

func getCurrentStatus() -> Bool {
if #available(macOS 13.0, *) {
return SMAppService.mainApp.status == .enabled
} else {
return FileManager.default.fileExists(atPath: getLaunchAgentPath())
}
}

@available(macOS 13.0, *)
private func setLoginItemEnabledModern(_ enabled: Bool) -> Bool {
do {
let status = SMAppService.mainApp.status
isEnabled = enabled
if enabled {
if status == .enabled {
DebugLogger.log("✅ 登录项已启用")
} else {
try SMAppService.mainApp.register()
DebugLogger.log("✅ 登录项已注册并启用")
}
} else {
if status == .notFound {
DebugLogger.log("✅ 登录项已禁用")
} else {
try SMAppService.mainApp.unregister()
DebugLogger.log("✅ 登录项已注销")
}
}
return true
} catch {
DebugLogger.logError("❌ 登录项操作失败: \(error.localizedDescription)")
return false
}
}

private func setLoginItemEnabledLegacy(_ enabled: Bool) -> Bool {
let launchAgentPath = getLaunchAgentPath()
let fileManager = FileManager.default

do {
if enabled {
let appPath = Bundle.main.bundlePath
guard !appPath.isEmpty else {
DebugLogger.logError("❌ 无法获取应用路径")
return false
}

let plistContent: [String: Any] = [
"Label": launchAgentFileName.replacingOccurrences(of: ".plist", with: ""),
"ProgramArguments": [appPath],
"RunAtLoad": true
]

let plistData = try PropertyListSerialization.data(fromPropertyList: plistContent, format: .xml, options: 0)
try plistData.write(to: URL(fileURLWithPath: launchAgentPath), options: .atomic)

isEnabled = true
DebugLogger.log("✅ LaunchAgent 已创建并启用")
return true
} else {
if fileManager.fileExists(atPath: launchAgentPath) {
try fileManager.removeItem(atPath: launchAgentPath)
DebugLogger.log("✅ LaunchAgent 已删除")
}

isEnabled = false
DebugLogger.log("✅ 登录项已禁用")
return true
}
} catch {
DebugLogger.logError("❌ LaunchAgent 操作失败: \(error.localizedDescription)")
return false
}
}

private func getLaunchAgentPath() -> String {
let homeDir = FileManager.default.homeDirectoryForCurrentUser.path
let launchAgentsDir = (homeDir as NSString).appendingPathComponent("Library/LaunchAgents")

let fileManager = FileManager.default
if !fileManager.fileExists(atPath: launchAgentsDir) {
try? fileManager.createDirectory(atPath: launchAgentsDir, withIntermediateDirectories: true, attributes: nil)
}

return (launchAgentsDir as NSString).appendingPathComponent(launchAgentFileName)
}
}
26 changes: 26 additions & 0 deletions MacEasySymbol/StatusBarManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ protocol StatusBarManagerDelegate: AnyObject {
func statusBarManagerDidRequestHotkeySettings(_ manager: StatusBarManager)
func statusBarManagerDidRequestWhitelistSettings(_ manager: StatusBarManager)
func statusBarManagerDidRequestSymbolSettings(_ manager: StatusBarManager)
func statusBarManagerDidRequestToggleLoginItem(_ manager: StatusBarManager)
}

class StatusBarManager: NSObject {
Expand All @@ -27,9 +28,17 @@ class StatusBarManager: NSObject {
}
}

private var loginItemEnabled: Bool {
didSet {
updateMenu()
}
}

override init() {
// 每次启动都强制设置为启用状态
self.isInterventionEnabled = true
// 读取登录项状态
self.loginItemEnabled = LoginItemManager.shared.getCurrentStatus()
super.init()
// 确保UserDefaults也设置为启用状态
UserDefaults.standard.set(true, forKey: "InterventionEnabled")
Expand Down Expand Up @@ -93,6 +102,11 @@ class StatusBarManager: NSObject {
DebugLogger.log("🔄 通过全局快捷键切换介入模式: \(isInterventionEnabled ? "启用" : "禁用")")
}

// 更新登录项状态
func updateLoginItemStatus(_ enabled: Bool) {
loginItemEnabled = enabled
}

// MARK: - Private Methods

private func updateStatusBarIcon() {
Expand Down Expand Up @@ -162,6 +176,14 @@ class StatusBarManager: NSObject {

menu.addItem(NSMenuItem.separator())

// 开机自启
let loginItemTitle = loginItemEnabled ? "✓ 开机自启" : "开机自启"
let loginItemMenuItem = NSMenuItem(title: loginItemTitle, action: #selector(toggleLoginItem), keyEquivalent: "")
loginItemMenuItem.target = self
menu.addItem(loginItemMenuItem)

menu.addItem(NSMenuItem.separator())

// 关于
let aboutItem = NSMenuItem(title: "关于", action: #selector(showAbout), keyEquivalent: "")
aboutItem.target = self
Expand Down Expand Up @@ -242,6 +264,10 @@ class StatusBarManager: NSObject {
delegate?.statusBarManagerDidRequestWhitelistSettings(self)
}

@objc private func toggleLoginItem() {
delegate?.statusBarManagerDidRequestToggleLoginItem(self)
}

@objc private func quitApp() {
delegate?.statusBarManagerDidRequestQuit(self)
}
Expand Down