punchnet-macos/punchnet/Views/Settings/SettingsAccountView.swift
2026-03-19 23:14:53 +08:00

229 lines
8.0 KiB
Swift

//
// SettingsAccountView.swift
// punchnet
//
// Created by on 2026/1/16.
//
import SwiftUI
struct SettingsAccountView: View {
@Environment(UserContext.self) var userContext: UserContext
@Environment(\.openWindow) var openWindow
@Environment(\.openURL) var openURL
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading, spacing: 24) {
// MARK: -
sectionHeader(title: "账户安全", icon: "shield.lefthalf.filled")
VStack(spacing: 0) {
if userContext.isLogined, let loginCredit = userContext.loginCredit {
switch loginCredit {
case .token(let token):
TokenCreditView(token: token)
case .accountAndPasword(let account, _):
AccountCreditView(username: account)
}
} else {
//
Button {
self.openMainWindow(id: "main")
} label: {
Text("登录")
.fontWeight(.medium)
}
.buttonStyle(.borderedProminent)
}
}
.background(Color.primary.opacity(0.03))
.cornerRadius(12)
.overlay(RoundedRectangle(cornerRadius: 12).stroke(Color.primary.opacity(0.05), lineWidth: 1))
// MARK: -
sectionHeader(title: "网络配置", icon: "network")
if let networkSession = userContext.networkSession {
VStack(spacing: 16) {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text("网络")
.font(.subheadline)
.foregroundColor(.secondary)
Text(networkSession.networkName)
.font(.headline)
}
Spacer()
//
// Menu {
// ForEach(state.networks, id: \.id) { network in
// Button(network.name) {
// self.state.selectedNetwork = network
// }
// }
// } label: {
// Text("")
// .font(.subheadline)
// .padding(.horizontal, 12)
// .padding(.vertical, 6)
// .background(Capsule().fill(Color.blue.opacity(0.1)))
// }
// .buttonStyle(.plain)
}
Divider()
HStack {
Button {
self.openNetworkUrl(url: networkSession.networkUrl)
} label: {
Label("进入管理平台", systemImage: "arrow.up.right.square")
}
.buttonStyle(.plain)
.foregroundColor(.blue)
Spacer()
Button("查看详情") {
self.openNetworkUrl(url: networkSession.networkUrl)
}
.buttonStyle(.bordered)
.controlSize(.small)
}
}
.padding(16)
.background(Color.primary.opacity(0.03))
.cornerRadius(12)
}
}
.frame(maxWidth: 600) //
}
}
private func openNetworkUrl(url: String) {
if let url = URL(string: url) {
openURL(url) { accepted in
if accepted {
print("浏览器已成功打开")
} else {
print("打开失败(可能是 URL 格式错误)")
}
}
}
}
//
private func openMainWindow(id: String) {
let window = NSApp.windows.first { win in
if let idStr = win.identifier?.rawValue {
return idStr.starts(with: id)
}
return false
}
if let window {
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
} else {
openWindow(id: id)
}
}
//
private func sectionHeader(title: String, icon: String) -> some View {
HStack {
Image(systemName: icon)
.foregroundColor(.blue)
Text(title)
.font(.system(size: 16, weight: .bold))
}
.padding(.leading, 4)
}
}
// MARK: -
extension SettingsAccountView {
//
struct AccountRow: View {
let icon: String
let title: String
let subtitle: String
var actions: AnyView
var body: some View {
HStack(spacing: 16) {
// Logo
Circle()
.fill(Color.blue.gradient)
.frame(width: 32, height: 32)
.overlay(
Image(systemName: icon)
.foregroundColor(.white)
.font(.system(size: 14))
)
VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.subheadline)
.foregroundColor(.secondary)
Text(subtitle)
.font(.system(size: 15, weight: .medium, design: .monospaced))
.lineLimit(1)
}
Spacer()
actions
}
.padding(16)
}
}
struct AccountCreditView: View {
@Environment(UserContext.self) var userContext: UserContext
let username: String
var body: some View {
AccountRow(icon: "person.fill", title: "当前登录账号", subtitle: username, actions: AnyView(
HStack(spacing: 12) {
Button("修改密码") {
}
.buttonStyle(.link)
Button("退出登录") {
Task { @MainActor in
try await userContext.logout()
}
}
.buttonStyle(.bordered)
.foregroundColor(.red)
}
))
}
}
struct TokenCreditView: View {
@Environment(UserContext.self) var userContext: UserContext
let token: String
var body: some View {
AccountRow(icon: "key.horizontal.fill", title: "Token 登录", subtitle: token, actions: AnyView(
Button("退出登录") {
Task { @MainActor in
try await userContext.logout()
}
}
.buttonStyle(.bordered)
.foregroundColor(.red)
))
}
}
}