From d6e6c961a2d01a20e3db0ea4014fb87d8245b5e4 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Wed, 25 Mar 2026 11:54:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...{LoginRootView.swift => AppRootView.swift} | 2 +- .../Views/Common/CustomWindowControls.swift | 62 +++++++++++++++ punchnet/Views/Settings/SettingsView.swift | 76 ++++++++++--------- punchnet/punchnetApp.swift | 5 +- 4 files changed, 108 insertions(+), 37 deletions(-) rename punchnet/Views/{LoginRootView.swift => AppRootView.swift} (99%) create mode 100644 punchnet/Views/Common/CustomWindowControls.swift diff --git a/punchnet/Views/LoginRootView.swift b/punchnet/Views/AppRootView.swift similarity index 99% rename from punchnet/Views/LoginRootView.swift rename to punchnet/Views/AppRootView.swift index 1b85866..c54f0ac 100644 --- a/punchnet/Views/LoginRootView.swift +++ b/punchnet/Views/AppRootView.swift @@ -7,7 +7,7 @@ import SwiftUI -struct LoginRootView: View { +struct AppRootView: View { @Environment(AppContext.self) var appContext: AppContext @State private var updateManager = AppUpdateManager.shared diff --git a/punchnet/Views/Common/CustomWindowControls.swift b/punchnet/Views/Common/CustomWindowControls.swift new file mode 100644 index 0000000..6fe2fc0 --- /dev/null +++ b/punchnet/Views/Common/CustomWindowControls.swift @@ -0,0 +1,62 @@ +// +// CustomWindowControls.swift +// punchnet +// +// Created by 安礼成 on 2026/3/25. +// +import SwiftUI + +struct CustomWindowControls: View { + @State private var isHovering = false + + var body: some View { + HStack(spacing: 8) { + // 关闭按钮 (红色) + CircleButton(color: .red, systemName: "xmark", isHovering: isHovering) { + // 执行关闭当前窗口的操作 + if let window = NSApp.keyWindow { + window.close() + } + } + +// // 最小化按钮 (黄色) +// CircleButton(color: .yellow, systemName: "minus", isHovering: isHovering) { +// NSApp.keyWindow?.miniaturize(nil) +// } +// +// // 全屏/放大按钮 (绿色) +// CircleButton(color: .green, systemName: "arrow.up.left.and.arrow.down.right", isHovering: isHovering) { +// NSApp.keyWindow?.toggleFullScreen(nil) +// } + } + .onHover { hovering in + withAnimation(.easeInOut(duration: 0.1)) { + isHovering = hovering + } + } + } +} + +struct CircleButton: View { + let color: Color + let systemName: String + let isHovering: Bool + let action: () -> Void + + var body: some View { + Button(action: action) { + ZStack { + Circle() + .fill(color.opacity(0.8)) + .frame(width: 12, height: 12) + + // 只有悬停时才显示里面的小图标,像原生一样 + Image(systemName: systemName) + .font(.system(size: 8, weight: .bold)) + .foregroundColor(.black.opacity(0.5)) + .opacity(isHovering ? 1 : 0) + } + } + .buttonStyle(.plain) + } +} diff --git a/punchnet/Views/Settings/SettingsView.swift b/punchnet/Views/Settings/SettingsView.swift index f874c28..9425494 100644 --- a/punchnet/Views/Settings/SettingsView.swift +++ b/punchnet/Views/Settings/SettingsView.swift @@ -35,13 +35,18 @@ struct SettingsView: View { } var body: some View { - NavigationSplitView(columnVisibility: $columnVisibility) { + NavigationSplitView(columnVisibility: $columnVisibility, sidebar: { // MARK: - 自定义侧边栏 VStack(alignment: .leading, spacing: 20) { Text("设置") .font(.system(size: 24, weight: .bold)) .padding(.horizontal, 16) - .padding(.top, 24) + .padding(.top, 45) + .overlay(alignment: .topLeading) { + CustomWindowControls() + .padding(.top, 12) + .padding(.leading, 12) + } VStack(spacing: 4) { ForEach(MenuItem.allCases, id: \.self) { menu in @@ -61,45 +66,48 @@ struct SettingsView: View { } .padding(.horizontal, 12) } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) .background(VisualEffectView(material: .sidebar, blendingMode: .behindWindow)) + .toolbar(.hidden, for: .windowToolbar) .navigationSplitViewColumnWidth(min: 180, ideal: 200, max: 250) - - } detail: { + .ignoresSafeArea(.all) + + }, detail: { // MARK: - 详情页转场 - ZStack(alignment: .topLeading) { - // 背景保持统一 - VisualEffectView(material: .hudWindow, blendingMode: .behindWindow) - .ignoresSafeArea() - - VStack(alignment: .leading, spacing: 0) { - Group { - // 使用 ID 辅助 SwiftUI 识别视图切换,触发 transition - switch self.selectedMenu { - case .accout: - SettingsAccountView() - case .network: - SettingsNetworkView() - case .device: - SettingsDeviceView() - case .system: - SettingsSystemView() - case .about: - SettingsAboutView() - } + VStack(alignment: .leading, spacing: 0) { + Group { + // 使用 ID 辅助 SwiftUI 识别视图切换,触发 transition + switch self.selectedMenu { + case .accout: + SettingsAccountView() + case .network: + SettingsNetworkView() + case .device: + SettingsDeviceView() + case .system: + SettingsSystemView() + case .about: + SettingsAboutView() } - .id(selectedMenu) // 关键:确保切换时触发转场 - .transition(.asymmetric( - insertion: .move(edge: .bottom).combined(with: .opacity), - removal: .opacity - )) - - Spacer() } - .padding(32) // 加大留白,显得更高级 - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .id(selectedMenu) // 关键:确保切换时触发转场 + .transition(.asymmetric( + insertion: .move(edge: .bottom).combined(with: .opacity), + removal: .opacity + )) + + Spacer() } - } + .padding(32) // 加大留白,显得更高级 + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .toolbar(.hidden, for: .windowToolbar) + .ignoresSafeArea(edges: .top) + }) + .navigationSplitViewStyle(.prominentDetail) + .background(VisualEffectView(material: .sidebar, blendingMode: .behindWindow)) + .ignoresSafeArea(.all) } + } // MARK: - 子组件:侧边栏按钮样式 diff --git a/punchnet/punchnetApp.swift b/punchnet/punchnetApp.swift index 610594f..a0cbe82 100644 --- a/punchnet/punchnetApp.swift +++ b/punchnet/punchnetApp.swift @@ -45,7 +45,7 @@ struct punchnetApp: App { var body: some Scene { Window("Punchnet", id: "main") { - LoginRootView() + AppRootView() .navigationTitle("") .environment(self.appContext) .frame( @@ -70,10 +70,11 @@ struct punchnetApp: App { Settings { SettingsView() .environment(self.appContext) - .frame(width: 750, height: 500) + .frame(width: 750, height: 450) } .windowResizability(.contentSize) .defaultPosition(.center) + .windowStyle(.hiddenTitleBar) MenuBarExtra("Punchnet", image: "logo_32") { MainMenuBar()