// // ContentView.swift // sdlan // // Created by 安礼成 on 2024/1/17. // import SwiftUI import SwiftData import Combine struct ContentView: View { @AppStorage("token") private var token: String = "" @State private var showToken: Bool = false @ObservedObject private var vpnManager = VPNManager.shared @State private var showAlert = false @State private var showStunAlert = false @State private var message: NoticeMessage.InboundMessage = .none @State private var cancel: AnyCancellable? @State private var showMenu: Bool = false var body: some View { VStack(alignment: .center, spacing: 10) { VStack(alignment: .center, spacing: 10) { Spacer() .frame(height: 100) Image("logo") .resizable() .frame(width: 150, height: 150) Text("Connecting the Infinite") .font(.system(size: 24, weight: .bold)) .foregroundColor(.white) .cornerRadius(5.0) Text("Welcome to PunchNet") .font(.system(size: 14, weight: .regular)) .foregroundColor(.white) .cornerRadius(5.0) } .contentShape(Rectangle()) .onTapGesture { self.showMenu = false } Spacer() .frame(width: 1, height: 10) if showToken { TextField("邀请码", text: $token) .multilineTextAlignment(.leading) .textFieldStyle(PlainTextFieldStyle()) .frame(width: 200, height: 25) .background(Color.white) .foregroundColor(Color.black) .cornerRadius(5.0) } Spacer() .frame(width: 1, height: 10) Rectangle() .overlay { Text(vpnManager.title) .font(.system(size: 14, weight: .regular)) .foregroundColor(vpnManager.color) } .frame(width: 120, height: 35) .foregroundColor(Color(red: 74 / 255, green: 207 / 255, blue: 154 / 255)) .cornerRadius(5.0) .onTapGesture { Task { do { try await self.clickSwitchButton() } catch let err { NSLog("start vpn get error: \(err)") } } } Spacer() } .overlay(alignment: .top) { HStack(spacing: 200) { HStack { Button(action: { NSApplication.shared.terminate(nil) }) { Image("close") .resizable() .frame(width: 15, height: 15) } .buttonStyle(PlainButtonStyle()) Button(action: { NSApplication.shared.keyWindow?.miniaturize(nil) }) { Image("line") .resizable() .frame(width: 15, height: 15) } .buttonStyle(PlainButtonStyle()) } Button(action: { showMenu.toggle() }) { Image("IosSettings") .resizable() .frame(width: 20, height: 20) } .buttonStyle(PlainButtonStyle()) .overlay(alignment: .leading) { showMenu ? GeometryReader { geometry in VStack(alignment: .leading, spacing: 8) { Button(action: { self.showMenu = false }) { Text("主页") .font(.system(size: 14)) .foregroundColor(.white) } .buttonStyle(PlainButtonStyle()) Button(action: { self.showToken.toggle() }) { Text("邀请码") .font(.system(size: 14)) .foregroundColor(.white) } .buttonStyle(PlainButtonStyle()) Button(action: { NSApplication.shared.terminate(nil) }) { Text("退出") .font(.system(size: 14)) .foregroundColor(.white) } .buttonStyle(PlainButtonStyle()) } .frame(width: 90, height: 80) .background(Color(red: 50 / 255, green: 55 / 255, blue: 52 / 255)) .offset(x: -55, y: 20) } : nil } } .offset(x: 0, y: 10) } .frame(width: 300, height: 500) .background(Color(red: 36 / 255, green: 38 / 255, blue: 51 / 255)) .alert(isPresented: $showAlert) { Alert(title: Text("请输入正确的邀请码")) } .alert(isPresented: $showStunAlert) { switch self.message { case .upgradeMessage(let upgradeMessage): Alert(title: Text(upgradeMessage.prompt)) case .alertMessage(let alertMessage): Alert(title: Text(alertMessage.alert)) default: Alert(title: Text("")) } } .onAppear { self.cancel = UDPNoticeCenterServer.shared.messageFlow.sink{ message in DispatchQueue.main.async { self.message = message self.showStunAlert = true } } } } private func clickSwitchButton() async throws { switch self.vpnManager.vpnStatus { case .connected: try await vpnManager.disableVpn() case .disconnected: /* if self.token.isEmpty { self.showAlert = true return } */ //print("use port: \(vpnManager.noticePort as NSObject)") try await vpnManager.enableVpn(options: [ "version:": SystemConfig.version as NSObject, "installed_channel": SystemConfig.installedChannel as NSObject, "token": self.token as NSObject ]) } } } #Preview { ContentView() //.modelContainer(for: Item.self, inMemory: true) }