From 28d28317e233bc25dd6c7b7dd1f0ec874d84f46c Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Fri, 22 Nov 2024 18:39:01 +0900 Subject: [PATCH 01/42] =?UTF-8?q?feat:=20UserHouse=20=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomain/Entity/UserHouse.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift new file mode 100644 index 00000000..02e07e53 --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift @@ -0,0 +1,15 @@ +public struct UserHouse { + public let name: String + public let categories: [String] + public let bookCovers: [BookCover] + + public init( + name: String, + categories: [String], + bookCovers: [BookCover] + ) { + self.name = name + self.categories = categories + self.bookCovers = bookCovers + } +} From a510a7f02746b6ec8726d263a07f9b5f778993b2 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Fri, 22 Nov 2024 18:39:07 +0900 Subject: [PATCH 02/42] =?UTF-8?q?feat:=20UserHouse=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20UseCase=20&=20Repository=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/Repository/UserHouseRepository.swift | 3 +++ .../MHDomain/UseCase/DefaultUserHouseUseCase.swift | 11 +++++++++++ .../MHDomain/UseCase/Interface/UserHouseUseCase.swift | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift create mode 100644 MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift create mode 100644 MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift diff --git a/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift b/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift new file mode 100644 index 00000000..a03f47e3 --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift @@ -0,0 +1,3 @@ +public protocol UserHouseRepository { + func fetchUserHouse() async -> UserHouse +} diff --git a/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift new file mode 100644 index 00000000..551c6a61 --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift @@ -0,0 +1,11 @@ +public struct DefaultFetchUserHouseUseCase: FetchUserHouseUseCase { + private let repository: UserHouseRepository + + public init(repository: UserHouseRepository) { + self.repository = repository + } + + public func execute() async -> UserHouse { + return await repository.fetchUserHouse() + } +} diff --git a/MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift b/MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift new file mode 100644 index 00000000..3f7b0da9 --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift @@ -0,0 +1,3 @@ +public protocol FetchUserHouseUseCase: Sendable { + func execute() async -> UserHouse +} From 917fc8d99694459d49b266555e8f6b92ef22f259 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 03:23:16 +0900 Subject: [PATCH 03/42] =?UTF-8?q?refactor:=20SceneDelegate=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=B5=9C=EC=B4=88=20=EB=B7=B0=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EC=84=A0=ED=83=9D=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DIContainer가 nil과 throw를 반환하기 때문에 initialViewController를 기존에 초기화 해두고, 이후 UserDefaults에 값이 있다면 do-catch를 진행했습니다 --- .../MHApplication/Source/App/SceneDelegate.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift index 8fbe1665..60b7ab64 100644 --- a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift +++ b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift @@ -1,4 +1,6 @@ import UIKit +import MHCore +import MHDomain import MHFoundation import MHPresentation @@ -12,12 +14,15 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { ) { guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: windowScene) - let initialViewController: UIViewController + var initialViewController: UIViewController = RegisterViewController(viewModel: RegisterViewModel()) if let houseName = UserDefaults.standard.object(forKey: Constant.houseNameUserDefaultKey) as? String { - let viewModel = HomeViewModel(houseName: houseName) - initialViewController = HomeViewController(viewModel: viewModel) - } else { - initialViewController = RegisterViewController(viewModel: RegisterViewModel()) + do { + let viewModelFactory = try DIContainer.shared.resolve(HomeViewModelFactory.self) + let viewModel = viewModelFactory.make() + initialViewController = HomeViewController(viewModel: viewModel) + } catch { + MHLogger.error(error.localizedDescription) + } } let navigationController = UINavigationController(rootViewController: initialViewController) From 47ec3666b69645e79008c854a7677f85e84b17c6 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 03:23:40 +0900 Subject: [PATCH 04/42] =?UTF-8?q?refactor:=20DIContainer=20shared=EB=A5=BC?= =?UTF-8?q?=20MainActor=EB=A1=9C=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MemorialHouse/MHCore/MHCore/DIContainer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MemorialHouse/MHCore/MHCore/DIContainer.swift b/MemorialHouse/MHCore/MHCore/DIContainer.swift index 33ccd2cc..a04c8915 100644 --- a/MemorialHouse/MHCore/MHCore/DIContainer.swift +++ b/MemorialHouse/MHCore/MHCore/DIContainer.swift @@ -1,5 +1,5 @@ -public actor DIContainer { - public static let shared = DIContainer() +public final class DIContainer { + @MainActor public static let shared = DIContainer() private var objects: [String: Any] = [:] private init() {} From fd0e502d5332f96cef5127925b0b4bbedf64e7f8 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 03:24:16 +0900 Subject: [PATCH 05/42] =?UTF-8?q?refactor:=20BookCover=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomain/Entity/BookCover.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift index af9f12d0..0a626eed 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift @@ -1,24 +1,24 @@ import MHFoundation public struct BookCover { - public let bookIdentifer = UUID() + public let identifier = UUID() public let title: String public let imageURL: String - public let bookColor: BookColor + public let color: BookColor public let category: String - public let isLike: Bool + public let favorite: Bool public init( title: String, imageURL: String, - bookColor: BookColor, + color: BookColor, category: String, - isLike: Bool = false + favorite: Bool = false ) { self.title = title self.imageURL = imageURL - self.bookColor = bookColor + self.color = color self.category = category - self.isLike = isLike + self.favorite = favorite } } From 92cebeafc4ae2e72a81cb81516e8bc99bffdb870 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 03:25:03 +0900 Subject: [PATCH 06/42] =?UTF-8?q?fix:=20HomeViewController=EC=9D=98=20MHDo?= =?UTF-8?q?main=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Home/HomeViewController.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index 792e4c57..77646182 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -1,10 +1,10 @@ import UIKit -import MHDomain +import MHCore import MHFoundation public final class HomeViewController: UIViewController { // MARK: - UI Components - private let navigationBar: MHNavigationBar + private let navigationBar = MHNavigationBar(title: "") private let currentCategoryLabel = UILabel(style: .header2) private let categorySelectButton = UIButton(type: .custom) private let makingBookFloatingButton: UIButton = { @@ -39,14 +39,12 @@ public final class HomeViewController: UIViewController { // MARK: - Initializer public init(viewModel: HomeViewModel) { self.viewModel = viewModel - self.navigationBar = MHNavigationBar(title: viewModel.houseName) super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { - guard let houseName = UserDefaults.standard.string(forKey: Constant.houseNameUserDefaultKey) else { return nil } - self.viewModel = HomeViewModel(houseName: houseName) - self.navigationBar = MHNavigationBar(title: viewModel.houseName) + let viewModelFactory = try! DIContainer.shared.resolve(HomeViewModelFactory.self) + self.viewModel = viewModelFactory.make() super.init(coder: coder) } From 6b699115d519fa366ba00a9ede980d7d78eb40fa Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 03:26:16 +0900 Subject: [PATCH 07/42] =?UTF-8?q?feat:=20HomeViewModelFactory=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20Register=20->=20Home=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Home/HomeViewModelFactory.swift | 13 +++++++++++++ .../Register/View/RegisterViewController.swift | 16 ++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift new file mode 100644 index 00000000..d644541c --- /dev/null +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift @@ -0,0 +1,13 @@ +import MHDomain + +public struct HomeViewModelFactory { + let fetchUserHouseUseCase: FetchUserHouseUseCase + + public init(fetchUserHouseUseCase: FetchUserHouseUseCase) { + self.fetchUserHouseUseCase = fetchUserHouseUseCase + } + + public func make() -> HomeViewModel { + HomeViewModel(fetchUserHouseUseCase: fetchUserHouseUseCase) + } +} diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift index 043a4eb3..821c6792 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift @@ -1,6 +1,8 @@ +import Combine import UIKit +import MHCore +import MHDomain import MHFoundation -import Combine public final class RegisterViewController: UIViewController { // MARK: - Property @@ -100,9 +102,15 @@ public final class RegisterViewController: UIViewController { case .registerButtonEnabled(let isEnabled): self?.registerButton.isEnabled = isEnabled case .moveToHome(let houseName): - let homeViewController = HomeViewController(viewModel: HomeViewModel(houseName: houseName)) - self?.navigationController?.pushViewController(homeViewController, animated: false) - self?.navigationController?.viewControllers.removeFirst() + do { + let homeViewModelFactory = try DIContainer.shared.resolve(HomeViewModelFactory.self) + let homeViewModel = homeViewModelFactory.make() + let homeViewController = HomeViewController(viewModel: homeViewModel) + self?.navigationController?.pushViewController(homeViewController, animated: false) + self?.navigationController?.viewControllers.removeFirst() + } catch { + MHLogger.error(error.localizedDescription) + } } }.store(in: &cancellables) } From 72a5abbeabb280489788f85b9cf3617dcbbf8483 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 03:26:29 +0900 Subject: [PATCH 08/42] =?UTF-8?q?fix:=20UserHouseRepository=EC=97=90=20Sen?= =?UTF-8?q?dable=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomain/Repository/UserHouseRepository.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift b/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift index a03f47e3..4ea2846b 100644 --- a/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift +++ b/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift @@ -1,3 +1,3 @@ -public protocol UserHouseRepository { +public protocol UserHouseRepository: Sendable { func fetchUserHouse() async -> UserHouse } From a558b54f283226644a1ecc74b06a82f5c9f36e51 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 03:27:06 +0900 Subject: [PATCH 09/42] =?UTF-8?q?feat:=20Home=EA=B3=BC=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=EB=90=9C=20DI=20ViewModel=20&=20UseCase=20&=20Repo=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/App/SceneDelegate.swift | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift index 60b7ab64..3e70d3aa 100644 --- a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift +++ b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift @@ -14,6 +14,8 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { ) { guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: windowScene) + registerDependency() + var initialViewController: UIViewController = RegisterViewController(viewModel: RegisterViewModel()) if let houseName = UserDefaults.standard.object(forKey: Constant.houseNameUserDefaultKey) as? String { do { @@ -29,4 +31,29 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { window?.rootViewController = navigationController window?.makeKeyAndVisible() } + + func registerDependency() { + do { + DIContainer.shared.register( + UserHouseRepository.self, + object: StubUserHouseRepository() + ) + + let userHouseRepository = try DIContainer.shared.resolve(UserHouseRepository.self) + DIContainer.shared.register( + FetchUserHouseUseCase.self, + object: DefaultFetchUserHouseUseCase(repository: userHouseRepository) + ) + + let fetchUserHouseUseCase = try DIContainer.shared.resolve(FetchUserHouseUseCase.self) + DIContainer.shared.register( + HomeViewModelFactory.self, + object: HomeViewModelFactory(fetchUserHouseUseCase: fetchUserHouseUseCase) + ) + } catch let error as MHError { + MHLogger.error("\(error.description)") + } catch { + MHLogger.error("\(error.localizedDescription)") + } + } } From a16da919945b4e19c55523d73925353ece66ec2b Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 16:47:44 +0900 Subject: [PATCH 10/42] =?UTF-8?q?refactor:=20SceneDelegate=EC=97=90?= =?UTF-8?q?=EC=84=9C=20HouseName=20=EB=84=98=EA=B2=A8=EC=A3=BC=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHApplication/MHApplication/Source/App/SceneDelegate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift index 3e70d3aa..834767f6 100644 --- a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift +++ b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift @@ -17,7 +17,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { registerDependency() var initialViewController: UIViewController = RegisterViewController(viewModel: RegisterViewModel()) - if let houseName = UserDefaults.standard.object(forKey: Constant.houseNameUserDefaultKey) as? String { + if UserDefaults.standard.object(forKey: Constant.houseNameUserDefaultKey) != nil { do { let viewModelFactory = try DIContainer.shared.resolve(HomeViewModelFactory.self) let viewModel = viewModelFactory.make() From 274d8d5bc660f0c3bde586bfd063f5c9a4741687 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 16:48:05 +0900 Subject: [PATCH 11/42] =?UTF-8?q?fix:=20required=20init=EC=97=90=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20=EA=B0=95=EC=A0=9C=EC=B6=94=EC=B6=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHPresentation/Source/Home/HomeViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index 77646182..ac98e150 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -43,7 +43,7 @@ public final class HomeViewController: UIViewController { } required init?(coder: NSCoder) { - let viewModelFactory = try! DIContainer.shared.resolve(HomeViewModelFactory.self) + guard let viewModelFactory = try? DIContainer.shared.resolve(HomeViewModelFactory.self) else { return nil } self.viewModel = viewModelFactory.make() super.init(coder: coder) } From e7b6bc2c43fc8dc2652b66a4686ae06e7f81736b Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 18:16:41 +0900 Subject: [PATCH 12/42] =?UTF-8?q?refactor:=20Entity=20=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=EC=97=90=20Sendable=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MemorialHouse/MHDomain/MHDomain/Entity/BookColor.swift | 2 +- MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift | 2 +- MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/BookColor.swift b/MemorialHouse/MHDomain/MHDomain/Entity/BookColor.swift index 7a4961ca..55c00296 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/BookColor.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/BookColor.swift @@ -1,4 +1,4 @@ -public enum BookColor { +public enum BookColor: Sendable { case beige case blue case green diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift index 0a626eed..21500299 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift @@ -1,6 +1,6 @@ import MHFoundation -public struct BookCover { +public struct BookCover: Sendable { public let identifier = UUID() public let title: String public let imageURL: String diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift index 02e07e53..d32c4307 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift @@ -1,4 +1,4 @@ -public struct UserHouse { +public struct UserHouse: Sendable { public let name: String public let categories: [String] public let bookCovers: [BookCover] From a2b5feb25d2f5b4ddafba936d17e5af8ef8f7388 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 18:17:11 +0900 Subject: [PATCH 13/42] =?UTF-8?q?refactor:=20MHNavigationBar=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=EC=A0=90=EC=97=90=20Title=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EC=9D=B4=20=EC=95=84=EB=8B=8C,=20configure=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Design/MHNavigationBar.swift | 13 ++++++++----- .../Source/Home/HomeViewController.swift | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Design/MHNavigationBar.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Design/MHNavigationBar.swift index 5e36a596..b1c02d8a 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Design/MHNavigationBar.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Design/MHNavigationBar.swift @@ -6,10 +6,10 @@ final class MHNavigationBar: UIView { private let settingButton = UIButton(type: .custom) // MARK: - Initializer - init(title: String) { + init() { super.init(frame: .zero) - setup(with: title) + setup() configureAddSubView() configureConstraints() configureAction() @@ -18,15 +18,14 @@ final class MHNavigationBar: UIView { required init?(coder: NSCoder) { super.init(coder: coder) - setup(with: "") + setup() configureAddSubView() configureConstraints() configureAction() } // MARK: - Setup & Configuration - private func setup(with title: String) { - titleLabel.text = "\(title) 기록소" + private func setup() { settingButton.setImage(.settingLight, for: .normal) backgroundColor = .baseBackground } @@ -54,4 +53,8 @@ final class MHNavigationBar: UIView { // TODO: 설정 버튼 클릭 시 설정화면 라우팅 필요 }, for: .touchUpInside) } + + func configureTitle(with title: String) { + titleLabel.text = "\(title) 기록소" + } } diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index ac98e150..45713be1 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -4,7 +4,7 @@ import MHFoundation public final class HomeViewController: UIViewController { // MARK: - UI Components - private let navigationBar = MHNavigationBar(title: "") + private let navigationBar = MHNavigationBar() private let currentCategoryLabel = UILabel(style: .header2) private let categorySelectButton = UIButton(type: .custom) private let makingBookFloatingButton: UIButton = { From c67cb460da986e47ace31f7485f3247dcd245bbb Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 18:18:21 +0900 Subject: [PATCH 14/42] =?UTF-8?q?feat:=20HomeViewModel=20=EB=B0=94?= =?UTF-8?q?=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Home/HomeViewController.swift | 14 +++++++- .../Source/Home/HomeViewModel.swift | 35 ++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index 45713be1..aec81c18 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -1,3 +1,4 @@ +import Combine import UIKit import MHCore import MHFoundation @@ -33,6 +34,8 @@ public final class HomeViewController: UIViewController { // MARK: - Properties private let viewModel: HomeViewModel + private let input = PassthroughSubject() + private var cancellables = Set() private var floatingButtonBottomConstraint: NSLayoutConstraint? private var isFloatingButtonHidden = false @@ -53,6 +56,7 @@ public final class HomeViewController: UIViewController { super.viewDidLoad() setup() + bind() configureAddSubView() configureAction() configureConstraints() @@ -73,10 +77,18 @@ public final class HomeViewController: UIViewController { BookCollectionViewCell.self, forCellWithReuseIdentifier: BookCollectionViewCell.identifier ) - currentCategoryLabel.text = "전체" // TODO: 카테고리 관리 필요 categorySelectButton.setImage(.dropDown, for: .normal) } + private func bind() { + let output = viewModel.transform(input: input.eraseToAnyPublisher()) + + output.sink { [weak self] event in + switch event { + } + }.store(in: &cancellables) + } + private func configureAddSubView() { view.addSubview(navigationBar) view.addSubview(currentCategoryLabel) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift index b8bccd40..778f14e2 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift @@ -1,9 +1,36 @@ +import Combine +import MHCore import MHDomain -public final class HomeViewModel { - let houseName: String // TODO: 기록소 모델 만들기 +public final class HomeViewModel: ViewModelType { + enum Input { + case viewDidLoad + } + + enum Output { + case fetchedUserHouse(UserHouse) + } + + private let output = PassthroughSubject() + private var fetchUserHouseUseCase: FetchUserHouseUseCase + private var cancellables = Set() + private(set) var userHouse = PassthroughSubject() + + public init(fetchUserHouseUseCase: FetchUserHouseUseCase) { + self.fetchUserHouseUseCase = fetchUserHouseUseCase + } + + @MainActor + func transform(input: AnyPublisher) -> AnyPublisher { + input.sink { [weak self] event in + switch event { + case .viewDidLoad: + self?.fetchUserHouse() + } + }.store(in: &cancellables) + + return output.eraseToAnyPublisher() + } - public init(houseName: String) { // TODO: 기록소 모델 만들기 - self.houseName = houseName } } From 2beda37658408f42a2f62cc3daaacb8e5af74fa4 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 19:03:10 +0900 Subject: [PATCH 15/42] =?UTF-8?q?feat:=20DefaultFetchUserHouseUseCase?= =?UTF-8?q?=EC=9D=98=20=EB=8B=89=EB=84=A4=EC=9E=84=20=EC=82=AC=EC=9D=B4=20?= =?UTF-8?q?=EA=B3=B5=EB=B0=B1=20=EC=B6=94=EA=B0=80=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UseCase/DefaultUserHouseUseCase.swift | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift index 551c6a61..639b0971 100644 --- a/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift +++ b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift @@ -1,4 +1,4 @@ -public struct DefaultFetchUserHouseUseCase: FetchUserHouseUseCase { +public struct DefaultFetchUserHouseUseCase: FetchUserHouseUseCase { private let repository: UserHouseRepository public init(repository: UserHouseRepository) { @@ -6,6 +6,23 @@ public struct DefaultFetchUserHouseUseCase: FetchUserHouseUseCase { } public func execute() async -> UserHouse { - return await repository.fetchUserHouse() + let userHouse = await repository.fetchUserHouse() + let transformedName = transformHouseName(with: userHouse.name) + + return UserHouse( + name: transformedName, + categories: userHouse.categories, + bookCovers: userHouse.bookCovers + ) + } + + /// 집 이름이 3글자 이상일 경우, 각 글자 사이에 공백을 추가하여 변환합니다. + /// + /// - Parameter name: 원본 이름 문자열. + /// - Returns: 글자 사이에 공백이 추가된 문자열(3글자 이상인 경우). + /// 2글자 이하라면 원본 문자열 그대로 반환합니다. + private func transformHouseName(with name: String) -> String { + guard name.count > 2 else { return name } + return name.map { String($0) }.joined(separator: " ") } } From 35de2bc3f91d9da08ab6e918c562dfdecffb12a8 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 19:03:35 +0900 Subject: [PATCH 16/42] =?UTF-8?q?feat:=20ViewDidLoad=20=EC=8B=9C=EC=A0=90?= =?UTF-8?q?=EC=97=90=20UserHouse=20Fetch=20=ED=95=98=EC=97=AC=20UI=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Home/HomeViewController.swift | 29 +++++++++++++++++-- .../Source/Home/HomeViewModel.swift | 16 ++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index aec81c18..cec64a20 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -57,6 +57,7 @@ public final class HomeViewController: UIViewController { setup() bind() + input.send(.viewDidLoad) configureAddSubView() configureAction() configureConstraints() @@ -84,11 +85,26 @@ public final class HomeViewController: UIViewController { let output = viewModel.transform(input: input.eraseToAnyPublisher()) output.sink { [weak self] event in + guard let self else { return } switch event { + case .fetchedUserHouse: + self.updateUserHouse() } }.store(in: &cancellables) } + private func updateUserHouse() { + // 네비게이션 타이틀 설정 + let houseName = viewModel.houseName + navigationBar.configureTitle(with: houseName) + + // 카테고리 설정 + currentCategoryLabel.text = viewModel.categories.first + + // BoockCover 설정 + collectionView.reloadData() + } + private func configureAddSubView() { view.addSubview(navigationBar) view.addSubview(currentCategoryLabel) @@ -203,7 +219,7 @@ extension HomeViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - 0 + viewModel.bookCovers.count } public func collectionView( @@ -214,7 +230,16 @@ extension HomeViewController: UICollectionViewDataSource { withReuseIdentifier: BookCollectionViewCell.identifier, for: indexPath ) as? BookCollectionViewCell else { return UICollectionViewCell() } - // TODO: 데이터 넣기 + // TODO: Image Loader 필요 & 메모리 캐싱 필요 + + let bookCover = viewModel.bookCovers[indexPath.item] + cell.configure( + title: bookCover.title, + bookCoverImage: bookCover.color.image, + targetImage: UIImage(systemName: "person")!, + isLike: bookCover.favorite, + houseName: viewModel.houseName + ) return cell } diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift index 778f14e2..d1e9e3aa 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift @@ -8,13 +8,15 @@ public final class HomeViewModel: ViewModelType { } enum Output { - case fetchedUserHouse(UserHouse) + case fetchedUserHouse } private let output = PassthroughSubject() private var fetchUserHouseUseCase: FetchUserHouseUseCase private var cancellables = Set() - private(set) var userHouse = PassthroughSubject() + private(set) var houseName = "" + private(set) var categories = ["전체", "즐겨찾기"] + private(set) var bookCovers = [BookCover]() public init(fetchUserHouseUseCase: FetchUserHouseUseCase) { self.fetchUserHouseUseCase = fetchUserHouseUseCase @@ -32,5 +34,15 @@ public final class HomeViewModel: ViewModelType { return output.eraseToAnyPublisher() } + @MainActor + private func fetchUserHouse() { + Task { + let userHouse = await fetchUserHouseUseCase.execute() + self.houseName = userHouse.name + self.categories.append(contentsOf: userHouse.categories) + self.bookCovers = userHouse.bookCovers + output.send(.fetchedUserHouse) + MHLogger.debug("\(#function): \(userHouse)") + } } } From f27b853115f4089bade4b6dbe6648eb302f46366 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 19:04:00 +0900 Subject: [PATCH 17/42] =?UTF-8?q?feat:=20ViewModelType=EC=97=90=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C=20MainActor=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHPresentation/Source/Common/ViewModelType.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Common/ViewModelType.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Common/ViewModelType.swift index aea216ce..c0f752fe 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Common/ViewModelType.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Common/ViewModelType.swift @@ -4,5 +4,6 @@ protocol ViewModelType { associatedtype Input associatedtype Output + @MainActor func transform(input: AnyPublisher) -> AnyPublisher } From 4dff15d379064dce9d79059b2c249eb10ebef20c Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 22:25:12 +0900 Subject: [PATCH 18/42] =?UTF-8?q?feat:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=8B=9C=ED=8A=B8=EC=A7=80=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EC=8B=9C=20=ED=99=88=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=9D=98=20=ED=98=84=EC=9E=AC=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20UI=20=EB=B0=94=EB=80=8C=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Category/CategoryViewController.swift | 18 ++++++++++++------ .../Source/Category/CategoryViewModel.swift | 5 +++++ .../Source/Home/HomeViewController.swift | 17 +++++++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift index 586ac1d4..863a5671 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift @@ -2,11 +2,17 @@ import Combine import MHFoundation import UIKit +@MainActor +protocol CategoryViewControllerDelegate: AnyObject { + func categoryViewController(_ categoryViewController: CategoryViewController, didSelectCategoryIndex index: Int) +} + final class CategoryViewController: UIViewController { // MARK: - UI Components private let categoryTableView = UITableView() // MARK: - Properties + weak var delegate: CategoryViewControllerDelegate? private let viewModel: CategoryViewModel private let input = PassthroughSubject() private var cancellables = Set() @@ -18,7 +24,7 @@ final class CategoryViewController: UIViewController { } required init?(coder: NSCoder) { - self.viewModel = CategoryViewModel() + self.viewModel = CategoryViewModel(categories: ["전체", "즐겨찾기"]) super.init(coder: coder) } @@ -35,8 +41,7 @@ final class CategoryViewController: UIViewController { func calculateSheetHeight() -> CGFloat { let cellHeight = CategoryTableViewCell.height - // TODO: 데이터 개수 받아와서 계산하기 - let itemCount = CGFloat(2) // 전체 + 즐겨찾기 포함 + let itemCount = CGFloat(viewModel.categories.count) return (cellHeight * itemCount) + Constant.navigationBarHeight } @@ -112,7 +117,8 @@ extension CategoryViewController: UITableViewDelegate { _ tableView: UITableView, didSelectRowAt indexPath: IndexPath ) { - // TODO: 카테고리 선택 시 로직 필요 + delegate?.categoryViewController(self, didSelectCategoryIndex: indexPath.row) + dismiss(animated: true, completion: nil) } func tableView( @@ -158,7 +164,7 @@ extension CategoryViewController: UITableViewDataSource { _ tableView: UITableView, numberOfRowsInSection section: Int ) -> Int { - 2 + viewModel.categories.count } func tableView( @@ -169,8 +175,8 @@ extension CategoryViewController: UITableViewDataSource { withIdentifier: CategoryTableViewCell.identifier, for: indexPath ) as? CategoryTableViewCell else { return UITableViewCell() } + cell.configure(category: viewModel.categories[indexPath.row], isSelected: false) - // TODO: 전체, 즐겨찾기, 데이터 받아와서 셀 구성하기 return cell } } diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift index 3a003996..62600b4d 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift @@ -12,6 +12,11 @@ final class CategoryViewModel: ViewModelType { private let output = PassthroughSubject() private var cancellables = Set() + private(set) var categories: [String] + + init(categories: [String]) { + self.categories = categories + } func transform(input: AnyPublisher) -> AnyPublisher { input.sink { [weak self] event in diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index cec64a20..ab54d0ce 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -38,6 +38,11 @@ public final class HomeViewController: UIViewController { private var cancellables = Set() private var floatingButtonBottomConstraint: NSLayoutConstraint? private var isFloatingButtonHidden = false + private var currentCategoryIndex = 0 { + didSet { + currentCategoryLabel.text = viewModel.categories[currentCategoryIndex] + } + } // MARK: - Initializer public init(viewModel: HomeViewModel) { @@ -115,8 +120,10 @@ public final class HomeViewController: UIViewController { private func configureAction() { categorySelectButton.addAction(UIAction { [weak self] _ in - let categoryViewModel = CategoryViewModel() + guard let self else { return } + let categoryViewModel = CategoryViewModel(categories: self.viewModel.categories) let categoryViewController = CategoryViewController(viewModel: categoryViewModel) + categoryViewController.delegate = self let navigationController = UINavigationController(rootViewController: categoryViewController) if let sheet = navigationController.sheetPresentationController { @@ -125,7 +132,7 @@ public final class HomeViewController: UIViewController { }] } - self?.present(navigationController, animated: true) + self.present(navigationController, animated: true) }, for: .touchUpInside) makingBookFloatingButton.addAction(UIAction { [weak self] _ in @@ -244,3 +251,9 @@ extension HomeViewController: UICollectionViewDataSource { return cell } } + +extension HomeViewController: CategoryViewControllerDelegate { + func categoryViewController(_ categoryViewController: CategoryViewController, didSelectCategoryIndex index: Int) { + currentCategoryIndex = index + } +} From a5780885a24bf0efab0cdede904267eecf508a30 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 22:33:46 +0900 Subject: [PATCH 19/42] =?UTF-8?q?feat:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=99=88=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EC=B1=85=20=ED=95=84=ED=84=B0=EB=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Home/HomeViewController.swift | 7 +++++-- .../Source/Home/HomeViewModel.swift | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index ab54d0ce..fc578427 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -94,6 +94,8 @@ public final class HomeViewController: UIViewController { switch event { case .fetchedUserHouse: self.updateUserHouse() + case .filteredBooks: + self.collectionView.reloadData() } }.store(in: &cancellables) } @@ -226,7 +228,7 @@ extension HomeViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - viewModel.bookCovers.count + viewModel.currentBookCovers.count } public func collectionView( @@ -239,7 +241,7 @@ extension HomeViewController: UICollectionViewDataSource { ) as? BookCollectionViewCell else { return UICollectionViewCell() } // TODO: Image Loader 필요 & 메모리 캐싱 필요 - let bookCover = viewModel.bookCovers[indexPath.item] + let bookCover = viewModel.currentBookCovers[indexPath.item] cell.configure( title: bookCover.title, bookCoverImage: bookCover.color.image, @@ -255,5 +257,6 @@ extension HomeViewController: UICollectionViewDataSource { extension HomeViewController: CategoryViewControllerDelegate { func categoryViewController(_ categoryViewController: CategoryViewController, didSelectCategoryIndex index: Int) { currentCategoryIndex = index + input.send(.selectedCategory(index: index)) } } diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift index d1e9e3aa..3e013271 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift @@ -5,10 +5,12 @@ import MHDomain public final class HomeViewModel: ViewModelType { enum Input { case viewDidLoad + case selectedCategory(index: Int) } enum Output { case fetchedUserHouse + case filteredBooks } private let output = PassthroughSubject() @@ -17,6 +19,7 @@ public final class HomeViewModel: ViewModelType { private(set) var houseName = "" private(set) var categories = ["전체", "즐겨찾기"] private(set) var bookCovers = [BookCover]() + private(set) var currentBookCovers = [BookCover]() public init(fetchUserHouseUseCase: FetchUserHouseUseCase) { self.fetchUserHouseUseCase = fetchUserHouseUseCase @@ -28,6 +31,8 @@ public final class HomeViewModel: ViewModelType { switch event { case .viewDidLoad: self?.fetchUserHouse() + case .selectedCategory(let index): + self?.filterBooks(with: index) } }.store(in: &cancellables) @@ -41,8 +46,21 @@ public final class HomeViewModel: ViewModelType { self.houseName = userHouse.name self.categories.append(contentsOf: userHouse.categories) self.bookCovers = userHouse.bookCovers + self.currentBookCovers = userHouse.bookCovers output.send(.fetchedUserHouse) MHLogger.debug("\(#function): \(userHouse)") } } + + private func filterBooks(with index: Int) { + if index == 0 { + currentBookCovers = bookCovers + } else if index == 1 { + currentBookCovers = bookCovers.filter { $0.favorite } + } else { + currentBookCovers = bookCovers.filter { $0.category == categories[index] } + } + + output.send(.filteredBooks) + } } From 473ad10eb88455eb193a1eff05f6d85f30629130 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 22:50:04 +0900 Subject: [PATCH 20/42] =?UTF-8?q?feat:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=8B=9C=ED=8A=B8=EC=A7=80=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=98=84=EC=9E=AC=20=EC=84=A0=ED=83=9D=EC=A4=91=EC=9D=B8=20?= =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Category/CategoryViewController.swift | 5 +++-- .../MHPresentation/Source/Category/CategoryViewModel.swift | 4 +++- .../MHPresentation/Source/Home/HomeViewController.swift | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift index 863a5671..c75e3625 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift @@ -24,7 +24,7 @@ final class CategoryViewController: UIViewController { } required init?(coder: NSCoder) { - self.viewModel = CategoryViewModel(categories: ["전체", "즐겨찾기"]) + self.viewModel = CategoryViewModel(categories: ["전체", "즐겨찾기"], currentCategoryIndex: 0) super.init(coder: coder) } @@ -175,7 +175,8 @@ extension CategoryViewController: UITableViewDataSource { withIdentifier: CategoryTableViewCell.identifier, for: indexPath ) as? CategoryTableViewCell else { return UITableViewCell() } - cell.configure(category: viewModel.categories[indexPath.row], isSelected: false) + let isSelected = indexPath.row == viewModel.currentCategoryIndex + cell.configure(category: viewModel.categories[indexPath.row], isSelected: isSelected) return cell } diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift index 62600b4d..dbf92c16 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift @@ -13,9 +13,11 @@ final class CategoryViewModel: ViewModelType { private let output = PassthroughSubject() private var cancellables = Set() private(set) var categories: [String] + private(set) var currentCategoryIndex: Int - init(categories: [String]) { + init(categories: [String], currentCategoryIndex: Int) { self.categories = categories + self.currentCategoryIndex = currentCategoryIndex } func transform(input: AnyPublisher) -> AnyPublisher { diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index fc578427..6018776e 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -123,7 +123,10 @@ public final class HomeViewController: UIViewController { private func configureAction() { categorySelectButton.addAction(UIAction { [weak self] _ in guard let self else { return } - let categoryViewModel = CategoryViewModel(categories: self.viewModel.categories) + let categoryViewModel = CategoryViewModel( + categories: self.viewModel.categories, + currentCategoryIndex: self.currentCategoryIndex + ) let categoryViewController = CategoryViewController(viewModel: categoryViewModel) categoryViewController.delegate = self let navigationController = UINavigationController(rootViewController: categoryViewController) From 8d50ce82b5a5fd1558b167664b56c8daee914884 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 22:52:21 +0900 Subject: [PATCH 21/42] =?UTF-8?q?chore:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Category/CategoryViewController.swift | 14 --------- .../Source/Category/CategoryViewModel.swift | 29 +------------------ 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift index c75e3625..5bbb2597 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewController.swift @@ -14,7 +14,6 @@ final class CategoryViewController: UIViewController { // MARK: - Properties weak var delegate: CategoryViewControllerDelegate? private let viewModel: CategoryViewModel - private let input = PassthroughSubject() private var cancellables = Set() // MARK: - Initializer @@ -33,8 +32,6 @@ final class CategoryViewController: UIViewController { super.viewDidLoad() setup() - bind() - input.send(.viewDidLoad) configureNavigationBar() configureConstraints() } @@ -57,17 +54,6 @@ final class CategoryViewController: UIViewController { ) } - private func bind() { - let output = viewModel.transform(input: input.eraseToAnyPublisher()) - - output.sink { [weak self] event in - switch event { - case .fetchedCategories: - self?.categoryTableView.reloadData() - } - }.store(in: &cancellables) - } - private func configureNavigationBar() { navigationController?.navigationBar.isHidden = false navigationController?.navigationBar.titleTextAttributes = [ diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift index dbf92c16..388baee3 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift @@ -1,17 +1,6 @@ -import Combine import MHFoundation -final class CategoryViewModel: ViewModelType { - enum Input { - case viewDidLoad - } - - enum Output { - case fetchedCategories - } - - private let output = PassthroughSubject() - private var cancellables = Set() +final class CategoryViewModel { private(set) var categories: [String] private(set) var currentCategoryIndex: Int @@ -19,20 +8,4 @@ final class CategoryViewModel: ViewModelType { self.categories = categories self.currentCategoryIndex = currentCategoryIndex } - - func transform(input: AnyPublisher) -> AnyPublisher { - input.sink { [weak self] event in - switch event { - case .viewDidLoad: - self?.fetchCategories() - } - }.store(in: &cancellables) - - return output.eraseToAnyPublisher() - } - - private func fetchCategories() { - // TODO: 데이터 받아오기 - output.send(.fetchedCategories) - } } From ac3d2b36854136dd90fd6b0a222438d95225cf5c Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 22:59:04 +0900 Subject: [PATCH 22/42] =?UTF-8?q?refactor:=20=EB=B7=B0=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=20=ED=95=84=ED=84=B0=EB=A7=81=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Home/HomeViewModel.swift | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift index 3e013271..1046dc95 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift @@ -47,20 +47,26 @@ public final class HomeViewModel: ViewModelType { self.categories.append(contentsOf: userHouse.categories) self.bookCovers = userHouse.bookCovers self.currentBookCovers = userHouse.bookCovers + output.send(.fetchedUserHouse) - MHLogger.debug("\(#function): \(userHouse)") } } private func filterBooks(with index: Int) { - if index == 0 { + guard index >= 0 && index < categories.count else { + MHLogger.error("유효하지 않은 인덱스: \(index)") + return + } + + switch categories[index] { + case "전체": currentBookCovers = bookCovers - } else if index == 1 { + case "즐겨찾기": currentBookCovers = bookCovers.filter { $0.favorite } - } else { + default: currentBookCovers = bookCovers.filter { $0.category == categories[index] } } - + output.send(.filteredBooks) } } From f5a3c4804c7f894f7fccf02ad8b21ba575748292 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Sun, 24 Nov 2024 23:23:29 +0900 Subject: [PATCH 23/42] =?UTF-8?q?fix:=20Stub=20=EB=A0=88=ED=8F=AC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=ED=9B=84=20Default=20=EB=A0=88=ED=8F=AC?= =?UTF-8?q?=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHApplication/Source/App/SceneDelegate.swift | 3 ++- .../MHData/Repository/DefaultUserHouseRepository.swift | 10 ++++++++++ MemorialHouse/MHData/MHData/Temp.swift | 8 -------- 3 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift delete mode 100644 MemorialHouse/MHData/MHData/Temp.swift diff --git a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift index 834767f6..ff27fb69 100644 --- a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift +++ b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift @@ -1,5 +1,6 @@ import UIKit import MHCore +import MHData import MHDomain import MHFoundation import MHPresentation @@ -36,7 +37,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { do { DIContainer.shared.register( UserHouseRepository.self, - object: StubUserHouseRepository() + object: DefaultUserHouseRepository() ) let userHouseRepository = try DIContainer.shared.resolve(UserHouseRepository.self) diff --git a/MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift b/MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift new file mode 100644 index 00000000..f1b3b47a --- /dev/null +++ b/MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift @@ -0,0 +1,10 @@ +import MHDomain + +public struct DefaultUserHouseRepository: UserHouseRepository { + public init() { } + + public func fetchUserHouse() async -> UserHouse { + // TODO: CoreData로부터 꺼내오기 + return UserHouse(name: "", categories: [], bookCovers: []) + } +} diff --git a/MemorialHouse/MHData/MHData/Temp.swift b/MemorialHouse/MHData/MHData/Temp.swift deleted file mode 100644 index 174dff24..00000000 --- a/MemorialHouse/MHData/MHData/Temp.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// Temp.swift -// MHData -// -// Created by 임정현 on 11/3/24. -// - -import Foundation From 46e5a47a64aea80d77b032f26728164bf923079d Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 00:51:32 +0900 Subject: [PATCH 24/42] =?UTF-8?q?feat:=20Entity=20=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=EC=97=90=20Equatable=20=EC=B1=84=ED=83=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift | 6 +++++- MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift index 21500299..d167faac 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift @@ -1,6 +1,6 @@ import MHFoundation -public struct BookCover: Sendable { +public struct BookCover: Equatable, Sendable { public let identifier = UUID() public let title: String public let imageURL: String @@ -21,4 +21,8 @@ public struct BookCover: Sendable { self.category = category self.favorite = favorite } + + public static func == (lhs: BookCover, rhs: BookCover) -> Bool { + lhs.identifier == rhs.identifier + } } diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift index d32c4307..562da5d8 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift @@ -1,4 +1,4 @@ -public struct UserHouse: Sendable { +public struct UserHouse: Equatable, Sendable { public let name: String public let categories: [String] public let bookCovers: [BookCover] @@ -12,4 +12,10 @@ public struct UserHouse: Sendable { self.categories = categories self.bookCovers = bookCovers } + + public static func == (lhs: UserHouse, rhs: UserHouse) -> Bool { + lhs.name == rhs.name + && lhs.categories == rhs.categories + && lhs.bookCovers == rhs.bookCovers + } } From 063c2e52ee3502a6d43fa9d61858da062871155b Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 00:52:15 +0900 Subject: [PATCH 25/42] =?UTF-8?q?feat:=20MHDomainTest=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain.xcodeproj/project.pbxproj | 131 ++++++++++++++++++ .../Stubs/StubUserHouseRepository.swift | 13 ++ .../MHDomainTests/UserHouseUseCaseTest.swift | 7 + 3 files changed, 151 insertions(+) create mode 100644 MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift create mode 100644 MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift diff --git a/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj b/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj index eec75035..adc4c428 100644 --- a/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj +++ b/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj @@ -7,17 +7,34 @@ objects = { /* Begin PBXBuildFile section */ + 0E931E4A2CF36949009B8645 /* MHDomain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE9AEB4E2CD7B31300F8471D /* MHDomain.framework */; platformFilter = ios; }; CE9AEBED2CD7BA0C00F8471D /* MHCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE9AEBEC2CD7BA0C00F8471D /* MHCore.framework */; }; DB382CCD2CD9B257000D7689 /* MHFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB382CCC2CD9B257000D7689 /* MHFoundation.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 0E931E4B2CF36949009B8645 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CE9AEB452CD7B31300F8471D /* Project object */; + proxyType = 1; + remoteGlobalIDString = CE9AEB4D2CD7B31300F8471D; + remoteInfo = MHDomain; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ + 0E931E462CF36949009B8645 /* MHDomainTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MHDomainTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CE9AEB4E2CD7B31300F8471D /* MHDomain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MHDomain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE9AEBEC2CD7BA0C00F8471D /* MHCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MHCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DB382CCC2CD9B257000D7689 /* MHFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MHFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ + 0E931E472CF36949009B8645 /* MHDomainTests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = MHDomainTests; + sourceTree = ""; + }; A8C9336F2CDFBCDD007D932A /* MHDomain */ = { isa = PBXFileSystemSynchronizedRootGroup; path = MHDomain; @@ -26,6 +43,14 @@ /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ + 0E931E432CF36949009B8645 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E931E4A2CF36949009B8645 /* MHDomain.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CE9AEB4B2CD7B31300F8471D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -42,6 +67,7 @@ isa = PBXGroup; children = ( A8C9336F2CDFBCDD007D932A /* MHDomain */, + 0E931E472CF36949009B8645 /* MHDomainTests */, CE9AEBEB2CD7BA0C00F8471D /* Frameworks */, CE9AEB4F2CD7B31300F8471D /* Products */, ); @@ -51,6 +77,7 @@ isa = PBXGroup; children = ( CE9AEB4E2CD7B31300F8471D /* MHDomain.framework */, + 0E931E462CF36949009B8645 /* MHDomainTests.xctest */, ); name = Products; sourceTree = ""; @@ -77,6 +104,29 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 0E931E452CF36949009B8645 /* MHDomainTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0E931E4F2CF36949009B8645 /* Build configuration list for PBXNativeTarget "MHDomainTests" */; + buildPhases = ( + 0E931E422CF36949009B8645 /* Sources */, + 0E931E432CF36949009B8645 /* Frameworks */, + 0E931E442CF36949009B8645 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0E931E4C2CF36949009B8645 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + 0E931E472CF36949009B8645 /* MHDomainTests */, + ); + name = MHDomainTests; + packageProductDependencies = ( + ); + productName = MHDomainTests; + productReference = 0E931E462CF36949009B8645 /* MHDomainTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; CE9AEB4D2CD7B31300F8471D /* MHDomain */ = { isa = PBXNativeTarget; buildConfigurationList = CE9AEB542CD7B31300F8471D /* Build configuration list for PBXNativeTarget "MHDomain" */; @@ -108,8 +158,12 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1610; LastUpgradeCheck = 1610; TargetAttributes = { + 0E931E452CF36949009B8645 = { + CreatedOnToolsVersion = 16.1; + }; CE9AEB4D2CD7B31300F8471D = { CreatedOnToolsVersion = 16.1; LastSwiftMigration = 1610; @@ -134,11 +188,19 @@ projectRoot = ""; targets = ( CE9AEB4D2CD7B31300F8471D /* MHDomain */, + 0E931E452CF36949009B8645 /* MHDomainTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 0E931E442CF36949009B8645 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CE9AEB4C2CD7B31300F8471D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -169,6 +231,13 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 0E931E422CF36949009B8645 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CE9AEB4A2CD7B31300F8471D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -178,7 +247,60 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 0E931E4C2CF36949009B8645 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + platformFilter = ios; + target = CE9AEB4D2CD7B31300F8471D /* MHDomain */; + targetProxy = 0E931E4B2CF36949009B8645 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ + 0E931E4D2CF36949009B8645 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = U5N99RCS73; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + MACOSX_DEPLOYMENT_TARGET = 15.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHDomainTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + XROS_DEPLOYMENT_TARGET = 2.1; + }; + name = Debug; + }; + 0E931E4E2CF36949009B8645 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = U5N99RCS73; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + MACOSX_DEPLOYMENT_TARGET = 15.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHDomainTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + XROS_DEPLOYMENT_TARGET = 2.1; + }; + name = Release; + }; CE9AEB552CD7B31300F8471D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -388,6 +510,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 0E931E4F2CF36949009B8645 /* Build configuration list for PBXNativeTarget "MHDomainTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E931E4D2CF36949009B8645 /* Debug */, + 0E931E4E2CF36949009B8645 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; CE9AEB482CD7B31300F8471D /* Build configuration list for PBXProject "MHDomain" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift b/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift new file mode 100644 index 00000000..5b59b047 --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift @@ -0,0 +1,13 @@ +@testable import MHDomain + +public struct StubUserHouseRepository: UserHouseRepository { + private let dummyData: UserHouse + + public init(dummyData: UserHouse) { + self.dummyData = dummyData + } + + public func fetchUserHouse() async -> UserHouse { + return dummyData + } +} diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift new file mode 100644 index 00000000..cb656b7a --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -0,0 +1,7 @@ +import Testing +import MHDomain + +struct UserHouseUseCaseTest { + var sut: FetchUserHouseUseCase! + +} From 35cca0f970fa8f32dfffdd45ef2403a8a7aa83ae Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 00:52:27 +0900 Subject: [PATCH 26/42] =?UTF-8?q?feat:=20UserHouseUseCaseTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomainTests/UserHouseUseCaseTest.swift | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift index cb656b7a..9982d68b 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -4,4 +4,57 @@ import MHDomain struct UserHouseUseCaseTest { var sut: FetchUserHouseUseCase! + @Test mutating func test유저하우스_엔티티모델_가져오기() async throws { + // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 + let dummyUserHouse = UserHouse( + name: "효준", + categories: ["가족", "친구"], + bookCovers: [ + BookCover(title: "책1", imageURL: "Temp", color: .beige, category: "가족"), + BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") + ] + ) + let stubUserHouseRepository = StubUserHouseRepository(dummyData: dummyUserHouse) + self.sut = DefaultFetchUserHouseUseCase(repository: stubUserHouseRepository) + + // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 + let result = await sut.execute() + + // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 + #expect(result == dummyUserHouse) + } + + @Test mutating func test세글자_이상인_경우_글자_사이에_공백추가() async throws { + // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 + let dummyUserHouse = UserHouse( + name: "Hello", + categories: [], + bookCovers: [] + ) + let stubUserHouseRepository = StubUserHouseRepository(dummyData: dummyUserHouse) + self.sut = DefaultFetchUserHouseUseCase(repository: stubUserHouseRepository) + + // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 + let result = await sut.execute() + + // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 + #expect(result.name == "H e l l o") + } + + @Test mutating func test두글자_이하인_경우_원본_문자열_그대로_반환() async throws { + // Arrange + let dummyUserHouse = UserHouse( + name: "Hi", + categories: [], + bookCovers: [] + ) + let stubUserHouseRepository = StubUserHouseRepository(dummyData: dummyUserHouse) + self.sut = DefaultFetchUserHouseUseCase(repository: stubUserHouseRepository) + + // Act + let result = await sut.execute() + + // Assert + #expect(result.name == "Hi") + } } From 88e9190fe82664ad398695c41b2d5f7515914e59 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 01:06:33 +0900 Subject: [PATCH 27/42] =?UTF-8?q?feat:=20MHPresentation=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHPresentation.xcodeproj/project.pbxproj | 129 ++++++++++++++++++ .../HomeViewModelTest.swift | 7 + .../Stubs/StubFetchUserHouseUseCase.swift | 13 ++ 3 files changed, 149 insertions(+) create mode 100644 MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift create mode 100644 MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift diff --git a/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj b/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj index 4453895b..b7983880 100644 --- a/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj +++ b/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj @@ -7,12 +7,24 @@ objects = { /* Begin PBXBuildFile section */ + 0E931E5F2CF38390009B8645 /* MHPresentation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE9AEB992CD7B4F200F8471D /* MHPresentation.framework */; platformFilter = ios; }; CE9AEBAB2CD7B51D00F8471D /* MHDomain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE9AEBAA2CD7B51D00F8471D /* MHDomain.framework */; }; CE9AEBFA2CD7BA2000F8471D /* MHCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE9AEBF92CD7BA2000F8471D /* MHCore.framework */; }; DB382CC52CD9B22E000D7689 /* MHFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB382CC42CD9B22E000D7689 /* MHFoundation.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 0E931E602CF38390009B8645 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CE9AEB902CD7B4F200F8471D /* Project object */; + proxyType = 1; + remoteGlobalIDString = CE9AEB982CD7B4F200F8471D; + remoteInfo = MHPresentation; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ + 0E931E5B2CF38390009B8645 /* MHPresentationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MHPresentationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CE9AEB992CD7B4F200F8471D /* MHPresentation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MHPresentation.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE9AEBAA2CD7B51D00F8471D /* MHDomain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MHDomain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE9AEBF92CD7BA2000F8471D /* MHCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MHCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -43,6 +55,11 @@ /* End PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ + 0E931E5C2CF38390009B8645 /* MHPresentationTests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = MHPresentationTests; + sourceTree = ""; + }; A8C9335B2CDFBCD4007D932A /* MHPresentation */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( @@ -55,6 +72,14 @@ /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ + 0E931E582CF38390009B8645 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E931E5F2CF38390009B8645 /* MHPresentation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CE9AEB962CD7B4F200F8471D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -72,6 +97,7 @@ isa = PBXGroup; children = ( A8C9335B2CDFBCD4007D932A /* MHPresentation */, + 0E931E5C2CF38390009B8645 /* MHPresentationTests */, CE9AEBA92CD7B51D00F8471D /* Frameworks */, CE9AEB9A2CD7B4F200F8471D /* Products */, ); @@ -81,6 +107,7 @@ isa = PBXGroup; children = ( CE9AEB992CD7B4F200F8471D /* MHPresentation.framework */, + 0E931E5B2CF38390009B8645 /* MHPresentationTests.xctest */, ); name = Products; sourceTree = ""; @@ -108,6 +135,29 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 0E931E5A2CF38390009B8645 /* MHPresentationTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0E931E622CF38390009B8645 /* Build configuration list for PBXNativeTarget "MHPresentationTests" */; + buildPhases = ( + 0E931E572CF38390009B8645 /* Sources */, + 0E931E582CF38390009B8645 /* Frameworks */, + 0E931E592CF38390009B8645 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0E931E612CF38390009B8645 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + 0E931E5C2CF38390009B8645 /* MHPresentationTests */, + ); + name = MHPresentationTests; + packageProductDependencies = ( + ); + productName = MHPresentationTests; + productReference = 0E931E5B2CF38390009B8645 /* MHPresentationTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; CE9AEB982CD7B4F200F8471D /* MHPresentation */ = { isa = PBXNativeTarget; buildConfigurationList = CE9AEB9F2CD7B4F200F8471D /* Build configuration list for PBXNativeTarget "MHPresentation" */; @@ -139,8 +189,12 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1610; LastUpgradeCheck = 1610; TargetAttributes = { + 0E931E5A2CF38390009B8645 = { + CreatedOnToolsVersion = 16.1; + }; CE9AEB982CD7B4F200F8471D = { CreatedOnToolsVersion = 16.1; LastSwiftMigration = 1610; @@ -165,11 +219,19 @@ projectRoot = ""; targets = ( CE9AEB982CD7B4F200F8471D /* MHPresentation */, + 0E931E5A2CF38390009B8645 /* MHPresentationTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 0E931E592CF38390009B8645 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CE9AEB972CD7B4F200F8471D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -201,6 +263,13 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 0E931E572CF38390009B8645 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CE9AEB952CD7B4F200F8471D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -210,7 +279,58 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 0E931E612CF38390009B8645 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + platformFilter = ios; + target = CE9AEB982CD7B4F200F8471D /* MHPresentation */; + targetProxy = 0E931E602CF38390009B8645 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ + 0E931E632CF38390009B8645 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = U5N99RCS73; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + MACOSX_DEPLOYMENT_TARGET = 15.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHPresentationTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2,7"; + XROS_DEPLOYMENT_TARGET = 2.1; + }; + name = Debug; + }; + 0E931E642CF38390009B8645 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = U5N99RCS73; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + MACOSX_DEPLOYMENT_TARGET = 15.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHPresentationTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2,7"; + XROS_DEPLOYMENT_TARGET = 2.1; + }; + name = Release; + }; CE9AEBA02CD7B4F200F8471D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -422,6 +542,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 0E931E622CF38390009B8645 /* Build configuration list for PBXNativeTarget "MHPresentationTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E931E632CF38390009B8645 /* Debug */, + 0E931E642CF38390009B8645 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; CE9AEB932CD7B4F200F8471D /* Build configuration list for PBXProject "MHPresentation" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift new file mode 100644 index 00000000..3bcc2c7c --- /dev/null +++ b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift @@ -0,0 +1,7 @@ +import Testing +import MHPresentation + +struct HomeViewModelTest { + var sut: HomeViewModel! + +} diff --git a/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift b/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift new file mode 100644 index 00000000..91c5164a --- /dev/null +++ b/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift @@ -0,0 +1,13 @@ +import MHDomain + +public struct StubFetchUserHouseUseCase: FetchUserHouseUseCase { + private var dummyUserHouse: UserHouse + + public init(dummyUserHouse: UserHouse) { + self.dummyUserHouse = dummyUserHouse + } + + public func execute() async -> UserHouse { + return dummyUserHouse + } +} From 6889e79d0c5a6786a49e63596f93416582bcbe0b Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 02:34:10 +0900 Subject: [PATCH 28/42] =?UTF-8?q?refactor:=20ViewModel=EC=9D=98=20Input-Ou?= =?UTF-8?q?tput=20public=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHPresentation/Source/Home/HomeViewModel.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift index 1046dc95..e0409998 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift @@ -3,12 +3,12 @@ import MHCore import MHDomain public final class HomeViewModel: ViewModelType { - enum Input { + public enum Input { case viewDidLoad case selectedCategory(index: Int) } - enum Output { + public enum Output { case fetchedUserHouse case filteredBooks } @@ -41,7 +41,7 @@ public final class HomeViewModel: ViewModelType { @MainActor private func fetchUserHouse() { - Task { + Task { @MainActor in let userHouse = await fetchUserHouseUseCase.execute() self.houseName = userHouse.name self.categories.append(contentsOf: userHouse.categories) From 291a2940dbd67c58d4f41e13188be6e7a1c84d40 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 02:34:38 +0900 Subject: [PATCH 29/42] =?UTF-8?q?refactor:=20@.testable=20=ED=82=A4?= =?UTF-8?q?=EC=9B=8C=EB=93=9C=20=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20int?= =?UTF-8?q?ernal=EC=97=90=EB=8F=84=20=EC=A0=91=EA=B7=BC=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=98=EA=B2=8C=20=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomainTests/UserHouseUseCaseTest.swift | 2 +- .../MHPresentationTests/HomeViewModelTest.swift | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift index 9982d68b..0ad64f4a 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -1,5 +1,5 @@ import Testing -import MHDomain +@testable import MHDomain struct UserHouseUseCaseTest { var sut: FetchUserHouseUseCase! diff --git a/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift index 3bcc2c7c..d292fc0d 100644 --- a/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift +++ b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift @@ -1,5 +1,7 @@ +import Combine import Testing -import MHPresentation +@testable import MHPresentation +@testable import MHDomain struct HomeViewModelTest { var sut: HomeViewModel! From b2a5e090b83ab9f2c42d2a7c4e16fb61e3768d08 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 02:34:49 +0900 Subject: [PATCH 30/42] =?UTF-8?q?feat:=20HomeViewModel=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeViewModelTest.swift | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift index d292fc0d..fdaf5af2 100644 --- a/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift +++ b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift @@ -5,5 +5,108 @@ import Testing struct HomeViewModelTest { var sut: HomeViewModel! + var cancellables = Set() + @MainActor + @Test mutating func test시작할때_UserHouse_모델을_가져온다() async throws { + // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 + let dummyUserHouse = UserHouse( + name: "효준", + categories: ["가족", "친구"], + bookCovers: [ + BookCover(title: "책1", imageURL: "Temp", color: .beige, category: "가족"), + BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") + ] + ) + let stubFetchUserHouseUseCase = StubFetchUserHouseUseCase(dummyUserHouse: dummyUserHouse) + self.sut = HomeViewModel(fetchUserHouseUseCase: stubFetchUserHouseUseCase) + + let input = PassthroughSubject() + var receivedOutputs: [HomeViewModel.Output] = [] + + sut.transform(input: input.eraseToAnyPublisher()) + .sink { output in + receivedOutputs.append(output) + } + .store(in: &cancellables) + + // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 + input.send(.viewDidLoad) + try await Task.sleep(nanoseconds: 500_000_000) + + // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 + #expect(sut.houseName == "효준") + #expect(sut.categories == ["전체", "즐겨찾기", "가족", "친구"]) + #expect(sut.bookCovers.count == 2) + } + + @MainActor + @Test mutating func test카테고리_선택시_해당_카테고리에_맞는_책들로_필터링한다() async throws { + // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 + let dummyUserHouse = UserHouse( + name: "효준", + categories: ["가족", "친구"], + bookCovers: [ + BookCover(title: "책1", imageURL: "Temp", color: .beige, category: "가족"), + BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") + ] + ) + let stubFetchUserHouseUseCase = StubFetchUserHouseUseCase(dummyUserHouse: dummyUserHouse) + self.sut = HomeViewModel(fetchUserHouseUseCase: stubFetchUserHouseUseCase) + + let input = PassthroughSubject() + var receivedOutputs: [HomeViewModel.Output] = [] + + sut.transform(input: input.eraseToAnyPublisher()) + .sink { output in + receivedOutputs.append(output) + } + .store(in: &cancellables) + + input.send(.viewDidLoad) + try await Task.sleep(nanoseconds: 500_000_000) + + // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 + input.send(.selectedCategory(index: 3)) // 전체, 즐겨찾기, 가족, 친구 중에서 친구 선택 + try await Task.sleep(nanoseconds: 500_000_000) + + // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 + #expect(sut.currentBookCovers.count == 1) + #expect(sut.currentBookCovers.first?.title == "책2") + } + + @MainActor + @Test mutating func test유효하지_않은_인덱스를_선택하면_에러를_발생시킨다() async throws { + // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 + let dummyUserHouse = UserHouse( + name: "효준", + categories: ["가족", "친구"], + bookCovers: [ + BookCover(title: "책1", imageURL: "Temp", color: .beige, category: "가족"), + BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") + ] + ) + let stubFetchUserHouseUseCase = StubFetchUserHouseUseCase(dummyUserHouse: dummyUserHouse) + self.sut = HomeViewModel(fetchUserHouseUseCase: stubFetchUserHouseUseCase) + + let input = PassthroughSubject() + var receivedOutputs: [HomeViewModel.Output] = [] + + sut.transform(input: input.eraseToAnyPublisher()) + .sink { output in + receivedOutputs.append(output) + } + .store(in: &cancellables) + + input.send(.viewDidLoad) + try await Task.sleep(nanoseconds: 500_000_000) + + // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 + receivedOutputs.removeAll() + input.send(.selectedCategory(index: 999)) + try await Task.sleep(nanoseconds: 500_000_000) + + // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 + #expect(receivedOutputs.isEmpty) + } } From 78ddd97e2760ff1a0de41a3b7ee653748fcbbdef Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 02:41:33 +0900 Subject: [PATCH 31/42] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EB=8F=99?= =?UTF-8?q?=EC=9D=BC=ED=95=98=EA=B2=8C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomainTests/UserHouseUseCaseTest.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift index 0ad64f4a..9fb766bf 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -42,7 +42,7 @@ struct UserHouseUseCaseTest { } @Test mutating func test두글자_이하인_경우_원본_문자열_그대로_반환() async throws { - // Arrange + // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 let dummyUserHouse = UserHouse( name: "Hi", categories: [], @@ -51,10 +51,10 @@ struct UserHouseUseCaseTest { let stubUserHouseRepository = StubUserHouseRepository(dummyData: dummyUserHouse) self.sut = DefaultFetchUserHouseUseCase(repository: stubUserHouseRepository) - // Act + // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 let result = await sut.execute() - // Assert + // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 #expect(result.name == "Hi") } } From ac53ec82e2fefb6c2cddae934f71ad578a497484 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 07:31:31 +0900 Subject: [PATCH 32/42] =?UTF-8?q?chore:=20UserHouse=20->=20MemorialHouse?= =?UTF-8?q?=EB=A1=9C=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/App/SceneDelegate.swift | 14 +++++------ .../DefaultUserHouseRepository.swift | 6 ++--- .../MHDomain/MHDomain/Entity/UserHouse.swift | 4 ++-- .../Repository/MemorialHouseRepository.swift | 3 +++ .../Repository/UserHouseRepository.swift | 3 --- .../UseCase/DefaultUserHouseUseCase.swift | 18 +++++++------- .../UseCase/Interface/UserHouseUseCase.swift | 4 ++-- .../Stubs/StubMemorialHouseRepository.swift | 13 ++++++++++ .../Stubs/StubUserHouseRepository.swift | 13 ---------- .../MHDomainTests/UserHouseUseCaseTest.swift | 24 +++++++++---------- .../Source/Home/HomeViewController.swift | 6 ++--- .../Source/Home/HomeViewModel.swift | 24 +++++++++---------- .../Source/Home/HomeViewModelFactory.swift | 8 +++---- .../HomeViewModelTest.swift | 20 ++++++++-------- .../Stubs/StubFetchMemorialHouseUseCase.swift | 13 ++++++++++ .../Stubs/StubFetchUserHouseUseCase.swift | 13 ---------- 16 files changed, 93 insertions(+), 93 deletions(-) create mode 100644 MemorialHouse/MHDomain/MHDomain/Repository/MemorialHouseRepository.swift delete mode 100644 MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift create mode 100644 MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift delete mode 100644 MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift create mode 100644 MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchMemorialHouseUseCase.swift delete mode 100644 MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift diff --git a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift index ff27fb69..1238b440 100644 --- a/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift +++ b/MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift @@ -36,20 +36,20 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { func registerDependency() { do { DIContainer.shared.register( - UserHouseRepository.self, - object: DefaultUserHouseRepository() + MemorialHouseRepository.self, + object: DefaultMemorialHouseRepository() ) - let userHouseRepository = try DIContainer.shared.resolve(UserHouseRepository.self) + let memorialHouseRepository = try DIContainer.shared.resolve(MemorialHouseRepository.self) DIContainer.shared.register( - FetchUserHouseUseCase.self, - object: DefaultFetchUserHouseUseCase(repository: userHouseRepository) + FetchMemorialHouseUseCase.self, + object: DefaultFetchMemorialHouseUseCase(repository: memorialHouseRepository) ) - let fetchUserHouseUseCase = try DIContainer.shared.resolve(FetchUserHouseUseCase.self) + let fetchMemorialHouseUseCase = try DIContainer.shared.resolve(FetchMemorialHouseUseCase.self) DIContainer.shared.register( HomeViewModelFactory.self, - object: HomeViewModelFactory(fetchUserHouseUseCase: fetchUserHouseUseCase) + object: HomeViewModelFactory(fetchMemorialHouseUseCase: fetchMemorialHouseUseCase) ) } catch let error as MHError { MHLogger.error("\(error.description)") diff --git a/MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift b/MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift index f1b3b47a..4c4c4907 100644 --- a/MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift +++ b/MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift @@ -1,10 +1,10 @@ import MHDomain -public struct DefaultUserHouseRepository: UserHouseRepository { +public struct DefaultMemorialHouseRepository: MemorialHouseRepository { public init() { } - public func fetchUserHouse() async -> UserHouse { + public func fetchMemorialHouse() async -> MemorialHouse { // TODO: CoreData로부터 꺼내오기 - return UserHouse(name: "", categories: [], bookCovers: []) + return MemorialHouse(name: "", categories: [], bookCovers: []) } } diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift index 562da5d8..ac47d811 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift @@ -1,4 +1,4 @@ -public struct UserHouse: Equatable, Sendable { +public struct MemorialHouse: Equatable, Sendable { public let name: String public let categories: [String] public let bookCovers: [BookCover] @@ -13,7 +13,7 @@ public struct UserHouse: Equatable, Sendable { self.bookCovers = bookCovers } - public static func == (lhs: UserHouse, rhs: UserHouse) -> Bool { + public static func == (lhs: MemorialHouse, rhs: MemorialHouse) -> Bool { lhs.name == rhs.name && lhs.categories == rhs.categories && lhs.bookCovers == rhs.bookCovers diff --git a/MemorialHouse/MHDomain/MHDomain/Repository/MemorialHouseRepository.swift b/MemorialHouse/MHDomain/MHDomain/Repository/MemorialHouseRepository.swift new file mode 100644 index 00000000..ae0713b6 --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomain/Repository/MemorialHouseRepository.swift @@ -0,0 +1,3 @@ +public protocol MemorialHouseRepository: Sendable { + func fetchMemorialHouse() async -> MemorialHouse +} diff --git a/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift b/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift deleted file mode 100644 index 4ea2846b..00000000 --- a/MemorialHouse/MHDomain/MHDomain/Repository/UserHouseRepository.swift +++ /dev/null @@ -1,3 +0,0 @@ -public protocol UserHouseRepository: Sendable { - func fetchUserHouse() async -> UserHouse -} diff --git a/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift index 639b0971..63939c0d 100644 --- a/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift +++ b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift @@ -1,18 +1,18 @@ -public struct DefaultFetchUserHouseUseCase: FetchUserHouseUseCase { - private let repository: UserHouseRepository +public struct DefaultFetchMemorialHouseUseCase: FetchMemorialHouseUseCase { + private let repository: MemorialHouseRepository - public init(repository: UserHouseRepository) { + public init(repository: MemorialHouseRepository) { self.repository = repository } - public func execute() async -> UserHouse { - let userHouse = await repository.fetchUserHouse() - let transformedName = transformHouseName(with: userHouse.name) + public func execute() async -> MemorialHouse { + let memorialHouse = await repository.fetchMemorialHouse() + let transformedName = transformHouseName(with: memorialHouse.name) - return UserHouse( + return MemorialHouse( name: transformedName, - categories: userHouse.categories, - bookCovers: userHouse.bookCovers + categories: memorialHouse.categories, + bookCovers: memorialHouse.bookCovers ) } diff --git a/MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift b/MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift index 3f7b0da9..c2adaafd 100644 --- a/MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift +++ b/MemorialHouse/MHDomain/MHDomain/UseCase/Interface/UserHouseUseCase.swift @@ -1,3 +1,3 @@ -public protocol FetchUserHouseUseCase: Sendable { - func execute() async -> UserHouse +public protocol FetchMemorialHouseUseCase: Sendable { + func execute() async -> MemorialHouse } diff --git a/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift b/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift new file mode 100644 index 00000000..fab971cd --- /dev/null +++ b/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift @@ -0,0 +1,13 @@ +@testable import MHDomain + +public struct StubMemorialHouseRepository: MemorialHouseRepository { + private let dummyData: MemorialHouse + + public init(dummyData: MemorialHouse) { + self.dummyData = dummyData + } + + public func fetchMemorialHouse() async -> MemorialHouse { + return dummyData + } +} diff --git a/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift b/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift deleted file mode 100644 index 5b59b047..00000000 --- a/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubUserHouseRepository.swift +++ /dev/null @@ -1,13 +0,0 @@ -@testable import MHDomain - -public struct StubUserHouseRepository: UserHouseRepository { - private let dummyData: UserHouse - - public init(dummyData: UserHouse) { - self.dummyData = dummyData - } - - public func fetchUserHouse() async -> UserHouse { - return dummyData - } -} diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift index 9fb766bf..453e8475 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -1,12 +1,12 @@ import Testing @testable import MHDomain -struct UserHouseUseCaseTest { - var sut: FetchUserHouseUseCase! +struct MemorialHouseUseCaseTest { + var sut: FetchMemorialHouseUseCase! @Test mutating func test유저하우스_엔티티모델_가져오기() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 - let dummyUserHouse = UserHouse( + let dummyMemorialHouse = MemorialHouse( name: "효준", categories: ["가족", "친구"], bookCovers: [ @@ -14,25 +14,25 @@ struct UserHouseUseCaseTest { BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") ] ) - let stubUserHouseRepository = StubUserHouseRepository(dummyData: dummyUserHouse) - self.sut = DefaultFetchUserHouseUseCase(repository: stubUserHouseRepository) + let stubMemorialHouseRepository = StubMemorialHouseRepository(dummyData: dummyMemorialHouse) + self.sut = DefaultFetchMemorialHouseUseCase(repository: stubMemorialHouseRepository) // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 let result = await sut.execute() // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 - #expect(result == dummyUserHouse) + #expect(result == dummyMemorialHouse) } @Test mutating func test세글자_이상인_경우_글자_사이에_공백추가() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 - let dummyUserHouse = UserHouse( + let dummyMemorialHouse = MemorialHouse( name: "Hello", categories: [], bookCovers: [] ) - let stubUserHouseRepository = StubUserHouseRepository(dummyData: dummyUserHouse) - self.sut = DefaultFetchUserHouseUseCase(repository: stubUserHouseRepository) + let stubMemorialHouseRepository = StubMemorialHouseRepository(dummyData: dummyMemorialHouse) + self.sut = DefaultFetchMemorialHouseUseCase(repository: stubMemorialHouseRepository) // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 let result = await sut.execute() @@ -43,13 +43,13 @@ struct UserHouseUseCaseTest { @Test mutating func test두글자_이하인_경우_원본_문자열_그대로_반환() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 - let dummyUserHouse = UserHouse( + let dummyMemorialHouse = MemorialHouse( name: "Hi", categories: [], bookCovers: [] ) - let stubUserHouseRepository = StubUserHouseRepository(dummyData: dummyUserHouse) - self.sut = DefaultFetchUserHouseUseCase(repository: stubUserHouseRepository) + let stubMemorialHouseRepository = StubMemorialHouseRepository(dummyData: dummyMemorialHouse) + self.sut = DefaultFetchMemorialHouseUseCase(repository: stubMemorialHouseRepository) // Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기 let result = await sut.execute() diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift index 6018776e..09348198 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift @@ -92,15 +92,15 @@ public final class HomeViewController: UIViewController { output.sink { [weak self] event in guard let self else { return } switch event { - case .fetchedUserHouse: - self.updateUserHouse() + case .fetchedMemorialHouse: + self.updateMemorialHouse() case .filteredBooks: self.collectionView.reloadData() } }.store(in: &cancellables) } - private func updateUserHouse() { + private func updateMemorialHouse() { // 네비게이션 타이틀 설정 let houseName = viewModel.houseName navigationBar.configureTitle(with: houseName) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift index e0409998..cbf5036a 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModel.swift @@ -9,20 +9,20 @@ public final class HomeViewModel: ViewModelType { } public enum Output { - case fetchedUserHouse + case fetchedMemorialHouse case filteredBooks } private let output = PassthroughSubject() - private var fetchUserHouseUseCase: FetchUserHouseUseCase + private var fetchMemorialHouseUseCase: FetchMemorialHouseUseCase private var cancellables = Set() private(set) var houseName = "" private(set) var categories = ["전체", "즐겨찾기"] private(set) var bookCovers = [BookCover]() private(set) var currentBookCovers = [BookCover]() - public init(fetchUserHouseUseCase: FetchUserHouseUseCase) { - self.fetchUserHouseUseCase = fetchUserHouseUseCase + public init(fetchMemorialHouseUseCase: FetchMemorialHouseUseCase) { + self.fetchMemorialHouseUseCase = fetchMemorialHouseUseCase } @MainActor @@ -30,7 +30,7 @@ public final class HomeViewModel: ViewModelType { input.sink { [weak self] event in switch event { case .viewDidLoad: - self?.fetchUserHouse() + self?.fetchMemorialHouse() case .selectedCategory(let index): self?.filterBooks(with: index) } @@ -40,15 +40,15 @@ public final class HomeViewModel: ViewModelType { } @MainActor - private func fetchUserHouse() { + private func fetchMemorialHouse() { Task { @MainActor in - let userHouse = await fetchUserHouseUseCase.execute() - self.houseName = userHouse.name - self.categories.append(contentsOf: userHouse.categories) - self.bookCovers = userHouse.bookCovers - self.currentBookCovers = userHouse.bookCovers + let memorialHouse = await fetchMemorialHouseUseCase.execute() + self.houseName = memorialHouse.name + self.categories.append(contentsOf: memorialHouse.categories) + self.bookCovers = memorialHouse.bookCovers + self.currentBookCovers = memorialHouse.bookCovers - output.send(.fetchedUserHouse) + output.send(.fetchedMemorialHouse) } } diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift index d644541c..e20344ed 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewModelFactory.swift @@ -1,13 +1,13 @@ import MHDomain public struct HomeViewModelFactory { - let fetchUserHouseUseCase: FetchUserHouseUseCase + let fetchMemorialHouseUseCase: FetchMemorialHouseUseCase - public init(fetchUserHouseUseCase: FetchUserHouseUseCase) { - self.fetchUserHouseUseCase = fetchUserHouseUseCase + public init(fetchMemorialHouseUseCase: FetchMemorialHouseUseCase) { + self.fetchMemorialHouseUseCase = fetchMemorialHouseUseCase } public func make() -> HomeViewModel { - HomeViewModel(fetchUserHouseUseCase: fetchUserHouseUseCase) + HomeViewModel(fetchMemorialHouseUseCase: fetchMemorialHouseUseCase) } } diff --git a/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift index fdaf5af2..8377c223 100644 --- a/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift +++ b/MemorialHouse/MHPresentation/MHPresentationTests/HomeViewModelTest.swift @@ -8,9 +8,9 @@ struct HomeViewModelTest { var cancellables = Set() @MainActor - @Test mutating func test시작할때_UserHouse_모델을_가져온다() async throws { + @Test mutating func test시작할때_MemorialHouse_모델을_가져온다() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 - let dummyUserHouse = UserHouse( + let dummyMemorialHouse = MemorialHouse( name: "효준", categories: ["가족", "친구"], bookCovers: [ @@ -18,8 +18,8 @@ struct HomeViewModelTest { BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") ] ) - let stubFetchUserHouseUseCase = StubFetchUserHouseUseCase(dummyUserHouse: dummyUserHouse) - self.sut = HomeViewModel(fetchUserHouseUseCase: stubFetchUserHouseUseCase) + let stubFetchMemorialHouseUseCase = StubFetchMemorialHouseUseCase(dummyMemorialHouse: dummyMemorialHouse) + self.sut = HomeViewModel(fetchMemorialHouseUseCase: stubFetchMemorialHouseUseCase) let input = PassthroughSubject() var receivedOutputs: [HomeViewModel.Output] = [] @@ -43,7 +43,7 @@ struct HomeViewModelTest { @MainActor @Test mutating func test카테고리_선택시_해당_카테고리에_맞는_책들로_필터링한다() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 - let dummyUserHouse = UserHouse( + let dummyMemorialHouse = MemorialHouse( name: "효준", categories: ["가족", "친구"], bookCovers: [ @@ -51,8 +51,8 @@ struct HomeViewModelTest { BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") ] ) - let stubFetchUserHouseUseCase = StubFetchUserHouseUseCase(dummyUserHouse: dummyUserHouse) - self.sut = HomeViewModel(fetchUserHouseUseCase: stubFetchUserHouseUseCase) + let stubFetchMemorialHouseUseCase = StubFetchMemorialHouseUseCase(dummyMemorialHouse: dummyMemorialHouse) + self.sut = HomeViewModel(fetchMemorialHouseUseCase: stubFetchMemorialHouseUseCase) let input = PassthroughSubject() var receivedOutputs: [HomeViewModel.Output] = [] @@ -78,7 +78,7 @@ struct HomeViewModelTest { @MainActor @Test mutating func test유효하지_않은_인덱스를_선택하면_에러를_발생시킨다() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 - let dummyUserHouse = UserHouse( + let dummyMemorialHouse = MemorialHouse( name: "효준", categories: ["가족", "친구"], bookCovers: [ @@ -86,8 +86,8 @@ struct HomeViewModelTest { BookCover(title: "책2", imageURL: "Temp", color: .beige, category: "친구") ] ) - let stubFetchUserHouseUseCase = StubFetchUserHouseUseCase(dummyUserHouse: dummyUserHouse) - self.sut = HomeViewModel(fetchUserHouseUseCase: stubFetchUserHouseUseCase) + let stubFetchMemorialHouseUseCase = StubFetchMemorialHouseUseCase(dummyMemorialHouse: dummyMemorialHouse) + self.sut = HomeViewModel(fetchMemorialHouseUseCase: stubFetchMemorialHouseUseCase) let input = PassthroughSubject() var receivedOutputs: [HomeViewModel.Output] = [] diff --git a/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchMemorialHouseUseCase.swift b/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchMemorialHouseUseCase.swift new file mode 100644 index 00000000..5b1239a7 --- /dev/null +++ b/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchMemorialHouseUseCase.swift @@ -0,0 +1,13 @@ +import MHDomain + +public struct StubFetchMemorialHouseUseCase: FetchMemorialHouseUseCase { + private var dummyMemorialHouse: MemorialHouse + + public init(dummyMemorialHouse: MemorialHouse) { + self.dummyMemorialHouse = dummyMemorialHouse + } + + public func execute() async -> MemorialHouse { + return dummyMemorialHouse + } +} diff --git a/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift b/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift deleted file mode 100644 index 91c5164a..00000000 --- a/MemorialHouse/MHPresentation/MHPresentationTests/Stubs/StubFetchUserHouseUseCase.swift +++ /dev/null @@ -1,13 +0,0 @@ -import MHDomain - -public struct StubFetchUserHouseUseCase: FetchUserHouseUseCase { - private var dummyUserHouse: UserHouse - - public init(dummyUserHouse: UserHouse) { - self.dummyUserHouse = dummyUserHouse - } - - public func execute() async -> UserHouse { - return dummyUserHouse - } -} From b65fe033ce5d9b3b751af50df23246d78df2e4e6 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 07:43:37 +0900 Subject: [PATCH 33/42] =?UTF-8?q?refactor:=20MHPresentationTests=EC=97=90?= =?UTF-8?q?=20macOS,=20visionOS=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHPresentation.xcodeproj/project.pbxproj | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj b/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj index b7983880..95aea260 100644 --- a/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj +++ b/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj @@ -302,10 +302,11 @@ PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHPresentationTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,7"; + TARGETED_DEVICE_FAMILY = "1,2"; XROS_DEPLOYMENT_TARGET = 2.1; }; name = Debug; @@ -323,10 +324,11 @@ PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHPresentationTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,7"; + TARGETED_DEVICE_FAMILY = "1,2"; XROS_DEPLOYMENT_TARGET = 2.1; }; name = Release; From e4c461b46a1a8e12e01c3a9e897d056133983757 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 07:47:59 +0900 Subject: [PATCH 34/42] =?UTF-8?q?fix:=20MemorialHouse=EC=97=90=20=EC=9E=88?= =?UTF-8?q?=EB=8D=98=20Equatable=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entity/{UserHouse.swift => MemorialHouse.swift} | 8 +------- .../MHDomain/MHDomainTests/UserHouseUseCaseTest.swift | 4 +++- 2 files changed, 4 insertions(+), 8 deletions(-) rename MemorialHouse/MHDomain/MHDomain/Entity/{UserHouse.swift => MemorialHouse.swift} (55%) diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift b/MemorialHouse/MHDomain/MHDomain/Entity/MemorialHouse.swift similarity index 55% rename from MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift rename to MemorialHouse/MHDomain/MHDomain/Entity/MemorialHouse.swift index ac47d811..5f59ba26 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/UserHouse.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/MemorialHouse.swift @@ -1,4 +1,4 @@ -public struct MemorialHouse: Equatable, Sendable { +public struct MemorialHouse: Sendable { public let name: String public let categories: [String] public let bookCovers: [BookCover] @@ -12,10 +12,4 @@ public struct MemorialHouse: Equatable, Sendable { self.categories = categories self.bookCovers = bookCovers } - - public static func == (lhs: MemorialHouse, rhs: MemorialHouse) -> Bool { - lhs.name == rhs.name - && lhs.categories == rhs.categories - && lhs.bookCovers == rhs.bookCovers - } } diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift index 453e8475..d579a363 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -21,7 +21,9 @@ struct MemorialHouseUseCaseTest { let result = await sut.execute() // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 - #expect(result == dummyMemorialHouse) + #expect(result.name == dummyMemorialHouse.name) + #expect(result.categories == dummyMemorialHouse.categories) + #expect(result.bookCovers == dummyMemorialHouse.bookCovers) } @Test mutating func test세글자_이상인_경우_글자_사이에_공백추가() async throws { From 3c28fb97d7b98d97f2bf373823b164744ccacd41 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 07:55:10 +0900 Subject: [PATCH 35/42] =?UTF-8?q?refactor:=20CategoryViewModel=EC=9D=84=20?= =?UTF-8?q?struct=EB=A1=9C=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Category/CategoryViewModel.swift | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift index 388baee3..07fc60b0 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Category/CategoryViewModel.swift @@ -1,11 +1,4 @@ -import MHFoundation - -final class CategoryViewModel { +struct CategoryViewModel { private(set) var categories: [String] private(set) var currentCategoryIndex: Int - - init(categories: [String], currentCategoryIndex: Int) { - self.categories = categories - self.currentCategoryIndex = currentCategoryIndex - } } From 18c85d35f9d439af0a6f7c246baea1f8b36445b7 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 08:01:24 +0900 Subject: [PATCH 36/42] =?UTF-8?q?refactor:=20Register=20->=20Home=20?= =?UTF-8?q?=EA=B0=88=20=EB=95=8C=20houseName=20=EB=84=98=EA=B2=A8=EC=A3=BC?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Register/View/RegisterViewController.swift | 2 +- .../Source/Register/ViewModel/RegisterViewModel.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift index 821c6792..1cf2d7c5 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Register/View/RegisterViewController.swift @@ -101,7 +101,7 @@ public final class RegisterViewController: UIViewController { switch event { case .registerButtonEnabled(let isEnabled): self?.registerButton.isEnabled = isEnabled - case .moveToHome(let houseName): + case .moveToHome: do { let homeViewModelFactory = try DIContainer.shared.resolve(HomeViewModelFactory.self) let homeViewModel = homeViewModelFactory.make() diff --git a/MemorialHouse/MHPresentation/MHPresentation/Source/Register/ViewModel/RegisterViewModel.swift b/MemorialHouse/MHPresentation/MHPresentation/Source/Register/ViewModel/RegisterViewModel.swift index 95a3f0e1..7a8d0c91 100644 --- a/MemorialHouse/MHPresentation/MHPresentation/Source/Register/ViewModel/RegisterViewModel.swift +++ b/MemorialHouse/MHPresentation/MHPresentation/Source/Register/ViewModel/RegisterViewModel.swift @@ -9,7 +9,7 @@ public final class RegisterViewModel: ViewModelType { enum Output { case registerButtonEnabled(isEnabled: Bool) - case moveToHome(destination: String) + case moveToHome } private let output = PassthroughSubject() @@ -43,6 +43,6 @@ public final class RegisterViewModel: ViewModelType { text, forKey: Constant.houseNameUserDefaultKey ) - output.send(.moveToHome(destination: text)) + output.send(.moveToHome) } } From 243aa863fd66f2c7adcc12255f94d37bdd5b9b86 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 11:02:54 +0900 Subject: [PATCH 37/42] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=ED=83=80=EA=B2=9F=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?16.0=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj | 4 ++-- .../MHPresentation/MHPresentation.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj b/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj index adc4c428..c055132e 100644 --- a/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj +++ b/MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj @@ -264,7 +264,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = U5N99RCS73; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MACOSX_DEPLOYMENT_TARGET = 15.1; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHDomainTests; @@ -286,7 +286,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = U5N99RCS73; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MACOSX_DEPLOYMENT_TARGET = 15.1; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHDomainTests; diff --git a/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj b/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj index 95aea260..8e8ac7cd 100644 --- a/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj +++ b/MemorialHouse/MHPresentation/MHPresentation.xcodeproj/project.pbxproj @@ -296,7 +296,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = U5N99RCS73; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MACOSX_DEPLOYMENT_TARGET = 15.1; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHPresentationTests; @@ -318,7 +318,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = U5N99RCS73; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MACOSX_DEPLOYMENT_TARGET = 15.1; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = kyxxn.MHPresentationTests; From 5b190806b0bae67f05c9d17f2c110d10b0b46ad7 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 14:18:59 +0900 Subject: [PATCH 38/42] =?UTF-8?q?fix:=202=EA=B8=80=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=EC=97=90=EB=A7=8C=20=EB=9D=84=EC=96=B4?= =?UTF-8?q?=EC=93=B0=EA=B8=B0=20=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B9=84?= =?UTF-8?q?=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/UseCase/DefaultUserHouseUseCase.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift index 63939c0d..5a88a9fb 100644 --- a/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift +++ b/MemorialHouse/MHDomain/MHDomain/UseCase/DefaultUserHouseUseCase.swift @@ -16,13 +16,13 @@ public struct DefaultFetchMemorialHouseUseCase: FetchMemorialHouseUseCase { ) } - /// 집 이름이 3글자 이상일 경우, 각 글자 사이에 공백을 추가하여 변환합니다. + /// 집 이름이 2글자인 경우, 각 글자 사이에 공백을 추가하여 변환합니다. /// /// - Parameter name: 원본 이름 문자열. - /// - Returns: 글자 사이에 공백이 추가된 문자열(3글자 이상인 경우). - /// 2글자 이하라면 원본 문자열 그대로 반환합니다. + /// - Returns: 글자 사이에 공백이 추가된 문자열(두 글자인 경우). + /// 한 글자, 혹은 세 글자 이상라면 원본 문자열 그대로 반환합니다. private func transformHouseName(with name: String) -> String { - guard name.count > 2 else { return name } + guard name.count == 2 else { return name } return name.map { String($0) }.joined(separator: " ") } } From 1fc9577cbc5a6fbff3f973e3341e47fb2381aecc Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 14:19:18 +0900 Subject: [PATCH 39/42] =?UTF-8?q?fix:=20=EB=91=90=20=EA=B8=80=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=EC=99=80=20=EB=82=98=EB=A8=B8?= =?UTF-8?q?=EC=A7=80=EC=9D=98=20=EA=B2=BD=EC=9A=B0=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomainTests/UserHouseUseCaseTest.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift index d579a363..ab80ea66 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -7,7 +7,7 @@ struct MemorialHouseUseCaseTest { @Test mutating func test유저하우스_엔티티모델_가져오기() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 let dummyMemorialHouse = MemorialHouse( - name: "효준", + name: "더미데이터", categories: ["가족", "친구"], bookCovers: [ BookCover(title: "책1", imageURL: "Temp", color: .beige, category: "가족"), @@ -26,7 +26,7 @@ struct MemorialHouseUseCaseTest { #expect(result.bookCovers == dummyMemorialHouse.bookCovers) } - @Test mutating func test세글자_이상인_경우_글자_사이에_공백추가() async throws { + @Test mutating func test세글자_이상인_경우_원본_문자열_그대로_반환() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 let dummyMemorialHouse = MemorialHouse( name: "Hello", @@ -40,10 +40,10 @@ struct MemorialHouseUseCaseTest { let result = await sut.execute() // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 - #expect(result.name == "H e l l o") + #expect(result.name == "Hello") } - @Test mutating func test두글자_이하인_경우_원본_문자열_그대로_반환() async throws { + @Test mutating func test두글자_이하인_경우_글자_사이에_공백추가() async throws { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 let dummyMemorialHouse = MemorialHouse( name: "Hi", @@ -57,6 +57,6 @@ struct MemorialHouseUseCaseTest { let result = await sut.execute() // Assert 검증 단계: 결과와 기대치를 비교해서 검증하기 - #expect(result.name == "Hi") + #expect(result.name == "H i") } } From d78fe3888a46ec1b24591f2013d268bdc3665e7f Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 14:19:34 +0900 Subject: [PATCH 40/42] =?UTF-8?q?fix:=20Stub=20Repository=EC=9D=98=20publi?= =?UTF-8?q?c=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomainTests/Stubs/StubMemorialHouseRepository.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift b/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift index fab971cd..c456146c 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/Stubs/StubMemorialHouseRepository.swift @@ -1,13 +1,13 @@ @testable import MHDomain -public struct StubMemorialHouseRepository: MemorialHouseRepository { +struct StubMemorialHouseRepository: MemorialHouseRepository { private let dummyData: MemorialHouse - public init(dummyData: MemorialHouse) { + init(dummyData: MemorialHouse) { self.dummyData = dummyData } - public func fetchMemorialHouse() async -> MemorialHouse { + func fetchMemorialHouse() async -> MemorialHouse { return dummyData } } From fa688a90640558ea5dd8297d3ee2fcd49d2dde39 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 14:24:36 +0900 Subject: [PATCH 41/42] =?UTF-8?q?refactor:=20BookCover=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomain/Entity/BookCover.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift index d167faac..91cf3dec 100644 --- a/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift +++ b/MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift @@ -1,20 +1,22 @@ import MHFoundation public struct BookCover: Equatable, Sendable { - public let identifier = UUID() + public let identifier: UUID public let title: String - public let imageURL: String + public let imageURL: String? public let color: BookColor - public let category: String + public let category: String? public let favorite: Bool public init( + identifier: UUID = .init(), title: String, - imageURL: String, + imageURL: String?, color: BookColor, - category: String, + category: String?, favorite: Bool = false ) { + self.identifier = identifier self.title = title self.imageURL = imageURL self.color = color From 26c6168208c95e96c0eb726605f374139ff8c059 Mon Sep 17 00:00:00 2001 From: Kyxxn Date: Mon, 25 Nov 2024 14:36:43 +0900 Subject: [PATCH 42/42] =?UTF-8?q?fix:=20MHDomain=EC=9D=98=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=97=90=EC=84=9C=20throws=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MHDomain/MHDomainTests/UserHouseUseCaseTest.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift index ab80ea66..62134a4c 100644 --- a/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift +++ b/MemorialHouse/MHDomain/MHDomainTests/UserHouseUseCaseTest.swift @@ -4,7 +4,7 @@ import Testing struct MemorialHouseUseCaseTest { var sut: FetchMemorialHouseUseCase! - @Test mutating func test유저하우스_엔티티모델_가져오기() async throws { + @Test mutating func test유저하우스_엔티티모델_가져오기() async { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 let dummyMemorialHouse = MemorialHouse( name: "더미데이터", @@ -26,7 +26,7 @@ struct MemorialHouseUseCaseTest { #expect(result.bookCovers == dummyMemorialHouse.bookCovers) } - @Test mutating func test세글자_이상인_경우_원본_문자열_그대로_반환() async throws { + @Test mutating func test세글자_이상인_경우_원본_문자열_그대로_반환() async { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 let dummyMemorialHouse = MemorialHouse( name: "Hello", @@ -43,7 +43,7 @@ struct MemorialHouseUseCaseTest { #expect(result.name == "Hello") } - @Test mutating func test두글자_이하인_경우_글자_사이에_공백추가() async throws { + @Test mutating func test두글자_이하인_경우_글자_사이에_공백추가() async { // Arrange 준비 단계: 테스트 대상 시스템(SUT)와 의존성을 원하는 상태로 만들기 let dummyMemorialHouse = MemorialHouse( name: "Hi",