// // punchnetApp.swift // punchnet // // Created by 安礼成 on 2025/5/12. // import SwiftUI import AppKit import SwiftData import Combine @main struct punchnetApp: App { /* var sharedModelContainer: ModelContainer = { let schema = Schema([ Item.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() */ @Environment(\.openWindow) private var openWindow @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate private var noticeServer: UDPNoticeCenterServer @State private var appContext: AppContext @AppStorage("hasAcceptedPrivacy") var hasAcceptedPrivacy: Bool = false // UI 控制状态:是否显示弹窗 @State private var showPrivacy: Bool = false @State private var vpnManager = VPNManager.shared init() { self.noticeServer = UDPNoticeCenterServer() self.noticeServer.start() self.appContext = AppContext(noticePort: self.noticeServer.port) } var body: some Scene { Window("登陆", id: "login") { LoginRootView() .navigationTitle("") .environment(self.appContext) .onAppear { self.showPrivacy = !hasAcceptedPrivacy } .sheet(isPresented: $showPrivacy) { PrivacyDetailView(showPrivacy: $showPrivacy) .interactiveDismissDisabled() // 强制阅读 } } .windowToolbarStyle(.unified) .windowResizability(.contentSize) .defaultPosition(.center) Window("网络", id: "logined") { NetworkView() .environment(self.appContext) .frame(width: 750, height: 500) } .windowResizability(.contentSize) .defaultPosition(.center) Window("设置", id: "settings") { SettingsView() .environment(self.appContext) .frame(width: 750, height: 500) } .windowResizability(.contentSize) .defaultPosition(.center) MenuBarExtra("punchnet", image: "logo_32") { VStack { switch self.vpnManager.vpnStatus { case .connected: Button(action: { Task { @MainActor in try await vpnManager.disableVpn() } }, label: { Text("停止") }) case .disconnected: Button(action: { Task { @MainActor in await self.startVPN() } }, label: { Text("启动") }) } Divider() Button(action: { NSApplication.shared.terminate(nil) }, label: { Text("退出应用") }) } } .menuBarExtraStyle(.menu) } private func startVPN() async { if let options = appContext.vpnOptions { try? await vpnManager.enableVpn(options: options) } else { openWindow(id: "login") } } } // 处理APP的生命周期 class AppDelegate: NSObject, NSApplicationDelegate { func applicationWillFinishLaunching(_ notification: Notification) { } func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { print("call me applicationShouldTerminate") Task { do { try await VPNManager.shared.disableVpn() NSLog("vpn disabled") } catch let err { NSLog("退出时关闭 VPN 失败: \(err)") } await MainActor.run { sender.reply(toApplicationShouldTerminate: true) } } return .terminateLater } }