import SwiftUI struct SettingsView: View { @ObservedObject var config = Configuration.shared @ObservedObject var monitor: SystemMonitor var body: some View { VStack(spacing: 0) { // 标题栏 HStack { Text("显示设置") .font(.system(size: 14, weight: .semibold)) Spacer() Button(action: { closeWindow() }) { Image(systemName: "xmark.circle.fill") .font(.system(size: 16)) .foregroundColor(.secondary) } .buttonStyle(.plain) } .padding(.horizontal, 16) .padding(.top, 16) .padding(.bottom, 12) Divider().background(Color.white.opacity(0.1)) ScrollView { VStack(spacing: 16) { // 显示/隐藏开关组 toggleGroup Divider().background(Color.white.opacity(0.08)) // 各指标样式 styleGroup Divider().background(Color.white.opacity(0.08)) // 进程设置 processGroup Divider().background(Color.white.opacity(0.08)) // 其他设置 otherGroup } .padding(16) } // 底部关闭 HStack { Spacer() Button("完成") { closeWindow() } .keyboardShortcut(.return) } .padding(.horizontal, 16) .padding(.bottom, 12) } .frame(width: 340, height: 680) .background(.ultraThinMaterial) } // MARK: - 显示/隐藏 private var toggleGroup: some View { VStack(alignment: .leading, spacing: 8) { Text("显示内容") .font(.system(size: 11, weight: .semibold)) .foregroundColor(.secondary) .padding(.leading, 4) toggleRow("CPU", binding: $config.showCPU, icon: "cpu") toggleRow("GPU", binding: $config.showGPU, icon: "display") toggleRow("内存", binding: $config.showMemory, icon: "memorychip") toggleRow("Swap", binding: $config.showSwap, icon: "arrow.left.arrow.right") toggleRow("CPU 温度", binding: $config.showCPUTemperature, icon: "thermometer.medium") toggleRow("GPU 温度", binding: $config.showGPUTemperature, icon: "thermometer.low") toggleRow("进程列表", binding: $config.showTopProcesses, icon: "list.bullet") } } private func toggleRow(_ label: String, binding: Binding, icon: String) -> some View { HStack { Image(systemName: icon) .frame(width: 18) .foregroundColor(binding.wrappedValue ? .accentColor : .secondary.opacity(0.5)) Text(label) .font(.system(size: 12)) Spacer() Toggle("", isOn: binding) .toggleStyle(.switch) .scaleEffect(0.7) .frame(width: 38) } } // MARK: - 样式选择 private var styleGroup: some View { VStack(alignment: .leading, spacing: 8) { Text("样式 · 行号 · 列位") .font(.system(size: 11, weight: .semibold)) .foregroundColor(.secondary) .padding(.leading, 4) styleRow("CPU", style: $config.cpuStyle, row: $config.cpuRow, pos: $config.cpuPos, icon: "cpu") styleRow("GPU", style: $config.gpuStyle, row: $config.gpuRow, pos: $config.gpuPos, icon: "display") styleRow("内存", style: $config.memoryStyle, row: $config.memoryRow, pos: $config.memoryPos, icon: "memorychip") styleRow("Swap", style: $config.swapStyle, row: $config.swapRow, pos: $config.swapPos, icon: "arrow.left.arrow.right") styleRow("CPU温度", style: $config.cpuTemperatureStyle, row: $config.cpuTemperatureRow, pos: $config.cpuTemperaturePos, icon: "thermometer.medium") styleRow("GPU温度", style: $config.gpuTemperatureStyle, row: $config.gpuTemperatureRow, pos: $config.gpuTemperaturePos, icon: "thermometer.low") styleRow("进程", style: .constant(.bar), row: $config.processesRow, pos: $config.processesPos, icon: "list.bullet", styleDisabled: true) } } private func styleRow(_ label: String, style: Binding, row: Binding, pos: Binding, icon: String, styleDisabled: Bool = false) -> some View { HStack(spacing: 6) { Image(systemName: icon) .frame(width: 14) .foregroundColor(.secondary) Text(label) .font(.system(size: 11)) .frame(width: 26, alignment: .leading) // 行号 stepper(+向上 -向下) Stepper { Text("") } onIncrement: { if row.wrappedValue > 1 { row.wrappedValue -= 1 } } onDecrement: { if row.wrappedValue < 10 { row.wrappedValue += 1 } } .labelsHidden() .scaleEffect(0.7) .frame(width: 24) Text("\(row.wrappedValue)") .font(.system(size: 11, design: .monospaced)) .foregroundColor(.secondary) .frame(width: 14, alignment: .center) Spacer() if styleDisabled { Text("—") .foregroundColor(.secondary.opacity(0.4)) .frame(width: 64) } else { Picker("", selection: style) { ForEach(GaugeDisplayStyle.allCases) { s in Text(s.displayName).tag(s) } } .pickerStyle(.menu) .frame(width: 76) } Picker("", selection: pos) { ForEach(ModulePosition.allCases) { p in Text(p.displayName).tag(p) } } .pickerStyle(.segmented) .frame(width: 90) } } // MARK: - 进程 private var processGroup: some View { VStack(alignment: .leading, spacing: 6) { Text("进程列表") .font(.system(size: 11, weight: .semibold)) .foregroundColor(.secondary) .padding(.leading, 4) HStack { Text("显示数量") .font(.system(size: 12)) Spacer() Picker("", selection: $config.processCount) { ForEach([3, 5, 8, 10], id: \.self) { n in Text("\(n) 个").tag(n) } } .pickerStyle(.segmented) .frame(width: 160) } } } // MARK: - 其他 private var otherGroup: some View { VStack(alignment: .leading, spacing: 8) { Text("其他") .font(.system(size: 11, weight: .semibold)) .foregroundColor(.secondary) .padding(.leading, 4) HStack { Text("刷新间隔") .font(.system(size: 12)) Spacer() Picker("", selection: Binding( get: { config.refreshInterval }, set: { newValue in config.refreshInterval = newValue NotificationCenter.default.post( name: .refreshIntervalChanged, object: newValue ) } )) { Text("0.5s").tag(0.5) Text("1.0s").tag(1.0) Text("1.5s").tag(1.5) Text("2.0s").tag(2.0) Text("3.0s").tag(3.0) } .pickerStyle(.segmented) .frame(width: 180) } HStack { Text("字体大小") .font(.system(size: 12)) .frame(width: 52, alignment: .leading) Slider(value: $config.fontSize, in: 9...16, step: 1) { Text("") } .frame(width: 130) Text(String(format: "%.0f", config.fontSize)) .font(.system(size: 11, design: .monospaced)) .foregroundColor(.secondary) .frame(width: 38, alignment: .trailing) } HStack { Text("窗口宽度") .font(.system(size: 12)) .frame(width: 52, alignment: .leading) Slider(value: $config.windowWidth, in: 240...500) { Text("") } onEditingChanged: { editing in if !editing { applyWindowSize() } } .frame(width: 130) Text(String(format: "%.0f", config.windowWidth)) .font(.system(size: 11, design: .monospaced)) .foregroundColor(.secondary) .frame(width: 38, alignment: .trailing) } HStack { Text("窗口高度") .font(.system(size: 12)) .frame(width: 52, alignment: .leading) Slider(value: $config.windowHeight, in: 200...700) { Text("") } onEditingChanged: { editing in if !editing { applyWindowSize() } } .frame(width: 130) Text(String(format: "%.0f", config.windowHeight)) .font(.system(size: 11, design: .monospaced)) .foregroundColor(.secondary) .frame(width: 38, alignment: .trailing) } HStack { Text("毛玻璃背板") .font(.system(size: 12)) Spacer() Toggle("", isOn: $config.backdropEnabled) .toggleStyle(.switch) .scaleEffect(0.7) .frame(width: 38) } HStack { Text("反转文字颜色") .font(.system(size: 12)) Spacer() Toggle("", isOn: $config.invertTextColor) .toggleStyle(.switch) .scaleEffect(0.7) .frame(width: 38) } HStack { Text("图形动画") .font(.system(size: 12)) Spacer() Toggle("", isOn: $config.gaugeAnimationEnabled) .toggleStyle(.switch) .scaleEffect(0.7) .frame(width: 38) } HStack { Text("文字动画") .font(.system(size: 12)) Spacer() Toggle("", isOn: $config.textAnimationEnabled) .toggleStyle(.switch) .scaleEffect(0.7) .frame(width: 38) } } } private func applyWindowSize() { NotificationCenter.default.post( name: .resizeMonitorWindow, object: NSSize(width: config.windowWidth, height: config.windowHeight) ) } private func closeWindow() { NSApp.keyWindow?.close() } }