Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

홈 화면에서 카테고리 별로 책 필터링하여 보여주기 #73

Merged
merged 42 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
28d2831
feat: UserHouse 모델 구현
Kyxxn Nov 22, 2024
a510a7f
feat: UserHouse에 대한 UseCase & Repository 구현
Kyxxn Nov 22, 2024
917fc8d
refactor: SceneDelegate에서 최초 뷰컨트롤러 선택 로직 변경
Kyxxn Nov 23, 2024
47ec366
refactor: DIContainer shared를 MainActor로 변환
Kyxxn Nov 23, 2024
fd0e502
refactor: BookCover 모델 변경
Kyxxn Nov 23, 2024
92cebea
fix: HomeViewController의 MHDomain 의존성 제거
Kyxxn Nov 23, 2024
6b69911
feat: HomeViewModelFactory를 추가하여 Register -> Home 수정
Kyxxn Nov 23, 2024
72a5abb
fix: UserHouseRepository에 Sendable 추가
Kyxxn Nov 23, 2024
a558b54
feat: Home과 관련된 DI ViewModel & UseCase & Repo 등록
Kyxxn Nov 23, 2024
a16da91
refactor: SceneDelegate에서 HouseName 넘겨주는 로직 제거
Kyxxn Nov 24, 2024
274d8d5
fix: required init에 있는 강제추출 제거
Kyxxn Nov 24, 2024
e7b6bc2
refactor: Entity 모델에 Sendable 추가
Kyxxn Nov 24, 2024
a2b5feb
refactor: MHNavigationBar 생성 시점에 Title 입력이 아닌, configure로 변경
Kyxxn Nov 24, 2024
c67cb46
feat: HomeViewModel 바인딩
Kyxxn Nov 24, 2024
2beda37
feat: DefaultFetchUserHouseUseCase의 닉네임 사이 공백 추가 로직 구현
Kyxxn Nov 24, 2024
35de2bc
feat: ViewDidLoad 시점에 UserHouse Fetch 하여 UI 업데이트 구현
Kyxxn Nov 24, 2024
f27b853
feat: ViewModelType에 임시 MainActor 추가
Kyxxn Nov 24, 2024
4dff15d
feat: 카테고리 시트지에서 선택 시 홈화면의 현재 카테고리 UI 바뀌는 로직 구현
Kyxxn Nov 24, 2024
a578088
feat: 카테고리에 따른 홈 화면 책 필터링 구현
Kyxxn Nov 24, 2024
473ad10
feat: 카테고리 시트지에서 현재 선택중인 카테고리 체크표시
Kyxxn Nov 24, 2024
8d50ce8
chore: 사용하지 않는 코드 삭제
Kyxxn Nov 24, 2024
ac3d2b3
refactor: 뷰모델 필터링 로직 개선
Kyxxn Nov 24, 2024
f5a3c48
fix: Stub 레포 삭제 후 Default 레포 연동
Kyxxn Nov 24, 2024
46e5a47
feat: Entity 모델에 Equatable 채택
Kyxxn Nov 24, 2024
063c2e5
feat: MHDomainTest 세팅
Kyxxn Nov 24, 2024
35cca0f
feat: UserHouseUseCaseTest 테스트 구현
Kyxxn Nov 24, 2024
88e9190
feat: MHPresentation 테스트 구조 완성
Kyxxn Nov 24, 2024
6889e79
refactor: ViewModel의 Input-Output public 추가
Kyxxn Nov 24, 2024
291a294
refactor: @.testable 키워드 추가하여 internal에도 접근 가능하게 함
Kyxxn Nov 24, 2024
b2a5e09
feat: HomeViewModel 테스트 구현
Kyxxn Nov 24, 2024
78ddd97
chore: 주석 동일하게 처리
Kyxxn Nov 24, 2024
ac53ec8
chore: UserHouse -> MemorialHouse로 엔티티 모델 이름 변경
Kyxxn Nov 24, 2024
b65fe03
refactor: MHPresentationTests에 macOS, visionOS 제거
Kyxxn Nov 24, 2024
e4c461b
fix: MemorialHouse에 있던 Equatable 제거
Kyxxn Nov 24, 2024
3c28fb9
refactor: CategoryViewModel을 struct로 변환
Kyxxn Nov 24, 2024
18c85d3
refactor: Register -> Home 갈 때 houseName 넘겨주는 로직 제거
Kyxxn Nov 24, 2024
243aa86
chore: 테스트코드 타겟 버전 16.0으로 변경
Kyxxn Nov 25, 2024
5b19080
fix: 2글자인 경우에만 띄어쓰기 하도록 비즈니스 로직 수정
Kyxxn Nov 25, 2024
1fc9577
fix: 두 글자인 경우와 나머지의 경우에 대한 테스트 수정
Kyxxn Nov 25, 2024
d78fe38
fix: Stub Repository의 public 제거
Kyxxn Nov 25, 2024
fa688a9
refactor: BookCover 모델 변경
Kyxxn Nov 25, 2024
26c6168
fix: MHDomain의 테스트에서 throws 제거
Kyxxn Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import UIKit
import MHCore
import MHData
import MHDomain
import MHFoundation
import MHPresentation

Expand All @@ -12,16 +15,46 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let initialViewController: UIViewController
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())
registerDependency()

