fix
This commit is contained in:
parent
7872604857
commit
2f2c5420e2
@ -19,11 +19,12 @@ class AppContext {
|
|||||||
var vpnOptions: [String: NSObject]? = nil
|
var vpnOptions: [String: NSObject]? = nil
|
||||||
|
|
||||||
// 当前app所处的场景
|
// 当前app所处的场景
|
||||||
var loginScene: LoginScene = .login(username: nil)
|
var appScene: AppScene = .login(username: nil)
|
||||||
|
|
||||||
// 当前的场景
|
// 当前的场景
|
||||||
enum LoginScene: Equatable {
|
enum AppScene: Equatable {
|
||||||
case login(username: String?)
|
case login(username: String?)
|
||||||
|
case logined
|
||||||
case register
|
case register
|
||||||
case resetPassword
|
case resetPassword
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,63 +19,67 @@ struct LoginView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
ZStack {
|
||||||
// 顶部 Logo 区域
|
Color.clear
|
||||||
VStack(spacing: 12) {
|
|
||||||
ZStack {
|
VStack(spacing: 0) {
|
||||||
Circle()
|
// 顶部 Logo 区域
|
||||||
.fill(Color.accentColor.opacity(0.1))
|
VStack(spacing: 12) {
|
||||||
.frame(width: 80, height: 80)
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.fill(Color.accentColor.opacity(0.1))
|
||||||
|
.frame(width: 80, height: 80)
|
||||||
|
|
||||||
|
Image(systemName: "network") // 建议使用 SF Symbol 保持精致感
|
||||||
|
.font(.system(size: 38, weight: .semibold))
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
}
|
||||||
|
|
||||||
Image(systemName: "network") // 建议使用 SF Symbol 保持精致感
|
Text("PunchNet")
|
||||||
.font(.system(size: 38, weight: .semibold))
|
.font(.system(size: 24, weight: .bold, design: .rounded))
|
||||||
.foregroundColor(.accentColor)
|
.tracking(1)
|
||||||
}
|
}
|
||||||
|
.padding(.top, 40)
|
||||||
|
.padding(.bottom, 30)
|
||||||
|
|
||||||
Text("PunchNet")
|
// 原生分段切换器
|
||||||
.font(.system(size: 24, weight: .bold, design: .rounded))
|
Picker("", selection: $authMethod) {
|
||||||
.tracking(1)
|
ForEach(AuthMethod.allCases, id: \.self) { method in
|
||||||
}
|
Text(method.rawValue).tag(method)
|
||||||
.padding(.top, 40)
|
}
|
||||||
.padding(.bottom, 30)
|
|
||||||
|
|
||||||
// 原生分段切换器
|
|
||||||
Picker("", selection: $authMethod) {
|
|
||||||
ForEach(AuthMethod.allCases, id: \.self) { method in
|
|
||||||
Text(method.rawValue).tag(method)
|
|
||||||
}
|
}
|
||||||
}
|
.pickerStyle(.segmented)
|
||||||
.pickerStyle(.segmented)
|
.frame(width: 220)
|
||||||
.frame(width: 220)
|
.padding(.bottom, 30)
|
||||||
.padding(.bottom, 30)
|
|
||||||
|
|
||||||
// 动态内容区
|
|
||||||
ZStack {
|
|
||||||
switch authMethod {
|
|
||||||
case .account:
|
|
||||||
LoginAccountView(username: self.username ?? "")
|
|
||||||
.transition(.move(edge: .leading).combined(with: .opacity))
|
|
||||||
case .token:
|
|
||||||
LoginTokenView()
|
|
||||||
.transition(.move(edge: .trailing).combined(with: .opacity))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.animation(.spring(response: 0.3, dampingFraction: 0.8), value: authMethod)
|
|
||||||
.frame(height: 180)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
// 底部页脚
|
|
||||||
HStack(spacing: 4) {
|
|
||||||
Circle()
|
|
||||||
.fill(Color.green)
|
|
||||||
.frame(width: 8, height: 8)
|
|
||||||
|
|
||||||
Text("服务状态正常")
|
// 动态内容区
|
||||||
.font(.system(size: 11))
|
ZStack {
|
||||||
.foregroundColor(.secondary)
|
switch authMethod {
|
||||||
|
case .account:
|
||||||
|
LoginAccountView(username: self.username ?? "")
|
||||||
|
.transition(.move(edge: .leading).combined(with: .opacity))
|
||||||
|
case .token:
|
||||||
|
LoginTokenView()
|
||||||
|
.transition(.move(edge: .trailing).combined(with: .opacity))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.animation(.spring(response: 0.3, dampingFraction: 0.8), value: authMethod)
|
||||||
|
.frame(height: 180)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
// 底部页脚
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Circle()
|
||||||
|
.fill(Color.green)
|
||||||
|
.frame(width: 8, height: 8)
|
||||||
|
|
||||||
|
Text("服务状态正常")
|
||||||
|
.font(.system(size: 11))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
.padding(.bottom, 20)
|
||||||
}
|
}
|
||||||
.padding(.bottom, 20)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,10 +93,6 @@ struct LoginAccountView: View {
|
|||||||
@State private var password: String = ""
|
@State private var password: String = ""
|
||||||
@State private var isLoading = false
|
@State private var isLoading = false
|
||||||
|
|
||||||
// 1. 引入环境操作
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
@Environment(\.openWindow) private var openWindow
|
|
||||||
|
|
||||||
// 错误提示
|
// 错误提示
|
||||||
@State private var showAlert: Bool = false
|
@State private var showAlert: Bool = false
|
||||||
@State private var errorMessage: String = ""
|
@State private var errorMessage: String = ""
|
||||||
@ -109,7 +109,7 @@ struct LoginAccountView: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Button("注册") {
|
Button("注册") {
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.loginScene = .register
|
self.appContext.appScene = .register
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.link)
|
.buttonStyle(.link)
|
||||||
@ -118,7 +118,7 @@ struct LoginAccountView: View {
|
|||||||
|
|
||||||
Button("忘记密码?") {
|
Button("忘记密码?") {
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.loginScene = .resetPassword
|
self.appContext.appScene = .resetPassword
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.link)
|
.buttonStyle(.link)
|
||||||
@ -173,10 +173,7 @@ struct LoginAccountView: View {
|
|||||||
do {
|
do {
|
||||||
_ = try await appContext.loginWith(username: username, password: password)
|
_ = try await appContext.loginWith(username: username, password: password)
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
// 2. 先打开新窗口(顺序通常不影响,但先打开更稳妥)
|
self.appContext.appScene = .logined
|
||||||
openWindow(id: "logined")
|
|
||||||
// 3. 销毁当前窗口
|
|
||||||
dismiss()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch let err as SDLAPIError {
|
} catch let err as SDLAPIError {
|
||||||
@ -192,10 +189,6 @@ struct LoginAccountView: View {
|
|||||||
// MARK: - 密钥登录组件
|
// MARK: - 密钥登录组件
|
||||||
struct LoginTokenView: View {
|
struct LoginTokenView: View {
|
||||||
@Environment(AppContext.self) var appContext: AppContext
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
|
|
||||||
// 1. 引入环境操作
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
@Environment(\.openWindow) private var openWindow
|
|
||||||
|
|
||||||
@State private var token = ""
|
@State private var token = ""
|
||||||
@State private var isLoading = false
|
@State private var isLoading = false
|
||||||
@ -242,10 +235,7 @@ struct LoginTokenView: View {
|
|||||||
do {
|
do {
|
||||||
_ = try await appContext.loginWith(token: token)
|
_ = try await appContext.loginWith(token: token)
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
// 2. 先打开新窗口(顺序通常不影响,但先打开更稳妥)
|
self.appContext.appScene = .logined
|
||||||
openWindow(id: "logined")
|
|
||||||
// 3. 销毁当前窗口
|
|
||||||
dismiss()
|
|
||||||
}
|
}
|
||||||
} catch let err as SDLAPIError {
|
} catch let err as SDLAPIError {
|
||||||
self.showAlert = true
|
self.showAlert = true
|
||||||
|
|||||||
@ -16,10 +16,13 @@ struct LoginRootView: View {
|
|||||||
// 1. 主要界面容器
|
// 1. 主要界面容器
|
||||||
// 使用 ZStack 代替 Group,因为它在处理内容对齐和转场重叠时更稳定
|
// 使用 ZStack 代替 Group,因为它在处理内容对齐和转场重叠时更稳定
|
||||||
ZStack(alignment: .center) {
|
ZStack(alignment: .center) {
|
||||||
switch appContext.loginScene {
|
switch appContext.appScene {
|
||||||
case .login(username: let username):
|
case .login(username: let username):
|
||||||
LoginView(username: username)
|
LoginView(username: username)
|
||||||
.id("scene_login") // 显式 ID 确保转场触发
|
.id("scene_login") // 显式 ID 确保转场触发
|
||||||
|
case .logined:
|
||||||
|
NetworkView()
|
||||||
|
.id("scene_logined")
|
||||||
case .register:
|
case .register:
|
||||||
RegisterRootView()
|
RegisterRootView()
|
||||||
.id("scene_register")
|
.id("scene_register")
|
||||||
@ -28,10 +31,6 @@ struct LoginRootView: View {
|
|||||||
.id("scene_reset")
|
.id("scene_reset")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. 关键:设置容器尺寸行为
|
|
||||||
.frame(width: 380, height: 500)
|
|
||||||
// 3. 限制裁剪,防止位移动画超出 RootView 的边界
|
|
||||||
.clipped()
|
|
||||||
.transition(.asymmetric(
|
.transition(.asymmetric(
|
||||||
insertion: .move(edge: .trailing).combined(with: .opacity),
|
insertion: .move(edge: .trailing).combined(with: .opacity),
|
||||||
removal: .move(edge: .leading).combined(with: .opacity) // 修改为 leading 更有“流转”感
|
removal: .move(edge: .leading).combined(with: .opacity) // 修改为 leading 更有“流转”感
|
||||||
@ -43,7 +42,7 @@ struct LoginRootView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 4. 统一处理 Scene 切换的动画
|
// 4. 统一处理 Scene 切换的动画
|
||||||
.animation(.spring(duration: 0.5), value: appContext.loginScene)
|
.animation(.spring(duration: 0.5), value: appContext.appScene)
|
||||||
.animation(.spring(duration: 0.4), value: updateManager.showUpdateOverlay)
|
.animation(.spring(duration: 0.4), value: updateManager.showUpdateOverlay)
|
||||||
// 关键:macOS 标准毛玻璃背景
|
// 关键:macOS 标准毛玻璃背景
|
||||||
.background(VisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
|
.background(VisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
|
||||||
|
|||||||
@ -11,7 +11,6 @@ struct MainMenuBar: View {
|
|||||||
@State private var vpnManager = VPNManager.shared
|
@State private var vpnManager = VPNManager.shared
|
||||||
@Environment(AppContext.self) private var appContext: AppContext
|
@Environment(AppContext.self) private var appContext: AppContext
|
||||||
@Environment(\.openWindow) private var openWindow
|
@Environment(\.openWindow) private var openWindow
|
||||||
@Environment(\.dismissWindow) private var dismissWindow
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
@ -36,9 +35,9 @@ struct MainMenuBar: View {
|
|||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
// Button("打开控制面板") {
|
Button("打开控制面板") {
|
||||||
// openWindow(id: appContext.isLoggedIn ? "logined" : "login")
|
openWindow(id: "main")
|
||||||
// }
|
}
|
||||||
|
|
||||||
SettingsLink {
|
SettingsLink {
|
||||||
Text("设置")
|
Text("设置")
|
||||||
@ -58,10 +57,6 @@ struct MainMenuBar: View {
|
|||||||
private func startVPN() async {
|
private func startVPN() async {
|
||||||
if let options = appContext.vpnOptions {
|
if let options = appContext.vpnOptions {
|
||||||
try? await vpnManager.enableVpn(options: options)
|
try? await vpnManager.enableVpn(options: options)
|
||||||
dismissWindow(id: "login")
|
|
||||||
openWindow(id: "logined")
|
|
||||||
} else {
|
|
||||||
openWindow(id: "login")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ enum NetworkShowMode: String, CaseIterable {
|
|||||||
// MARK: - 主网络视图
|
// MARK: - 主网络视图
|
||||||
struct NetworkView: View {
|
struct NetworkView: View {
|
||||||
@Environment(AppContext.self) var appContext: AppContext
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
@Environment(\.openWindow) private var openWindow
|
|
||||||
|
|
||||||
@State private var showMode: NetworkShowMode = .resource
|
@State private var showMode: NetworkShowMode = .resource
|
||||||
@State private var connectState: ConnectState = .disconnected
|
@State private var connectState: ConnectState = .disconnected
|
||||||
|
|||||||
@ -44,7 +44,7 @@ struct RegisterRootView: View {
|
|||||||
Button(action: {
|
Button(action: {
|
||||||
// 执行返回逻辑,例如重置到登录
|
// 执行返回逻辑,例如重置到登录
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.loginScene = .login(username: nil)
|
self.appContext.appScene = .login(username: nil)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
HStack {
|
HStack {
|
||||||
@ -439,7 +439,7 @@ struct RegisterSuccessView: View {
|
|||||||
Button(action: {
|
Button(action: {
|
||||||
// 关闭当前注册窗口
|
// 关闭当前注册窗口
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.loginScene = .login(username: registerModel.username)
|
self.appContext.appScene = .login(username: registerModel.username)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("立即开始使用")
|
Text("立即开始使用")
|
||||||
|
|||||||
@ -40,7 +40,7 @@ struct ResetPasswordRootView: View {
|
|||||||
Button(action: {
|
Button(action: {
|
||||||
// 执行返回逻辑,例如重置到登录
|
// 执行返回逻辑,例如重置到登录
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.loginScene = .login(username: nil)
|
self.appContext.appScene = .login(username: nil)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
HStack {
|
HStack {
|
||||||
@ -362,7 +362,7 @@ struct ResetPasswordSuccessView: View {
|
|||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.loginScene = .login(username: self.resetPasswordModel.username)
|
self.appContext.appScene = .login(username: self.resetPasswordModel.username)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("返回登录")
|
Text("返回登录")
|
||||||
|
|||||||
@ -28,7 +28,7 @@ struct SettingsAccountView: View {
|
|||||||
} else {
|
} else {
|
||||||
// 蓝色主按钮
|
// 蓝色主按钮
|
||||||
Button {
|
Button {
|
||||||
self.openMainWindow(id: "login")
|
self.openWindow(id: "main")
|
||||||
} label: {
|
} label: {
|
||||||
Text("登录")
|
Text("登录")
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
@ -44,23 +44,6 @@ struct SettingsAccountView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开窗口
|
|
||||||
private func openMainWindow(id: String) {
|
|
||||||
let window = NSApp.windows.first { win in
|
|
||||||
if let idStr = win.identifier?.rawValue {
|
|
||||||
return idStr.starts(with: id)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if let window {
|
|
||||||
window.makeKeyAndOrderFront(nil)
|
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
|
||||||
} else {
|
|
||||||
openWindow(id: id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 辅助头部组件
|
// 辅助头部组件
|
||||||
private func sectionHeader(title: String, icon: String) -> some View {
|
private func sectionHeader(title: String, icon: String) -> some View {
|
||||||
HStack {
|
HStack {
|
||||||
@ -117,7 +100,6 @@ extension SettingsAccountView {
|
|||||||
struct AccountCreditView: View {
|
struct AccountCreditView: View {
|
||||||
@Environment(AppContext.self) var appContext: AppContext
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
@Environment(\.openWindow) var openWindow
|
@Environment(\.openWindow) var openWindow
|
||||||
@Environment(\.dismissWindow) var dismissWindow
|
|
||||||
|
|
||||||
let username: String
|
let username: String
|
||||||
|
|
||||||
@ -133,12 +115,7 @@ extension SettingsAccountView {
|
|||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
try await appContext.logout()
|
try await appContext.logout()
|
||||||
}
|
}
|
||||||
|
self.openWindow(id: "main")
|
||||||
self.dismissWindow(id: "logined")
|
|
||||||
self.dismissWindow(id: "settings")
|
|
||||||
|
|
||||||
self.openWindow(id: "login")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.bordered)
|
.buttonStyle(.bordered)
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
@ -150,7 +127,6 @@ extension SettingsAccountView {
|
|||||||
struct TokenCreditView: View {
|
struct TokenCreditView: View {
|
||||||
@Environment(AppContext.self) var appContext: AppContext
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
@Environment(\.openWindow) var openWindow
|
@Environment(\.openWindow) var openWindow
|
||||||
@Environment(\.dismissWindow) var dismissWindow
|
|
||||||
|
|
||||||
let token: String
|
let token: String
|
||||||
|
|
||||||
@ -160,11 +136,7 @@ extension SettingsAccountView {
|
|||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
try await appContext.logout()
|
try await appContext.logout()
|
||||||
}
|
}
|
||||||
|
self.openWindow(id: "main")
|
||||||
self.dismissWindow(id: "logined")
|
|
||||||
self.dismissWindow(id: "settings")
|
|
||||||
|
|
||||||
self.openWindow(id: "login")
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.bordered)
|
.buttonStyle(.bordered)
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
|
|||||||
@ -27,7 +27,6 @@ struct punchnetApp: App {
|
|||||||
}()
|
}()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Environment(\.openWindow) private var openWindow
|
|
||||||
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||||
|
|
||||||
private var noticeServer: UDPNoticeCenterServer
|
private var noticeServer: UDPNoticeCenterServer
|
||||||
@ -45,10 +44,16 @@ struct punchnetApp: App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
Window("登陆", id: "login") {
|
Window("Punchnet", id: "main") {
|
||||||
LoginRootView()
|
LoginRootView()
|
||||||
.navigationTitle("")
|
.navigationTitle("")
|
||||||
.environment(self.appContext)
|
.environment(self.appContext)
|
||||||
|
.frame(
|
||||||
|
width: self.appContext.isLogined ? 900 : 380,
|
||||||
|
height: self.appContext.isLogined ? 600 : 500
|
||||||
|
)
|
||||||
|
// 增加动画:当状态改变时,窗口会像微信那样丝滑地变大/变小
|
||||||
|
.animation(.spring(response: 0.4, dampingFraction: 0.8), value: self.appContext.isLogined)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
self.showPrivacy = !hasAcceptedPrivacy
|
self.showPrivacy = !hasAcceptedPrivacy
|
||||||
}
|
}
|
||||||
@ -60,14 +65,7 @@ struct punchnetApp: App {
|
|||||||
.windowToolbarStyle(.unified)
|
.windowToolbarStyle(.unified)
|
||||||
.windowResizability(.contentSize)
|
.windowResizability(.contentSize)
|
||||||
.defaultPosition(.center)
|
.defaultPosition(.center)
|
||||||
|
.windowStyle(.hiddenTitleBar)
|
||||||
Window("网络", id: "logined") {
|
|
||||||
NetworkView()
|
|
||||||
.environment(self.appContext)
|
|
||||||
.frame(width: 750, height: 500)
|
|
||||||
}
|
|
||||||
.windowResizability(.contentSize)
|
|
||||||
.defaultPosition(.center)
|
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
SettingsView()
|
SettingsView()
|
||||||
@ -77,7 +75,7 @@ struct punchnetApp: App {
|
|||||||
.windowResizability(.contentSize)
|
.windowResizability(.contentSize)
|
||||||
.defaultPosition(.center)
|
.defaultPosition(.center)
|
||||||
|
|
||||||
MenuBarExtra("punchnet", image: "logo_32") {
|
MenuBarExtra("Punchnet", image: "logo_32") {
|
||||||
MainMenuBar()
|
MainMenuBar()
|
||||||
.environment(appContext)
|
.environment(appContext)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user