146 lines
4.9 KiB
Swift
146 lines
4.9 KiB
Swift
//
|
||
// SettingsView.swift
|
||
// punchnet
|
||
//
|
||
// Created by 安礼成 on 2026/1/16.
|
||
//
|
||
import SwiftUI
|
||
|
||
struct SettingsView: View {
|
||
@State private var columnVisibility: NavigationSplitViewVisibility = .all
|
||
@State private var state = SettingsState()
|
||
@State private var selectedMenu: MenuItem = .accout
|
||
|
||
enum MenuItem: String, CaseIterable {
|
||
case accout = "账号"
|
||
case network = "网络"
|
||
case device = "设备"
|
||
case system = "软件"
|
||
case about = "关于"
|
||
|
||
// 图标信息
|
||
var icon: String {
|
||
switch self {
|
||
case .accout:
|
||
return "person.crop.circle.fill"
|
||
case .network:
|
||
return "network"
|
||
case .device:
|
||
return "laptopcomputer"
|
||
case .system:
|
||
return "gearshape.fill"
|
||
case .about:
|
||
return "info.circle.fill"
|
||
}
|
||
}
|
||
}
|
||
|
||
var body: some View {
|
||
NavigationSplitView(columnVisibility: $columnVisibility) {
|
||
// MARK: - 自定义侧边栏
|
||
VStack(alignment: .leading, spacing: 20) {
|
||
Text("设置")
|
||
.font(.system(size: 24, weight: .bold))
|
||
.padding(.horizontal, 16)
|
||
.padding(.top, 24)
|
||
|
||
VStack(spacing: 4) {
|
||
ForEach(MenuItem.allCases, id: \.self) { menu in
|
||
SidebarItem(
|
||
icon: menu.icon,
|
||
title: menu.rawValue,
|
||
isSelected: selectedMenu == menu
|
||
)
|
||
.onTapGesture {
|
||
// 使用精调的 spring 动画切换
|
||
withAnimation(.spring(response: 0.35, dampingFraction: 0.8)) {
|
||
self.selectedMenu = menu
|
||
}
|
||
}
|
||
}
|
||
Spacer()
|
||
}
|
||
.padding(.horizontal, 12)
|
||
}
|
||
.background(VisualEffectView(material: .sidebar, blendingMode: .behindWindow))
|
||
.navigationSplitViewColumnWidth(min: 180, ideal: 200, max: 250)
|
||
|
||
} 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(state: self.state)
|
||
case .network:
|
||
SettingsNetworkView(state: self.state)
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - 子组件:侧边栏按钮样式
|
||
struct SidebarItem: View {
|
||
let icon: String
|
||
let title: String
|
||
let isSelected: Bool
|
||
@State private var isHovering = false
|
||
|
||
var body: some View {
|
||
HStack(spacing: 12) {
|
||
Image(systemName: icon)
|
||
.font(.system(size: 14, weight: .medium))
|
||
.frame(width: 20)
|
||
|
||
Text(title)
|
||
.font(.system(size: 14, weight: .medium))
|
||
|
||
Spacer()
|
||
}
|
||
.padding(.horizontal, 12)
|
||
.padding(.vertical, 8)
|
||
.foregroundColor(isSelected ? .white : .primary.opacity(0.8))
|
||
.background {
|
||
if isSelected {
|
||
RoundedRectangle(cornerRadius: 8, style: .continuous)
|
||
.fill(Color.blue.gradient) // 保持一致的蓝色渐变
|
||
} else if isHovering {
|
||
RoundedRectangle(cornerRadius: 8, style: .continuous)
|
||
.fill(Color.primary.opacity(0.05))
|
||
}
|
||
}
|
||
.onHover {
|
||
isHovering = $0
|
||
}
|
||
.contentShape(Rectangle())
|
||
}
|
||
}
|
||
|
||
#Preview {
|
||
SettingsView()
|
||
}
|