
- 在swift-assistant-style.mdc中添加项目背景、代码结构、命名规范、Swift最佳实践、UI开发、性能、安全性、测试与质量、核心功能、开发流程、App Store指南等详细规则。 - 在yanaApp.swift中将SplashView替换为Splash,简化应用结构。
182 lines
5.0 KiB
Swift
182 lines
5.0 KiB
Swift
import SwiftUI
|
||
import Combine
|
||
|
||
// MARK: - Splash ViewModel
|
||
|
||
@MainActor
|
||
class SplashViewModel: ObservableObject {
|
||
// MARK: - Published Properties
|
||
@Published var isLoading = true
|
||
@Published var shouldShowMainApp = false
|
||
@Published var authenticationStatus: UserInfoManager.AuthenticationStatus = .notFound
|
||
@Published var isCheckingAuthentication = false
|
||
@Published var navigationDestination: NavigationDestination?
|
||
|
||
// MARK: - Private Properties
|
||
private var cancellables = Set<AnyCancellable>()
|
||
|
||
// MARK: - Navigation Destination
|
||
enum NavigationDestination: Equatable {
|
||
case login
|
||
case main
|
||
}
|
||
|
||
// MARK: - Initialization
|
||
init() {
|
||
setupBindings()
|
||
}
|
||
|
||
// MARK: - Public Methods
|
||
func onAppear() {
|
||
isLoading = true
|
||
shouldShowMainApp = false
|
||
authenticationStatus = .notFound
|
||
isCheckingAuthentication = false
|
||
navigationDestination = nil
|
||
|
||
// 1秒延迟后显示主应用
|
||
Task {
|
||
try await Task.sleep(nanoseconds: 1_000_000_000)
|
||
await MainActor.run {
|
||
self.splashFinished()
|
||
}
|
||
}
|
||
}
|
||
|
||
func splashFinished() {
|
||
isLoading = false
|
||
checkAuthentication()
|
||
}
|
||
|
||
func checkAuthentication() {
|
||
isCheckingAuthentication = true
|
||
|
||
Task {
|
||
let authStatus = await UserInfoManager.checkAuthenticationStatus()
|
||
await MainActor.run {
|
||
self.authenticationChecked(authStatus)
|
||
}
|
||
}
|
||
}
|
||
|
||
func authenticationChecked(_ status: UserInfoManager.AuthenticationStatus) {
|
||
isCheckingAuthentication = false
|
||
authenticationStatus = status
|
||
|
||
if status.canAutoLogin {
|
||
debugInfoSync("🎉 自动登录成功,开始获取用户信息")
|
||
fetchUserInfo()
|
||
} else {
|
||
debugInfoSync("🔑 需要手动登录")
|
||
navigateToLogin()
|
||
}
|
||
}
|
||
|
||
func fetchUserInfo() {
|
||
Task {
|
||
let success = await UserInfoManager.autoFetchUserInfoOnAppLaunch(apiService: LiveAPIService())
|
||
await MainActor.run {
|
||
self.userInfoFetched(success)
|
||
}
|
||
}
|
||
}
|
||
|
||
func userInfoFetched(_ success: Bool) {
|
||
if success {
|
||
debugInfoSync("✅ 用户信息获取成功,进入主页")
|
||
} else {
|
||
debugInfoSync("⚠️ 用户信息获取失败,但仍进入主页")
|
||
}
|
||
navigateToMain()
|
||
}
|
||
|
||
func navigateToLogin() {
|
||
navigationDestination = .login
|
||
}
|
||
|
||
func navigateToMain() {
|
||
navigationDestination = .main
|
||
shouldShowMainApp = true
|
||
}
|
||
|
||
// MARK: - Private Methods
|
||
private func setupBindings() {
|
||
// 可以在这里设置 Combine 绑定
|
||
}
|
||
}
|
||
|
||
// MARK: - Splash View
|
||
|
||
struct Splash: View {
|
||
@StateObject private var viewModel = SplashViewModel()
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
Group {
|
||
// 根据导航目标显示不同页面
|
||
if let navigationDestination = viewModel.navigationDestination {
|
||
switch navigationDestination {
|
||
case .login:
|
||
// 显示登录页面
|
||
LoginPage(
|
||
onLoginSuccess: {
|
||
// 登录成功后导航到主页面
|
||
viewModel.navigateToMain()
|
||
}
|
||
)
|
||
case .main:
|
||
// 显示主应用页面
|
||
MainPage(
|
||
onLogout: {
|
||
viewModel.navigateToLogin()
|
||
}
|
||
)
|
||
}
|
||
} else {
|
||
// 显示启动画面
|
||
splashContent
|
||
}
|
||
}
|
||
.onAppear {
|
||
viewModel.onAppear()
|
||
}
|
||
|
||
// API Loading 效果视图 - 显示在所有内容之上
|
||
APILoadingEffectView()
|
||
}
|
||
}
|
||
|
||
// 启动画面内容
|
||
private var splashContent: some View {
|
||
ZStack {
|
||
// 背景图片 - 全屏显示
|
||
LoginBackgroundView()
|
||
|
||
VStack(spacing: 32) {
|
||
Spacer()
|
||
.frame(height: 200) // 与 storyboard 中的约束对应
|
||
|
||
// Logo 图片 - 100x100
|
||
Image("logo")
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fit)
|
||
.frame(width: 100, height: 100)
|
||
|
||
// 应用标题 - 白色,40pt字体
|
||
Text(LocalizedString("splash.title", comment: "E-Parti"))
|
||
.font(.system(size: 40, weight: .regular))
|
||
.foregroundColor(.white)
|
||
|
||
Spacer()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//#Preview {
|
||
// Splash()
|
||
//}
|
||
|
||
#Preview {
|
||
Splash()
|
||
} |