修复到第一版的UI
3
dmg.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
create-dmg --volname "punchnet" --window-pos 200 120 --window-size 800 400 --icon "punchnet.app" 200 190 --hide-extension "punchnet.app" --app-drop-link 600 185 ~/Desktop/punchnet.dmg /Users/anlicheng/Desktop/sdlan_v1
|
||||||
@ -1,46 +1,55 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
|
"filename" : "logo.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "16x16"
|
"size" : "16x16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_32.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "16x16"
|
"size" : "16x16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_32 1.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "32x32"
|
"size" : "32x32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_64.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "32x32"
|
"size" : "32x32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_128.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "128x128"
|
"size" : "128x128"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_256.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "128x128"
|
"size" : "128x128"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_256 1.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "256x256"
|
"size" : "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_512.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "256x256"
|
"size" : "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "logo_512 1.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "512x512"
|
"size" : "512x512"
|
||||||
|
|||||||
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_128.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_256 1.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_256.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_32 1.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_32.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_512 1.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_512.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
punchnet/Assets.xcassets/AppIcon.appiconset/logo_64.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
21
punchnet/Assets.xcassets/IosSettings.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "IosSettings.svg",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
8
punchnet/Assets.xcassets/IosSettings.imageset/IosSettings.svg
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg version="1.1" fill="#fff" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path d="M416.3,256c0-21,13.1-38.9,31.7-46.1c-4.9-20.5-13-39.7-23.7-57.1c-6.4,2.8-13.2,4.3-20.1,4.3c-12.6,0-25.2-4.8-34.9-14.4
|
||||||
|
c-14.9-14.9-18.2-36.8-10.2-55C341.8,77,322.5,68.9,302.1,64C295,82.5,277,95.7,256,95.7c-21,0-39-13.2-46.1-31.7
|
||||||
|
c-20.5,4.9-39.7,13-57.1,23.7c8.1,18.1,4.7,40.1-10.2,55c-9.6,9.6-22.3,14.4-34.9,14.4c-6.9,0-13.7-1.4-20.1-4.3
|
||||||
|
C77,170.3,68.9,189.5,64,210c18.5,7.1,31.7,25,31.7,46.1c0,21-13.1,38.9-31.6,46.1c4.9,20.5,13,39.7,23.7,57.1
|
||||||
|
c6.4-2.8,13.2-4.2,20-4.2c12.6,0,25.2,4.8,34.9,14.4c14.8,14.8,18.2,36.8,10.2,54.9c17.4,10.7,36.7,18.8,57.1,23.7
|
||||||
|
c7.1-18.5,25-31.6,46-31.6c21,0,38.9,13.1,46,31.6c20.5-4.9,39.7-13,57.1-23.7c-8-18.1-4.6-40,10.2-54.9
|
||||||
|
c9.6-9.6,22.2-14.4,34.9-14.4c6.8,0,13.7,1.4,20,4.2c10.7-17.4,18.8-36.7,23.7-57.1C429.5,295,416.3,277.1,416.3,256z M256.9,335.9
|
||||||
|
c-44.3,0-80-35.9-80-80c0-44.1,35.7-80,80-80s80,35.9,80,80C336.9,300,301.2,335.9,256.9,335.9z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
21
punchnet/Assets.xcassets/close.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "close.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
punchnet/Assets.xcassets/close.imageset/close.png
vendored
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
21
punchnet/Assets.xcassets/line.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "line.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
punchnet/Assets.xcassets/line.imageset/line.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "logo.jpg",
|
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
@ -12,6 +11,15 @@
|
|||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "logo.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
BIN
punchnet/Assets.xcassets/logo.imageset/logo.jpg
vendored
|
Before Width: | Height: | Size: 22 KiB |
BIN
punchnet/Assets.xcassets/logo.imageset/logo.png
vendored
Normal file
|
After Width: | Height: | Size: 216 KiB |
21
punchnet/Assets.xcassets/logo_32.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "logo_32.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
punchnet/Assets.xcassets/logo_32.imageset/logo_32.png
vendored
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
@ -10,67 +10,154 @@ import SwiftData
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
//@Environment(\.modelContext) private var modelContext
|
|
||||||
//@Query private var items: [Item]
|
|
||||||
|
|
||||||
@AppStorage("token") private var token: String = ""
|
@AppStorage("token") private var token: String = ""
|
||||||
|
@State private var showToken: Bool = false
|
||||||
|
|
||||||
@ObservedObject private var vpnManager = VPNManager.shared
|
@ObservedObject private var vpnManager = VPNManager.shared
|
||||||
@State private var showAlert = false
|
@State private var showAlert = false
|
||||||
@State private var showStunAlert = false
|
@State private var showStunAlert = false
|
||||||
@State private var message: NoticeMessage.InboundMessage = .none
|
@State private var message: NoticeMessage.InboundMessage = .none
|
||||||
@State private var cancel: AnyCancellable?
|
@State private var cancel: AnyCancellable?
|
||||||
|
|
||||||
|
@State private var showMenu: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|
||||||
VStack(alignment: .center, spacing: 10) {
|
VStack(alignment: .center, spacing: 10) {
|
||||||
|
VStack(alignment: .center, spacing: 10) {
|
||||||
Image("logo")
|
Spacer()
|
||||||
|
.frame(height: 100)
|
||||||
Text("PUNCHENT")
|
|
||||||
.font(.system(size: 46, weight: .bold))
|
Image("logo")
|
||||||
.foregroundColor(.white)
|
.resizable()
|
||||||
.cornerRadius(5.0)
|
.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()
|
Spacer()
|
||||||
.frame(width: 1, height: 10)
|
.frame(width: 1, height: 10)
|
||||||
|
|
||||||
TextField("邀请码", text: $token)
|
if showToken {
|
||||||
.multilineTextAlignment(.center)
|
TextField("邀请码", text: $token)
|
||||||
.frame(width: 245, height: 27)
|
.multilineTextAlignment(.leading)
|
||||||
.cornerRadius(5.0)
|
.textFieldStyle(PlainTextFieldStyle())
|
||||||
|
.frame(width: 200, height: 25)
|
||||||
|
.background(Color.white)
|
||||||
|
.foregroundColor(Color.black)
|
||||||
|
.cornerRadius(5.0)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
.frame(width: 1, height: 10)
|
.frame(width: 1, height: 10)
|
||||||
|
|
||||||
Button(action: {
|
Rectangle()
|
||||||
Task {
|
.overlay {
|
||||||
switch self.vpnManager.vpnStatus {
|
Text(vpnManager.title)
|
||||||
case .connected:
|
.font(.system(size: 14, weight: .regular))
|
||||||
try await vpnManager.disableVpn()
|
.foregroundColor(vpnManager.color)
|
||||||
case .disconnected:
|
}
|
||||||
if self.token.isEmpty {
|
.frame(width: 120, height: 35)
|
||||||
self.showAlert = true
|
.foregroundColor(Color(red: 74 / 255, green: 207 / 255, blue: 154 / 255))
|
||||||
return
|
.cornerRadius(5.0)
|
||||||
}
|
.onTapGesture {
|
||||||
try await vpnManager.enableVpn(options: [
|
Task {
|
||||||
"version:": SystemConfig.version as NSObject,
|
try await self.clickSwitchButton()
|
||||||
"installed_channel": SystemConfig.installedChannel as NSObject,
|
|
||||||
"token": self.token as NSObject
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, label: {
|
|
||||||
Text(vpnManager.title)
|
Spacer()
|
||||||
.font(.system(size: 16, weight: .regular))
|
|
||||||
.foregroundColor(vpnManager.color)
|
|
||||||
.cornerRadius(5.0)
|
|
||||||
})
|
|
||||||
.frame(width: 138, height: 33)
|
|
||||||
.buttonStyle(PlainButtonStyle())
|
|
||||||
.background(Color(red: 74 / 255, green: 207 / 255, blue: 154 / 255))
|
|
||||||
.cornerRadius(5.0)
|
|
||||||
}
|
}
|
||||||
.frame(width: 380, height: 560)
|
.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))
|
.background(Color(red: 36 / 255, green: 38 / 255, blue: 51 / 255))
|
||||||
.alert(isPresented: $showAlert) {
|
.alert(isPresented: $showAlert) {
|
||||||
Alert(title: Text("请输入正确的邀请码"))
|
Alert(title: Text("请输入正确的邀请码"))
|
||||||
@ -93,51 +180,31 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
NavigationSplitView {
|
|
||||||
List {
|
|
||||||
ForEach(items) { item in
|
|
||||||
NavigationLink {
|
|
||||||
Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
|
|
||||||
} label: {
|
|
||||||
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onDelete(perform: deleteItems)
|
|
||||||
}
|
|
||||||
.navigationSplitViewColumnWidth(min: 180, ideal: 200)
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem {
|
|
||||||
Button(action: addItem) {
|
|
||||||
Label("Add Item", systemImage: "plus")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} detail: {
|
|
||||||
Text("Select an item")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func clickSwitchButton() async throws {
|
||||||
private func addItem() {
|
switch self.vpnManager.vpnStatus {
|
||||||
withAnimation {
|
case .connected:
|
||||||
|
try await vpnManager.disableVpn()
|
||||||
}
|
case .disconnected:
|
||||||
}
|
/*
|
||||||
|
if self.token.isEmpty {
|
||||||
private func deleteItems(offsets: IndexSet) {
|
self.showAlert = true
|
||||||
withAnimation {
|
return
|
||||||
// for index in offsets {
|
}
|
||||||
// modelContext.delete(items[index])
|
*/
|
||||||
// }
|
//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 {
|
#Preview {
|
||||||
ContentView()
|
ContentView()
|
||||||
//.modelContainer(for: Item.self, inMemory: true)
|
//.modelContainer(for: Item.self, inMemory: true)
|
||||||
}
|
}
|
||||||
|
|||||||