fix network

This commit is contained in:
anlicheng 2026-03-24 00:39:12 +08:00
parent c8c37954ce
commit fbbef96aa9
2 changed files with 108 additions and 126 deletions

View File

@ -6,7 +6,15 @@ import Observation
// MARK: - // MARK: -
enum ConnectState { enum ConnectState {
case waitAuth, connected, disconnected case waitAuth
case connected
case disconnected
}
//
enum NetworkShowMode: String, CaseIterable {
case resource = "访问资源"
case device = "成员设备"
} }
// MARK: - // MARK: -
@ -15,21 +23,67 @@ struct NetworkView: View {
@Environment(\.openWindow) private var openWindow @Environment(\.openWindow) private var openWindow
@State private var networkModel = NetworkModel() @State private var networkModel = NetworkModel()
@State private var showMode: ShowMode = .resource @State private var showMode: NetworkShowMode = .resource
@State private var connectState: ConnectState = .disconnected @State private var connectState: ConnectState = .disconnected
@State private var isConnecting: Bool = false @State private var isConnecting: Bool = false
private var vpnManager = VPNManager.shared private var vpnManager = VPNManager.shared
enum ShowMode: String, CaseIterable {
case resource = "访问资源"
case device = "成员设备"
}
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
// 1. (Header) // 1. (Header)
headerSection HStack(spacing: 16) {
ZStack {
Circle()
.fill(connectState == .connected ? Color.green.opacity(0.15) : Color.primary.opacity(0.05))
.frame(width: 36, height: 36)
Image(systemName: connectState == .connected ? "checkmark.shield.fill" : "shield.slash.fill")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(connectState == .connected ? Color.green : Color.secondary)
.font(.system(size: 16))
}
VStack(alignment: .leading, spacing: 2) {
Text(appContext.networkSession?.networkName ?? "未连接网络")
.font(.system(size: 14, weight: .semibold))
if connectState == .connected {
Text("虚拟局域网 IP: \(networkModel.networkContext.ip)")
.font(.system(size: 11, design: .monospaced))
.foregroundColor(.secondary)
} else {
Text("PunchNet 服务未就绪")
.font(.caption)
.foregroundColor(.secondary)
}
}
Spacer()
if connectState == .connected {
Picker("", selection: $showMode) {
ForEach(NetworkShowMode.allCases, id: \.self) {
Text($0.rawValue).tag($0)
}
}
.pickerStyle(.segmented)
.frame(width: 160)
}
Button {
openWindow(id: "settings")
} label: {
Image(systemName: "slider.horizontal.3")
.font(.system(size: 14))
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
.help("配置中心")
}
.padding(.horizontal, 20)
.padding(.vertical, 14)
.background(VisualEffectView(material: .headerView, blendingMode: .withinWindow))
Divider() Divider()
@ -39,9 +93,52 @@ struct NetworkView: View {
case .waitAuth: case .waitAuth:
NetworkWaitAuthView(networkModel: networkModel) NetworkWaitAuthView(networkModel: networkModel)
case .connected: case .connected:
connectedContent if showMode == .resource {
//
ScrollView {
LazyVGrid(columns: [
GridItem(.flexible(), spacing: 8),
GridItem(.flexible(), spacing: 8),
GridItem(.flexible(), spacing: 8)
], spacing: 10) {
ForEach(networkModel.networkContext.resourceList, id: \.uuid) { res in
ResourceItemCard(resource: res)
}
}
.padding(20)
}
.transition(.opacity)
.frame(maxWidth: .infinity)
} else {
//
NetworkDeviceGroupView(networkModel: networkModel)
.transition(.asymmetric(insertion: .move(edge: .trailing), removal: .opacity))
}
case .disconnected: case .disconnected:
disconnectedContent VStack(spacing: 20) {
Spacer()
Image(systemName: "antenna.radiowaves.left.and.right")
.font(.system(size: 40, weight: .ultraLight))
.foregroundStyle(.tertiary)
.symbolEffect(.pulse, options: .repeating)
Text("尚未接入网络")
.font(.headline)
Button(action: { startConnection() }) {
if isConnecting {
ProgressView()
.controlSize(.small)
.frame(width: 80)
} else {
Text("建立安全连接")
.frame(width: 80)
}
}
.buttonStyle(.borderedProminent)
.disabled(isConnecting)
Spacer()
}
} }
} }
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
@ -57,121 +154,6 @@ struct NetworkView: View {
} }
} }
} }
}
// MARK: -
extension NetworkView {
private var headerSection: some View {
HStack(spacing: 16) {
statusIndicator
VStack(alignment: .leading, spacing: 2) {
Text(appContext.networkSession?.networkName ?? "未连接网络")
.font(.system(size: 14, weight: .semibold))
if connectState == .connected {
Text("虚拟局域网 IP: \(networkModel.networkContext.ip)")
.font(.system(size: 11, design: .monospaced))
.foregroundColor(.secondary)
} else {
Text("PunchNet 服务未就绪")
.font(.caption)
.foregroundColor(.secondary)
}
}
Spacer()
if connectState == .connected {
Picker("", selection: $showMode) {
ForEach(ShowMode.allCases, id: \.self) {
Text($0.rawValue).tag($0)
}
}
.pickerStyle(.segmented)
.frame(width: 160)
}
Button {
openWindow(id: "settings")
} label: {
Image(systemName: "slider.horizontal.3")
.font(.system(size: 14))
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
.help("配置中心")
}
.padding(.horizontal, 20)
.padding(.vertical, 14)
.background(VisualEffectView(material: .headerView, blendingMode: .withinWindow))
}
private var statusIndicator: some View {
ZStack {
Circle()
.fill(connectState == .connected ? Color.green.opacity(0.15) : Color.primary.opacity(0.05))
.frame(width: 36, height: 36)
Image(systemName: connectState == .connected ? "checkmark.shield.fill" : "shield.slash.fill")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(connectState == .connected ? Color.green : Color.secondary)
.font(.system(size: 16))
}
}
@ViewBuilder
private var connectedContent: some View {
if showMode == .resource {
//
ScrollView {
LazyVGrid(columns: [
GridItem(.flexible(), spacing: 8),
GridItem(.flexible(), spacing: 8),
GridItem(.flexible(), spacing: 8)
], spacing: 10) {
ForEach(networkModel.networkContext.resourceList, id: \.uuid) { res in
ResourceItemCard(resource: res)
}
}
.padding(20)
}
.transition(.opacity)
.frame(maxWidth: .infinity)
} else {
//
NetworkDeviceGroupView(networkModel: networkModel)
.transition(.asymmetric(insertion: .move(edge: .trailing), removal: .opacity))
}
}
private var disconnectedContent: some View {
VStack(spacing: 20) {
Spacer()
Image(systemName: "antenna.radiowaves.left.and.right")
.font(.system(size: 40, weight: .ultraLight))
.foregroundStyle(.tertiary)
.symbolEffect(.pulse, options: .repeating)
Text("尚未接入网络")
.font(.headline)
Button(action: { startConnection() }) {
if isConnecting {
ProgressView()
.controlSize(.small)
.frame(width: 80)
} else {
Text("建立安全连接")
.frame(width: 80)
}
}
.buttonStyle(.borderedProminent)
.disabled(isConnecting)
Spacer()
}
}
private func syncState(_ status: VPNManager.VPNStatus) { private func syncState(_ status: VPNManager.VPNStatus) {
switch status { switch status {

View File

@ -64,7 +64,7 @@ struct punchnetApp: App {
// } // }
// } // }
// } // }
.windowResizability(.contentSize) //.windowResizability(.contentSize)
.windowToolbarStyle(.unified) .windowToolbarStyle(.unified)
.defaultPosition(.center) .defaultPosition(.center)