feat: 初始化偏好设置窗口管理器并添加标签导航

This commit is contained in:
ZhangLei
2025-11-03 22:40:42 +08:00
parent c6150b1b8f
commit 91127faebe
3 changed files with 127 additions and 9 deletions

View File

@@ -22,12 +22,17 @@ class MenuBarManager: NSObject, ObservableObject {
private let aboutWindowManager = AboutWindowManager()
//
private lazy var preferencesWindowManager = PreferencesWindowManager(appSettings: appSettings)
private var preferencesWindowManager: PreferencesWindowManager!
override init() {
// AppSettings
let settings = AppSettings()
self.appSettings = settings
self.priceManager = PriceManager(initialSymbol: settings.selectedSymbol, appSettings: settings)
// 使 appSettings
self.preferencesWindowManager = PreferencesWindowManager(appSettings: settings)
super.init()
setupMenuBar()
setupConfigurationObservers()

View File

@@ -7,9 +7,36 @@
import SwiftUI
/**
*
*
*/
enum SettingsTab: String, CaseIterable {
case general = "通用"
case custom = "自定义币种"
case proxy = "代理设置"
/// SF Symbols
var icon: String {
switch self {
case .general:
return "gear"
case .custom:
return "plus.circle"
case .proxy:
return "network"
}
}
///
var displayText: String {
return self.rawValue
}
}
/**
*
* 使 SwiftUI
* 使SwiftUI
*/
struct PreferencesWindowView: View {
//
@@ -46,6 +73,12 @@ struct PreferencesWindowView: View {
@State private var customSymbolErrorMessage: String?
@State private var showingCustomSymbolDeleteConfirmation: Bool = false
// -
@State private var selectedTab: SettingsTab = .general
//
@State private var hoveredTab: SettingsTab? = nil
init(appSettings: AppSettings, onClose: @escaping () -> Void) {
self.appSettings = appSettings
self.onClose = onClose
@@ -62,7 +95,7 @@ struct PreferencesWindowView: View {
var body: some View {
mainContentView
.frame(width: 480, height: 800)
.frame(width: 480, height: 500)
.alert("配置验证", isPresented: $showingValidationError) {
Button("确定", role: .cancel) { }
} message: {
@@ -86,6 +119,12 @@ struct PreferencesWindowView: View {
//
private var mainContentView: some View {
VStack(spacing: 0) {
//
topTabBarView
Divider()
//
ScrollView {
settingsContentView
.padding(24)
@@ -97,18 +136,90 @@ struct PreferencesWindowView: View {
}
}
//
//
private var topTabBarView: some View {
HStack(spacing: 0) {
ForEach(SettingsTab.allCases, id: \.self) { tab in
// 使
HStack(spacing: 8) {
Image(systemName: tab.icon)
.font(.system(size: 14))
.foregroundColor(selectedTab == tab ? .blue : .secondary)
Text(tab.displayText)
.font(.system(size: 13))
.fontWeight(selectedTab == tab ? .medium : .regular)
.foregroundColor(selectedTab == tab ? .blue : .primary)
}
.frame(maxWidth: .infinity, maxHeight: .infinity) //
.contentShape(Rectangle()) //
.background(
RoundedRectangle(cornerRadius: 0)
.fill(selectedTab == tab ? Color(NSColor.controlAccentColor).opacity(0.1) : Color.clear)
)
.background(
//
RoundedRectangle(cornerRadius: 0)
.fill(hoveredTab == tab && selectedTab != tab ? Color(NSColor.controlAccentColor).opacity(0.05) : Color.clear)
)
.onTapGesture {
withAnimation(.easeInOut(duration: 0.2)) {
selectedTab = tab
}
}
.onHover { isHovered in
if isHovered {
NSCursor.pointingHand.set()
hoveredTab = tab
} else {
NSCursor.arrow.set()
if hoveredTab == tab {
hoveredTab = nil
}
}
}
// 线
if tab != SettingsTab.allCases.last {
Rectangle()
.fill(Color(NSColor.separatorColor))
.frame(width: 1)
.padding(.vertical, 8)
}
}
}
.frame(height: 44)
.background(Color(NSColor.controlBackgroundColor))
}
// -
private var settingsContentView: some View {
VStack(spacing: 24) {
refreshSettingsView
launchSettingsView
proxySettingsView
customCryptoSettingsView
//
Group {
switch selectedTab {
case .general:
generalSettingsView
case .custom:
customCryptoSettingsView
case .proxy:
proxySettingsView
}
}
Spacer(minLength: 20)
}
}
// +
private var generalSettingsView: some View {
VStack(spacing: 24) {
refreshSettingsView
launchSettingsView
}
}
//
private var refreshSettingsView: some View {
SettingsGroupView(title: "刷新设置", icon: "timer") {
@@ -633,6 +744,8 @@ struct SettingsGroupView<Content: View>: View {
}
}
/**
*
*/

View File

@@ -40,7 +40,7 @@ class PreferencesWindowManager: ObservableObject {
let hostingView = NSHostingView(rootView: preferencesView)
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 620),
contentRect: NSRect(x: 0, y: 0, width: 480, height: 600),
styleMask: [.titled, .closable],
backing: .buffered,
defer: false