Refactor AppServices into assembly, feature facades, and lifecycle coordinator.

Extract dependency wiring and session lifecycle from the container and RootViewController, split NetworkBundle by domain, and add module-level feature services while keeping flat accessors for compatibility.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-29 09:32:44 +08:00
parent 1a6d4a1791
commit 0d8f97417b
11 changed files with 686 additions and 197 deletions

View File

@ -11,11 +11,13 @@ import UIKit
final class RootViewController: UIViewController {
private let services: AppServices
private let lifecycleCoordinator: AppSessionLifecycleCoordinator
private var currentAuthChild: UIViewController?
///
init(services: AppServices = .shared) {
self.services = services
lifecycleCoordinator = AppSessionLifecycleCoordinator(services: services)
super.init(nibName: nil, bundle: nil)
}
@ -34,64 +36,14 @@ final class RootViewController: UIViewController {
}
applyRoot(for: services.appSession.phase)
bootstrapSession()
services.configurePushNotifications()
}
///
private func bootstrapSession() {
Task {
await services.globalLoading.withLoading {
await services.sessionBootstrapper.restore(
appSession: services.appSession,
accountContext: services.accountContext,
permissionContext: services.permissionContext,
profileAPI: services.profileAPI,
accountContextAPI: services.accountContextAPI,
toastCenter: services.toastCenter
)
}
if services.appSession.isLoggedIn, !AppUITestLaunchState.isRunningUITests {
PushNotificationManager.shared.requestAuthorizationAndRegister()
}
}
lifecycleCoordinator.bootstrapSession()
lifecycleCoordinator.configurePushNotifications()
}
/// window
private func handleSessionPhaseChange() {
applyRoot(for: services.appSession.phase)
switch services.appSession.phase {
case .loggedIn:
if !AppUITestLaunchState.isRunningUITests {
PushNotificationManager.shared.requestAuthorizationAndRegister()
}
Task { await reloadScenicSpotContextIfNeeded() }
case .loggedOut:
//
services.accountContext.reset()
services.permissionContext.reset()
services.scenicSpotContext.reset()
services.appNavigator.resetAllStacks()
services.appNavigator.detach()
services.toastCenter.dismiss()
services.scenicQueueRuntime.stop()
case .restoring:
break
}
}
/// ID
private func reloadScenicSpotContextIfNeeded() async {
guard services.appSession.isLoggedIn else {
services.scenicSpotContext.reset()
return
}
await services.scenicSpotContext.reload(
scenicId: services.accountContext.currentScenic?.id,
api: services.accountContextAPI
)
lifecycleCoordinator.handleSessionPhaseChange()
}
/// window