var initialViewController: UIViewController = RegisterViewController(viewModel: RegisterViewModel())
if UserDefaults.standard.object(forKey: Constant.houseNameUserDefaultKey) != nil {
do {
let viewModelFactory = try DIContainer.shared.resolve(HomeViewModelFactory.self)
let viewModel = viewModelFactory.make()
initialViewController = HomeViewController(viewModel: viewModel)
} catch {
MHLogger.error(error.localizedDescription)
}
Comment on lines +20 to +28
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 UserDefaults에서 이름을 꺼내고 HomeViewModel에 넘겨주던 로직을 제거하고,
HomeViewModel이 CoreData에 저장되어 있는 MemorialHouse 엔티티 모델로부터 이름을 받아오는 것으로 변경했습니다

}

let navigationController = UINavigationController(rootViewController: initialViewController)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
}

func registerDependency() {
do {
DIContainer.shared.register(
MemorialHouseRepository.self,
object: DefaultMemorialHouseRepository()
)

let memorialHouseRepository = try DIContainer.shared.resolve(MemorialHouseRepository.self)
DIContainer.shared.register(
FetchMemorialHouseUseCase.self,
object: DefaultFetchMemorialHouseUseCase(repository: memorialHouseRepository)
)

let fetchMemorialHouseUseCase = try DIContainer.shared.resolve(FetchMemorialHouseUseCase.self)
DIContainer.shared.register(
HomeViewModelFactory.self,
object: HomeViewModelFactory(fetchMemorialHouseUseCase: fetchMemorialHouseUseCase)
)
} catch let error as MHError {
MHLogger.error("\(error.description)")
} catch {
MHLogger.error("\(error.localizedDescription)")
}
}
}
4 changes: 2 additions & 2 deletions MemorialHouse/MHCore/MHCore/DIContainer.swift
Original file line number Diff line number Diff line change
@@ -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() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import MHDomain

public struct DefaultMemorialHouseRepository: MemorialHouseRepository {
public init() { }

public func fetchMemorialHouse() async -> MemorialHouse {
// TODO: CoreData로부터 꺼내오기

Check warning on line 7 in MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Todo Violation: TODOs should be resolved (CoreData로부터 꺼내오기) (todo)

Check warning on line 7 in MemorialHouse/MHData/MHData/Repository/DefaultUserHouseRepository.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Todo Violation: TODOs should be resolved (CoreData로부터 꺼내오기) (todo)
return MemorialHouse(name: "", categories: [], bookCovers: [])
}
}
8 changes: 0 additions & 8 deletions MemorialHouse/MHData/MHData/Temp.swift

This file was deleted.

131 changes: 131 additions & 0 deletions MemorialHouse/MHDomain/MHDomain.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "<group>";
};
A8C9336F2CDFBCDD007D932A /* MHDomain */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = MHDomain;
Expand All @@ -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;
Expand All @@ -42,6 +67,7 @@
isa = PBXGroup;
children = (
A8C9336F2CDFBCDD007D932A /* MHDomain */,
0E931E472CF36949009B8645 /* MHDomainTests */,
CE9AEBEB2CD7BA0C00F8471D /* Frameworks */,
CE9AEB4F2CD7B31300F8471D /* Products */,
);
Expand All @@ -51,6 +77,7 @@
isa = PBXGroup;
children = (
CE9AEB4E2CD7B31300F8471D /* MHDomain.framework */,
0E931E462CF36949009B8645 /* MHDomainTests.xctest */,
);
name = Products;
sourceTree = "<group>";
Expand All @@ -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" */;
Expand Down Expand Up @@ -108,8 +158,12 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1610;
LastUpgradeCheck = 1610;
TargetAttributes = {
0E931E452CF36949009B8645 = {
CreatedOnToolsVersion = 16.1;
};
CE9AEB4D2CD7B31300F8471D = {
CreatedOnToolsVersion = 16.1;
LastSwiftMigration = 1610;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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 = 16.0;
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 = 16.0;
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 = {
Expand Down Expand Up @@ -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 = (
Expand Down
2 changes: 1 addition & 1 deletion MemorialHouse/MHDomain/MHDomain/Entity/BookColor.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
public enum BookColor {
public enum BookColor: Sendable {
case beige
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: 엔티티에 Sendable을 붙여주는 이유가 무엇인가요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크린샷 2024-11-25 오후 2 42 17

붙이지 않으면 모델이 non-isolated 하다는 에러를 내뿜어서 일단 붙여둔 상태입니다..!

case blue
case green
Expand Down
30 changes: 18 additions & 12 deletions MemorialHouse/MHDomain/MHDomain/Entity/BookCover.swift
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import MHFoundation

public struct BookCover {
public let bookIdentifer = UUID()
public struct BookCover: Equatable, Sendable {
public let identifier: UUID
public let title: String
public let imageURL: String
public let bookColor: BookColor
public let category: String
public let isLike: Bool
public let imageURL: String?
public let color: BookColor
public let category: String?
public let favorite: Bool

public init(
identifier: UUID = .init(),
title: String,
imageURL: String,
bookColor: BookColor,
category: String,
isLike: Bool = false
imageURL: String?,
color: BookColor,
category: String?,
favorite: Bool = false
) {
self.identifier = identifier
self.title = title
self.imageURL = imageURL
self.bookColor = bookColor
self.color = color
self.category = category
self.isLike = isLike
self.favorite = favorite
}

public static func == (lhs: BookCover, rhs: BookCover) -> Bool {
lhs.identifier == rhs.identifier
}
}
15 changes: 15 additions & 0 deletions MemorialHouse/MHDomain/MHDomain/Entity/MemorialHouse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
public struct MemorialHouse: Sendable {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserHouse에서 MemorialHouse로 네이밍 변경했습니다

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
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public protocol MemorialHouseRepository: Sendable {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: 여기도 Sendable이 붙었군요.. 혹시 왜 붙었는지 알 수 있을까요??

func fetchMemorialHouse() async -> MemorialHouse
}
Loading
Loading