feat(UI): 改进菜单界面布局和样式
重构菜单界面,添加应用标题和版本信息,优化按钮和状态显示样式 使用卡片式布局和阴影效果提升整体视觉体验 简化状态显示逻辑,增加更直观的状态指示图标
This commit is contained in:
@@ -14,7 +14,7 @@ class AppState: ObservableObject {
|
||||
|
||||
// 内部属性
|
||||
private var monitorTimer: Timer?
|
||||
private var caffeinateProcess: Process?
|
||||
private var caffeinateProcess: Process? // 直接使用Process对象,但简化实现
|
||||
|
||||
// 配置参数
|
||||
private let idleThreshold: TimeInterval = 300 // 5分钟无操作视为空闲
|
||||
@@ -82,19 +82,18 @@ class AppState: ObservableObject {
|
||||
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 }
|
||||
// 查找 HID 系统服务,这是正确的获取 HIDIdleTime 的服务
|
||||
let hidSystem = IOServiceGetMatchingService(onPort, IOServiceMatching("IOHIDSystem"))
|
||||
guard hidSystem != 0 else { return 0 }
|
||||
|
||||
// 尝试获取空闲时间属性
|
||||
let result = IORegistryEntryCreateCFProperty(powerService, "HIDIdleTime" as CFString, kCFAllocatorDefault, 0)
|
||||
IOObjectRelease(powerService)
|
||||
let result = IORegistryEntryCreateCFProperty(hidSystem, "HIDIdleTime" as CFString, kCFAllocatorDefault, 0)
|
||||
IOObjectRelease(hidSystem)
|
||||
|
||||
guard let data = result?.takeRetainedValue() as? Data else { return 0 }
|
||||
|
||||
@@ -111,12 +110,21 @@ class AppState: ObservableObject {
|
||||
guard caffeinateProcess == nil else { return }
|
||||
|
||||
print("用户活动,启动 caffeinate 阻止睡眠...")
|
||||
|
||||
// 简化实现,直接启动 caffeinate 进程
|
||||
caffeinateProcess = Process()
|
||||
caffeinateProcess?.executableURL = URL(fileURLWithPath: "/usr/bin/caffeinate")
|
||||
caffeinateProcess?.arguments = ["-d"] // -d 指示系统不要关闭显示屏
|
||||
|
||||
// 配置输出,避免产生不必要的输出
|
||||
let outputPipe = Pipe()
|
||||
caffeinateProcess?.standardOutput = outputPipe
|
||||
caffeinateProcess?.standardError = outputPipe
|
||||
caffeinateProcess?.standardInput = Pipe()
|
||||
|
||||
do {
|
||||
try caffeinateProcess?.run()
|
||||
print("成功启动 caffeinate 进程")
|
||||
} catch {
|
||||
print("启动 caffeinate 失败: \(error)")
|
||||
caffeinateProcess = nil
|
||||
@@ -124,11 +132,16 @@ class AppState: ObservableObject {
|
||||
}
|
||||
|
||||
private func stopCaffeinate() {
|
||||
guard caffeinateProcess != nil else { return }
|
||||
guard let process = caffeinateProcess else { return }
|
||||
|
||||
print("用户空闲或功能关闭,停止 caffeinate.")
|
||||
caffeinateProcess?.terminate()
|
||||
print("用户空闲或功能关闭,停止 caffeinate 进程")
|
||||
|
||||
// 简化实现,直接终止进程
|
||||
process.terminate()
|
||||
|
||||
// 不等待进程退出,避免阻塞
|
||||
caffeinateProcess = nil
|
||||
print("已重置 caffeinate 进程引用")
|
||||
}
|
||||
|
||||
// MARK: - UI State Update
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// PowerBar
|
||||
//
|
||||
// Created by Leo on 2025/12/27.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
Image(systemName: "globe")
|
||||
.imageScale(.large)
|
||||
.foregroundStyle(.tint)
|
||||
Text("Hello, world!")
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
}
|
||||
@@ -32,42 +32,88 @@ struct MenuContent: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
// 应用标题和版本
|
||||
HStack {
|
||||
Image(systemName: "power")
|
||||
.foregroundColor(.blue)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("PowerBar")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
Text("v1.0.0")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 4)
|
||||
|
||||
// 主要操作按钮:切换功能
|
||||
Button(action: {
|
||||
// 点击按钮,切换功能的开关状态
|
||||
appState.toggleFunction()
|
||||
}) {
|
||||
HStack {
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: appState.isFunctionEnabled ? "stop.circle.fill" : "play.circle.fill")
|
||||
.foregroundColor(appState.isFunctionEnabled ? .red : .green)
|
||||
.frame(width: 20)
|
||||
.font(.title2)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(appState.isFunctionEnabled ? "关闭常亮" : "开启常亮")
|
||||
.font(.body)
|
||||
Text(appState.isFunctionEnabled ? "系统将恢复自动睡眠" : "防止系统进入睡眠状态")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(8)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(appState.isFunctionEnabled ? Color.red.opacity(0.1) : Color.green.opacity(0.1))
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Divider()
|
||||
|
||||
// 状态显示
|
||||
HStack {
|
||||
Text("当前状态:")
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("当前状态")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
HStack {
|
||||
if appState.isFunctionEnabled {
|
||||
HStack(spacing: 6) {
|
||||
Circle()
|
||||
.fill(appState.isUserIdle ? Color.orange : Color.green)
|
||||
.frame(width: 8, height: 8)
|
||||
Text(appState.isUserIdle ? "空闲" : "活动中")
|
||||
.foregroundColor(appState.isUserIdle ? .orange : .green)
|
||||
.font(.body)
|
||||
|
||||
// 附加显示 caffeinate 状态
|
||||
if !appState.isUserIdle {
|
||||
Text("(保护中)")
|
||||
.foregroundColor(.green)
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HStack(spacing: 6) {
|
||||
Circle()
|
||||
.fill(Color.gray)
|
||||
.frame(width: 8, height: 8)
|
||||
Text("已关闭")
|
||||
.foregroundColor(.gray)
|
||||
.font(.body)
|
||||
}
|
||||
}
|
||||
.font(.caption)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.padding(8)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(Color.secondary.opacity(0.05))
|
||||
)
|
||||
|
||||
Divider()
|
||||
|
||||
@@ -75,8 +121,17 @@ struct MenuContent: View {
|
||||
Button("退出 PowerBar") {
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(4)
|
||||
}
|
||||
.padding(8)
|
||||
.frame(minWidth: 220)
|
||||
.padding(12)
|
||||
.frame(minWidth: 280)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Color.white)
|
||||
.shadow(radius: 4)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user