diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1230b26..e2cb683 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,5 +40,5 @@ jobs: -scheme "$SCHEME" \ -configuration Debug \ -skipMacroValidation \ - -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.4" \ + -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=26.2" \ clean build diff --git a/Alarm/Package.swift b/Alarm/Package.swift index 53eea3b..049bae6 100644 --- a/Alarm/Package.swift +++ b/Alarm/Package.swift @@ -37,7 +37,6 @@ let package = Package( ) ], dependencies: [ - .package(name: "DI", path: "../DI"), .package(name: "Common", path: "../Common"), .package(name: "Infrastructure", path: "../Infrastructure"), ], @@ -48,8 +47,7 @@ let package = Package( .target(config: .domain), .target(config: .data), .target(config: .presentation), - .product(name: "DI", package: "DI"), - .product(name: "AppDI", package: "DI"), + .product(name: "DIKit", package: "Common"), .product(name: "NetworkInterface", package: "Infrastructure"), ], ), diff --git a/Alarm/Sources/DI/AlarmDIContainer.swift b/Alarm/Sources/DI/AlarmDIContainer.swift index 3c08f17..ffbce80 100644 --- a/Alarm/Sources/DI/AlarmDIContainer.swift +++ b/Alarm/Sources/DI/AlarmDIContainer.swift @@ -7,7 +7,6 @@ import Foundation import DIKit -import AppDI import NetworkInterface import AlarmDomain import AlarmData diff --git a/DI/.gitignore b/AppCore/.gitignore similarity index 100% rename from DI/.gitignore rename to AppCore/.gitignore diff --git a/AppCore/Package.swift b/AppCore/Package.swift new file mode 100644 index 0000000..a453a68 --- /dev/null +++ b/AppCore/Package.swift @@ -0,0 +1,98 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +enum Config: String, CaseIterable { + static let name: String = "AppCore" + + case di = "DI" + + var name: String { + return "\(Config.name)\(rawValue)" + } + + var path: String { + "Sources/\(rawValue)" + } +} + +let package = Package( + name: Config.name, + platforms: [.iOS(.v17)], + products: [ + .library( + name: "AppCore", + targets: Config.allCases.map(\.name) + ), + ], + dependencies: [ + .package(name: "Intro", path: "../Intro"), + .package(name: "Login", path: "../Login"), + .package(name: "Home", path: "../Home"), + .package(name: "Community", path: "../Community"), + .package(name: "MyPage", path: "../MyPage"), + .package(name: "Alarm", path: "../Alarm"), + + .package(name: "3rdParty", path: "../3rdParty"), + .package(name: "Common", path: "../Common"), + .package(name: "Infrastructure", path: "../Infrastructure"), + ], + targets: [ + .target( + config: .di, + dependencies: [ + .product(name: "DataSources", package: "Common"), + .product(name: "Managers", package: "Common"), + .product(name: "NetworkInterface", package: "Infrastructure"), + .product(name: "NetworkImpl", package: "Infrastructure"), + .product(name: "FCMService", package: "3rdParty"), + + .product(name: "IntroDI", package: "Intro"), + .product(name: "LoginDI", package: "Login"), + .product(name: "HomeDI", package: "Home"), + .product(name: "CommunityDI", package: "Community"), + .product(name: "MyPageDI", package: "MyPage"), + .product(name: "AlarmDI", package: "Alarm"), + ] + ) + ] +) + +extension Target { + static func target( + config: Config, + dependencies: [Dependency] = [], + exclude: [String] = [], + sources: [String]? = nil, + resources: [Resource]? = nil, + publicHeadersPath: String? = nil, + packageAccess: Bool = false, + cSettings: [CSetting]? = nil, + cxxSettings: [CXXSetting]? = nil, + swiftSettings: [SwiftSetting]? = nil, + linkerSettings: [LinkerSetting]? = nil, + plugins: [PluginUsage]? = nil, + ) -> Target { + return .target( + name: config.name, + dependencies: dependencies, + path: config.path, + exclude: exclude, + sources: sources, + resources: resources, + publicHeadersPath: publicHeadersPath, + packageAccess: packageAccess, + cSettings: cSettings, + cxxSettings: cxxSettings, + swiftSettings: swiftSettings, + linkerSettings: linkerSettings, + plugins: plugins) + } +} + +extension Target.Dependency { + static func target(config: Config) -> Self { + return .target(name: config.name) + } +} diff --git a/DI/Sources/AppDI/AppDIContainer.swift b/AppCore/Sources/DI/AppDIContainer.swift similarity index 63% rename from DI/Sources/AppDI/AppDIContainer.swift rename to AppCore/Sources/DI/AppDIContainer.swift index 3bc00b0..841d76e 100644 --- a/DI/Sources/AppDI/AppDIContainer.swift +++ b/AppCore/Sources/DI/AppDIContainer.swift @@ -15,6 +15,13 @@ import NetworkInterface import NetworkImpl import FCMService +import IntroDI +import LoginDI +import HomeDI +import CommunityDI +import MyPageDI +import AlarmDI + // MARK: - App Assembly struct AppAssembly: Assembly { func assemble(container: GenericDIContainer) { @@ -71,6 +78,37 @@ struct AppAssembly: Assembly { udManager: resolver.resolve(UserDefaultsManager.self) ) } + + // MARK: - IntroDIContainer + container.register(IntroDIContainer.self, scope: .singleton) { r in + IntroDIContainer(appContainer: container) + } + + // MARK: - LoginDIContainer + container.register(LoginDIContainer.self, scope: .singleton) { r in + LoginDIContainer(appContainer: container) + } + + // MARK: - HomeDIContainer + container.register(HomeDIContainer.self, scope: .singleton) { r in + HomeDIContainer(appContainer: container) + } + + // MARK: - CommunityDIContainer + container.register(CommunityDIContainer.self, scope: .singleton) { r in + CommunityDIContainer(appContainer: container) + } + + // MARK: - MyPageDIContainer + container.register(MyPageDIContainer.self, scope: .singleton) { r in + MyPageDIContainer(appContainer: container) + } + + // MARK: - AlarmDIContainer + container.register(AlarmDIContainer.self, scope: .singleton) { r in + AlarmDIContainer(appContainer: container) + } + } } @@ -96,6 +134,26 @@ public final class AppDIContainer: @unchecked Sendable { return container } + public var introDIContainer: IntroDIContainer { + return container.resolve(IntroDIContainer.self) + } + + public var loginDIContainer: LoginDIContainer { + return container.resolve(LoginDIContainer.self) + } + + public var homeDIContainer: HomeDIContainer { + return container.resolve(HomeDIContainer.self) + } + + public var communityDIContainer: CommunityDIContainer { + return container.resolve(CommunityDIContainer.self) + } + + public var mypageDIContainer: MyPageDIContainer { + return container.resolve(MyPageDIContainer.self) + } + /// Direct access to AppStateManager for app initialization public func makeAppStateManager() -> AppStateManager { return container.resolve(AppStateManager.self) diff --git a/Common/Package.swift b/Common/Package.swift index 2cc80e0..1a11159 100644 --- a/Common/Package.swift +++ b/Common/Package.swift @@ -19,6 +19,10 @@ let package = Package( name: "DataSources", targets: ["DataSources"] ), + .library( + name: "DIKit", + targets: ["DIKit"] + ), .library( name: "LocalizedString", targets: ["LocalizedString"] @@ -48,6 +52,7 @@ let package = Package( ] ), .target(name: "DataSources"), + .target(name: "DIKit"), .target(name: "LocalizedString"), .target(name: "Util"), .target( diff --git a/DI/Sources/DIKit/DIContainer+Assembly.swift b/Common/Sources/DIKit/DIContainer+Assembly.swift similarity index 100% rename from DI/Sources/DIKit/DIContainer+Assembly.swift rename to Common/Sources/DIKit/DIContainer+Assembly.swift diff --git a/Common/Sources/Managers/AppStateManager.swift b/Common/Sources/Managers/AppStateManager.swift index badb8cf..0c01cc9 100644 --- a/Common/Sources/Managers/AppStateManager.swift +++ b/Common/Sources/Managers/AppStateManager.swift @@ -49,8 +49,10 @@ public final class AppStateManager { } public func completeSplash() { - if isOnboardingCompleted { - state = isLoginCompleted ? .main : .login + if isLoginCompleted { + state = .main + } else if isOnboardingCompleted { + state = .main } else { state = .onboarding } @@ -59,7 +61,7 @@ public final class AppStateManager { // 온보딩 완료 public func completeOnboarding() { udManager.isOnboardingCompleted = true - state = isLoginCompleted ? .main : .login + state = .login } // 로그인 완료 diff --git a/Community/Package.swift b/Community/Package.swift index e6cb936..69f86ea 100644 --- a/Community/Package.swift +++ b/Community/Package.swift @@ -29,12 +29,19 @@ let package = Package( targets: Config.allCases.map(\.name) ), .library( - name: "CommunityDomain", - targets: ["CommunityDomain"] + name: Config.di.name, + targets: [Config.di.name] + ), + .library( + name: Config.domain.name, + targets: [Config.domain.name] + ), + .library( + name: Config.presentation.name, + targets: [Config.presentation.name] ), ], dependencies: [ - .package(name: "DI", path: "../DI"), .package(name: "Common", path: "../Common"), .package(name: "Infrastructure", path: "../Infrastructure"), .package(name: "Alarm", path: "../Alarm"), @@ -46,8 +53,7 @@ let package = Package( .target(config: .domain), .target(config: .data), .target(config: .presentation), - .product(name: "DI", package: "DI"), - .product(name: "AppDI", package: "DI"), + .product(name: "DIKit", package: "Common"), .product(name: "NetworkInterface", package: "Infrastructure"), .product(name: "NetworkImpl", package: "Infrastructure"), ], diff --git a/Community/Sources/DI/CommunityDIContainer.swift b/Community/Sources/DI/CommunityDIContainer.swift index 1d5a7f1..8a05eac 100644 --- a/Community/Sources/DI/CommunityDIContainer.swift +++ b/Community/Sources/DI/CommunityDIContainer.swift @@ -7,7 +7,6 @@ import Foundation import DIKit -import AppDI import NetworkInterface import NetworkImpl import CommunityDomain @@ -15,6 +14,9 @@ import CommunityData import CommunityPresentation import Managers +import AlarmDI +import AlarmPresentation + struct CommunityWriteAssembly: Assembly { func assemble(container: GenericDIContainer) { container.register(CreateBoardUseCase.self) { resolver in @@ -100,42 +102,45 @@ public final class CommunityDIContainer { private let container: GenericDIContainer // MARK: - Initialization - public init(appContainer: AppDIContainer = .shared) { - self.container = GenericDIContainer(parent: appContainer.baseContainer) + public init(appContainer: GenericDIContainer) { + self.container = appContainer CommunityAssembly().assemble(container: container) CommunityWriteAssembly().assemble(container: container) } +} + +extension CommunityDIContainer: CommunityDependency { + public var alarmListComponent: any AlarmPresentation.AlarmListDependecy { + container.resolve(AlarmDIContainer.self) + } + + public var component: any CommunityPresentation.CommunityDetailDependency { + self + } + // MARK: - Factory Methods - @MainActor public func makeCommunityViewModel() -> CommunityViewModel { return container.resolve(CommunityViewModel.self) } -} - -extension CommunityDIContainer: CommunityWriteFactory { - public func makeWriteViewModel() -> any CommunityWriteViewModelProtocol { + + public func makeWriteViewModel() -> any CommunityPresentation.CommunityWriteViewModelProtocol { container.resolve(CommunityWriteViewModel.self) } } -extension CommunityDIContainer: CommunityDetailFactory { - @MainActor - public func makeDetailViewModel() -> CommunityDetailViewModel { - return container.resolve(CommunityDetailViewModel.self) +extension CommunityDIContainer: CommunityDetailDependency { + public func makeDetailViewModel() -> CommunityPresentation.CommunityDetailViewModel { + container.resolve(CommunityDetailViewModel.self) } -} - -extension CommunityDIContainer: UpdateBoardFactory { - public func makeViewModel(boardId: Int) -> CommunityWriteViewModelProtocol { - return UpdateBoardViewModel( + + public func makeViewModel(boardId: Int) -> any CommunityPresentation.CommunityWriteViewModelProtocol { + UpdateBoardViewModel( boardId: boardId, updateBoardUseCase: container.resolve(UpdateBoardUseCase.self) ) } -} - -extension CommunityDIContainer: ReportBoardFactory { + public func makeViewModel(req: ReportRequest) -> CommunityReportViewModel { return CommunityReportViewModel( usecase: container.resolve(ReportContentUseCase.self), diff --git a/Community/Sources/Presentation/Community/CommunityView.swift b/Community/Sources/Presentation/Community/CommunityView.swift index e38f542..7721632 100644 --- a/Community/Sources/Presentation/Community/CommunityView.swift +++ b/Community/Sources/Presentation/Community/CommunityView.swift @@ -9,6 +9,20 @@ import SwiftUI import DesignSystem import CommunityDomain import SharedUI +import AlarmPresentation + +public protocol CommunityDependency: CommunityFactory,CommunityWriteFactory { + var component: CommunityDetailDependency { get } + var alarmListComponent: AlarmListDependecy { get } +} + +public protocol CommunityDetailDependency: CommunityDetailFactory, UpdateBoardFactory, ReportBoardFactory { + +} + +public protocol CommunityFactory { + func makeCommunityViewModel() -> CommunityViewModel +} public protocol CommunityWriteFactory { func makeWriteViewModel() -> CommunityWriteViewModelProtocol @@ -20,23 +34,13 @@ public protocol CommunityDetailFactory { public struct CommunityView: View { @State private var viewModel: CommunityViewModel - private let writeFactory: CommunityWriteFactory - private let detailFactory: CommunityDetailFactory - private let updateFactory: UpdateBoardFactory - private let reportFactory: ReportBoardFactory + private let dependency: CommunityDependency public init( - viewModel: CommunityViewModel, - writeFactory: CommunityWriteFactory, - detailFactory: CommunityDetailFactory, - updateFactory: UpdateBoardFactory, - reportFactory: ReportBoardFactory + dependency: CommunityDependency, ) { - self._viewModel = State(initialValue: viewModel) - self.writeFactory = writeFactory - self.detailFactory = detailFactory - self.updateFactory = updateFactory - self.reportFactory = reportFactory + self._viewModel = State(initialValue: dependency.makeCommunityViewModel()) + self.dependency = dependency } public var body: some View { @@ -50,9 +54,13 @@ public struct CommunityView: View { VStack(spacing: 0) { // 헤더 - HeaderBar(type: .community) - .safeAreaPadding(.vertical, 18) - .safeAreaPadding(.horizontal, 15) + HeaderBar(type: .community) { + AlarmListView( + dependency: dependency.alarmListComponent + ) + } + .safeAreaPadding(.vertical, 18) + .safeAreaPadding(.horizontal, 15) VStack(spacing: 0) { // 카테고리 필터와 뷰 토글 @@ -73,19 +81,15 @@ public struct CommunityView: View { ZStack { if viewModel.isListView { CommunityListView( - boards: viewModel.filteredBoards, - detailFactory: detailFactory, - updateFactory: updateFactory, - reportFactory: reportFactory, - viewModel: viewModel + viewModel: viewModel, + dependency: dependency, + boards: viewModel.filteredBoards ) } else { CommunityFeedView( - boards: viewModel.filteredBoards, - detailFactory: detailFactory, - updateFactory: updateFactory, - reportFactory: reportFactory, - viewModel: viewModel + viewModel: viewModel, + dependency: dependency, + boards: viewModel.filteredBoards ) } } @@ -100,7 +104,7 @@ public struct CommunityView: View { Spacer() NavigationLink( destination: CommunityWriteView( - viewModel: writeFactory.makeWriteViewModel() + viewModel: dependency.makeWriteViewModel() ) ) { Color.bgPencil @@ -169,25 +173,18 @@ fileprivate struct CommunityFilterChip: View { // MARK: - List View public struct CommunityListView: View { + @State private var viewModel: CommunityViewModel + private let dependency: CommunityDependency let boards: [Board] - let detailFactory: CommunityDetailFactory - let updateFactory: UpdateBoardFactory - let reportFactory: ReportBoardFactory - @State private var viewModel: CommunityViewModel - public init( + viewModel: CommunityViewModel, + dependency: CommunityDependency, boards: [Board], - detailFactory: CommunityDetailFactory, - updateFactory: UpdateBoardFactory, - reportFactory: ReportBoardFactory, - viewModel: CommunityViewModel ) { - self.boards = boards - self.detailFactory = detailFactory - self.updateFactory = updateFactory - self.reportFactory = reportFactory self._viewModel = State(initialValue: viewModel) + self.dependency = dependency + self.boards = boards } public var body: some View { @@ -196,11 +193,10 @@ public struct CommunityListView: View { ForEach(Array(boards.enumerated()), id: \.element.id) { index, board in NavigationLink( destination: CommunityDetailView( - viewModel: detailFactory.makeDetailViewModel(), - boardId: board.id, - updateFactory: updateFactory, - reportFactory: reportFactory - )) { + dependency: dependency.component, + boardId: board.id + ) + ) { CommunityPostListCard(board: board) } .buttonStyle(PlainButtonStyle()) @@ -234,25 +230,18 @@ public struct CommunityListView: View { // MARK: - Feed View fileprivate struct CommunityFeedView: View { - let boards: [Board] - let detailFactory: CommunityDetailFactory - let updateFactory: UpdateBoardFactory - let reportFactory: ReportBoardFactory - @State private var viewModel: CommunityViewModel + private let dependency: CommunityDependency + let boards: [Board] init( + viewModel: CommunityViewModel, + dependency: CommunityDependency, boards: [Board], - detailFactory: CommunityDetailFactory, - updateFactory: UpdateBoardFactory, - reportFactory: ReportBoardFactory, - viewModel: CommunityViewModel ) { - self.boards = boards - self.detailFactory = detailFactory - self.updateFactory = updateFactory - self.reportFactory = reportFactory self._viewModel = State(initialValue: viewModel) + self.dependency = dependency + self.boards = boards } var body: some View { @@ -261,10 +250,8 @@ fileprivate struct CommunityFeedView: View { ForEach(Array(boards.enumerated()), id: \.element.id) { index, board in NavigationLink( destination: CommunityDetailView( - viewModel: detailFactory.makeDetailViewModel(), - boardId: board.id, - updateFactory: updateFactory, - reportFactory: reportFactory + dependency: dependency.component, + boardId: board.id ) ) { CommunityPostFeedCard(board: board) diff --git a/Community/Sources/Presentation/Detail/CommunityDetail.swift b/Community/Sources/Presentation/Detail/CommunityDetail.swift index 5adb4a9..d6ce55c 100644 --- a/Community/Sources/Presentation/Detail/CommunityDetail.swift +++ b/Community/Sources/Presentation/Detail/CommunityDetail.swift @@ -39,19 +39,14 @@ public struct CommunityDetailView: View { @State private var reportReason: String = "" private let boardId: Int - private let updateFactory: UpdateBoardFactory - private let reportFactory: ReportBoardFactory - + private let dependency: CommunityDetailDependency public init( - viewModel: CommunityDetailViewModel, - boardId: Int, - updateFactory: UpdateBoardFactory, - reportFactory: ReportBoardFactory, + dependency: CommunityDetailDependency, + boardId: Int ) { - _viewModel = State(initialValue: viewModel) + _viewModel = State(initialValue: dependency.makeDetailViewModel()) self.boardId = boardId - self.updateFactory = updateFactory - self.reportFactory = reportFactory + self.dependency = dependency } public var body: some View { @@ -132,7 +127,7 @@ public struct CommunityDetailView: View { Int64(comment.authorId) != currentUserId { NavigationLink( destination: CommunityReportView( - viewModel: reportFactory.makeViewModel( + viewModel: dependency.makeViewModel( req: CommunityDomain.ReportRequest.init( targetId: comment.id, targetType: .comment, @@ -154,7 +149,7 @@ public struct CommunityDetailView: View { Int64(authorId) == currentUserId { NavigationLink( destination: CommunityWriteView( - viewModel: updateFactory.makeViewModel(boardId: boardId), + viewModel: dependency.makeViewModel(boardId: boardId), title: viewModel.board?.title ?? "", content: viewModel.board?.content ?? "" ) @@ -174,7 +169,7 @@ public struct CommunityDetailView: View { Int64(authorId) != currentUserId { NavigationLink( destination: CommunityReportView( - viewModel: reportFactory.makeViewModel( + viewModel: dependency.makeViewModel( req: CommunityDomain.ReportRequest.init( targetId: boardId, targetType: .board, diff --git a/DI/Package.swift b/DI/Package.swift deleted file mode 100644 index 36fb438..0000000 --- a/DI/Package.swift +++ /dev/null @@ -1,81 +0,0 @@ -// swift-tools-version: 5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -enum Config: String, CaseIterable { - static let name: String = "DI" - - case interface = "DI" - case app = "App" - case intro = "Intro" - case login = "Login" - - var name: String { - switch self { - case .interface: "\(rawValue)Kit" - default: "\(rawValue)DI" - } - - } -} -let package = Package( - name: Config.name, - platforms: [.iOS(.v17)], - products: [ - .library( - name: Config.interface.name, - targets: Config.allCases.map(\.name) - ), - .library( - name: Config.interface.rawValue, - targets: [Config.interface.name] - ), - .library( - name: Config.app.name, - targets: [Config.app.name] - ) - ], - dependencies: [ - .package(name: "3rdParty", path: "../3rdParty"), - .package(name: "Common", path: "../Common"), - .package(name: "Infrastructure", path: "../Infrastructure"), - .package(name: "Intro", path: "../Intro"), - .package(name: "Login", path: "../Login"), - ], - targets: [ - .target(name: Config.interface.name), - .target( - name: Config.app.name, - dependencies: [ - .target(config: .interface), - .product(name: "DataSources", package: "Common"), - .product(name: "Managers", package: "Common"), - .product(name: "NetworkInterface", package: "Infrastructure"), - .product(name: "NetworkImpl", package: "Infrastructure"), - .product(name: "FCMService", package: "3rdParty"), - ] - ), - .target( - name: Config.intro.name, - dependencies: [ - .target(config: .app), - .product(name: "Onboarding", package: "Intro"), - .product(name: "Splash", package: "Intro"), - ] - ), - .target( - name: Config.login.name, - dependencies: [ - .target(config: .app), - .product(name: "Login", package: "Login"), - ] - ) - ] -) - -extension Target.Dependency { - static func target(config: Config) -> Self { - .target(name: config.name) - } -} diff --git a/Hambug.xcodeproj/project.pbxproj b/Hambug.xcodeproj/project.pbxproj index 639b147..4c83f9a 100644 --- a/Hambug.xcodeproj/project.pbxproj +++ b/Hambug.xcodeproj/project.pbxproj @@ -15,13 +15,13 @@ B54128772EF1CD3100CC4938 /* Login in Frameworks */ = {isa = PBXBuildFile; productRef = B54128762EF1CD3100CC4938 /* Login */; }; B5412A882EF277A200CC4938 /* NetworkImpl in Frameworks */ = {isa = PBXBuildFile; productRef = B5412A872EF277A200CC4938 /* NetworkImpl */; }; B5412A8A2EF277A200CC4938 /* NetworkInterface in Frameworks */ = {isa = PBXBuildFile; productRef = B5412A892EF277A200CC4938 /* NetworkInterface */; }; - B54134082EF535FC00CC4938 /* MyPage in Frameworks */ = {isa = PBXBuildFile; productRef = B54134072EF535FC00CC4938 /* MyPage */; }; - B54134FD2EF5B09D00CC4938 /* Community in Frameworks */ = {isa = PBXBuildFile; productRef = B54134FC2EF5B09D00CC4938 /* Community */; }; - B54134FF2EF5B0A400CC4938 /* Home in Frameworks */ = {isa = PBXBuildFile; productRef = B54134FE2EF5B0A400CC4938 /* Home */; }; B54135802EF5B4CC00CC4938 /* KakaoLogin in Frameworks */ = {isa = PBXBuildFile; productRef = B541357F2EF5B4CC00CC4938 /* KakaoLogin */; }; B57DE3412E92CB6100575CDA /* Onboarding in Frameworks */ = {isa = PBXBuildFile; productRef = B57DE3402E92CB6100575CDA /* Onboarding */; }; B57DE3432E92CB6100575CDA /* Splash in Frameworks */ = {isa = PBXBuildFile; productRef = B57DE3422E92CB6100575CDA /* Splash */; }; - B5EDA8F82F0B9C0C002F72B9 /* DIKit in Frameworks */ = {isa = PBXBuildFile; productRef = B5EDA8F72F0B9C0C002F72B9 /* DIKit */; }; + B5C7D2112F1C09C100C20E14 /* AppCore in Frameworks */ = {isa = PBXBuildFile; productRef = B5C7D2102F1C09C100C20E14 /* AppCore */; }; + B5C7D2132F1C0AD300C20E14 /* CommunityPresentation in Frameworks */ = {isa = PBXBuildFile; productRef = B5C7D2122F1C0AD300C20E14 /* CommunityPresentation */; }; + B5C7D2152F1C0AD300C20E14 /* HomePresentation in Frameworks */ = {isa = PBXBuildFile; productRef = B5C7D2142F1C0AD300C20E14 /* HomePresentation */; }; + B5C7D2172F1C0AD900C20E14 /* MyPagePresentation in Frameworks */ = {isa = PBXBuildFile; productRef = B5C7D2162F1C0AD900C20E14 /* MyPagePresentation */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -49,12 +49,12 @@ B52285C62E8844BD00678ECC /* Common */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Common; sourceTree = ""; }; B54125132EF161BF00CC4938 /* Login */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Login; sourceTree = ""; }; B54126322EF1A99B00CC4938 /* Infrastructure */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Infrastructure; sourceTree = ""; }; - B5412CD62EF3C9EA00CC4938 /* DI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = DI; sourceTree = ""; }; B54134062EF5330A00CC4938 /* MyPage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = MyPage; sourceTree = ""; }; B54134FA2EF57F4100CC4938 /* Home */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Home; sourceTree = ""; }; B54134FB2EF57F6400CC4938 /* Community */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Community; sourceTree = ""; }; B54135972EF5B58100CC4938 /* 3rdParty */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = 3rdParty; sourceTree = ""; }; B5C7D1B32F1B7B6600C20E14 /* Alarm */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Alarm; sourceTree = ""; }; + B5C7D20B2F1BEFAB00C20E14 /* AppCore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = AppCore; sourceTree = ""; }; B5E822EB2EA2791900F3E10E /* Intro */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Intro; sourceTree = ""; }; /* End PBXFileReference section */ @@ -101,16 +101,16 @@ files = ( B57DE3432E92CB6100575CDA /* Splash in Frameworks */, B52286032E884E5B00678ECC /* DesignSystem in Frameworks */, - B54134082EF535FC00CC4938 /* MyPage in Frameworks */, - B5EDA8F82F0B9C0C002F72B9 /* DIKit in Frameworks */, - B54134FF2EF5B0A400CC4938 /* Home in Frameworks */, + B5C7D2132F1C0AD300C20E14 /* CommunityPresentation in Frameworks */, + B5C7D2172F1C0AD900C20E14 /* MyPagePresentation in Frameworks */, + B5C7D2152F1C0AD300C20E14 /* HomePresentation in Frameworks */, B57DE3412E92CB6100575CDA /* Onboarding in Frameworks */, B52285C92E88469C00678ECC /* Managers in Frameworks */, B54128772EF1CD3100CC4938 /* Login in Frameworks */, + B5C7D2112F1C09C100C20E14 /* AppCore in Frameworks */, B54135802EF5B4CC00CC4938 /* KakaoLogin in Frameworks */, B53088172F15712500586850 /* FCMService in Frameworks */, B5412A882EF277A200CC4938 /* NetworkImpl in Frameworks */, - B54134FD2EF5B09D00CC4938 /* Community in Frameworks */, B5412A8A2EF277A200CC4938 /* NetworkInterface in Frameworks */, B53086D12F115A3800586850 /* SharedUI in Frameworks */, ); @@ -136,12 +136,12 @@ 915BC5C92E3CB9B50062B78E = { isa = PBXGroup; children = ( + B5C7D20B2F1BEFAB00C20E14 /* AppCore */, B5C7D1B32F1B7B6600C20E14 /* Alarm */, B54135972EF5B58100CC4938 /* 3rdParty */, B54134FB2EF57F6400CC4938 /* Community */, B54134FA2EF57F4100CC4938 /* Home */, B54134062EF5330A00CC4938 /* MyPage */, - B5412CD62EF3C9EA00CC4938 /* DI */, B54126322EF1A99B00CC4938 /* Infrastructure */, B54125132EF161BF00CC4938 /* Login */, B513799A2EE2ED8F00DAF2F7 /* Common.xcconfig */, @@ -209,13 +209,13 @@ B54128762EF1CD3100CC4938 /* Login */, B5412A872EF277A200CC4938 /* NetworkImpl */, B5412A892EF277A200CC4938 /* NetworkInterface */, - B54134072EF535FC00CC4938 /* MyPage */, - B54134FC2EF5B09D00CC4938 /* Community */, - B54134FE2EF5B0A400CC4938 /* Home */, B541357F2EF5B4CC00CC4938 /* KakaoLogin */, - B5EDA8F72F0B9C0C002F72B9 /* DIKit */, B53086D02F115A3800586850 /* SharedUI */, B53088162F15712500586850 /* FCMService */, + B5C7D2102F1C09C100C20E14 /* AppCore */, + B5C7D2122F1C0AD300C20E14 /* CommunityPresentation */, + B5C7D2142F1C0AD300C20E14 /* HomePresentation */, + B5C7D2162F1C0AD900C20E14 /* MyPagePresentation */, ); productName = Hambug; productReference = 915BC5D22E3CB9B50062B78E /* Hambug.app */; @@ -741,18 +741,6 @@ isa = XCSwiftPackageProductDependency; productName = NetworkInterface; }; - B54134072EF535FC00CC4938 /* MyPage */ = { - isa = XCSwiftPackageProductDependency; - productName = MyPage; - }; - B54134FC2EF5B09D00CC4938 /* Community */ = { - isa = XCSwiftPackageProductDependency; - productName = Community; - }; - B54134FE2EF5B0A400CC4938 /* Home */ = { - isa = XCSwiftPackageProductDependency; - productName = Home; - }; B541357F2EF5B4CC00CC4938 /* KakaoLogin */ = { isa = XCSwiftPackageProductDependency; productName = KakaoLogin; @@ -765,9 +753,21 @@ isa = XCSwiftPackageProductDependency; productName = Splash; }; - B5EDA8F72F0B9C0C002F72B9 /* DIKit */ = { + B5C7D2102F1C09C100C20E14 /* AppCore */ = { + isa = XCSwiftPackageProductDependency; + productName = AppCore; + }; + B5C7D2122F1C0AD300C20E14 /* CommunityPresentation */ = { + isa = XCSwiftPackageProductDependency; + productName = CommunityPresentation; + }; + B5C7D2142F1C0AD300C20E14 /* HomePresentation */ = { + isa = XCSwiftPackageProductDependency; + productName = HomePresentation; + }; + B5C7D2162F1C0AD900C20E14 /* MyPagePresentation */ = { isa = XCSwiftPackageProductDependency; - productName = DIKit; + productName = MyPagePresentation; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/Hambug/AppDelegate.swift b/Hambug/AppDelegate.swift index 504156d..53bb3bb 100644 --- a/Hambug/AppDelegate.swift +++ b/Hambug/AppDelegate.swift @@ -6,8 +6,8 @@ // import UIKit +import AppCoreDI import FCMService -import AppDI class AppDelegate: NSObject, UIApplicationDelegate { private let appDIContainer: AppDIContainer = .shared diff --git a/Hambug/ContentView.swift b/Hambug/ContentView.swift index b67f396..0181736 100644 --- a/Hambug/ContentView.swift +++ b/Hambug/ContentView.swift @@ -6,56 +6,36 @@ // import SwiftUI -import AppDI +import AppCoreDI +import SharedUI import HomePresentation -import HomeDI import CommunityPresentation -import CommunityDI -import SharedUI import MyPagePresentation -import MyPageDI struct ContentView: View { @Environment(AppDIContainer.self) var appContainer - private var homeDIContainer: HomeDIContainer { - HomeDIContainer(appContainer: appContainer) - } - - private var communityDIContainer: CommunityDIContainer { - CommunityDIContainer(appContainer: appContainer) - } - - private var mypageDIContainer: MyPageDIContainer { - MyPageDIContainer(appContainer: appContainer) - } - @State private var selectedTab: Int = 0 var body: some View { CustomTabView(selectedTab: $selectedTab) { Group { NavigationStack { - HomeView(viewModel: homeDIContainer.homeViewModel) + HomeView(dependency: appContainer.homeDIContainer) } .tag(0) NavigationStack { - CommunityView( - viewModel: communityDIContainer.makeCommunityViewModel(), - writeFactory: communityDIContainer, - detailFactory: communityDIContainer, - updateFactory: communityDIContainer, - reportFactory: communityDIContainer - ) + CommunityView(dependency: appContainer.communityDIContainer) } .tag(1) NavigationStack { MyPageView( - viewModel: mypageDIContainer.makeMyPageViewModel(), - activitesFactory: mypageDIContainer + viewModel: appContainer.mypageDIContainer.makeMyPageViewModel(), + activitesFactory: appContainer.mypageDIContainer, + dependency: appContainer.communityDIContainer ) } .tag(2) diff --git a/Hambug/HambugApp.swift b/Hambug/HambugApp.swift index 8917daf..a7ca78c 100644 --- a/Hambug/HambugApp.swift +++ b/Hambug/HambugApp.swift @@ -9,7 +9,7 @@ import SwiftUI import Managers import DesignSystem import KakaoLogin -import AppDI +import AppCoreDI @main struct HambugApp: App { diff --git a/Hambug/RootView.swift b/Hambug/RootView.swift index 6e081f7..40edd93 100644 --- a/Hambug/RootView.swift +++ b/Hambug/RootView.swift @@ -11,10 +11,7 @@ import Managers import Splash import Onboarding import LoginPresentation -import LoginDI -import AppDI -import IntroDI -import NetworkImpl +import AppCoreDI import Util import FCMService @@ -32,27 +29,19 @@ struct RootView: View { Group { switch appStateManager.currentState { case .splash: + SplashView( - viewModel: IntroDIContainer( - appContainer: appContainer, - appStateManager: appStateManager - ).resolve(SplashViewModel.self) + viewModel: appContainer.introDIContainer.splashViewModel ) case .onboarding: OnboardingView( - viewModel: IntroDIContainer( - appContainer: appContainer, - appStateManager: appStateManager - ).resolve(OnboardingViewModel.self) + viewModel: appContainer.introDIContainer.onboardingViewModel ) case .login: LoginView( - viewModel: LoginDIContainer( - appContainer: appContainer, - appStateManager: appStateManager - ).makeLoginViewModel() + viewModel: appContainer.loginDIContainer.makeLoginViewModel() ) case .main: diff --git a/Home/Package.swift b/Home/Package.swift index bd4e63a..70d958e 100644 --- a/Home/Package.swift +++ b/Home/Package.swift @@ -28,10 +28,17 @@ let package = Package( name: Config.name, targets: Config.allCases.map(\.name) ), + .library( + name: Config.di.name, + targets: [Config.di.name] + ), + .library( + name: Config.presentation.name, + targets: [Config.presentation.name] + ), ], dependencies: [ .package(name: "Common", path: "../Common"), - .package(name: "DI", path: "../DI"), .package(name: "Infrastructure", path: "../Infrastructure"), .package(name: "Community", path: "../Community"), .package(name: "Alarm", path: "../Alarm"), @@ -43,8 +50,7 @@ let package = Package( .target(config: .domain), .target(config: .data), .target(config: .presentation), - .product(name: "DI", package: "DI"), - .product(name: "AppDI", package: "DI"), + .product(name: "DIKit", package: "Common"), .product(name: "Managers", package: "Common"), .product(name: "DataSources", package: "Common"), ], diff --git a/Home/Sources/DI/HomeDIContainer.swift b/Home/Sources/DI/HomeDIContainer.swift index c3eab32..ab392e1 100644 --- a/Home/Sources/DI/HomeDIContainer.swift +++ b/Home/Sources/DI/HomeDIContainer.swift @@ -7,7 +7,6 @@ import Foundation import DIKit -import AppDI import Managers import DataSources import NetworkInterface @@ -15,7 +14,12 @@ import HomeDomain import HomeData import HomePresentation +import CommunityPresentation +import AlarmPresentation + import SwiftUI +import CommunityDI +import AlarmDI // MARK: - Home Assembly struct HomeAssembly: Assembly { @@ -48,21 +52,26 @@ public final class HomeDIContainer { private let container: GenericDIContainer // MARK: - Initialization - public init(appContainer: AppDIContainer = .shared) { - self.container = GenericDIContainer(parent: appContainer.baseContainer) + public init(appContainer: GenericDIContainer) { + self.container = appContainer HomeAssembly().assemble(container: container) } +} - // MARK: - Factory Methods - public var homeViewModel: HomeViewModel { - return container.resolve(HomeViewModel.self) +extension HomeDIContainer: Homedependency { + public var component: any CommunityPresentation.CommunityDetailDependency { + container.resolve(CommunityDIContainer.self) } - - public func resolve(_ type: T.Type) -> T { - return container.resolve(type) + + public var alarmListComponent: any AlarmPresentation.AlarmListDependecy { + container.resolve(AlarmDIContainer.self) + } + + public func makeHomeViewModel() -> HomePresentation.HomeViewModel { + container.resolve(HomeViewModel.self) } } -#Preview { - HomeView(viewModel: HomeDIContainer.init().homeViewModel) -} +//#Preview { +// HomeView(viewModel: HomeDIContainer.init().homeViewModel) +//} diff --git a/Home/Sources/Presentation/HomeView.swift b/Home/Sources/Presentation/HomeView.swift index d2a1207..3b59a29 100644 --- a/Home/Sources/Presentation/HomeView.swift +++ b/Home/Sources/Presentation/HomeView.swift @@ -9,25 +9,41 @@ import SwiftUI import HomeDomain import DesignSystem import SharedUI -import CommunityDI import CommunityPresentation +import AlarmPresentation + +public protocol Homedependency: HomeFactory { + var component: CommunityDetailDependency { get } + var alarmListComponent: AlarmListDependecy { get } +} +public protocol HomeFactory { + func makeHomeViewModel() -> HomeViewModel +} public struct HomeView: View { @State private var viewModel: HomeViewModel - - public init(viewModel: HomeViewModel) { - self._viewModel = State(initialValue: viewModel) + private let dependency: Homedependency + + public init( + dependency: Homedependency, + ) { + self.dependency = dependency + self._viewModel = State(initialValue: dependency.makeHomeViewModel()) } - + public var body: some View { ZStack { Color.bgG100 .ignoresSafeArea(.container, edges: .top) VStack { - HeaderBar(type: .home) - .safeAreaPadding(18) + HeaderBar(type: .home) { + AlarmListView( + dependency: dependency.alarmListComponent + ) + } + .safeAreaPadding(18) ScrollView { SuggestView(burgers: viewModel.recommendedBurgers) @@ -37,7 +53,10 @@ public struct HomeView: View { Spacer() .frame(height: 30) - PopularPostsView(postItems: viewModel.trendingPosts) + PopularPostsView( + postItems: viewModel.trendingPosts, + dependency: dependency + ) .padding(.horizontal, 18) } @@ -53,11 +72,11 @@ public struct HomeView: View { struct PopularPostsView: View { private let postItems: [TrendingPost] - private let communityDIContainer: CommunityDIContainer + private let dependency: Homedependency - init(postItems: [TrendingPost]) { + init(postItems: [TrendingPost], dependency: Homedependency) { self.postItems = postItems - self.communityDIContainer = .init(appContainer: .shared) + self.dependency = dependency } var body: some View { @@ -68,11 +87,10 @@ struct PopularPostsView: View { ForEach(postItems) { post in NavigationLink( destination: CommunityDetailView( - viewModel: communityDIContainer.makeDetailViewModel(), - boardId: post.id, - updateFactory: communityDIContainer, - reportFactory: communityDIContainer - )) { + dependency: dependency.component, + boardId: post.id + ) + ) { PostView(post: post) } } diff --git a/Intro/Package.swift b/Intro/Package.swift index 19ffe3b..4db0864 100644 --- a/Intro/Package.swift +++ b/Intro/Package.swift @@ -1,40 +1,110 @@ -// swift-tools-version: 6.1 +// swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription +enum Config: String, CaseIterable { + static let name: String = "Intro" + + case di = "DI" + case onboarding = "Onboarding" + case splash = "Splash" + + var name: String { + switch self { + case .di: + return Config.name + rawValue + case .onboarding, .splash: + return rawValue + } + } + + var path: String { + "Sources/\(rawValue)" + } +} + let package = Package( - name: "Intro", - platforms: [ - .iOS(.v17) - ], - products: [ - .library( - name: "Onboarding", - targets: ["Onboarding"] - ), - .library( - name: "Splash", - targets: ["Splash"] - ), - ], - dependencies: [ - .package(name: "Common", path: "../Common") - ], - targets: [ - .target( - name: "Onboarding", - dependencies: [ - .product(name: "Managers", package: "Common"), - .product(name: "DesignSystem", package: "Common") - ] - ), - .target( - name: "Splash", - dependencies: [ - .product(name: "Managers", package: "Common"), - .product(name: "DesignSystem", package: "Common") - ], - ), - ] + name: Config.name, + platforms: [ + .iOS(.v17) + ], + products: [ + .library( + name: Config.di.name, + targets: [Config.di.name] + ), + .library( + name: Config.onboarding.name, + targets: [Config.onboarding.name] + ), + .library( + name: Config.splash.name, + targets: [Config.splash.name] + ), + ], + dependencies: [ + .package(name: "Common", path: "../Common") + ], + targets: [ + .target( + config: .di, + dependencies: [ + .target(config: .onboarding), + .target(config: .splash), + ] + ), + .target( + config: .onboarding, + dependencies: [ + .product(name: "Managers", package: "Common"), + .product(name: "DesignSystem", package: "Common") + ] + ), + .target( + config: .splash, + dependencies: [ + .product(name: "Managers", package: "Common"), + .product(name: "DesignSystem", package: "Common") + ], + ), + ] ) + +extension Target { + static func target( + config: Config, + dependencies: [Dependency] = [], + exclude: [String] = [], + sources: [String]? = nil, + resources: [Resource]? = nil, + publicHeadersPath: String? = nil, + packageAccess: Bool = false, + cSettings: [CSetting]? = nil, + cxxSettings: [CXXSetting]? = nil, + swiftSettings: [SwiftSetting]? = nil, + linkerSettings: [LinkerSetting]? = nil, + plugins: [PluginUsage]? = nil, + ) -> Target { + return .target( + name: config.name, + dependencies: dependencies, + path: config.path, + exclude: exclude, + sources: sources, + resources: resources, + publicHeadersPath: publicHeadersPath, + packageAccess: packageAccess, + cSettings: cSettings, + cxxSettings: cxxSettings, + swiftSettings: swiftSettings, + linkerSettings: linkerSettings, + plugins: plugins) + } +} + +extension Target.Dependency { + static func target(config: Config) -> Self { + return .target(name: config.name) + } +} diff --git a/DI/Sources/IntroDI/IntroDIContainer.swift b/Intro/Sources/DI/IntroDIContainer.swift similarity index 52% rename from DI/Sources/IntroDI/IntroDIContainer.swift rename to Intro/Sources/DI/IntroDIContainer.swift index 65e31ab..66a91ca 100644 --- a/DI/Sources/IntroDI/IntroDIContainer.swift +++ b/Intro/Sources/DI/IntroDIContainer.swift @@ -6,29 +6,22 @@ // import DIKit -import AppDI import Splash import Onboarding import Managers // MARK: - Login Assembly struct IntroAssembly: Assembly { - private let appStateManager: AppStateManager - - init(appStateManager: AppStateManager) { - self.appStateManager = appStateManager - } - func assemble(container: GenericDIContainer) { container.register(OnboardingViewModel.self) { resolver in OnboardingViewModel( - appStateManager: self.appStateManager + appStateManager: resolver.resolve(AppStateManager.self) ) } container.register(SplashViewModel.self) { resolver in SplashViewModel( - appStateManager: self.appStateManager + appStateManager: resolver.resolve(AppStateManager.self) ) } } @@ -41,13 +34,17 @@ public final class IntroDIContainer { private let container: GenericDIContainer // MARK: - Initialization - public init(appContainer: AppDIContainer, appStateManager: AppStateManager) { - self.container = GenericDIContainer(parent: appContainer.baseContainer) - IntroAssembly(appStateManager: appStateManager).assemble(container: container) + public init(appContainer: GenericDIContainer) { + self.container = appContainer + IntroAssembly().assemble(container: container) } - // MARK: - Factory Methods - public func resolve(_ type: T.Type) -> T { - return container.resolve(type) + // MARK: - Factory + public var onboardingViewModel: OnboardingViewModel { + return container.resolve(OnboardingViewModel.self) + } + + public var splashViewModel: SplashViewModel { + return container.resolve(SplashViewModel.self) } } diff --git a/Login/Package.swift b/Login/Package.swift index 4f36f4b..c1bcd66 100644 --- a/Login/Package.swift +++ b/Login/Package.swift @@ -6,6 +6,7 @@ import PackageDescription enum Config: String, CaseIterable { static let name: String = "Login" + case di = "DI" case data = "Data" case domain = "Domain" case presentation = "Presentation" @@ -25,10 +26,17 @@ let package = Package( .iOS(.v17) ], products: [ - // Products define the executables and libraries a package produces, making them visible to other packages. + .library( + name: Config.di.name, + targets: [Config.di.name] + ), .library( name: Config.name, - targets: Config.allCases.map(\.name) + targets: [ + Config.data.name, + Config.domain.name, + Config.presentation.name + ] ), ], dependencies: [ @@ -37,6 +45,17 @@ let package = Package( .package(name: "Infrastructure", path: "../Infrastructure") ], targets: [ + // Domain: 독립적 (외부 SDK만 의존) + .target( + name: Config.di.name, + dependencies: [ + .target(config: Config.domain), + .target(config: Config.data), + .target(config: Config.presentation), + ], + path: Config.di.path + ), + // Domain: 독립적 (외부 SDK만 의존) .target( name: Config.domain.name, diff --git a/DI/Sources/LoginDI/LoginDIContainer.swift b/Login/Sources/DI/LoginDIContainer.swift similarity index 73% rename from DI/Sources/LoginDI/LoginDIContainer.swift rename to Login/Sources/DI/LoginDIContainer.swift index 2c3e809..d11719e 100644 --- a/DI/Sources/LoginDI/LoginDIContainer.swift +++ b/Login/Sources/DI/LoginDIContainer.swift @@ -7,7 +7,6 @@ import Foundation import DIKit -import AppDI import LoginDomain import LoginData import LoginPresentation @@ -17,12 +16,6 @@ import NetworkInterface // MARK: - Login Assembly struct LoginAssembly: Assembly { - private let appStateManager: AppStateManager - - init(appStateManager: AppStateManager) { - self.appStateManager = appStateManager - } - func assemble(container: GenericDIContainer) { // Note: NetworkService and TokenStorage come from parent container @@ -46,7 +39,7 @@ struct LoginAssembly: Assembly { container.register(LoginViewModel.self) { resolver in LoginViewModel( useCase: resolver.resolve(LoginUseCase.self), - appStateManager: self.appStateManager + appStateManager: resolver.resolve(AppStateManager.self) ) } } @@ -59,17 +52,13 @@ public final class LoginDIContainer { private let container: GenericDIContainer // MARK: - Initialization - public init(appContainer: AppDIContainer, appStateManager: AppStateManager) { - self.container = GenericDIContainer(parent: appContainer.baseContainer) - LoginAssembly(appStateManager: appStateManager).assemble(container: container) + public init(appContainer: GenericDIContainer) { + self.container = appContainer + LoginAssembly().assemble(container: container) } // MARK: - Factory Methods public func makeLoginViewModel() -> LoginViewModel { return container.resolve(LoginViewModel.self) } - - public func resolve(_ type: T.Type) -> T { - return container.resolve(type) - } } diff --git a/MyPage/Package.swift b/MyPage/Package.swift index 5fc7542..198ac22 100644 --- a/MyPage/Package.swift +++ b/MyPage/Package.swift @@ -28,12 +28,19 @@ let package = Package( name: Config.name, targets: Config.allCases.map(\.name) ), + .library( + name: Config.di.name, + targets: [Config.di.name] + ), + .library( + name: Config.presentation.name, + targets: [Config.presentation.name] + ), ], dependencies: [ .package(name: "Common", path: "../Common"), .package(name: "Infrastructure", path: "../Infrastructure"), .package(name: "Community", path: "../Community"), - .package(name: "DI", path: "../DI"), ], targets: [ .target( @@ -44,8 +51,7 @@ let package = Package( .target(config: .presentation), .product(name: "NetworkInterface", package: "Infrastructure"), .product(name: "NetworkImpl", package: "Infrastructure"), - .product(name: "DIKit", package: "DI"), - .product(name: "AppDI", package: "DI"), + .product(name: "DIKit", package: "Common"), ], path: Config.di.path ), @@ -77,6 +83,7 @@ let package = Package( .product(name: "DesignSystem", package: "Common"), .product(name: "Community", package: "Community"), .product(name: "CommunityDomain", package: "Community"), + .product(name: "CommunityDI", package: "Community"), ], path: Config.presentation.path ), diff --git a/MyPage/Sources/DI/MyPageDIContainer.swift b/MyPage/Sources/DI/MyPageDIContainer.swift index ffc069b..e8393a0 100644 --- a/MyPage/Sources/DI/MyPageDIContainer.swift +++ b/MyPage/Sources/DI/MyPageDIContainer.swift @@ -6,7 +6,6 @@ // import DIKit -import AppDI import NetworkInterface import NetworkImpl import MyPageDomain @@ -68,9 +67,8 @@ public final class MyPageDIContainer { private let container: GenericDIContainer // MARK: - Initialization - public init(appContainer: AppDIContainer? = nil) { - let parent = appContainer ?? AppDIContainer.shared - self.container = AppDIContainer.shared.baseContainer + public init(appContainer: GenericDIContainer) { + self.container = appContainer MyPageAssembly().assemble(container: container) } diff --git a/MyPage/Sources/Presentation/MyActivitiesView.swift b/MyPage/Sources/Presentation/MyActivitiesView.swift index 185eacb..9bb9d8a 100644 --- a/MyPage/Sources/Presentation/MyActivitiesView.swift +++ b/MyPage/Sources/Presentation/MyActivitiesView.swift @@ -16,11 +16,14 @@ import CommunityPresentation public struct MyActivitiesView: View { @State private var viewModel: MyActivitiesViewModel - private let communityDIContainer: CommunityDIContainer + private let dependency: CommunityDependency - public init(viewModel: MyActivitiesViewModel) { + public init( + viewModel: MyActivitiesViewModel, + dependency: CommunityDependency + ) { self._viewModel = State(initialValue: viewModel) - self.communityDIContainer = .init(appContainer: .shared) + self.dependency = dependency } public var body: some View { @@ -68,17 +71,15 @@ public struct MyActivitiesView: View { private var contentView: some View { if viewModel.selectedTab == .posts { CommunityListView( - boards: viewModel.myBoards, - detailFactory: communityDIContainer, - updateFactory: communityDIContainer, - reportFactory: communityDIContainer, - viewModel: communityDIContainer.makeCommunityViewModel() + viewModel: dependency.makeCommunityViewModel(), + dependency: dependency, + boards: viewModel.myBoards ) .padding(.horizontal, 20) .padding(.vertical, 12) } else { MyCommentsListView( - communityDIContainer: communityDIContainer, + dependency: dependency.component, comments: viewModel.myComments, isLoadingMore: viewModel.isLoadingMoreComments, onLoadMore: { index in @@ -188,7 +189,7 @@ fileprivate struct MyBoardListCard: View { // MARK: - 댓글 리스트 뷰 struct MyCommentsListView: View { - let communityDIContainer: CommunityDIContainer + let dependency: CommunityDetailDependency let comments: [MyCommentActivity] let isLoadingMore: Bool let onLoadMore: (Int) -> Void @@ -198,12 +199,12 @@ struct MyCommentsListView: View { LazyVStack(spacing: 0) { ForEach(Array(comments.enumerated()), id: \.element.id) { index, comment in NavigationLink( - destination: CommunityDetailView( - viewModel: communityDIContainer.makeDetailViewModel(), - boardId: Int(comment.boardId), - updateFactory: communityDIContainer, - reportFactory: communityDIContainer - )) { + destination: + CommunityDetailView( + dependency: dependency, + boardId: Int(comment.boardId) + ) + ) { MyCommentActivityCard(comment: comment) } .buttonStyle(PlainButtonStyle()) @@ -290,16 +291,6 @@ struct HambugNavigationView: View { } } -#Preview { - // Preview requires mocked dependencies - MyActivitiesView( - viewModel: MyActivitiesViewModel( - getMyBoardsUseCase: MockGetMyBoardsUseCase(), - getMyCommentsUseCase: MockGetMyCommentsUseCase() - ) - ) -} - // MARK: - Mock UseCases for Preview private final class MockGetMyBoardsUseCase: GetMyBoardsUseCase { func execute(lastId: Int?, limit: Int, order: String) async throws -> BoardListData { diff --git a/MyPage/Sources/Presentation/MyPage/MyPageView.swift b/MyPage/Sources/Presentation/MyPage/MyPageView.swift index af63fb1..cb3a23b 100644 --- a/MyPage/Sources/Presentation/MyPage/MyPageView.swift +++ b/MyPage/Sources/Presentation/MyPage/MyPageView.swift @@ -9,6 +9,8 @@ import SwiftUI import PhotosUI import DesignSystem import Util +import CommunityDI +import CommunityPresentation public protocol ActivitesFactory { func makeMyActivitiesViewModel() -> MyActivitiesViewModel @@ -28,13 +30,16 @@ public struct MyPageView: View { @State private var showPhotoPicker: Bool = false private let activitesFactory: ActivitesFactory + private let dependency: CommunityDependency public init( viewModel: MyPageViewModel, - activitesFactory: ActivitesFactory + activitesFactory: ActivitesFactory, + dependency: CommunityDependency ) { self._viewModel = Bindable(viewModel) self.activitesFactory = activitesFactory + self.dependency = dependency } public var body: some View { @@ -52,7 +57,10 @@ public struct MyPageView: View { Spacer() } .navigationDestination(isPresented: $showMyActivitiesView, destination: { - MyActivitiesView(viewModel: activitesFactory.makeMyActivitiesViewModel()) + MyActivitiesView( + viewModel: activitesFactory.makeMyActivitiesViewModel(), + dependency: dependency + ) }) } .confirmationDialog("프로필 편집", isPresented: $showInfoActionSheet, actions: {