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

108 lines
3.7 KiB
Swift

import Foundation
import Metrics
import Observation
import ServiceManagement
import SMC
/// 应用状态总入口,注入到所有 SwiftUI 视图
@MainActor
@Observable
public final class AppModel {
public let settings: AppSettings
public let store: MetricsStore
public let helper: HelperClient
public let fans: FanController
public let keepAwake: KeepAwakeController
public let cleaner: CleanerController
public let maintenance: MaintenanceController
@ObservationIgnored public let hub = MetricsHub()
public var isPanelVisible = false
public private(set) var launchAtLoginEnabled = SMAppService.mainApp.status == .enabled
public private(set) var launchAtLoginError: String?
@ObservationIgnored var openSettings: () -> Void = {}
@ObservationIgnored var quit: () -> Void = {}
public init(settings: AppSettings = AppSettings()) {
let store = MetricsStore()
let helper = HelperClient()
self.settings = settings
self.store = store
self.helper = helper
fans = FanController(helper: helper, store: store, settings: settings)
keepAwake = KeepAwakeController(helper: helper, settings: settings)
cleaner = CleanerController(settings: settings)
maintenance = MaintenanceController(helper: helper)
}
/// 根据当前可见内容决定采集范围
var demand: MetricsDemand {
var demand = MetricsDemand()
let tab = settings.panelTab
let panel = isPanelVisible
let menu = settings.menuBarItems
demand.interval = panel ? .seconds(1) : .seconds(settings.refreshSeconds)
demand.memory = true
demand.network = true
demand.gpu = (panel && tab == .overview) || menu.contains(.gpu)
demand.disk = panel && (tab == .overview || tab == .cleaner)
demand.battery = (panel && (tab == .overview || tab == .keepAwake)) || keepAwake.lidClosedActive
demand.processes = panel && (tab == .processes || tab == .overview)
var groups = Set<TemperatureGroup>()
if panel && tab == .overview { groups.formUnion([.cpu, .gpu]) }
if panel && tab == .thermal { groups.formUnion(TemperatureGroup.allCases) }
if menu.contains(.temperature) || fans.mode != .automatic { groups.insert(.cpu) }
demand.temperatures = groups
demand.fans = (panel && (tab == .thermal || tab == .overview)) || menu.contains(.fan) || fans.mode != .automatic
return demand
}
func refreshLaunchAtLogin() {
launchAtLoginEnabled = SMAppService.mainApp.status == .enabled
}
func setLaunchAtLogin(_ enabled: Bool) {
launchAtLoginError = nil
do {
if enabled {
try SMAppService.mainApp.register()
} else {
try SMAppService.mainApp.unregister()
}
} catch {
launchAtLoginError = error.localizedDescription
}
refreshLaunchAtLogin()
}
/// 概览页快捷切换风扇:未安装辅助工具时跳到散热页引导安装
func requestFanMode(_ mode: FanController.Mode) {
guard helper.isReady else {
settings.panelTab = .thermal
return
}
Task { await fans.select(mode) }
}
/// 概览页快捷开关合盖运行:同时开启防休眠
func requestLidMode(_ enabled: Bool) {
guard helper.isReady else {
settings.panelTab = .keepAwake
return
}
Task {
await keepAwake.setLidClosed(enabled)
if enabled, !keepAwake.isActive { await keepAwake.start() }
}
}
func handle(_ snapshot: MetricsSnapshot) {
store.apply(snapshot)
fans.evaluateSafety()
keepAwake.evaluateBattery(store.battery)
}
}