Files
PowerBar/PowerBar/AppState.swift
leo12025 8eb0086779 feat: 实现状态栏应用和防睡眠功能
添加 AppState 类管理应用状态和防睡眠逻辑
将主应用改为状态栏应用并添加交互菜单
使用 IOKit 检测系统空闲时间并控制 caffeinate 进程
2025-12-27 18:17:16 +08:00

151 lines
4.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
import Combine
import IOKit.pwr_mgt
// MARK: - App State Manager
class AppState: ObservableObject {
// MARK: - Published Properties (UI )
//
@Published var isFunctionEnabled: Bool = false
//
@Published var isUserIdle: Bool = false
//
private var monitorTimer: Timer?
private var caffeinateProcess: Process?
//
private let idleThreshold: TimeInterval = 300 // 5
private let checkInterval: TimeInterval = 10 // 10
// MARK: - Public Methods
///
func toggleFunction() {
isFunctionEnabled.toggle()
if isFunctionEnabled {
//
performCheck()
startMonitoringTimer()
} else {
//
stopMonitoringTimer()
stopCaffeinate()
updateUserIdleStatus(false) //
}
}
// MARK: - Monitoring Logic
private func startMonitoringTimer() {
guard monitorTimer == nil else { return }
print("开始监控...")
// 使 weak self
monitorTimer = Timer.scheduledTimer(withTimeInterval: checkInterval, repeats: true) { [weak self] _ in
self?.performCheck()
}
}
private func stopMonitoringTimer() {
monitorTimer?.invalidate()
monitorTimer = nil
print("监控已停止。")
}
private func performCheck() {
// 1.
let idleTime = getSystemIdleTime()
// 2.
let isIdleNow = (idleTime >= idleThreshold)
// 3.
if isIdleNow != isUserIdle {
updateUserIdleStatus(isIdleNow)
if isIdleNow {
//
stopCaffeinate()
} else {
//
startCaffeinate()
}
}
}
// MARK: - User Idle Detection
/// 使 IOKit ()
/// - Returns:
private func getSystemIdleTime() -> TimeInterval {
//
var onPort: mach_port_t = 0
var prop: Unmanaged<CFTypeRef>?
// IO Master Port
let kr = IOMainPort(0, &onPort)
guard kr == KERN_SUCCESS else { return 0 }
//
let powerService = IOServiceGetMatchingService(onPort, IOServiceMatching("IOPMPowerSource"))
guard powerService != 0 else { return 0 }
//
let result = IORegistryEntryCreateCFProperty(powerService, "HIDIdleTime" as CFString, kCFAllocatorDefault, 0)
IOObjectRelease(powerService)
guard let data = result?.takeRetainedValue() as? Data else { return 0 }
// UInt64
var idleTime: UInt64 = 0
(data as NSData).getBytes(&idleTime, length: MemoryLayout<UInt64>.size)
return Double(idleTime) / 1_000_000_000.0 //
}
// MARK: - Caffeinate Management
private func startCaffeinate() {
guard caffeinateProcess == nil else { return }
print("用户活动,启动 caffeinate 阻止睡眠...")
caffeinateProcess = Process()
caffeinateProcess?.executableURL = URL(fileURLWithPath: "/usr/bin/caffeinate")
caffeinateProcess?.arguments = ["-d"] // -d
do {
try caffeinateProcess?.run()
} catch {
print("启动 caffeinate 失败: \(error)")
caffeinateProcess = nil
}
}
private func stopCaffeinate() {
guard caffeinateProcess != nil else { return }
print("用户空闲或功能关闭,停止 caffeinate.")
caffeinateProcess?.terminate()
caffeinateProcess = nil
}
// MARK: - UI State Update
/// 线
private func updateUserIdleStatus(_ isIdle: Bool) {
DispatchQueue.main.async {
self.isUserIdle = isIdle
}
}
// MARK: - Deinitializer
deinit {
// App 退
stopMonitoringTimer()
stopCaffeinate()
}
}