99 lines
3.4 KiB
Swift
99 lines
3.4 KiB
Swift
//
|
||
// RootView.swift
|
||
// punchnet
|
||
//
|
||
// Created by 安礼成 on 2026/1/19.
|
||
//
|
||
|
||
import SwiftUI
|
||
|
||
struct AppRootView: View {
|
||
@Environment(AppContext.self) var appContext: AppContext
|
||
@State private var updateManager = AppUpdateManager.shared
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
// 1. 主要界面容器
|
||
// 使用 ZStack 代替 Group,因为它在处理内容对齐和转场重叠时更稳定
|
||
ZStack(alignment: .center) {
|
||
switch appContext.appScene {
|
||
case .login(username: let username):
|
||
LoginView(username: username)
|
||
.id("scene_login") // 显式 ID 确保转场触发
|
||
case .logined:
|
||
NetworkView()
|
||
.id("scene_logined")
|
||
case .register:
|
||
RegisterRootView()
|
||
.id("scene_register")
|
||
case .resetPassword:
|
||
ResetPasswordRootView()
|
||
.id("scene_reset")
|
||
}
|
||
}
|
||
.transition(.asymmetric(
|
||
insertion: .move(edge: .trailing).combined(with: .opacity),
|
||
removal: .move(edge: .leading).combined(with: .opacity) // 修改为 leading 更有“流转”感
|
||
))
|
||
|
||
// 自动更新遮罩层级
|
||
if updateManager.showUpdateOverlay, let info = updateManager.updateInfo {
|
||
updateOverlay(info: info)
|
||
}
|
||
}
|
||
// 4. 统一处理 Scene 切换的动画
|
||
.animation(.spring(duration: 0.5), value: appContext.appScene)
|
||
.animation(.spring(duration: 0.4), value: updateManager.showUpdateOverlay)
|
||
// 关键:macOS 标准毛玻璃背景
|
||
.background(VisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
|
||
.alert("提示", isPresented: tunnelEventPresented, presenting: appContext.tunnelEvent) { _ in
|
||
Button("确定", role: .cancel) {
|
||
appContext.dismissTunnelEvent()
|
||
}
|
||
} message: { event in
|
||
Text(event.message)
|
||
}
|
||
.task {
|
||
let checkUpdateResult = await updateManager.checkUpdate(isManual: false)
|
||
NSLog("[RootView] checkUpdateResult: \(checkUpdateResult)")
|
||
}
|
||
}
|
||
|
||
// 将遮罩抽离,保持 body 清爽
|
||
@ViewBuilder
|
||
private func updateOverlay(info: SDLAPIClient.AppUpgradeInfo) -> some View {
|
||
ZStack {
|
||
Color.black.opacity(0.4)
|
||
.ignoresSafeArea()
|
||
.onTapGesture {
|
||
if !info.forceUpdate {
|
||
updateManager.showUpdateOverlay = false
|
||
}
|
||
}
|
||
|
||
AppUpdateView(info: info) {
|
||
updateManager.showUpdateOverlay = false
|
||
}
|
||
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||
.shadow(color: .black.opacity(0.3), radius: 20)
|
||
}
|
||
.transition(.asymmetric(
|
||
insertion: .scale(scale: 0.9).combined(with: .opacity),
|
||
removal: .opacity
|
||
))
|
||
.zIndex(100) // 确保更新遮罩永远在最上层
|
||
}
|
||
|
||
private var tunnelEventPresented: Binding<Bool> {
|
||
Binding(
|
||
get: { self.appContext.tunnelEvent != nil },
|
||
set: { isPresented in
|
||
if !isPresented {
|
||
self.appContext.dismissTunnelEvent()
|
||
}
|
||
}
|
||
)
|
||
}
|
||
|
||
}
|