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