解决登陆问题
This commit is contained in:
parent
616ba21662
commit
27d0d11508
@ -1,120 +0,0 @@
|
||||
//
|
||||
// SDLApi.swift
|
||||
// sdlan
|
||||
//
|
||||
// Created by 安礼成 on 2024/6/5.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct JSONRPCResponse<T: Decodable>: Decodable {
|
||||
let result: T?
|
||||
let error: JSONRPCError?
|
||||
}
|
||||
|
||||
struct JSONRPCError: Error, Decodable {
|
||||
let code: Int
|
||||
let message: String
|
||||
let data: String?
|
||||
}
|
||||
|
||||
struct SDLAPI {
|
||||
|
||||
enum Mode {
|
||||
case debug
|
||||
case prod
|
||||
}
|
||||
|
||||
static let mode: Mode = .debug
|
||||
|
||||
static var baseUrl: String {
|
||||
switch mode {
|
||||
case .debug:
|
||||
return "http://127.0.0.1:18082/test"
|
||||
case .prod:
|
||||
return "https://punchnet.s5s8.com/api"
|
||||
}
|
||||
}
|
||||
|
||||
struct Upgrade: Decodable {
|
||||
let upgrade_type: Int
|
||||
let upgrade_prompt: String
|
||||
let upgrade_address: String
|
||||
}
|
||||
|
||||
struct NetworkProfile: Decodable {
|
||||
struct NetworkItem: Decodable {
|
||||
let name: String
|
||||
let code: String
|
||||
}
|
||||
let network: [NetworkItem]
|
||||
}
|
||||
|
||||
static func checkVersion(clientId: String, version: Int, channel: String) async throws -> JSONRPCResponse<Upgrade> {
|
||||
let params: [String:Any] = [
|
||||
"client_id": clientId,
|
||||
"version": version,
|
||||
"channel": channel
|
||||
]
|
||||
|
||||
let postData = try! JSONSerialization.data(withJSONObject: params)
|
||||
var request = URLRequest(url: URL(string: baseUrl + "/upgrade")!)
|
||||
request.httpMethod = "POST"
|
||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = postData
|
||||
|
||||
let (data, _) = try await URLSession.shared.data(for: request)
|
||||
|
||||
return try JSONDecoder().decode(JSONRPCResponse<Upgrade>.self, from: data)
|
||||
}
|
||||
|
||||
static func getUserNetworks(clientId: String) async throws -> JSONRPCResponse<NetworkProfile> {
|
||||
let params: [String:Any] = [
|
||||
"client_id": clientId
|
||||
]
|
||||
|
||||
let postData = try! JSONSerialization.data(withJSONObject: params)
|
||||
var request = URLRequest(url: URL(string: baseUrl + "/get_user_network")!)
|
||||
request.httpMethod = "POST"
|
||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = postData
|
||||
|
||||
let (data, _) = try await URLSession.shared.data(for: request)
|
||||
|
||||
return try JSONDecoder().decode(JSONRPCResponse<NetworkProfile>.self, from: data)
|
||||
}
|
||||
|
||||
static func loginWithAccountAndPassword<T: Decodable>(clientId: String, username: String, password: String, as: T.Type) async throws -> T {
|
||||
let params: [String:Any] = [
|
||||
"client_id": clientId,
|
||||
"username": username,
|
||||
"password": password
|
||||
]
|
||||
|
||||
return try await doPost(path: "/login_with_account", params: params, as: T.self)
|
||||
}
|
||||
|
||||
private static func doPost<T: Decodable>(path: String, params: [String: Any], as: T.Type) async throws -> T {
|
||||
let postData = try! JSONSerialization.data(withJSONObject: params)
|
||||
var request = URLRequest(url: URL(string: baseUrl + path)!)
|
||||
request.httpMethod = "POST"
|
||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = postData
|
||||
|
||||
let (data, _) = try await URLSession.shared.data(for: request)
|
||||
let rpcResponse = try JSONDecoder().decode(JSONRPCResponse<T>.self, from: data)
|
||||
if let result = rpcResponse.result {
|
||||
return result
|
||||
} else if let error = rpcResponse.error {
|
||||
throw error
|
||||
} else {
|
||||
throw DecodingError.dataCorrupted(
|
||||
.init(
|
||||
codingPath: [],
|
||||
debugDescription: "Invalid JSON-RPC response: \(String(data: data, encoding: .utf8) ?? "")"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
49
punchnet/Core/SDLAPIClient.swift
Normal file
49
punchnet/Core/SDLAPIClient.swift
Normal file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// SDLApi.swift
|
||||
// sdlan
|
||||
//
|
||||
// Created by 安礼成 on 2024/6/5.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SDLAPIResponse<T: Decodable>: Decodable {
|
||||
let code: Int
|
||||
let message: String?
|
||||
let data: T?
|
||||
}
|
||||
|
||||
struct SDLAPIError: Error, Decodable {
|
||||
let code: Int
|
||||
let message: String
|
||||
}
|
||||
|
||||
struct SDLAPIClient {
|
||||
|
||||
static var baseUrl: String = "https://punchnet.s5s8.com/api"
|
||||
|
||||
static func doPost<T: Decodable>(path: String, params: [String: Any], as: T.Type) async throws -> T {
|
||||
let postData = try! JSONSerialization.data(withJSONObject: params)
|
||||
var request = URLRequest(url: URL(string: baseUrl + path)!)
|
||||
request.httpMethod = "POST"
|
||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = postData
|
||||
|
||||
let (data, _) = try await URLSession.shared.data(for: request)
|
||||
let apiResponse = try JSONDecoder().decode(SDLAPIResponse<T>.self, from: data)
|
||||
|
||||
if apiResponse.code == 0, let data = apiResponse.data {
|
||||
return data
|
||||
} else if let message = apiResponse.message {
|
||||
throw SDLAPIError(code: apiResponse.code, message: message)
|
||||
} else {
|
||||
throw DecodingError.dataCorrupted(
|
||||
.init(
|
||||
codingPath: [],
|
||||
debugDescription: "Invalid JSON-RPC response: \(String(data: data, encoding: .utf8) ?? "")"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -75,6 +75,11 @@ struct SystemConfig {
|
||||
}
|
||||
}
|
||||
|
||||
public static func macAddressString(mac: Data, separator: String = ":") -> String {
|
||||
return mac.map { String(format: "%02X", $0) }
|
||||
.joined(separator: separator)
|
||||
}
|
||||
|
||||
// 随机生成mac地址
|
||||
private static func generateMacAddress() -> Data {
|
||||
var macAddress = [UInt8](repeating: 0, count: 6)
|
||||
|
||||
@ -30,34 +30,34 @@ struct AbortView: View {
|
||||
Text("Version1.1")
|
||||
|
||||
Button {
|
||||
Task {
|
||||
guard let response = try? await SDLAPI.checkVersion(clientId: "test", version: 1, channel: "macos") else {
|
||||
DispatchQueue.main.async {
|
||||
self.alertShow = AlertShow(id: "network_error", content: .error("Network Error"))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let result = response.result {
|
||||
if result.upgrade_type == 0 {
|
||||
DispatchQueue.main.async {
|
||||
self.alertShow = AlertShow(id: "upgrade_0", content: .upgrade(result.upgrade_prompt, ""))
|
||||
}
|
||||
} else if result.upgrade_type == 1 {
|
||||
DispatchQueue.main.async {
|
||||
self.alertShow = AlertShow(id: "upgrade_1", content: .upgrade(result.upgrade_prompt, result.upgrade_address))
|
||||
}
|
||||
} else if result.upgrade_type == 2 {
|
||||
DispatchQueue.main.async {
|
||||
self.alertShow = AlertShow(id: "upgrade_1", content: .upgrade(result.upgrade_prompt, result.upgrade_address))
|
||||
}
|
||||
}
|
||||
} else if let error = response.error {
|
||||
DispatchQueue.main.async {
|
||||
self.alertShow = AlertShow(id: "response_error", content: .error(error.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Task {
|
||||
// guard let response = try? await SDLAPI.checkVersion(clientId: "test", version: 1, channel: "macos") else {
|
||||
// DispatchQueue.main.async {
|
||||
// self.alertShow = AlertShow(id: "network_error", content: .error("Network Error"))
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if let result = response.result {
|
||||
// if result.upgrade_type == 0 {
|
||||
// DispatchQueue.main.async {
|
||||
// self.alertShow = AlertShow(id: "upgrade_0", content: .upgrade(result.upgrade_prompt, ""))
|
||||
// }
|
||||
// } else if result.upgrade_type == 1 {
|
||||
// DispatchQueue.main.async {
|
||||
// self.alertShow = AlertShow(id: "upgrade_1", content: .upgrade(result.upgrade_prompt, result.upgrade_address))
|
||||
// }
|
||||
// } else if result.upgrade_type == 2 {
|
||||
// DispatchQueue.main.async {
|
||||
// self.alertShow = AlertShow(id: "upgrade_1", content: .upgrade(result.upgrade_prompt, result.upgrade_address))
|
||||
// }
|
||||
// }
|
||||
// } else if let error = response.error {
|
||||
// DispatchQueue.main.async {
|
||||
// self.alertShow = AlertShow(id: "response_error", content: .error(error.message))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
} label: {
|
||||
Text("版本检测")
|
||||
|
||||
@ -1,303 +0,0 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// sdlan
|
||||
//
|
||||
// Created by 安礼成 on 2024/1/17.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
import Combine
|
||||
|
||||
struct IndexView: View {
|
||||
@AppStorage("token") private var token: String = ""
|
||||
@AppStorage("hostname") private var hostname: String = ""
|
||||
@AppStorage("network_code") private var networkCode: 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
|
||||
|
||||
@State private var networkProfile: SDLAPI.NetworkProfile = .init(network: [])
|
||||
@State private var selectedIdx: Int = 0
|
||||
|
||||
// 显示ip信息
|
||||
@State private var showIpAdress: Bool = false
|
||||
@State private var ipAddress: String = ""
|
||||
|
||||
public var noticeServer: UDPNoticeCenterServer
|
||||
|
||||
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
|
||||
}
|
||||
TextField("主机名", text: $hostname)
|
||||
.multilineTextAlignment(.leading)
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
.frame(width: 200, height: 25)
|
||||
.background(Color.white)
|
||||
.foregroundColor(Color.black)
|
||||
.cornerRadius(5.0)
|
||||
|
||||
if showIpAdress {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Text("ip: ")
|
||||
.font(.system(size: 16, weight: .medium))
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(5.0)
|
||||
|
||||
Text(ipAddress)
|
||||
.font(.system(size: 16, weight: .medium))
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(5.0)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
.frame(width: 1, height: 10)
|
||||
|
||||
VStack(spacing: 0) {
|
||||
ForEach(Array(networkProfile.network.enumerated()), id: \.offset) { idx, network in
|
||||
NetworkItemView(idx: idx, item: network)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 6)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(selectedIdx == idx ? Color.blue.opacity(0.3) : Color.clear)
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
selectedIdx = idx
|
||||
self.networkCode = network.code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextField("邀请码", text: $token)
|
||||
.multilineTextAlignment(.leading)
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
.frame(width: 200, height: 25)
|
||||
.background(Color.white)
|
||||
.foregroundColor(Color.black)
|
||||
.cornerRadius(5.0)
|
||||
.opacity(showToken ? 1 : 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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.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)
|
||||
}
|
||||
.padding([.leading, .trailing, .top], 10)
|
||||
.padding([.bottom], 20)
|
||||
.background(Color(red: 36 / 255, green: 38 / 255, blue: 51 / 255))
|
||||
.frame(width: 320)
|
||||
.alert(isPresented: $showAlert) {
|
||||
Alert(title: Text("请输入正确的邀请码"))
|
||||
}
|
||||
.alert(isPresented: $showStunAlert) {
|
||||
switch self.message {
|
||||
case .alertMessage(let alert):
|
||||
Alert(title: Text(alert))
|
||||
default:
|
||||
Alert(title: Text(""))
|
||||
}
|
||||
}
|
||||
.task {
|
||||
do {
|
||||
let response = try await SDLAPI.getUserNetworks(clientId: SystemConfig.getClientId())
|
||||
print("get user networks: \(response)")
|
||||
if let result = response.result {
|
||||
self.networkProfile = result
|
||||
if self.networkProfile.network.count > 0 {
|
||||
self.networkCode = self.networkProfile.network[0].code
|
||||
}
|
||||
}
|
||||
} catch let err {
|
||||
NSLog("get user networks get error: \(err)")
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
self.cancel = self.noticeServer.messageFlow.sink{ message in
|
||||
DispatchQueue.main.async {
|
||||
switch message {
|
||||
case .none:
|
||||
()
|
||||
default:
|
||||
self.message = message
|
||||
self.showStunAlert = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func clickSwitchButton() async throws {
|
||||
switch self.vpnManager.vpnStatus {
|
||||
case .connected:
|
||||
self.showIpAdress = false
|
||||
self.ipAddress = ""
|
||||
try await vpnManager.disableVpn()
|
||||
case .disconnected:
|
||||
// let clientId = SystemConfig.getClientId()
|
||||
// NSLog("[IndexView] use token: \(self.token), network_code: \(networkCode)")
|
||||
// // token存在则优先使用token
|
||||
// try await vpnManager.enableVpn(options: SystemConfig.getOptions(networkCode: self.networkCode, token: self.token, clientId: clientId, hostname: self.hostname, noticePort: self.noticeServer.port)!)
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension IndexView {
|
||||
struct NetworkItemView: View {
|
||||
let idx: Int
|
||||
let item: SDLAPI.NetworkProfile.NetworkItem
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(item.name)
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.white)
|
||||
.frame(width: 80, alignment: .leading)
|
||||
|
||||
Text(item.code)
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.white)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
let server = UDPNoticeCenterServer()
|
||||
IndexView(noticeServer: server)
|
||||
//.modelContainer(for: Item.self, inMemory: true)
|
||||
}
|
||||
@ -12,10 +12,74 @@ import Observation
|
||||
class UserContext {
|
||||
var isLogined: Bool = false
|
||||
var loginCredit: LoginCredit?
|
||||
|
||||
var networkSession: NetworkSession?
|
||||
|
||||
enum LoginCredit {
|
||||
case token(token: String, networkdId: Int)
|
||||
case accountAndPasword(account: String, password: String, networkId: Int)
|
||||
case token(token: String)
|
||||
case accountAndPasword(account: String, password: String)
|
||||
}
|
||||
|
||||
// 登陆后的网络会话信息
|
||||
struct NetworkSession: Codable {
|
||||
struct ExitNode: Codable {
|
||||
let nnid: Int
|
||||
let nodeName: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case nnid
|
||||
case nodeName = "node_name"
|
||||
}
|
||||
}
|
||||
|
||||
let accessToken: String
|
||||
let username: String
|
||||
let userType: String
|
||||
let audit: Int
|
||||
let networkId: Int
|
||||
let networkName: String
|
||||
let networkDomain: String
|
||||
let exitNodes: [ExitNode]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case accessToken = "access_token"
|
||||
case username
|
||||
case userType = "user_type"
|
||||
case audit
|
||||
case networkId = "network_id"
|
||||
case networkName = "network_name"
|
||||
case networkDomain = "network_domain"
|
||||
case exitNodes = "exit_node"
|
||||
}
|
||||
}
|
||||
|
||||
private let baseParams: [String: Any] = [
|
||||
"client_id": SystemConfig.getClientId(),
|
||||
"mac": SystemConfig.macAddressString(mac: SystemConfig.getMacAddress())
|
||||
]
|
||||
|
||||
@MainActor
|
||||
func loginWithAccountAndPassword(username: String, password: String) async throws {
|
||||
var params: [String: Any] = [
|
||||
"username": username,
|
||||
"password": password,
|
||||
]
|
||||
params.merge(baseParams) {$1}
|
||||
|
||||
self.networkSession = try await SDLAPIClient.doPost(path: "/auth/login", params: params, as: NetworkSession.self)
|
||||
self.loginCredit = .accountAndPasword(account: username, password: password)
|
||||
self.isLogined = true
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func loginWithToken(token: String) async throws {
|
||||
var params: [String: Any] = [
|
||||
"token": token,
|
||||
]
|
||||
params.merge(baseParams) {$1}
|
||||
|
||||
self.networkSession = try await SDLAPIClient.doPost(path: "/auth/token", params: params, as: NetworkSession.self)
|
||||
self.loginCredit = .token(token: token)
|
||||
self.isLogined = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -10,9 +10,10 @@ import Observation
|
||||
|
||||
// 登陆页面
|
||||
struct LoginView: View {
|
||||
@State private var loginMode: LoginMode = .account
|
||||
@Environment(UserContext.self) var userContext: UserContext
|
||||
@State private var authMethod: AuthMethod = .account
|
||||
|
||||
enum LoginMode {
|
||||
enum AuthMethod {
|
||||
case token
|
||||
case account
|
||||
}
|
||||
@ -24,7 +25,7 @@ struct LoginView: View {
|
||||
|
||||
HStack(alignment: .center, spacing: 30) {
|
||||
Button {
|
||||
self.loginMode = .token
|
||||
self.authMethod = .token
|
||||
} label: {
|
||||
HStack {
|
||||
Image("logo")
|
||||
@ -33,14 +34,14 @@ struct LoginView: View {
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text("密钥登陆")
|
||||
.foregroundColor(self.loginMode == .token ? .blue : .black)
|
||||
.foregroundColor(self.authMethod == .token ? .blue : .black)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Button {
|
||||
self.loginMode = .account
|
||||
self.authMethod = .account
|
||||
} label: {
|
||||
HStack {
|
||||
Image("logo")
|
||||
@ -48,7 +49,7 @@ struct LoginView: View {
|
||||
.clipped()
|
||||
.frame(width: 25, height: 25)
|
||||
Text("账户登陆")
|
||||
.foregroundColor(self.loginMode == .account ? .blue : .black)
|
||||
.foregroundColor(self.authMethod == .account ? .blue : .black)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
@ -56,7 +57,7 @@ struct LoginView: View {
|
||||
}
|
||||
|
||||
Group {
|
||||
switch loginMode {
|
||||
switch self.authMethod {
|
||||
case .token:
|
||||
LoginTokenView()
|
||||
case .account:
|
||||
@ -75,6 +76,9 @@ struct LoginTokenView: View {
|
||||
@Environment(UserContext.self) var userContext: UserContext
|
||||
@State private var token: String = ""
|
||||
|
||||
@State private var showAlert = false
|
||||
@State private var errorMessage = ""
|
||||
|
||||
var body: some View {
|
||||
TextField("认证密钥", text: $token)
|
||||
.multilineTextAlignment(.leading)
|
||||
@ -99,17 +103,44 @@ struct LoginTokenView: View {
|
||||
.foregroundColor(Color(red: 74 / 255, green: 207 / 255, blue: 154 / 255))
|
||||
.cornerRadius(5.0)
|
||||
.onTapGesture {
|
||||
print("call me here")
|
||||
Task {
|
||||
await self.doLogin()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行登陆操作
|
||||
private func doLogin() async {
|
||||
do {
|
||||
try await self.userContext.loginWithToken(token: self.token)
|
||||
print(self.userContext.networkSession?.accessToken)
|
||||
|
||||
// 保存信息到KeychainStore
|
||||
// let store = KeychainStore.shared
|
||||
// if let tokenData = loginResult.accessToken.data(using: .utf8) {
|
||||
// try store.save(tokenData, account: self.username)
|
||||
// }
|
||||
|
||||
} catch let err as SDLAPIError {
|
||||
await MainActor.run {
|
||||
self.showAlert = true
|
||||
self.errorMessage = err.message
|
||||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
self.showAlert = true
|
||||
self.errorMessage = "内部错误,请稍后重试"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct LoginAccountView: View {
|
||||
@Environment(UserContext.self) var userContext: UserContext
|
||||
|
||||
@State private var username: String = ""
|
||||
@State private var password: String = ""
|
||||
@State private var username: String = "test3"
|
||||
@State private var password: String = "111111"
|
||||
|
||||
@State private var showAlert = false
|
||||
@State private var errorMessage = ""
|
||||
@ -181,34 +212,26 @@ struct LoginAccountView: View {
|
||||
|
||||
// 执行登陆操作
|
||||
private func doLogin() async {
|
||||
// let clientId = SystemConfig.getClientId()
|
||||
// do {
|
||||
// let loginResult = try await SDLAPI.loginWithAccountAndPassword(clientId: clientId, username: self.username, password: self.password, as: LoginResult.self)
|
||||
//
|
||||
// print(loginResult.accessToken)
|
||||
//
|
||||
// // 保存信息到KeychainStore
|
||||
do {
|
||||
try await self.userContext.loginWithAccountAndPassword(username: self.username, password: self.password)
|
||||
|
||||
// 保存信息到KeychainStore
|
||||
// let store = KeychainStore.shared
|
||||
// if let tokenData = loginResult.accessToken.data(using: .utf8) {
|
||||
// try store.save(tokenData, account: self.username)
|
||||
// }
|
||||
//
|
||||
// await MainActor.run {
|
||||
// self.userContext.isLogined = true
|
||||
// self.userContext.loginCredit = .accountAndPasword(account: username, password: password, networkId: loginResult.networkId)
|
||||
// }
|
||||
//
|
||||
// } catch let err as JSONRPCError {
|
||||
// await MainActor.run {
|
||||
// self.showAlert = true
|
||||
// self.errorMessage = err.message
|
||||
// }
|
||||
// } catch {
|
||||
// await MainActor.run {
|
||||
// self.showAlert = true
|
||||
// self.errorMessage = "内部错误,请稍后重试"
|
||||
// }
|
||||
// }
|
||||
|
||||
} catch let err as SDLAPIError {
|
||||
await MainActor.run {
|
||||
self.showAlert = true
|
||||
self.errorMessage = err.message
|
||||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
self.showAlert = true
|
||||
self.errorMessage = "内部错误,请稍后重试"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -44,9 +44,8 @@ struct punchnetApp: App {
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup(id: "mainWindow") {
|
||||
//IndexView(noticeServer: self.noticeServer)
|
||||
//RootView()
|
||||
NetworkDisconnctedView(state: NetworkState())
|
||||
RootView()
|
||||
//NetworkDisconnctedView(state: NetworkState())
|
||||
.onAppear {
|
||||
// 获取主屏幕的尺寸
|
||||
guard let screenFrame = NSScreen.main?.frame else { return }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user