Files
OpenStats/Packages/OpenStatsKit/Sources/OpenStatsUI/State/FanController.swift
T
gentpan 1205483b5e 新增清理与系统维护,修复面板抖动,更换应用图标
- 清理:应用缓存、日志、浏览器缓存、Xcode/模拟器/npm 缓存、下载残留、安装包、废纸篓;
  白名单目录 + 安全守卫,运行中的应用自动跳过,执行前逐项复核,操作日志
- 系统维护:刷新 DNS 缓存、释放内存(辅助工具或管理员授权)
- 面板:去掉打开后的二次调整高度与窗口高度动画,内容放得下时不回弹,
  修复点击菜单栏图标关闭时被重新打开
- 更换应用图标,面板与关于页使用应用图标作为 Logo
- 清理未使用的组件、格式化方法、设计 token 与辅助工具接口
2026-09-13 03:03:08 +05:00

116 lines
3.5 KiB
Swift

import Foundation
import Metrics
import Observation
import SMC
@MainActor
@Observable
public final class FanController {
public enum Mode: String, CaseIterable, Identifiable {
case automatic, cooling, maximum, custom
public var id: String { rawValue }
var title: String {
switch self {
case .automatic: "自动"
case .cooling: "降温"
case .maximum: "强冷"
case .custom: "自定义"
}
}
/// “降温”档位于最低与最高转速之间的 60%
static let coolingLevel = 0.6
}
public private(set) var mode: Mode = .automatic
/// 自定义档位:0 为最低转速,1 为最高转速
public var customLevel: Double = 0.5
public private(set) var isApplying = false
public private(set) var notice: String?
public private(set) var noticeIsError = false
@ObservationIgnored private let helper: HelperClient
@ObservationIgnored private let store: MetricsStore
@ObservationIgnored private let settings: AppSettings
init(helper: HelperClient, store: MetricsStore, settings: AppSettings) {
self.helper = helper
self.store = store
self.settings = settings
}
func select(_ newMode: Mode) async {
guard newMode != mode || newMode == .custom else { return }
let previous = mode
mode = newMode
if let error = await apply() {
mode = previous
show(error, isError: true)
} else {
clearNotice()
}
}
func commitCustomLevel() async {
guard mode == .custom else { return }
if let error = await apply() { show(error, isError: true) }
}
/// 连接恢复或唤醒后重新下发
func reapply() async {
guard mode != .automatic else { return }
if let error = await apply() { show(error, isError: true) }
}
/// 每次收到新指标时检查温度,自定义档位过低且 CPU 过热时交还系统控制
func evaluateSafety() {
guard mode == .custom, customLevel < 1,
let hottest = store.sensors?.temperature(.cpu)?.maximum,
hottest >= Double(settings.fanSafetyTemperature) else { return }
Task {
mode = .automatic
_ = await apply()
show("CPU 温度达到 \(Format.temperature(hottest, fahrenheit: settings.useFahrenheit)),已恢复系统自动控制", isError: false)
}
}
func targetRPM(for fan: FanState) -> Double {
switch mode {
case .automatic: fan.target
case .cooling: fan.minimum + (fan.maximum - fan.minimum) * Mode.coolingLevel
case .maximum: fan.maximum
case .custom: fan.minimum + (fan.maximum - fan.minimum) * customLevel
}
}
private func apply() async -> String? {
let fans = store.sensors?.fans ?? []
guard !fans.isEmpty else { return "未检测到可调节的风扇" }
isApplying = true
defer { isApplying = false }
if mode == .automatic {
return await helper.resetAllFans()
}
for fan in fans {
if let error = await helper.setFanTarget(fan: fan.id, rpm: targetRPM(for: fan)) {
_ = await helper.resetAllFans()
return error
}
}
return nil
}
private func show(_ message: String, isError: Bool) {
notice = message
noticeIsError = isError
}
private func clearNotice() {
notice = nil
noticeIsError = false
}
}