From 547ce92050cc2f16356b336c9ea8887889fe39b9 Mon Sep 17 00:00:00 2001 From: AndyChen1024 Date: Tue, 15 Sep 2026 14:35:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=84=E5=90=88=E6=A0=B9=E8=A3=85?= =?UTF-8?q?=E9=85=8D=E4=BC=9A=E8=AF=9D=E4=B8=8E=E5=AF=BC=E8=88=AA=EF=BC=88?= =?UTF-8?q?Tab=20+=20=E7=99=BB=E5=BD=95=20+=20=E6=8F=90=E4=BA=A4=E9=A1=B5?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IosClientKit/Package.swift | 16 ++++++- IosClientKit/Sources/App/AppContainer.swift | 39 ++++++++++++++- IosClientKit/Sources/App/AppRootView.swift | 53 +++++++++++++++++---- 3 files changed, 97 insertions(+), 11 deletions(-) diff --git a/IosClientKit/Package.swift b/IosClientKit/Package.swift index 160ecfc..c308c21 100644 --- a/IosClientKit/Package.swift +++ b/IosClientKit/Package.swift @@ -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", ] ), diff --git a/IosClientKit/Sources/App/AppContainer.swift b/IosClientKit/Sources/App/AppContainer.swift index 356801d..431fb15 100644 --- a/IosClientKit/Sources/App/AppContainer.swift +++ b/IosClientKit/Sources/App/AppContainer.swift @@ -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) } } diff --git a/IosClientKit/Sources/App/AppRootView.swift b/IosClientKit/Sources/App/AppRootView.swift index 33e4b69..ad4ae65 100644 --- a/IosClientKit/Sources/App/AppRootView.swift +++ b/IosClientKit/Sources/App/AppRootView.swift @@ -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") + CheckinScreen(viewModel: checkinViewModel, onNavigateToAuth: { isAuthPresented = true }) } - .tabItem { Label("计划", systemImage: "calendar") } + .tabItem { Label("打卡", systemImage: "checkmark.seal.fill") } + .tag(AppTab.checkin) NavigationStack { - PlaceholderView("打卡", systemImage: "checkmark.seal.fill") + PlanScreen( + viewModel: planViewModel, + onNavigateToAuth: { isAuthPresented = true }, + makePlanSubmitViewModel: { type, periodKey in + AppContainer.makePlanSubmitViewModel(type: type, periodKey: periodKey) + } + ) } - .tabItem { Label("打卡", systemImage: "checkmark.seal.fill") } + .tabItem { Label("计划", systemImage: "calendar") } + .tag(AppTab.plan) NavigationStack { - AuthScreen() + 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 +}