diff --git a/Packages/OpenStatsKit/Sources/Localization/Translations.swift b/Packages/OpenStatsKit/Sources/Localization/Translations.swift index cd96f64..2d7eaec 100644 --- a/Packages/OpenStatsKit/Sources/Localization/Translations.swift +++ b/Packages/OpenStatsKit/Sources/Localization/Translations.swift @@ -389,6 +389,7 @@ npm 缓存 npm Cache 同步失败 Sync failed 同步的内容:菜单栏项目与风格、刷新频率、外观与语言、详情弹窗的区块、连接探测、通知、快捷键、风扇安全温度、合盖电量下限。当前页面、辅助工具与历史记录留在本机。 What syncs: menu bar items and styles, refresh rate, appearance and language, popover sections, connection probe, notifications, hotkeys, fan safety temperature and lid-mode battery floor. The current page, the helper and history stay on this Mac. 后台低频探测 Background Probing +启动中… Starting… 启动于 Booted 启动时和之后每天检查一次,发现新版本时显示更新摘要 Checks at launch and daily, and shows what's new when an update is found 启动磁盘 Startup Disk @@ -749,6 +750,7 @@ npm 缓存 npm Cache 正在修改 DNS… Changing DNS… 正在同步 Syncing 正在同步… Syncing… +正在启动风扇… Starting fans… 正在安装,完成后 OpenStats 会自动重启。 Installing. OpenStats will relaunch when it's done. 正在导出… Exporting… 正在导出诊断信息… Exporting diagnostics… diff --git a/Packages/OpenStatsKit/Sources/OpenStatsUI/Panel/ThermalPage.swift b/Packages/OpenStatsKit/Sources/OpenStatsUI/Panel/ThermalPage.swift index a8eeab9..ee98ab5 100644 --- a/Packages/OpenStatsKit/Sources/OpenStatsUI/Panel/ThermalPage.swift +++ b/Packages/OpenStatsKit/Sources/OpenStatsUI/Panel/ThermalPage.swift @@ -158,7 +158,7 @@ private struct FanRow: View { HStack { Text(name).dsFont(.sm, weight: .medium).foregroundStyle(DS.Palette.textPrimary) Spacer() - Text(Format.rpm(fan.current)) + Text(fan.isStarting ? tr("启动中…") : Format.rpm(fan.current)) .dsFont(.sm, weight: .semibold) .monospacedDigit() .foregroundStyle(DS.Palette.textPrimary) diff --git a/Packages/OpenStatsKit/Sources/OpenStatsUI/Popover/MetricPopovers.swift b/Packages/OpenStatsKit/Sources/OpenStatsUI/Popover/MetricPopovers.swift index ffc09ea..d26cbb9 100644 --- a/Packages/OpenStatsKit/Sources/OpenStatsUI/Popover/MetricPopovers.swift +++ b/Packages/OpenStatsKit/Sources/OpenStatsUI/Popover/MetricPopovers.swift @@ -751,7 +751,7 @@ struct ThermalPopover: View { } else { ForEach(fans) { fan in VStack(spacing: DS.Space.s1) { - InfoRow(label: tr("风扇 \(fan.id + 1)"), text: Format.rpm(fan.current)) + InfoRow(label: tr("风扇 \(fan.id + 1)"), text: fan.isStarting ? tr("启动中…") : Format.rpm(fan.current)) ProgressTrack(fraction: fan.maximum > 0 ? fan.current / fan.maximum : 0, height: DS.Space.s1) } } @@ -779,6 +779,7 @@ struct ThermalPopover: View { @MainActor func fanStatusText(fans: [FanState], mode: FanController.Mode) -> String { if fans.isEmpty { return tr("未检测到风扇") } + if fans.contains(where: \.isStarting) { return tr("正在启动风扇…") } guard fans.contains(where: \.isManual) else { return tr("由 macOS 调节") } return mode == .automatic ? tr("其他程序手动控制") : tr("OpenStats 控制中") } diff --git a/Packages/OpenStatsKit/Sources/SMC/FanControl.swift b/Packages/OpenStatsKit/Sources/SMC/FanControl.swift index b70b391..59625fa 100644 --- a/Packages/OpenStatsKit/Sources/SMC/FanControl.swift +++ b/Packages/OpenStatsKit/Sources/SMC/FanControl.swift @@ -15,14 +15,18 @@ public struct FanState: Sendable, Equatable, Identifiable { public var maximum: Double public var target: Double public var isManual: Bool + /// 风扇从停转起步:Apple 芯片的固件先低速拖转约 5 秒,期间转速读数为 0 + public var isStarting: Bool - public init(id: Int, current: Double, minimum: Double, maximum: Double, target: Double, isManual: Bool) { + public init(id: Int, current: Double, minimum: Double, maximum: Double, target: Double, isManual: Bool, + isStarting: Bool = false) { self.id = id self.current = current self.minimum = minimum self.maximum = maximum self.target = target self.isManual = isManual + self.isStarting = isStarting } /// 当前转速在 min...max 区间的占比 @@ -51,8 +55,10 @@ public final class FanControl { let maximum = smc.double(SMCKey("F\(id)Mx")) ?? 0 let target = smc.double(SMCKey("F\(id)Tg")) ?? current let mode = smc.double(modeKey(id)) ?? 0 + // F0St:3 停转、1 起步、5 运行;没有这个键的机型按“有目标转速但还没转起来”判断 + let starting = smc.double(SMCKey("F\(id)St")).map { $0 == 1 } ?? (mode == 1 && target > 0) return FanState(id: id, current: current, minimum: minimum, maximum: maximum, - target: target, isManual: mode == 1) + target: target, isManual: mode == 1, isStarting: starting && current == 0) } }