解决UI的布局问题
This commit is contained in:
parent
21be7cef58
commit
e4a0728345
@ -16,7 +16,14 @@ class AppContext {
|
|||||||
var networkContext: SDLAPIClient.NetworkContext = .default()
|
var networkContext: SDLAPIClient.NetworkContext = .default()
|
||||||
|
|
||||||
// 当前app所处的场景
|
// 当前app所处的场景
|
||||||
var appScene: AppScene = .login(username: nil)
|
var loginScene: LoginScene = .login(username: nil)
|
||||||
|
|
||||||
|
// 当前的场景
|
||||||
|
enum LoginScene: Equatable {
|
||||||
|
case login(username: String?)
|
||||||
|
case register
|
||||||
|
case resetPassword
|
||||||
|
}
|
||||||
|
|
||||||
// 登陆凭证
|
// 登陆凭证
|
||||||
var loginCredit: Credit?
|
var loginCredit: Credit?
|
||||||
@ -40,14 +47,6 @@ class AppContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当前的场景
|
|
||||||
enum AppScene: Equatable {
|
|
||||||
case login(username: String?)
|
|
||||||
case logined
|
|
||||||
case register
|
|
||||||
case resetPassword
|
|
||||||
}
|
|
||||||
|
|
||||||
init(noticePort: Int) {
|
init(noticePort: Int) {
|
||||||
self.noticePort = noticePort
|
self.noticePort = noticePort
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,7 +77,6 @@ struct LoginView: View {
|
|||||||
}
|
}
|
||||||
.padding(.bottom, 20)
|
.padding(.bottom, 20)
|
||||||
}
|
}
|
||||||
.frame(width: 380, height: 520)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -106,7 +105,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.appScene = .register
|
self.appContext.loginScene = .register
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.link)
|
.buttonStyle(.link)
|
||||||
@ -115,7 +114,7 @@ struct LoginAccountView: View {
|
|||||||
|
|
||||||
Button("忘记密码?") {
|
Button("忘记密码?") {
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.appScene = .resetPassword
|
self.appContext.loginScene = .resetPassword
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.link)
|
.buttonStyle(.link)
|
||||||
@ -170,7 +169,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)) {
|
||||||
self.appContext.appScene = .logined
|
//self.appContext.appScene = .logined
|
||||||
}
|
}
|
||||||
} catch let err as SDLAPIError {
|
} catch let err as SDLAPIError {
|
||||||
self.showAlert = true
|
self.showAlert = true
|
||||||
@ -231,7 +230,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)) {
|
||||||
self.appContext.appScene = .logined
|
//self.appContext.appScene = .logined
|
||||||
}
|
}
|
||||||
} catch let err as SDLAPIError {
|
} catch let err as SDLAPIError {
|
||||||
self.showAlert = true
|
self.showAlert = true
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct RootView: View {
|
struct LoginRootView: View {
|
||||||
@Environment(AppContext.self) var appContext: AppContext
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
@State private var updateManager = AppUpdateManager.shared
|
@State private var updateManager = AppUpdateManager.shared
|
||||||
|
|
||||||
@ -16,13 +16,10 @@ struct RootView: View {
|
|||||||
// 1. 主要界面容器
|
// 1. 主要界面容器
|
||||||
// 使用 ZStack 代替 Group,因为它在处理内容对齐和转场重叠时更稳定
|
// 使用 ZStack 代替 Group,因为它在处理内容对齐和转场重叠时更稳定
|
||||||
ZStack(alignment: .center) {
|
ZStack(alignment: .center) {
|
||||||
switch appContext.appScene {
|
switch appContext.loginScene {
|
||||||
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")
|
||||||
@ -32,9 +29,7 @@ struct RootView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. 关键:设置容器尺寸行为
|
// 2. 关键:设置容器尺寸行为
|
||||||
// 如果是全屏应用,用 maxWidth/Height .infinity
|
.frame(width: 380, height: 500)
|
||||||
// 如果是固定大小窗口,可以在这里写死 minWidth/minHeight
|
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
||||||
// 3. 限制裁剪,防止位移动画超出 RootView 的边界
|
// 3. 限制裁剪,防止位移动画超出 RootView 的边界
|
||||||
.clipped()
|
.clipped()
|
||||||
.transition(.asymmetric(
|
.transition(.asymmetric(
|
||||||
@ -48,7 +43,7 @@ struct RootView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 4. 统一处理 Scene 切换的动画
|
// 4. 统一处理 Scene 切换的动画
|
||||||
.animation(.spring(duration: 0.5), value: appContext.appScene)
|
.animation(.spring(duration: 0.5), value: appContext.loginScene)
|
||||||
.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))
|
||||||
@ -82,8 +77,5 @@ struct RootView: View {
|
|||||||
))
|
))
|
||||||
.zIndex(100) // 确保更新遮罩永远在最上层
|
.zIndex(100) // 确保更新遮罩永远在最上层
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
RootView()
|
|
||||||
}
|
}
|
||||||
@ -14,21 +14,25 @@ struct RegisterRootView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .center) {
|
ZStack(alignment: .center) {
|
||||||
switch registerModel.stage {
|
Color.clear
|
||||||
case .requestVerifyCode:
|
|
||||||
RegisterRequestVerifyCodeView()
|
ZStack(alignment: .center) {
|
||||||
case .submitVerifyCode:
|
switch registerModel.stage {
|
||||||
RegisterSubmitVerifyCodeView()
|
case .requestVerifyCode:
|
||||||
case .setPassword:
|
RegisterRequestVerifyCodeView()
|
||||||
RegisterSetPasswordView()
|
case .submitVerifyCode:
|
||||||
case .success:
|
RegisterSubmitVerifyCodeView()
|
||||||
RegisterSuccessView()
|
case .setPassword:
|
||||||
|
RegisterSetPasswordView()
|
||||||
|
case .success:
|
||||||
|
RegisterSuccessView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.transition(.asymmetric(
|
||||||
|
insertion: .move(edge: registerModel.transitionEdge).combined(with: .opacity),
|
||||||
|
removal: .move(edge: registerModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
.transition(.asymmetric(
|
|
||||||
insertion: .move(edge: registerModel.transitionEdge).combined(with: .opacity),
|
|
||||||
removal: .move(edge: registerModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
|
|
||||||
))
|
|
||||||
.environment(registerModel)
|
.environment(registerModel)
|
||||||
// --- 核心改动:使用 overlay ---
|
// --- 核心改动:使用 overlay ---
|
||||||
.overlay(alignment: .topLeading) {
|
.overlay(alignment: .topLeading) {
|
||||||
@ -40,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.appScene = .login(username: nil)
|
self.appContext.loginScene = .login(username: nil)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
HStack {
|
HStack {
|
||||||
@ -127,8 +131,6 @@ struct RegisterRequestVerifyCodeView: View {
|
|||||||
.controlSize(.large)
|
.controlSize(.large)
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
|
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(40)
|
||||||
.alert(isPresented: $showAlert) {
|
.alert(isPresented: $showAlert) {
|
||||||
@ -244,8 +246,6 @@ struct RegisterSubmitVerifyCodeView: View {
|
|||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(40)
|
||||||
.alert(isPresented: $showAlert) {
|
.alert(isPresented: $showAlert) {
|
||||||
@ -362,8 +362,6 @@ struct RegisterSetPasswordView: View {
|
|||||||
.controlSize(.large)
|
.controlSize(.large)
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
.disabled(passwordError != nil)
|
.disabled(passwordError != nil)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(40)
|
||||||
.alert(isPresented: $showAlert) {
|
.alert(isPresented: $showAlert) {
|
||||||
@ -441,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.appScene = .login(username: registerModel.username)
|
self.appContext.loginScene = .login(username: registerModel.username)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("立即开始使用")
|
Text("立即开始使用")
|
||||||
|
|||||||
@ -14,21 +14,25 @@ struct ResetPasswordRootView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .center) {
|
ZStack(alignment: .center) {
|
||||||
switch resetPasswordModel.stage {
|
Color.clear
|
||||||
case .requestVerifyCode:
|
|
||||||
GetVerifyCodeView()
|
ZStack(alignment: .center) {
|
||||||
case .submitVerifyCode:
|
switch resetPasswordModel.stage {
|
||||||
SubmitVerifyCodeView()
|
case .requestVerifyCode:
|
||||||
case .resetPassword:
|
GetVerifyCodeView()
|
||||||
ResetPasswordView()
|
case .submitVerifyCode:
|
||||||
case .success:
|
SubmitVerifyCodeView()
|
||||||
ResetPasswordSuccessView()
|
case .resetPassword:
|
||||||
|
ResetPasswordView()
|
||||||
|
case .success:
|
||||||
|
ResetPasswordSuccessView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.transition(.asymmetric(
|
||||||
|
insertion: .move(edge: resetPasswordModel.transitionEdge).combined(with: .opacity),
|
||||||
|
removal: .move(edge: resetPasswordModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
.transition(.asymmetric(
|
|
||||||
insertion: .move(edge: resetPasswordModel.transitionEdge).combined(with: .opacity),
|
|
||||||
removal: .move(edge: resetPasswordModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
|
|
||||||
))
|
|
||||||
.environment(resetPasswordModel)
|
.environment(resetPasswordModel)
|
||||||
.overlay(alignment: .topLeading) {
|
.overlay(alignment: .topLeading) {
|
||||||
// 仅在非成功页面显示返回按钮
|
// 仅在非成功页面显示返回按钮
|
||||||
@ -36,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.appScene = .login(username: nil)
|
self.appContext.loginScene = .login(username: nil)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
HStack {
|
HStack {
|
||||||
@ -86,8 +90,6 @@ struct GetVerifyCodeView: View {
|
|||||||
.controlSize(.large)
|
.controlSize(.large)
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
|
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(40)
|
||||||
.alert(isPresented: $showAlert) {
|
.alert(isPresented: $showAlert) {
|
||||||
@ -179,8 +181,6 @@ struct SubmitVerifyCodeView: View {
|
|||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(40)
|
||||||
.task {
|
.task {
|
||||||
@ -294,8 +294,6 @@ struct ResetPasswordView: View {
|
|||||||
.controlSize(.large)
|
.controlSize(.large)
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
.disabled(!isInputValid || isProcessing)
|
.disabled(!isInputValid || isProcessing)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(40)
|
||||||
.alert(isPresented: $showAlert) {
|
.alert(isPresented: $showAlert) {
|
||||||
@ -364,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.appScene = .login(username: self.resetPasswordModel.username)
|
self.appContext.loginScene = .login(username: self.resetPasswordModel.username)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("返回登录")
|
Text("返回登录")
|
||||||
@ -377,8 +375,6 @@ struct ResetPasswordSuccessView: View {
|
|||||||
}
|
}
|
||||||
.opacity(animateText ? 1.0 : 0.0)
|
.opacity(animateText ? 1.0 : 0.0)
|
||||||
.offset(y: animateText ? 0 : 20)
|
.offset(y: animateText ? 0 : 20)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(40)
|
.padding(40)
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
|||||||
@ -43,8 +43,8 @@ struct punchnetApp: App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup(id: "main") {
|
Window("登陆", id: "login") {
|
||||||
RootView()
|
LoginRootView()
|
||||||
.navigationTitle("")
|
.navigationTitle("")
|
||||||
.environment(self.appContext)
|
.environment(self.appContext)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
@ -59,6 +59,14 @@ struct punchnetApp: App {
|
|||||||
.windowToolbarStyle(.unified)
|
.windowToolbarStyle(.unified)
|
||||||
.defaultPosition(.center)
|
.defaultPosition(.center)
|
||||||
|
|
||||||
|
Window("网络", id: "logined") {
|
||||||
|
SettingsView()
|
||||||
|
.environment(self.appContext)
|
||||||
|
.frame(width: 750, height: 500)
|
||||||
|
}
|
||||||
|
.windowResizability(.contentSize)
|
||||||
|
.defaultPosition(.center)
|
||||||
|
|
||||||
Window("设置", id: "settings") {
|
Window("设置", id: "settings") {
|
||||||
SettingsView()
|
SettingsView()
|
||||||
.environment(self.appContext)
|
.environment(self.appContext)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user