feat: 组合根装配会话与导航(Tab + 登录 + 提交页)

This commit is contained in:
AndyChen1024
2026-09-15 14:35:52 +08:00
parent affe326e90
commit 547ce92050
3 changed files with 99 additions and 13 deletions

View File

@@ -38,12 +38,26 @@ let package = Package(
dependencies: ["CoreDomain", "CoreUI", "CoreModel", "CoreCommon"]
),
.target(name: "FeatureAuth", dependencies: ["CoreDomain", "CoreUI", "CoreModel"]),
.target(
name: "FeaturePlan",
dependencies: ["CoreDomain", "CoreUI", "CoreModel", "CoreCommon"]
),
.target(
name: "FeatureCheckin",
dependencies: ["CoreDomain", "CoreUI", "CoreModel", "CoreCommon"]
),
.target(
name: "FeatureProfile",
dependencies: ["CoreDomain", "CoreUI", "CoreModel", "CoreCommon"]
),
// 组合根(依赖一切,用于 DI 装配)
.target(
name: "App",
dependencies: [
"FeatureHome", "FeatureAuth", "CoreRepository",
"FeatureHome", "FeatureAuth",
"FeaturePlan", "FeatureCheckin", "FeatureProfile",
"CoreRepository",
"CoreUI", "DesignSystem", "CoreDomain", "CoreModel",
]
),

View File

@@ -1,14 +1,49 @@
import CoreDomain
import CoreModel
import CoreRepository
import FeatureAuth
import FeatureCheckin
import FeatureHome
import FeaturePlan
import FeatureProfile
/// 手写组合根 / DI 容器(对应 Android Hilt 的 AppContainer)。
@MainActor
public enum AppContainer {
/// 装配 FeatureHome 依赖并返回 ViewModel。
// 共享的有状态仓库(登录态、打卡、计划可提交,需跨页面共享单例)。
private static let sessionRepository: SessionRepository = FakeSessionRepository()
private static let checkinRepository: CheckinRepository = FakeCheckinRepository()
private static let planRepository: PlanRepository = FakePlanRepository()
private static let sessionUseCase = SessionUseCase(repository: sessionRepository)
private static let checkinUseCase = CheckinUseCase(repository: checkinRepository)
private static let planUseCase = PlanUseCase(repository: planRepository)
public static func makeHomeViewModel() -> HomeViewModel {
let repository: HomeRepository = FakeHomeRepository()
let useCase = HomeUseCase(repository: repository)
return HomeViewModel(homeUseCase: useCase)
return HomeViewModel(homeUseCase: useCase, sessionUseCase: sessionUseCase)
}
public static func makeCheckinViewModel() -> CheckinViewModel {
CheckinViewModel(checkinUseCase: checkinUseCase, sessionUseCase: sessionUseCase)
}
public static func makePlanViewModel() -> PlanViewModel {
PlanViewModel(planUseCase: planUseCase, sessionUseCase: sessionUseCase)
}
public static func makeProfileViewModel() -> ProfileViewModel {
let repository: ProfileRepository = FakeProfileRepository()
let useCase = ProfileUseCase(repository: repository)
return ProfileViewModel(profileUseCase: useCase, sessionUseCase: sessionUseCase)
}
public static func makeAuthViewModel() -> AuthViewModel {
AuthViewModel(sessionUseCase: sessionUseCase)
}
public static func makePlanSubmitViewModel(type: PlanType, periodKey: String) -> PlanSubmitViewModel {
PlanSubmitViewModel(planUseCase: planUseCase, type: type, periodKey: periodKey)
}
}

View File

@@ -1,36 +1,73 @@
import SwiftUI
import CoreUI
import FeatureAuth
import FeatureCheckin
import FeatureHome
import FeaturePlan
import FeatureProfile
public struct AppRootView: View {
@State private var homeViewModel: HomeViewModel
@State private var checkinViewModel: CheckinViewModel
@State private var planViewModel: PlanViewModel
@State private var profileViewModel: ProfileViewModel
@State private var authViewModel: AuthViewModel
@State private var selectedTab: AppTab = .home
@State private var isAuthPresented = false
public init() {
_homeViewModel = State(initialValue: AppContainer.makeHomeViewModel())
_checkinViewModel = State(initialValue: AppContainer.makeCheckinViewModel())
_planViewModel = State(initialValue: AppContainer.makePlanViewModel())
_profileViewModel = State(initialValue: AppContainer.makeProfileViewModel())
_authViewModel = State(initialValue: AppContainer.makeAuthViewModel())
}
public var body: some View {
TabView {
TabView(selection: $selectedTab) {
NavigationStack {
HomeScreen(viewModel: homeViewModel)
HomeScreen(
viewModel: homeViewModel,
onNavigateToCheckin: { selectedTab = .checkin },
onNavigateToPlan: { selectedTab = .plan },
onNavigateToAuth: { isAuthPresented = true }
)
}
.tabItem { Label("首页", systemImage: "house.fill") }
.tag(AppTab.home)
NavigationStack {
PlaceholderView("计划", systemImage: "calendar")
}
.tabItem { Label("计划", systemImage: "calendar") }
NavigationStack {
PlaceholderView("打卡", systemImage: "checkmark.seal.fill")
CheckinScreen(viewModel: checkinViewModel, onNavigateToAuth: { isAuthPresented = true })
}
.tabItem { Label("打卡", systemImage: "checkmark.seal.fill") }
.tag(AppTab.checkin)
NavigationStack {
AuthScreen()
PlanScreen(
viewModel: planViewModel,
onNavigateToAuth: { isAuthPresented = true },
makePlanSubmitViewModel: { type, periodKey in
AppContainer.makePlanSubmitViewModel(type: type, periodKey: periodKey)
}
)
}
.tabItem { Label("计划", systemImage: "calendar") }
.tag(AppTab.plan)
NavigationStack {
ProfileScreen(viewModel: profileViewModel, onNavigateToAuth: { isAuthPresented = true })
}
.tabItem { Label("我的", systemImage: "person.crop.circle") }
.tag(AppTab.profile)
}
.sheet(isPresented: $isAuthPresented) {
AuthScreen(viewModel: authViewModel, onLoggedIn: { isAuthPresented = false })
}
}
}
private enum AppTab: Hashable {
case home
case checkin
case plan
case profile
}