From ff40387f79bfbe8c37ee0e6785fc84861db0a0ca Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 19 May 2024 15:10:05 +0900 Subject: [PATCH 1/8] =?UTF-8?q?Add:=20MyReview=20=EB=A6=AC=EB=B8=94?= =?UTF-8?q?=EB=A0=9B=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pyonsnal-Color.xcodeproj/project.pbxproj | 26 ++++++++++- .../MyReview/MyReviewBuilder.swift | 39 ++++++++++++++++ .../MyReview/MyReviewInteractor.swift | 44 +++++++++++++++++++ .../MyReview/MyReviewRouter.swift | 26 +++++++++++ .../MyReview/MyReviewViewController.swift | 20 +++++++++ .../ProfileHome/ProfileHomeBuilder.swift | 3 ++ .../ProfileHome/ProfileHomeInteractor.swift | 7 +++ .../ProfileHome/ProfileHomeRouter.swift | 21 +++++++++ .../ProfileHomeViewController.swift | 37 +++++++++++++--- 9 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj index 2700944e..1e085d9c 100644 --- a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj +++ b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj @@ -261,6 +261,10 @@ F040E9D32A6D8E8800DF0C4A /* RefreshFilterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F040E9D22A6D8E8800DF0C4A /* RefreshFilterCell.swift */; }; F040E9D52A6D967300DF0C4A /* KeywordFilterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F040E9D42A6D967300DF0C4A /* KeywordFilterCell.swift */; }; F049E8C52A51CAE700E61199 /* ImageAssetKind+StoreTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = F049E8C42A51CAE700E61199 /* ImageAssetKind+StoreTag.swift */; }; + F0614E2C2BF9C901008AAF10 /* MyReviewRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E282BF9C901008AAF10 /* MyReviewRouter.swift */; }; + F0614E2D2BF9C901008AAF10 /* MyReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E292BF9C901008AAF10 /* MyReviewViewController.swift */; }; + F0614E2E2BF9C901008AAF10 /* MyReviewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E2A2BF9C901008AAF10 /* MyReviewBuilder.swift */; }; + F0614E2F2BF9C901008AAF10 /* MyReviewInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E2B2BF9C901008AAF10 /* MyReviewInteractor.swift */; }; F0687BED2A529679004B5EAE /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0687BEC2A529679004B5EAE /* Config.swift */; }; F068A9702A99E76A000AFD52 /* FilterRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */; }; F069DBE62A30B9850001D3DD /* UIFont+.swift in Sources */ = {isa = PBXBuildFile; fileRef = F069DBE52A30B9850001D3DD /* UIFont+.swift */; }; @@ -584,6 +588,10 @@ F040E9D22A6D8E8800DF0C4A /* RefreshFilterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshFilterCell.swift; sourceTree = ""; }; F040E9D42A6D967300DF0C4A /* KeywordFilterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeywordFilterCell.swift; sourceTree = ""; }; F049E8C42A51CAE700E61199 /* ImageAssetKind+StoreTag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ImageAssetKind+StoreTag.swift"; sourceTree = ""; }; + F0614E282BF9C901008AAF10 /* MyReviewRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewRouter.swift; sourceTree = ""; }; + F0614E292BF9C901008AAF10 /* MyReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewViewController.swift; sourceTree = ""; }; + F0614E2A2BF9C901008AAF10 /* MyReviewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewBuilder.swift; sourceTree = ""; }; + F0614E2B2BF9C901008AAF10 /* MyReviewInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewInteractor.swift; sourceTree = ""; }; F0687BEC2A529679004B5EAE /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterRenderable.swift; sourceTree = ""; }; F069DBE52A30B9850001D3DD /* UIFont+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+.swift"; sourceTree = ""; }; @@ -1334,6 +1342,7 @@ BA87E3DA2A4623D7000A9DEC /* Entity */, BA87E3C72A45C579000A9DEC /* ProductDetail */, B2538B8F2A3454FA00B7C3F0 /* ProfileHome */, + F0614E272BF9C8D4008AAF10 /* MyReview */, F075D0C32B052ED500DD0F5E /* ProfileEdit */, B2538B8E2A3454F100B7C3F0 /* EventHome */, B2538B8D2A3454EA00B7C3F0 /* ProductHome */, @@ -1517,6 +1526,17 @@ path = EventDetail; sourceTree = ""; }; + F0614E272BF9C8D4008AAF10 /* MyReview */ = { + isa = PBXGroup; + children = ( + F0614E282BF9C901008AAF10 /* MyReviewRouter.swift */, + F0614E292BF9C901008AAF10 /* MyReviewViewController.swift */, + F0614E2A2BF9C901008AAF10 /* MyReviewBuilder.swift */, + F0614E2B2BF9C901008AAF10 /* MyReviewInteractor.swift */, + ); + path = MyReview; + sourceTree = ""; + }; F0687BEB2A529666004B5EAE /* Config */ = { isa = PBXGroup; children = ( @@ -1973,6 +1993,10 @@ BA7532E22A595B140002659A /* UserAuthService.swift in Sources */, F0E915D52AAC9E3F000919DA /* CommonProductPageViewControllerRenderable.swift in Sources */, BA8924562A582EE700D1B097 /* NewTagBigView.swift in Sources */, + F0614E2C2BF9C901008AAF10 /* MyReviewRouter.swift in Sources */, + F0614E2D2BF9C901008AAF10 /* MyReviewViewController.swift in Sources */, + F0614E2E2BF9C901008AAF10 /* MyReviewBuilder.swift in Sources */, + F0614E2F2BF9C901008AAF10 /* MyReviewInteractor.swift in Sources */, F075D0C82B052EF300DD0F5E /* ProfileEditRouter.swift in Sources */, BA6CAB802AE84C6600B9E1BF /* UserInfoService.swift in Sources */, BAE442C22A6D2C7A00BD6582 /* LoadingReusableView.swift in Sources */, @@ -2490,7 +2514,7 @@ repositoryURL = "https://github.com/googleads/swift-package-manager-google-mobile-ads.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 10.14.0; + minimumVersion = 11.2.0; }; }; F0C9E0C62A7BF63600A53166 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift new file mode 100644 index 00000000..d058af96 --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift @@ -0,0 +1,39 @@ +// +// MyReviewBuilder.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs + +protocol MyReviewDependency: Dependency { + // TODO: Declare the set of dependencies required by this RIB, but cannot be + // created by this RIB. +} + +final class MyReviewComponent: Component { + + // TODO: Declare 'fileprivate' dependencies that are only used by this RIB. +} + +// MARK: - Builder + +protocol MyReviewBuildable: Buildable { + func build(withListener listener: MyReviewListener) -> MyReviewRouting +} + +final class MyReviewBuilder: Builder, MyReviewBuildable { + + override init(dependency: MyReviewDependency) { + super.init(dependency: dependency) + } + + func build(withListener listener: MyReviewListener) -> MyReviewRouting { + let component = MyReviewComponent(dependency: dependency) + let viewController = MyReviewViewController() + let interactor = MyReviewInteractor(presenter: viewController) + interactor.listener = listener + return MyReviewRouter(interactor: interactor, viewController: viewController) + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift new file mode 100644 index 00000000..fac593ac --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift @@ -0,0 +1,44 @@ +// +// MyReviewInteractor.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs + +protocol MyReviewRouting: ViewableRouting { + // TODO: Declare methods the interactor can invoke to manage sub-tree via the router. +} + +protocol MyReviewPresentable: Presentable { + var listener: MyReviewPresentableListener? { get set } + // TODO: Declare methods the interactor can invoke the presenter to present data. +} + +protocol MyReviewListener: AnyObject { + // TODO: Declare methods the interactor can invoke to communicate with other RIBs. +} + +final class MyReviewInteractor: PresentableInteractor, MyReviewInteractable, MyReviewPresentableListener { + + weak var router: MyReviewRouting? + weak var listener: MyReviewListener? + + // TODO: Add additional dependencies to constructor. Do not perform any logic + // in constructor. + override init(presenter: MyReviewPresentable) { + super.init(presenter: presenter) + presenter.listener = self + } + + override func didBecomeActive() { + super.didBecomeActive() + // TODO: Implement business logic here. + } + + override func willResignActive() { + super.willResignActive() + // TODO: Pause any business logic. + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift new file mode 100644 index 00000000..294385ed --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift @@ -0,0 +1,26 @@ +// +// MyReviewRouter.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs + +protocol MyReviewInteractable: Interactable { + var router: MyReviewRouting? { get set } + var listener: MyReviewListener? { get set } +} + +protocol MyReviewViewControllable: ViewControllable { + // TODO: Declare methods the router invokes to manipulate the view hierarchy. +} + +final class MyReviewRouter: ViewableRouter, MyReviewRouting { + + // TODO: Constructor inject child builder protocols to allow building children. + override init(interactor: MyReviewInteractable, viewController: MyReviewViewControllable) { + super.init(interactor: interactor, viewController: viewController) + interactor.router = self + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift new file mode 100644 index 00000000..52bd880c --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift @@ -0,0 +1,20 @@ +// +// MyReviewViewController.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs +import UIKit + +protocol MyReviewPresentableListener: AnyObject { + // TODO: Declare properties and methods that the view controller can invoke to perform + // business logic, such as signIn(). This protocol is implemented by the corresponding + // interactor class. +} + +final class MyReviewViewController: UIViewController, MyReviewPresentable, MyReviewViewControllable { + + weak var listener: MyReviewPresentableListener? +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeBuilder.swift b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeBuilder.swift index 00a9025c..0d833b88 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeBuilder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeBuilder.swift @@ -14,6 +14,7 @@ final class ProfileHomeComponent: Component, ProfileEditDependency, AccountSettingDependency, CommonWebDependency, + MyReviewDependency, LoggedOutDependency { var appleLoginService: AppleLoginService var kakaoLoginService: KakaoLoginService @@ -57,6 +58,7 @@ final class ProfileHomeBuilder: Builder, let profileEditBuilder = ProfileEditBuilder(dependency: component) let accountSettingBuilder = AccountSettingBuilder(dependency: component) let commonWebBuilder = CommonWebBuilder(dependency: component) + let myReviewBuilder = MyReviewBuilder(dependency: component) let loggedOutBuilder = LoggedOutBuilder(dependency: component) return ProfileHomeRouter( @@ -65,6 +67,7 @@ final class ProfileHomeBuilder: Builder, profileEditBuilder: profileEditBuilder, accountSettingBuilder: accountSettingBuilder, commonWebBuilder: commonWebBuilder, + myReviewBuilder: myReviewBuilder, loggedOutBuilder: loggedOutBuilder ) } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift index d1a62047..682062b3 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift @@ -18,6 +18,9 @@ protocol ProfileHomeRouting: ViewableRouting { func attachAccountSetting() func detachAccountSetting() + func attachMyReview() + func detachMyReview() + func attachLoggedOut() func detachLoggedOut() } @@ -67,6 +70,10 @@ final class ProfileHomeInteractor: PresentableInteractor }.store(in: &cancellable) } + func didTapMyReview() { + router?.attachMyReview() + } + func didTapAccountSetting() { router?.attachAccountSetting() } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift index 186ba899..2a90f365 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift @@ -11,6 +11,7 @@ protocol ProfileHomeInteractable: Interactable, ProfileEditListener, AccountSettingListener, CommonWebListener, + MyReviewListener, LoggedOutListener { var router: ProfileHomeRouting? { get set } var listener: ProfileHomeListener? { get set } @@ -35,6 +36,9 @@ final class ProfileHomeRouter: ViewableRouter() private var memberInfo: MemberInfoEntity? - private let sections: [Section] = [.setting] + private let sections: [Section] = [.review, .setting] + private var reviews: [Review] = [.review, .myReview] private var settings: [Setting] = [.etc, .email, .version, .teams, .account] // MARK: - Initializer @@ -162,6 +179,8 @@ extension ProfileHomeViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let section = sections[section] switch section { + case .review: + return reviews.count case .setting: return settings.count } @@ -173,11 +192,15 @@ extension ProfileHomeViewController: UITableViewDataSource { let section = sections[indexPath.section] let isSectionIndex = isSectionIndex(with: indexPath.row) let isSubLabelToShow = isSubLabelToShow(section: section, index: indexPath.row) + let title: String + switch section { + case .review: + title = reviews[indexPath.row].title case .setting: - cell.update(text: settings[indexPath.row].title, - isSectionIndex: isSectionIndex) + title = settings[indexPath.row].title } + cell.update(text: title, isSectionIndex: isSectionIndex) cell.setSubLabelHidden(isShow: isSubLabelToShow) return cell } @@ -195,6 +218,10 @@ extension ProfileHomeViewController: UITableViewDelegate { let section = sections[indexPath.section] if !isSectionIndex(with: indexPath.row) { switch section { + case .review: + if indexPath.row == Review.myReview.rawValue { + listener?.didTapMyReview() + } case .setting: if indexPath.row == Setting.email.rawValue { showEmailReport() From 058e2fccfc9b27773e2c97623a590a1400b97a13 Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 19 May 2024 15:04:35 +0900 Subject: [PATCH 2/8] =?UTF-8?q?Etc:=20google=20package=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xcshareddata/swiftpm/Package.resolved | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fbd11f36..728b9e7a 100644 --- a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "2ae251365e2bd450b633726d7085f35a9a46a0f82ec34d41708921f1b80bb996", "pins" : [ { "identity" : "abseil-cpp-binary", @@ -41,8 +42,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleDataTransport.git", "state" : { - "revision" : "98a00258d4518b7521253a70b7f70bb76d2120fe", - "version" : "9.2.4" + "revision" : "a637d318ae7ae246b02d7305121275bc75ed5565", + "version" : "9.4.0" } }, { @@ -50,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleUtilities.git", "state" : { - "revision" : "58d03d22beae762eaddbd30cb5a61af90d4b309f", - "version" : "7.11.3" + "revision" : "57a1d307f42df690fdef2637f3e5b776da02aad6", + "version" : "7.13.3" } }, { @@ -149,8 +150,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", "state" : { - "revision" : "70516c9e799a366ff90c1a70c09c48f7c076fd8a", - "version" : "10.14.0" + "revision" : "746253bf8803826e4de14c9e619739733ea8fb3b", + "version" : "11.5.0" } }, { @@ -158,8 +159,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", "state" : { - "revision" : "129fa838520cd02174f890ae0cfe0242e60714ae", - "version" : "2.1.0" + "revision" : "9b68aa69fb508f0274853e226c734151a973c7b7", + "version" : "2.4.0" } }, { @@ -172,5 +173,5 @@ } } ], - "version" : 2 + "version" : 3 } From f10e305160914f1daddac3bb271c79739fa7979b Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 19 May 2024 15:27:50 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Update:=20charactorView=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProfileHomeViewController.swift | 117 ++--------------- .../ProfileHome/ProfileHomeViewHolder.swift | 123 ++++++++++++++++++ 2 files changed, 133 insertions(+), 107 deletions(-) create mode 100644 Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewHolder.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewController.swift index e117b741..c8e738ef 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewController.swift @@ -21,17 +21,6 @@ protocol ProfileHomePresentableListener: AnyObject { final class ProfileHomeViewController: UIViewController, ProfileHomePresentable, ProfileHomeViewControllable { - - enum Size { - static let profileImageViewSize: CGFloat = 40 - static let profileEditButtonSize: CGFloat = 48 - static let profileImageViewLeading: CGFloat = 17 - static let profileContainerViewHeight: CGFloat = 104 - - static let dividerMargin: CGFloat = 12 - static let cellHeight: CGFloat = 48 - static let dividerHeight: CGFloat = 1 - } enum Section: String { case review // 리뷰 @@ -136,10 +125,17 @@ final class ProfileHomeViewController: UIViewController, guard let self, let memberInfo else { return } self.listener?.didTapProfileEditButton(memberInfo: memberInfo) }.store(in: &cancellable) + + viewHolder.charactorLandingButton + .tapPublisher + .throttle(for: 0.5, scheduler: RunLoop.main, latest: false) + .sink { [weak self] _ in + guard let self else { return } + // TODO: Landing to charactor page + }.store(in: &cancellable) } private func configureTabBarItem() { - tabBarItem.setTitleTextAttributes([.font: UIFont.label2], for: .normal) tabBarItem = UITabBarItem( title: "마이페이지", @@ -210,7 +206,7 @@ extension ProfileHomeViewController: UITableViewDataSource { extension ProfileHomeViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - let defaultHeight = Size.cellHeight + let defaultHeight: CGFloat = 48 return defaultHeight } @@ -238,100 +234,7 @@ extension ProfileHomeViewController: UITableViewDelegate { } } -// MARK: - UI Component -extension ProfileHomeViewController { - class ViewHolder: ViewHolderable { - - private let profileContainerView: UIView = { - let view = UIView() - view.backgroundColor = .white - return view - }() - - let profileImageView: UIImageView = { - let imageView = UIImageView() - imageView.contentMode = .scaleAspectFill - imageView.makeRounded(with: Size.profileImageViewSize / 2) - imageView.setImage(.tagStore) - return imageView - }() - - let nickNameLabel: UILabel = { - let label = UILabel() - label.font = .title2 - label.textColor = .black - label.numberOfLines = 1 - return label - }() - - let profileEditButton: UIButton = { - let button = UIButton() - button.setImage(ImageAssetKind.Profile.profileEdit.image, for: .normal) - return button - }() - - let tableView: UITableView = { - let tableView = UITableView() - tableView.separatorStyle = .none - tableView.bounces = false - return tableView - }() - - private let dividerView: UIView = { - let view = UIView() - view.backgroundColor = .gray100 - return view - }() - - func place(in view: UIView) { - view.addSubview(profileContainerView) - profileContainerView.addSubview(profileImageView) - profileContainerView.addSubview(nickNameLabel) - profileContainerView.addSubview(profileEditButton) - view.addSubview(dividerView) - view.addSubview(tableView) - } - - func configureConstraints(for view: UIView) { - profileContainerView.snp.makeConstraints { - $0.top.equalTo(view.safeAreaLayoutGuide.snp.top) - $0.leading.trailing.equalToSuperview() - $0.height.equalTo(Size.profileContainerViewHeight) - } - - profileImageView.snp.makeConstraints { - $0.size.equalTo(Size.profileImageViewSize) - $0.leading.equalToSuperview().offset(Size.profileImageViewLeading) - $0.centerY.equalToSuperview() - } - - nickNameLabel.snp.makeConstraints { - $0.leading.equalTo(profileImageView.snp.trailing).offset(.spacing12) - $0.centerY.equalTo(profileContainerView.snp.centerY) - $0.trailing.greaterThanOrEqualTo(profileEditButton.snp.leading).inset(.spacing12) - } - - profileEditButton.snp.makeConstraints { - $0.top.equalToSuperview().offset(.spacing28) - $0.trailing.equalToSuperview().inset(.spacing4) - $0.size.equalTo(Size.profileEditButtonSize) - } - - dividerView.snp.makeConstraints { - $0.top.equalTo(profileContainerView.snp.bottom) - $0.leading.trailing.equalToSuperview() - $0.height.equalTo(Size.dividerMargin) - } - - tableView.snp.makeConstraints { - $0.top.equalTo(dividerView.snp.bottom) - $0.leading.trailing.bottom.equalToSuperview() - } - - } - } -} - +// MARK: - MFMailComposeViewControllerDelegate extension ProfileHomeViewController: MFMailComposeViewControllerDelegate { func mailComposeController( _ controller: MFMailComposeViewController, diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewHolder.swift new file mode 100644 index 00000000..2449d84b --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeViewHolder.swift @@ -0,0 +1,123 @@ +// +// ProfileHomeViewHolder.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import UIKit +import SnapKit + +// MARK: - UI Component +extension ProfileHomeViewController { + class ViewHolder: ViewHolderable { + + enum Size { + static let profileImageViewSize: CGFloat = 40 + static let profileEditButtonSize: CGFloat = 48 + static let profileImageViewLeading: CGFloat = 17 + static let profileContainerViewHeight: CGFloat = 104 + static let charactorSlotViewHeight: CGFloat = 152 + } + + private let profileContainerView: UIView = { + let view = UIView() + view.backgroundColor = .white + return view + }() + + let profileImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFill + imageView.makeRounded(with: Size.profileImageViewSize / 2) + imageView.setImage(.tagStore) + return imageView + }() + + let nickNameLabel: UILabel = { + let label = UILabel() + label.font = .title2 + label.textColor = .black + label.numberOfLines = 1 + return label + }() + + let profileEditButton: UIButton = { + let button = UIButton() + button.setImage(ImageAssetKind.Profile.profileEdit.image, for: .normal) + return button + }() + + let tableView: UITableView = { + let tableView = UITableView() + tableView.separatorStyle = .none + tableView.bounces = false + return tableView + }() + + private let charactorSlotView: UIView = { + let view = UIView() + view.backgroundColor = .gray100 + return view + }() + + let charactorLandingButton: UIButton = { + let button = UIButton() + button.backgroundColor = .gray400 + return button + }() + + func place(in view: UIView) { + view.addSubview(profileContainerView) + profileContainerView.addSubview(profileImageView) + profileContainerView.addSubview(nickNameLabel) + profileContainerView.addSubview(profileEditButton) + view.addSubview(charactorSlotView) + charactorSlotView.addSubview(charactorLandingButton) + view.addSubview(tableView) + } + + func configureConstraints(for view: UIView) { + profileContainerView.snp.makeConstraints { + $0.top.equalTo(view.safeAreaLayoutGuide.snp.top) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(Size.profileContainerViewHeight) + } + + profileImageView.snp.makeConstraints { + $0.size.equalTo(Size.profileImageViewSize) + $0.leading.equalToSuperview().offset(Size.profileImageViewLeading) + $0.centerY.equalToSuperview() + } + + nickNameLabel.snp.makeConstraints { + $0.leading.equalTo(profileImageView.snp.trailing).offset(.spacing12) + $0.centerY.equalTo(profileContainerView.snp.centerY) + $0.trailing.greaterThanOrEqualTo(profileEditButton.snp.leading).inset(.spacing12) + } + + profileEditButton.snp.makeConstraints { + $0.top.equalToSuperview().offset(.spacing28) + $0.trailing.equalToSuperview().inset(.spacing4) + $0.size.equalTo(Size.profileEditButtonSize) + } + + charactorSlotView.snp.makeConstraints { + $0.top.equalTo(profileContainerView.snp.bottom) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(Size.charactorSlotViewHeight) + } + + charactorLandingButton.snp.makeConstraints { + $0.top.leading.equalToSuperview().offset(10) + $0.trailing.bottom.equalToSuperview().inset(10) + } + + tableView.snp.makeConstraints { + $0.top.equalTo(charactorSlotView.snp.bottom) + $0.leading.trailing.bottom.equalToSuperview() + } + + } + } +} From 344a0282b6eee7449653f1bde8077d6561add146 Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 19 May 2024 15:59:16 +0900 Subject: [PATCH 4/8] =?UTF-8?q?Add:=20Review=20product=20view=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pyonsnal-Color.xcodeproj/project.pbxproj | 12 +++ .../Common/Review/ProductInfoStackView.swift | 82 +++++++++++++++++++ .../DetailReviewViewController.swift | 10 +-- .../DetailReview/DetailReviewViewHolder.swift | 68 ++------------- .../MyReview/MyReviewViewController.swift | 16 ++++ .../MyReview/MyReviewViewHolder.swift | 46 +++++++++++ 6 files changed, 167 insertions(+), 67 deletions(-) create mode 100644 Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj index 1e085d9c..d7b6574b 100644 --- a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj +++ b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj @@ -265,6 +265,9 @@ F0614E2D2BF9C901008AAF10 /* MyReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E292BF9C901008AAF10 /* MyReviewViewController.swift */; }; F0614E2E2BF9C901008AAF10 /* MyReviewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E2A2BF9C901008AAF10 /* MyReviewBuilder.swift */; }; F0614E2F2BF9C901008AAF10 /* MyReviewInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E2B2BF9C901008AAF10 /* MyReviewInteractor.swift */; }; + F0614E312BF9D037008AAF10 /* ProfileHomeViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E302BF9D037008AAF10 /* ProfileHomeViewHolder.swift */; }; + F0614E332BF9D2F8008AAF10 /* MyReviewViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E322BF9D2F8008AAF10 /* MyReviewViewHolder.swift */; }; + F0614E352BF9D7D5008AAF10 /* ProductInfoStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E342BF9D7D5008AAF10 /* ProductInfoStackView.swift */; }; F0687BED2A529679004B5EAE /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0687BEC2A529679004B5EAE /* Config.swift */; }; F068A9702A99E76A000AFD52 /* FilterRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */; }; F069DBE62A30B9850001D3DD /* UIFont+.swift in Sources */ = {isa = PBXBuildFile; fileRef = F069DBE52A30B9850001D3DD /* UIFont+.swift */; }; @@ -592,6 +595,9 @@ F0614E292BF9C901008AAF10 /* MyReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewViewController.swift; sourceTree = ""; }; F0614E2A2BF9C901008AAF10 /* MyReviewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewBuilder.swift; sourceTree = ""; }; F0614E2B2BF9C901008AAF10 /* MyReviewInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewInteractor.swift; sourceTree = ""; }; + F0614E302BF9D037008AAF10 /* ProfileHomeViewHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHomeViewHolder.swift; sourceTree = ""; }; + F0614E322BF9D2F8008AAF10 /* MyReviewViewHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewViewHolder.swift; sourceTree = ""; }; + F0614E342BF9D7D5008AAF10 /* ProductInfoStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductInfoStackView.swift; sourceTree = ""; }; F0687BEC2A529679004B5EAE /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterRenderable.swift; sourceTree = ""; }; F069DBE52A30B9850001D3DD /* UIFont+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+.swift"; sourceTree = ""; }; @@ -708,6 +714,7 @@ B2EFFAB82ACBF63D007AF2EE /* StarView.swift */, B2EFFABA2ACBF680007AF2EE /* StarRatingView.swift */, B2EFFABC2ACBF69C007AF2EE /* StarRatedView.swift */, + F0614E342BF9D7D5008AAF10 /* ProductInfoStackView.swift */, ); path = Review; sourceTree = ""; @@ -892,6 +899,7 @@ B28205012A346FDD00F9242F /* ProfileHomeInteractor.swift */, F0EE10A22A4B242C00B8DF4F /* ProfileCell.swift */, F00609512A5EED4600A2A79D /* SettingInfo.swift */, + F0614E302BF9D037008AAF10 /* ProfileHomeViewHolder.swift */, ); path = ProfileHome; sourceTree = ""; @@ -1533,6 +1541,7 @@ F0614E292BF9C901008AAF10 /* MyReviewViewController.swift */, F0614E2A2BF9C901008AAF10 /* MyReviewBuilder.swift */, F0614E2B2BF9C901008AAF10 /* MyReviewInteractor.swift */, + F0614E322BF9D2F8008AAF10 /* MyReviewViewHolder.swift */, ); path = MyReview; sourceTree = ""; @@ -1953,6 +1962,7 @@ F0168D542A500AC900978ED9 /* EventDetailInteractor.swift in Sources */, BA87501C2A519A9200B80088 /* ImageAssetKind+StoreIcon.swift in Sources */, B24891632B3AD2E5009D0FBF /* HomeBannerEntity.swift in Sources */, + F0614E312BF9D037008AAF10 /* ProfileHomeViewHolder.swift in Sources */, B2F169D62A347208008199D8 /* RootTabBarBuilder.swift in Sources */, BA50FD092A680D2500721782 /* SearchBarView.swift in Sources */, BAE984472AACFFEF00ED22CB /* ProductDetailReviewCell.swift in Sources */, @@ -2013,6 +2023,7 @@ B24891672B3C2525009D0FBF /* EventBannerHeaderView.swift in Sources */, BA18C0A62A7596F5007D00BD /* BottomToTopPresentAnimator.swift in Sources */, BA18075C2A2F189A00295398 /* UIButton+.swift in Sources */, + F0614E352BF9D7D5008AAF10 /* ProductInfoStackView.swift in Sources */, BAD6AEFD2AEC52550062B16F /* ReviewEvaluationLabelView.swift in Sources */, BA50FD042A680AA900721782 /* ProductSearchInteractor.swift in Sources */, B28A592A2A6FCFED00431F39 /* SortFilterCell.swift in Sources */, @@ -2153,6 +2164,7 @@ BA87E3D72A45D40A000A9DEC /* GiftInformationView.swift in Sources */, F0B90DCC2ADD2167005DE34A /* FavoriteHomePageViewController.swift in Sources */, BA83225E2AB77E9E00D2E1EB /* ReviewEvaluationState.swift in Sources */, + F0614E332BF9D2F8008AAF10 /* MyReviewViewHolder.swift in Sources */, F0E915B12AA87BB4000919DA /* ControlSubscription.swift in Sources */, B28205042A346FDD00F9242F /* ProfileHomeBuilder.swift in Sources */, BAE984432AACFE3200ED22CB /* ProductDetailInformationCell.swift in Sources */, diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift new file mode 100644 index 00000000..f8764b94 --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift @@ -0,0 +1,82 @@ +// +// ProductInfoStackView.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import UIKit +import SnapKit + +class ProductInfoStackView: UIStackView { + let productImageView: UIImageView = { + let imageView = UIImageView() + imageView.makeBorder(width: 1, color: UIColor.gray200.cgColor) + imageView.makeRounded(with: .spacing16) + return imageView + }() + + private let productInformationStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.spacing = .spacing8 + stackView.alignment = .leading + stackView.distribution = .equalSpacing + return stackView + }() + + let storeImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + return imageView + }() + + let productNameLabel: UILabel = { + let label = UILabel() + label.font = .body3m + label.numberOfLines = 1 + return label + }() + + let starRatedView = StarRatedView(score: 0) + + override init(frame: CGRect) { + super.init(frame: .zero) + self.initialize() + self.configureView() + } + + required init(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func initialize() { + self.axis = .horizontal + self.alignment = .center + self.spacing = .spacing16 + self.isLayoutMarginsRelativeArrangement = true + self.layoutMargins = .init( + top: .spacing24, + left: .spacing16, + bottom: .spacing24, + right: 0 + ) + } + + private func configureView() { + self.addArrangedSubview(productImageView) + self.addArrangedSubview(productInformationStackView) + + self.productInformationStackView.addArrangedSubview(storeImageView) + self.productInformationStackView.addArrangedSubview(productNameLabel) + self.productInformationStackView.addArrangedSubview(starRatedView) + + self.productImageView.snp.makeConstraints { + $0.width.height.equalTo(100) + } + + self.storeImageView.snp.makeConstraints { + $0.height.equalTo(20) + } + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewController.swift index 5439de6d..969d78a5 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewController.swift @@ -69,8 +69,8 @@ final class DetailReviewViewController: UIViewController, private func configureView() { view.backgroundColor = .white viewHolder.detailReviewTextView.text = Constant.textViewPlaceholder - viewHolder.productImageView.setImage(with: productDetail.imageURL) - viewHolder.productNameLabel.text = productDetail.name + viewHolder.productInfoStackView.productImageView.setImage(with: productDetail.imageURL) + viewHolder.productInfoStackView.productNameLabel.text = productDetail.name setResizedStoreIcon(productDetail.storeType.storeIcon.image) updateStarRatedView(score: score) viewHolder.totalScrollView.addTapGesture( @@ -167,16 +167,16 @@ final class DetailReviewViewController: UIViewController, } private func updateStarRatedView(score: Int) { - viewHolder.starRatedView.updateScore(to: Double(score)) + viewHolder.productInfoStackView.starRatedView.updateScore(to: Double(score)) } private func setResizedStoreIcon(_ image: UIImage?) { - viewHolder.storeImageView.image = image + viewHolder.productInfoStackView.storeImageView.image = image if let storeIcon = image { let ratio = storeIcon.size.width / storeIcon.size.height let newWidth = Constant.storeIconHeight * ratio - viewHolder.storeImageView.snp.makeConstraints { + viewHolder.productInfoStackView.storeImageView.snp.makeConstraints { $0.width.equalTo(newWidth) } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift index c148f4c3..a0e6f023 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift @@ -48,52 +48,11 @@ extension DetailReviewViewController { return stackView }() - private let productTotalStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.alignment = .center - stackView.spacing = .spacing16 - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = .init( - top: .spacing24, - left: .spacing16, - bottom: .spacing24, - right: 0 - ) - return stackView - }() - - let productImageView: UIImageView = { - let imageView = UIImageView() - imageView.makeBorder(width: 1, color: UIColor.gray200.cgColor) - imageView.makeRounded(with: .spacing16) - return imageView - }() - - private let productInformationStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.spacing = .spacing8 - stackView.alignment = .leading - stackView.distribution = .equalSpacing - return stackView - }() - - let storeImageView: UIImageView = { - let imageView = UIImageView() - imageView.contentMode = .scaleAspectFit - return imageView - }() - - let productNameLabel: UILabel = { - let label = UILabel() - label.font = .body3m - label.numberOfLines = 1 - return label + let productInfoStackView: ProductInfoStackView = { + let infoStackView = ProductInfoStackView() + return infoStackView }() - let starRatedView = StarRatedView(score: 0) - private let separatorView: UIView = { let view = UIView() view.backgroundColor = .gray100 @@ -225,19 +184,12 @@ extension DetailReviewViewController { applyButtonBackgroundView.addSubview(applyReviewButton) - contentStackView.addArrangedSubview(productTotalStackView) + contentStackView.addArrangedSubview(productInfoStackView) contentStackView.addArrangedSubview(separatorView) contentStackView.addArrangedSubview(reviewButtonStackView) contentStackView.addArrangedSubview(detailReviewStackView) contentStackView.addArrangedSubview(imageUploadStackView) - productTotalStackView.addArrangedSubview(productImageView) - productTotalStackView.addArrangedSubview(productInformationStackView) - - productInformationStackView.addArrangedSubview(storeImageView) - productInformationStackView.addArrangedSubview(productNameLabel) - productInformationStackView.addArrangedSubview(starRatedView) - reviewButtonStackView.addArrangedSubview(tasteReview) reviewButtonStackView.addArrangedSubview(qualityReview) reviewButtonStackView.addArrangedSubview(priceReview) @@ -281,21 +233,13 @@ extension DetailReviewViewController { $0.height.equalToSuperview() } - productTotalStackView.snp.makeConstraints { + productInfoStackView.snp.makeConstraints { $0.leading.top.trailing.equalToSuperview() } - productImageView.snp.makeConstraints { - $0.width.height.equalTo(100) - } - - storeImageView.snp.makeConstraints { - $0.height.equalTo(20) - } - separatorView.snp.makeConstraints { $0.leading.trailing.equalToSuperview() - $0.top.equalTo(productTotalStackView.snp.bottom) + $0.top.equalTo(productInfoStackView.snp.bottom) $0.height.equalTo(12) } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift index 52bd880c..a1c58714 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift @@ -17,4 +17,20 @@ protocol MyReviewPresentableListener: AnyObject { final class MyReviewViewController: UIViewController, MyReviewPresentable, MyReviewViewControllable { weak var listener: MyReviewPresentableListener? + var viewHolder: MyReviewViewController.ViewHolder = .init() + + override func viewDidLoad() { + super.viewDidLoad() + viewHolder.place(in: view) + viewHolder.configureConstraints(for: view) + } + + func update(reviews: [ReviewEntity]) { + self.updateNavigationTitle(reviewCount: reviews.count) + } + + private func updateNavigationTitle(reviewCount: Int) { + let updatedTitle = Text.navigationTitleView + "(\(reviewCount))" + self.viewHolder.backNavigationView.setText(with: updatedTitle) + } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift new file mode 100644 index 00000000..66f5ea50 --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift @@ -0,0 +1,46 @@ +// +// MyReviewViewHolder.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import UIKit + +extension MyReviewViewController { + enum Text { + static let navigationTitleView = "내 리뷰" + } + + class ViewHolder: ViewHolderable { + let backNavigationView: BackNavigationView = { + let navigationView = BackNavigationView() + navigationView.payload = .init(mode: .text) + navigationView.setText(with: Text.navigationTitleView) + return navigationView + }() + + let tableView: UITableView = { + let tableView = UITableView() + return tableView + }() + + func place(in view: UIView) { + view.addSubview(backNavigationView) + view.addSubview(tableView) + } + + func configureConstraints(for view: UIView) { + backNavigationView.snp.makeConstraints { + $0.top.equalTo(view.safeAreaLayoutGuide) + $0.leading.trailing.equalTo(view) + } + + tableView.snp.makeConstraints { + $0.top.equalTo(backNavigationView.snp.bottom) + $0.leading.trailing.bottom.equalToSuperview() + } + } + + } +} From fb1ad98e853cc6aa1219d82c45070909e9b14c38 Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 19 May 2024 16:52:12 +0900 Subject: [PATCH 5/8] =?UTF-8?q?Add:=20=EB=82=B4=20=EB=A6=AC=EB=B7=B0=20vie?= =?UTF-8?q?w=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pyonsnal-Color.xcodeproj/project.pbxproj | 16 +++++ .../Common/Review/ProductInfoStackView.swift | 26 +++++++-- .../DetailReview/DetailReviewViewHolder.swift | 2 +- .../MyReview/MyReviewViewController.swift | 45 ++++++++++++++ .../MyReview/MyReviewViewHolder.swift | 2 +- .../View/MyReviewContentConfiguration.swift | 30 ++++++++++ .../MyReview/View/MyReviewContentView.swift | 58 +++++++++++++++++++ 7 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj index d7b6574b..c712175e 100644 --- a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj +++ b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj @@ -268,6 +268,8 @@ F0614E312BF9D037008AAF10 /* ProfileHomeViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E302BF9D037008AAF10 /* ProfileHomeViewHolder.swift */; }; F0614E332BF9D2F8008AAF10 /* MyReviewViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E322BF9D2F8008AAF10 /* MyReviewViewHolder.swift */; }; F0614E352BF9D7D5008AAF10 /* ProductInfoStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E342BF9D7D5008AAF10 /* ProductInfoStackView.swift */; }; + F0614E3E2BF9DD01008AAF10 /* MyReviewContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E3D2BF9DD01008AAF10 /* MyReviewContentView.swift */; }; + F0614E412BF9DE43008AAF10 /* MyReviewContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E402BF9DE43008AAF10 /* MyReviewContentConfiguration.swift */; }; F0687BED2A529679004B5EAE /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0687BEC2A529679004B5EAE /* Config.swift */; }; F068A9702A99E76A000AFD52 /* FilterRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */; }; F069DBE62A30B9850001D3DD /* UIFont+.swift in Sources */ = {isa = PBXBuildFile; fileRef = F069DBE52A30B9850001D3DD /* UIFont+.swift */; }; @@ -598,6 +600,8 @@ F0614E302BF9D037008AAF10 /* ProfileHomeViewHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHomeViewHolder.swift; sourceTree = ""; }; F0614E322BF9D2F8008AAF10 /* MyReviewViewHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewViewHolder.swift; sourceTree = ""; }; F0614E342BF9D7D5008AAF10 /* ProductInfoStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductInfoStackView.swift; sourceTree = ""; }; + F0614E3D2BF9DD01008AAF10 /* MyReviewContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewContentView.swift; sourceTree = ""; }; + F0614E402BF9DE43008AAF10 /* MyReviewContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewContentConfiguration.swift; sourceTree = ""; }; F0687BEC2A529679004B5EAE /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterRenderable.swift; sourceTree = ""; }; F069DBE52A30B9850001D3DD /* UIFont+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+.swift"; sourceTree = ""; }; @@ -1537,6 +1541,7 @@ F0614E272BF9C8D4008AAF10 /* MyReview */ = { isa = PBXGroup; children = ( + F0614E3F2BF9DE2D008AAF10 /* View */, F0614E282BF9C901008AAF10 /* MyReviewRouter.swift */, F0614E292BF9C901008AAF10 /* MyReviewViewController.swift */, F0614E2A2BF9C901008AAF10 /* MyReviewBuilder.swift */, @@ -1546,6 +1551,15 @@ path = MyReview; sourceTree = ""; }; + F0614E3F2BF9DE2D008AAF10 /* View */ = { + isa = PBXGroup; + children = ( + F0614E3D2BF9DD01008AAF10 /* MyReviewContentView.swift */, + F0614E402BF9DE43008AAF10 /* MyReviewContentConfiguration.swift */, + ); + path = View; + sourceTree = ""; + }; F0687BEB2A529666004B5EAE /* Config */ = { isa = PBXGroup; children = ( @@ -2087,6 +2101,7 @@ BA6CAB822AE8509000B9E1BF /* ReviewLikeCountEntity.swift in Sources */, F0D6FFAB2A39F89D00C55E27 /* UIView+.swift in Sources */, F0C2B9F12AA4740000ACF3D7 /* EventHomeViewHolder.swift in Sources */, + F0614E3E2BF9DD01008AAF10 /* MyReviewContentView.swift in Sources */, BAE984412AACFC3600ED22CB /* ProductDetailImageCell+ViewHolder.swift in Sources */, B24259102A594862006C5223 /* SortEntity.swift in Sources */, B24CAAE32A55AC2D005BE499 /* NotificationListBuilder.swift in Sources */, @@ -2234,6 +2249,7 @@ B224965B2ABD8A7700BC6B09 /* UIImage+.swift in Sources */, B28A59242A6FB2B200431F39 /* ProductFilterBuilder.swift in Sources */, B2C25CDB2B65166E005C6F0D /* ProductType.swift in Sources */, + F0614E412BF9DE43008AAF10 /* MyReviewContentConfiguration.swift in Sources */, F0DEABA02AAF410B00941A5F /* FavoriteHomeBuilder.swift in Sources */, BA00B7392A46B8BF00BB3795 /* Spacing.swift in Sources */, BA00B73C2A46B98700BB3795 /* SnapKit+.swift in Sources */, diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift index f8764b94..d716d96b 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift @@ -9,6 +9,11 @@ import UIKit import SnapKit class ProductInfoStackView: UIStackView { + enum Mode { + case starRating + case date + } + let productImageView: UIImageView = { let imageView = UIImageView() imageView.makeBorder(width: 1, color: UIColor.gray200.cgColor) @@ -40,10 +45,17 @@ class ProductInfoStackView: UIStackView { let starRatedView = StarRatedView(score: 0) - override init(frame: CGRect) { + let dateLabel: UILabel = { + let label = UILabel() + label.font = .body3r + label.textColor = .gray400 + return label + }() + + init(mode: Mode) { super.init(frame: .zero) self.initialize() - self.configureView() + self.configureView(with: mode) } required init(coder: NSCoder) { @@ -63,13 +75,19 @@ class ProductInfoStackView: UIStackView { ) } - private func configureView() { + private func configureView(with mode: Mode) { self.addArrangedSubview(productImageView) self.addArrangedSubview(productInformationStackView) self.productInformationStackView.addArrangedSubview(storeImageView) self.productInformationStackView.addArrangedSubview(productNameLabel) - self.productInformationStackView.addArrangedSubview(starRatedView) + + switch mode { + case .starRating: + self.productInformationStackView.addArrangedSubview(starRatedView) + case .date: + self.productInformationStackView.addArrangedSubview(dateLabel) + } self.productImageView.snp.makeConstraints { $0.width.height.equalTo(100) diff --git a/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift index a0e6f023..c92ddf4f 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/DetailReview/DetailReviewViewHolder.swift @@ -49,7 +49,7 @@ extension DetailReviewViewController { }() let productInfoStackView: ProductInfoStackView = { - let infoStackView = ProductInfoStackView() + let infoStackView = ProductInfoStackView(mode: .starRating) return infoStackView }() diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift index a1c58714..132f848e 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift @@ -23,14 +23,59 @@ final class MyReviewViewController: UIViewController, MyReviewPresentable, MyRev super.viewDidLoad() viewHolder.place(in: view) viewHolder.configureConstraints(for: view) + self.configureUI() + self.configureTableView() } func update(reviews: [ReviewEntity]) { self.updateNavigationTitle(reviewCount: reviews.count) } + // MARK: - Private Mehods + private func configureUI() { + self.view.backgroundColor = .white + } + private func updateNavigationTitle(reviewCount: Int) { let updatedTitle = Text.navigationTitleView + "(\(reviewCount))" self.viewHolder.backNavigationView.setText(with: updatedTitle) } + + private func configureTableView() { + self.viewHolder.tableView.register( + UITableViewCell.self, + forCellReuseIdentifier: MyReviewContentView.identifier + ) + self.viewHolder.tableView.delegate = self + self.viewHolder.tableView.dataSource = self + } +} + +// MARK: - UITableViewDelegate +extension MyReviewViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + // TODO: MyDetailReview + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return UITableView.automaticDimension + } +} + +// MARK: - UITableViewDataSource +extension MyReviewViewController: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 10 // TODO: interactor로부터 받아온 값으로 변경 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: MyReviewContentView.identifier, for: indexPath) + cell.contentConfiguration = MyReviewContentConfiguration( + storeImageIcon: .sevenEleven, + imageUrl: "", + title: "테스트", + date: "2024.05.19" + ) + return cell + } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift index 66f5ea50..b9ec02df 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewHolder.swift @@ -24,7 +24,7 @@ extension MyReviewViewController { let tableView = UITableView() return tableView }() - + func place(in view: UIView) { view.addSubview(backNavigationView) view.addSubview(tableView) diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift new file mode 100644 index 00000000..c4edf423 --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift @@ -0,0 +1,30 @@ +// +// MyReviewContentConfiguration.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import UIKit + +struct MyReviewContentConfiguration: UIContentConfiguration { + var storeImageIcon: ConvenienceStore + var imageUrl: String + var title: String + var date: String? + + init(storeImageIcon: ConvenienceStore, imageUrl: String, title: String, date: String? = nil) { + self.storeImageIcon = storeImageIcon + self.imageUrl = imageUrl + self.title = title + self.date = date + } + + func makeContentView() -> any UIView & UIContentView { + return MyReviewContentView(configuration: self) + } + + func updated(for state: any UIConfigurationState) -> MyReviewContentConfiguration { + return self + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift new file mode 100644 index 00000000..c59a4b55 --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift @@ -0,0 +1,58 @@ +// +// MyReviewContentView.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import UIKit +import SnapKit + +class MyReviewContentView: UIView, UIContentView { + static let identifier = "MyReviewContentView" + + var configuration: any UIContentConfiguration + private let storeImageViewHeight: CGFloat = 20 + + private var productInfoStackView = ProductInfoStackView(mode: .date) + + init(configuration: any UIContentConfiguration) { + self.configuration = configuration + super.init(frame: .zero) + configureView() + configureUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configureView() { + self.addSubview(productInfoStackView) + productInfoStackView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } + + private func configureUI() { + guard let configuration = configuration as? MyReviewContentConfiguration else { return } + if let imageUrl = URL(string: configuration.imageUrl) { + self.productInfoStackView.productImageView.setImage(with: imageUrl) + } + + self.productInfoStackView.productNameLabel.text = configuration.title + + self.productInfoStackView.storeImageView.setImage(configuration.storeImageIcon.storeIcon) + self.productInfoStackView.storeImageView.snp.makeConstraints { make in + guard let storeIcon = configuration.storeImageIcon.storeIcon.image else { return } + let ratio = storeIcon.size.width / storeIcon.size.height + let newWidth = self.storeImageViewHeight * ratio + make.width.equalTo(newWidth) + } + + if let date = configuration.date { + let dateString = DateFormatter.productLastUpdateFormatter.date(from: date)?.toString() + self.productInfoStackView.dateLabel.text = dateString + } + } +} From 36a89d37ab55881404969ecebce28cd8f8132f4b Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 19 May 2024 17:27:15 +0900 Subject: [PATCH 6/8] =?UTF-8?q?Add:=20=EB=82=B4=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0=20=EB=A6=AC=EB=B8=94?= =?UTF-8?q?=EB=A0=9B=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pyonsnal-Color.xcodeproj/project.pbxproj | 28 ++++++++ .../Common/Review/ProductInfoStackView.swift | 10 +++ .../MyDetailReviewBuilder.swift | 39 +++++++++++ .../MyDetailReviewInteractor.swift | 46 +++++++++++++ .../MyDetailReview/MyDetailReviewRouter.swift | 26 +++++++ .../MyDetailReviewViewController.swift | 44 ++++++++++++ .../MyDetailReviewViewHolder.swift | 67 +++++++++++++++++++ .../MyReview/MyReviewBuilder.swift | 14 ++-- .../MyReview/MyReviewInteractor.swift | 11 ++- .../MyReview/MyReviewRouter.swift | 31 ++++++++- .../MyReview/MyReviewViewController.swift | 20 ++++-- 11 files changed, 319 insertions(+), 17 deletions(-) create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewRouter.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift create mode 100644 Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj index c712175e..0a209657 100644 --- a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj +++ b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj @@ -270,6 +270,11 @@ F0614E352BF9D7D5008AAF10 /* ProductInfoStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E342BF9D7D5008AAF10 /* ProductInfoStackView.swift */; }; F0614E3E2BF9DD01008AAF10 /* MyReviewContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E3D2BF9DD01008AAF10 /* MyReviewContentView.swift */; }; F0614E412BF9DE43008AAF10 /* MyReviewContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E402BF9DE43008AAF10 /* MyReviewContentConfiguration.swift */; }; + F0614E472BF9E775008AAF10 /* MyDetailReviewRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E432BF9E775008AAF10 /* MyDetailReviewRouter.swift */; }; + F0614E482BF9E775008AAF10 /* MyDetailReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E442BF9E775008AAF10 /* MyDetailReviewViewController.swift */; }; + F0614E492BF9E775008AAF10 /* MyDetailReviewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E452BF9E775008AAF10 /* MyDetailReviewBuilder.swift */; }; + F0614E4A2BF9E775008AAF10 /* MyDetailReviewInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E462BF9E775008AAF10 /* MyDetailReviewInteractor.swift */; }; + F0614E4C2BF9EA55008AAF10 /* MyDetailReviewViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0614E4B2BF9EA55008AAF10 /* MyDetailReviewViewHolder.swift */; }; F0687BED2A529679004B5EAE /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0687BEC2A529679004B5EAE /* Config.swift */; }; F068A9702A99E76A000AFD52 /* FilterRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */; }; F069DBE62A30B9850001D3DD /* UIFont+.swift in Sources */ = {isa = PBXBuildFile; fileRef = F069DBE52A30B9850001D3DD /* UIFont+.swift */; }; @@ -602,6 +607,11 @@ F0614E342BF9D7D5008AAF10 /* ProductInfoStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductInfoStackView.swift; sourceTree = ""; }; F0614E3D2BF9DD01008AAF10 /* MyReviewContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewContentView.swift; sourceTree = ""; }; F0614E402BF9DE43008AAF10 /* MyReviewContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewContentConfiguration.swift; sourceTree = ""; }; + F0614E432BF9E775008AAF10 /* MyDetailReviewRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyDetailReviewRouter.swift; sourceTree = ""; }; + F0614E442BF9E775008AAF10 /* MyDetailReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyDetailReviewViewController.swift; sourceTree = ""; }; + F0614E452BF9E775008AAF10 /* MyDetailReviewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyDetailReviewBuilder.swift; sourceTree = ""; }; + F0614E462BF9E775008AAF10 /* MyDetailReviewInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyDetailReviewInteractor.swift; sourceTree = ""; }; + F0614E4B2BF9EA55008AAF10 /* MyDetailReviewViewHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyDetailReviewViewHolder.swift; sourceTree = ""; }; F0687BEC2A529679004B5EAE /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterRenderable.swift; sourceTree = ""; }; F069DBE52A30B9850001D3DD /* UIFont+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+.swift"; sourceTree = ""; }; @@ -1355,6 +1365,7 @@ BA87E3C72A45C579000A9DEC /* ProductDetail */, B2538B8F2A3454FA00B7C3F0 /* ProfileHome */, F0614E272BF9C8D4008AAF10 /* MyReview */, + F0614E422BF9E74D008AAF10 /* MyDetailReview */, F075D0C32B052ED500DD0F5E /* ProfileEdit */, B2538B8E2A3454F100B7C3F0 /* EventHome */, B2538B8D2A3454EA00B7C3F0 /* ProductHome */, @@ -1560,6 +1571,18 @@ path = View; sourceTree = ""; }; + F0614E422BF9E74D008AAF10 /* MyDetailReview */ = { + isa = PBXGroup; + children = ( + F0614E432BF9E775008AAF10 /* MyDetailReviewRouter.swift */, + F0614E442BF9E775008AAF10 /* MyDetailReviewViewController.swift */, + F0614E452BF9E775008AAF10 /* MyDetailReviewBuilder.swift */, + F0614E462BF9E775008AAF10 /* MyDetailReviewInteractor.swift */, + F0614E4B2BF9EA55008AAF10 /* MyDetailReviewViewHolder.swift */, + ); + path = MyDetailReview; + sourceTree = ""; + }; F0687BEB2A529666004B5EAE /* Config */ = { isa = PBXGroup; children = ( @@ -1954,6 +1977,7 @@ F0C698732A6D4DBF0019C677 /* TopCommonSectionLayout.swift in Sources */, F097EF2E2A57187400A7FB9C /* ProfileUrl.swift in Sources */, B21C1A8C2A513FBB007D98E9 /* RIBs+.swift in Sources */, + F0614E4C2BF9EA55008AAF10 /* MyDetailReviewViewHolder.swift in Sources */, BA1807622A2F21D900295398 /* URLRequest+.swift in Sources */, BA18C0B12A759EAC007D00BD /* ProductSearchSortBottomSheetViewController.swift in Sources */, BA18C0922A753464007D00BD /* SearchFilterHeader+ViewHolder.swift in Sources */, @@ -2116,6 +2140,10 @@ BA1807552A2F151F00295398 /* ImageAssetKind.swift in Sources */, F06F40372B37361500897396 /* NativeAdView.swift in Sources */, B22496522ABC1BE400BC6B09 /* ReviewPopupRouter.swift in Sources */, + F0614E472BF9E775008AAF10 /* MyDetailReviewRouter.swift in Sources */, + F0614E482BF9E775008AAF10 /* MyDetailReviewViewController.swift in Sources */, + F0614E492BF9E775008AAF10 /* MyDetailReviewBuilder.swift in Sources */, + F0614E4A2BF9E775008AAF10 /* MyDetailReviewInteractor.swift in Sources */, F0168D512A500AC900978ED9 /* EventDetailRouter.swift in Sources */, BAF8725D2AD404C0001427DF /* ProductGiftEntity.swift in Sources */, BA87E3DC2A4623E3000A9DEC /* GiftItemEntity.swift in Sources */, diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift index d716d96b..005e5a09 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift @@ -12,6 +12,7 @@ class ProductInfoStackView: UIStackView { enum Mode { case starRating case date + case taste } let productImageView: UIImageView = { @@ -52,6 +53,13 @@ class ProductInfoStackView: UIStackView { return label }() + let tasteLabel: UILabel = { + let label = UILabel() + label.font = .body3r + label.textColor = .red500 + return label + }() + init(mode: Mode) { super.init(frame: .zero) self.initialize() @@ -87,6 +95,8 @@ class ProductInfoStackView: UIStackView { self.productInformationStackView.addArrangedSubview(starRatedView) case .date: self.productInformationStackView.addArrangedSubview(dateLabel) + case .taste: + self.productInformationStackView.addArrangedSubview(tasteLabel) } self.productImageView.snp.makeConstraints { diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift new file mode 100644 index 00000000..59e5315c --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift @@ -0,0 +1,39 @@ +// +// MyDetailReviewBuilder.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs + +protocol MyDetailReviewDependency: Dependency { + // TODO: Declare the set of dependencies required by this RIB, but cannot be + // created by this RIB. +} + +final class MyDetailReviewComponent: Component { + + // TODO: Declare 'fileprivate' dependencies that are only used by this RIB. +} + +// MARK: - Builder + +protocol MyDetailReviewBuildable: Buildable { + func build(withListener listener: MyDetailReviewListener) -> MyDetailReviewRouting +} + +final class MyDetailReviewBuilder: Builder, MyDetailReviewBuildable { + + override init(dependency: MyDetailReviewDependency) { + super.init(dependency: dependency) + } + + func build(withListener listener: MyDetailReviewListener) -> MyDetailReviewRouting { + let component = MyDetailReviewComponent(dependency: dependency) + let viewController = MyDetailReviewViewController() + let interactor = MyDetailReviewInteractor(presenter: viewController) + interactor.listener = listener + return MyDetailReviewRouter(interactor: interactor, viewController: viewController) + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift new file mode 100644 index 00000000..bc1e368b --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift @@ -0,0 +1,46 @@ +// +// MyDetailReviewInteractor.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs + +protocol MyDetailReviewRouting: ViewableRouting { + // TODO: Declare methods the interactor can invoke to manage sub-tree via the router. +} + +protocol MyDetailReviewPresentable: Presentable { + var listener: MyDetailReviewPresentableListener? { get set } + // TODO: Declare methods the interactor can invoke the presenter to present data. +} + +protocol MyDetailReviewListener: AnyObject { + func didTapBackButton() +} + +final class MyDetailReviewInteractor: PresentableInteractor, MyDetailReviewInteractable, MyDetailReviewPresentableListener { + + weak var router: MyDetailReviewRouting? + weak var listener: MyDetailReviewListener? + + // TODO: Add additional dependencies to constructor. Do not perform any logic + // in constructor. + override init(presenter: MyDetailReviewPresentable) { + super.init(presenter: presenter) + presenter.listener = self + } + + override func didBecomeActive() { + super.didBecomeActive() + } + + override func willResignActive() { + super.willResignActive() + } + + func didTapBackButton() { + listener?.didTapBackButton() + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewRouter.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewRouter.swift new file mode 100644 index 00000000..8d9c8865 --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewRouter.swift @@ -0,0 +1,26 @@ +// +// MyDetailReviewRouter.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs + +protocol MyDetailReviewInteractable: Interactable { + var router: MyDetailReviewRouting? { get set } + var listener: MyDetailReviewListener? { get set } +} + +protocol MyDetailReviewViewControllable: ViewControllable { + // TODO: Declare methods the router invokes to manipulate the view hierarchy. +} + +final class MyDetailReviewRouter: ViewableRouter, MyDetailReviewRouting { + + // TODO: Constructor inject child builder protocols to allow building children. + override init(interactor: MyDetailReviewInteractable, viewController: MyDetailReviewViewControllable) { + super.init(interactor: interactor, viewController: viewController) + interactor.router = self + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift new file mode 100644 index 00000000..162f7c1c --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift @@ -0,0 +1,44 @@ +// +// MyDetailReviewViewController.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import ModernRIBs +import UIKit + +protocol MyDetailReviewPresentableListener: AnyObject { + func didTapBackButton() +} + +final class MyDetailReviewViewController: UIViewController, + MyDetailReviewPresentable, + MyDetailReviewViewControllable { + + weak var listener: MyDetailReviewPresentableListener? + let viewHolder: ViewHolder = .init() + + override func viewDidLoad() { + super.viewDidLoad() + viewHolder.place(in: view) + viewHolder.configureConstraints(for: view) + self.bindActions() + } + + private func configureUI() { + self.view.backgroundColor = .white + } + + + private func bindActions() { + self.viewHolder.backNavigationView.delegate = self + } + +} + +extension MyDetailReviewViewController: BackNavigationViewDelegate { + func didTapBackButton() { + listener?.didTapBackButton() + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift new file mode 100644 index 00000000..a6034a8d --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift @@ -0,0 +1,67 @@ +// +// MyDetailReviewViewHolder.swift +// Pyonsnal-Color +// +// Created by 조소정 on 5/19/24. +// + +import UIKit +import SnapKit + +extension MyDetailReviewViewController { + enum Text { + static let navigationTitleView = "상세 리뷰" + } + + enum Size { + static let productInfoStackView: CGFloat = 146 + static let dividerHeight: CGFloat = 1 + } + + class ViewHolder: ViewHolderable { + let backNavigationView: BackNavigationView = { + let navigationView = BackNavigationView() + navigationView.payload = .init(mode: .text) + navigationView.setText(with: Text.navigationTitleView) + return navigationView + }() + + let productInfoStackView: ProductInfoStackView = { + let infoStackView = ProductInfoStackView(mode: .taste) + return infoStackView + }() + + let dividerView: UIView = { + let view = UIView() + view.backgroundColor = .gray200 + return view + }() + + // TODO: 아무래도 scrollView ..?? + // TODO: productDetailReviewCell + func place(in view: UIView) { + view.addSubview(backNavigationView) + view.addSubview(productInfoStackView) + view.addSubview(dividerView) + } + + func configureConstraints(for view: UIView) { + backNavigationView.snp.makeConstraints { + $0.top.equalTo(view.safeAreaLayoutGuide) + $0.leading.trailing.equalTo(view) + } + + productInfoStackView.snp.makeConstraints { + $0.top.equalTo(backNavigationView.snp.bottom) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(Size.dividerHeight) + } + + dividerView.snp.makeConstraints { + $0.leading.equalToSuperview().offset(.spacing24) + $0.trailing.equalToSuperview().inset(.spacing24) + $0.height.equalTo(Size.dividerHeight) + } + } + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift index d058af96..a1b119b1 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewBuilder.swift @@ -7,15 +7,10 @@ import ModernRIBs -protocol MyReviewDependency: Dependency { - // TODO: Declare the set of dependencies required by this RIB, but cannot be - // created by this RIB. -} - -final class MyReviewComponent: Component { +protocol MyReviewDependency: Dependency { } - // TODO: Declare 'fileprivate' dependencies that are only used by this RIB. -} +final class MyReviewComponent: Component, + MyDetailReviewDependency {} // MARK: - Builder @@ -32,8 +27,9 @@ final class MyReviewBuilder: Builder, MyReviewBuildable { func build(withListener listener: MyReviewListener) -> MyReviewRouting { let component = MyReviewComponent(dependency: dependency) let viewController = MyReviewViewController() + let myDetailReviewBuilder = MyDetailReviewBuilder(dependency: component) let interactor = MyReviewInteractor(presenter: viewController) interactor.listener = listener - return MyReviewRouter(interactor: interactor, viewController: viewController) + return MyReviewRouter(interactor: interactor, viewController: viewController, myDetailReviewBuilder: myDetailReviewBuilder) } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift index fac593ac..35761bb7 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift @@ -8,7 +8,8 @@ import ModernRIBs protocol MyReviewRouting: ViewableRouting { - // TODO: Declare methods the interactor can invoke to manage sub-tree via the router. + func attachMyDetailReview() + func detachMyDetailReview() } protocol MyReviewPresentable: Presentable { @@ -41,4 +42,12 @@ final class MyReviewInteractor: PresentableInteractor, MyRe super.willResignActive() // TODO: Pause any business logic. } + + func didTapMyDetailReview(with reviewId: String) { + router?.attachMyDetailReview() + } + + func didTapBackButton() { + router?.detachMyDetailReview() + } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift index 294385ed..846f9a09 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift @@ -7,7 +7,8 @@ import ModernRIBs -protocol MyReviewInteractable: Interactable { +protocol MyReviewInteractable: Interactable, + MyDetailReviewListener { var router: MyReviewRouting? { get set } var listener: MyReviewListener? { get set } } @@ -17,10 +18,34 @@ protocol MyReviewViewControllable: ViewControllable { } final class MyReviewRouter: ViewableRouter, MyReviewRouting { + - // TODO: Constructor inject child builder protocols to allow building children. - override init(interactor: MyReviewInteractable, viewController: MyReviewViewControllable) { + private let myDetailReviewBuilder: MyDetailReviewBuildable + private var myDetailReviewRouting: ViewableRouting? + + init( + interactor: MyReviewInteractable, + viewController: MyReviewViewControllable, + myDetailReviewBuilder: MyDetailReviewBuilder + ) { + self.myDetailReviewBuilder = myDetailReviewBuilder super.init(interactor: interactor, viewController: viewController) interactor.router = self } + + func attachMyDetailReview() { + if myDetailReviewRouting != nil { return } + let myDetailReviewRouter = myDetailReviewBuilder.build( + withListener: interactor) + myDetailReviewRouting = myDetailReviewRouter + attachChild(myDetailReviewRouter) + viewController.pushViewController(myDetailReviewRouter.viewControllable, animated: true) + } + + func detachMyDetailReview() { + guard let myDetailReviewRouting else { return } + viewController.popViewController(animated: true) + self.myDetailReviewRouting = nil + detachChild(myDetailReviewRouting) + } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift index 132f848e..f072ae22 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift @@ -9,9 +9,8 @@ import ModernRIBs import UIKit protocol MyReviewPresentableListener: AnyObject { - // TODO: Declare properties and methods that the view controller can invoke to perform - // business logic, such as signIn(). This protocol is implemented by the corresponding - // interactor class. + func didTapBackButton() + func didTapMyDetailReview(with reviewId: String) } final class MyReviewViewController: UIViewController, MyReviewPresentable, MyReviewViewControllable { @@ -24,6 +23,7 @@ final class MyReviewViewController: UIViewController, MyReviewPresentable, MyRev viewHolder.place(in: view) viewHolder.configureConstraints(for: view) self.configureUI() + self.bindActions() self.configureTableView() } @@ -36,6 +36,10 @@ final class MyReviewViewController: UIViewController, MyReviewPresentable, MyRev self.view.backgroundColor = .white } + private func bindActions() { + self.viewHolder.backNavigationView.delegate = self + } + private func updateNavigationTitle(reviewCount: Int) { let updatedTitle = Text.navigationTitleView + "(\(reviewCount))" self.viewHolder.backNavigationView.setText(with: updatedTitle) @@ -54,7 +58,7 @@ final class MyReviewViewController: UIViewController, MyReviewPresentable, MyRev // MARK: - UITableViewDelegate extension MyReviewViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - // TODO: MyDetailReview + listener?.didTapMyDetailReview(with: "11") } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { @@ -70,6 +74,7 @@ extension MyReviewViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: MyReviewContentView.identifier, for: indexPath) + cell.selectionStyle = .none // TODO: interactor로부터 받아온 값으로 변경 cell.contentConfiguration = MyReviewContentConfiguration( storeImageIcon: .sevenEleven, imageUrl: "", @@ -79,3 +84,10 @@ extension MyReviewViewController: UITableViewDataSource { return cell } } + +// MARK: - BackNavigationViewDelegate +extension MyReviewViewController: BackNavigationViewDelegate { + func didTapBackButton() { + listener?.didTapBackButton() + } +} From c14e6346f0ab0156b8a7a788869ceacd6a5691f8 Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 2 Jun 2024 16:25:38 +0900 Subject: [PATCH 7/8] =?UTF-8?q?Update:=20=EB=82=B4=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20UI=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pyonsnal-Color.xcodeproj/project.pbxproj | 26 +++- .../ActionButtonCell/ActionButtonCell.swift | 67 +++++++++++ .../EmptyCell+ViewHolder.swift | 0 .../Cell/{ => EmptyCell}/EmptyCell.swift | 0 .../ProductDetailReviewCell+ViewHolder.swift | 4 + .../ReviewCell/ProductDetailReviewCell.swift | 0 .../Entity/Products/ProductDetailEntity.swift | 6 +- .../Products/ProductDetailSectionItem.swift | 1 + .../MyDetailReviewBuilder.swift | 26 +++- .../MyDetailReviewInteractor.swift | 14 ++- .../MyDetailReviewViewController.swift | 111 +++++++++++++++++- .../MyDetailReviewViewHolder.swift | 28 ++--- .../MyReview/MyReviewInteractor.swift | 8 +- .../MyReview/MyReviewRouter.swift | 7 +- .../MyReview/MyReviewViewController.swift | 10 +- .../View/MyReviewContentConfiguration.swift | 4 +- .../MyReview/View/MyReviewContentView.swift | 6 +- .../ProductDetailViewController.swift | 8 +- .../ReviewEvaluationLabelView.swift | 3 - ...ductDetailReviewWriteCell+ViewHolder.swift | 16 --- .../ProductDetailReviewWriteCell.swift | 9 -- ...ProductDetailReviewWriteCellDelegate.swift | 1 - 22 files changed, 268 insertions(+), 87 deletions(-) create mode 100644 Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ActionButtonCell/ActionButtonCell.swift rename Pyonsnal-Color/Pyonsnal-Color/Common/Cell/{ => EmptyCell}/EmptyCell+ViewHolder.swift (100%) rename Pyonsnal-Color/Pyonsnal-Color/Common/Cell/{ => EmptyCell}/EmptyCell.swift (100%) rename Pyonsnal-Color/Pyonsnal-Color/{ProductDetail/Subview => Common/Cell}/ReviewCell/ProductDetailReviewCell+ViewHolder.swift (97%) rename Pyonsnal-Color/Pyonsnal-Color/{ProductDetail/Subview => Common/Cell}/ReviewCell/ProductDetailReviewCell.swift (100%) diff --git a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj index 0a209657..07e6d79b 100644 --- a/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj +++ b/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.pbxproj @@ -278,6 +278,7 @@ F0687BED2A529679004B5EAE /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0687BEC2A529679004B5EAE /* Config.swift */; }; F068A9702A99E76A000AFD52 /* FilterRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F068A96F2A99E76A000AFD52 /* FilterRenderable.swift */; }; F069DBE62A30B9850001D3DD /* UIFont+.swift in Sources */ = {isa = PBXBuildFile; fileRef = F069DBE52A30B9850001D3DD /* UIFont+.swift */; }; + F06E3D982C0C428D00D6C195 /* ActionButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06E3D972C0C428D00D6C195 /* ActionButtonCell.swift */; }; F06F40292B35E2FC00897396 /* AdMobManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06F40282B35E2FC00897396 /* AdMobManager.swift */; }; F06F40322B35EE2800897396 /* CurationAdCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06F40312B35EE2800897396 /* CurationAdCell.swift */; }; F06F40372B37361500897396 /* NativeAdView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06F40362B37361500897396 /* NativeAdView.swift */; }; @@ -618,6 +619,7 @@ F069DBE82A30BA8C0001D3DD /* Pretendard-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Medium.otf"; sourceTree = ""; }; F069DBE92A30BA8C0001D3DD /* Pretendard-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Regular.otf"; sourceTree = ""; }; F069DBEA2A30BA8C0001D3DD /* Pretendard-SemiBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-SemiBold.otf"; sourceTree = ""; }; + F06E3D972C0C428D00D6C195 /* ActionButtonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButtonCell.swift; sourceTree = ""; }; F06F40282B35E2FC00897396 /* AdMobManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdMobManager.swift; sourceTree = ""; }; F06F40312B35EE2800897396 /* CurationAdCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurationAdCell.swift; sourceTree = ""; }; F06F40362B37361500897396 /* NativeAdView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeAdView.swift; sourceTree = ""; }; @@ -1424,7 +1426,6 @@ BAE9843A2AACFB3400ED22CB /* ImageCell */, BAE9843B2AACFB5F00ED22CB /* InformationCell */, BAE9843C2AACFB7000ED22CB /* ReviewWriteCell */, - BAE9843D2AACFB8C00ED22CB /* ReviewCell */, ); path = Subview; sourceTree = ""; @@ -1609,6 +1610,23 @@ path = Font; sourceTree = ""; }; + F06E3D952C0C401B00D6C195 /* EmptyCell */ = { + isa = PBXGroup; + children = ( + BAE442C52A6D7B9E00BD6582 /* EmptyCell.swift */, + BAE442C72A6D7C3900BD6582 /* EmptyCell+ViewHolder.swift */, + ); + path = EmptyCell; + sourceTree = ""; + }; + F06E3D962C0C412500D6C195 /* ActionButtonCell */ = { + isa = PBXGroup; + children = ( + F06E3D972C0C428D00D6C195 /* ActionButtonCell.swift */, + ); + path = ActionButtonCell; + sourceTree = ""; + }; F06F40272B35E2D800897396 /* Manager */ = { isa = PBXGroup; children = ( @@ -1772,10 +1790,11 @@ F0D6FFA72A39F57600C55E27 /* Cell */ = { isa = PBXGroup; children = ( + F06E3D962C0C412500D6C195 /* ActionButtonCell */, + BAE9843D2AACFB8C00ED22CB /* ReviewCell */, + F06E3D952C0C401B00D6C195 /* EmptyCell */, F0B6E6C82AB8A2E700AA7006 /* ProductCell */, B24F1D302A431E1700AA03DC /* ConvenienceStoreCell.swift */, - BAE442C52A6D7B9E00BD6582 /* EmptyCell.swift */, - BAE442C72A6D7C3900BD6582 /* EmptyCell+ViewHolder.swift */, F0C698642A6BA9B00019C677 /* CategoryFilterCell.swift */, F040E9D22A6D8E8800DF0C4A /* RefreshFilterCell.swift */, F040E9D42A6D967300DF0C4A /* KeywordFilterCell.swift */, @@ -2096,6 +2115,7 @@ BAE442C82A6D7C3900BD6582 /* EmptyCell+ViewHolder.swift in Sources */, B24F1D4B2A4BB82D00AA03DC /* TitleNavigationView.swift in Sources */, F00022462A5280FC00FFB4A4 /* NetworkRequestBuilder.swift in Sources */, + F06E3D982C0C428D00D6C195 /* ActionButtonCell.swift in Sources */, F00352242A62BD9F00A66FF9 /* UserLoginStatusEntity.swift in Sources */, B28A59272A6FCE9700431F39 /* ProductFilterSectionLayout.swift in Sources */, B242590E2A5947E7006C5223 /* PageableEntity.swift in Sources */, diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ActionButtonCell/ActionButtonCell.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ActionButtonCell/ActionButtonCell.swift new file mode 100644 index 00000000..bd529623 --- /dev/null +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ActionButtonCell/ActionButtonCell.swift @@ -0,0 +1,67 @@ +// +// ActionButtonCell.swift +// Pyonsnal-Color +// +// Created by 조소정 on 6/2/24. +// + +import UIKit +import Combine + +protocol ActionButtonCellDelegate: AnyObject { + func actionButtonDidTap() +} + +final class ActionButtonCell: UICollectionViewCell { + // MARK: - Interfaces + enum Constants { + enum Size { + static let actionButtonHeight: CGFloat = 40 + static let actionButtonRadius: CGFloat = 16 + } + + enum Text { + static let writeReview = "상품 리뷰 작성 하기" + static let showProduct = "상품 보러 가기" + } + } + + weak var delegate: ActionButtonCellDelegate? + private var cancellables = Set() + + // MARK: - Initializer + override init(frame: CGRect) { + super.init(frame: .zero) + self.setConstraints() + self.bindActions() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + let actionButton: UIButton = { + let button = UIButton(frame: .zero) + button.makeRounded(with: Constants.Size.actionButtonRadius) + button.backgroundColor = .black + button.titleLabel?.textColor = .white + button.titleLabel?.font = .body2m + return button + }() + + // MARK: - Private Methods + private func setConstraints() { + self.addSubview(actionButton) + actionButton.snp.makeConstraints { make in + make.height.equalTo(Constants.Size.actionButtonHeight) + make.top.bottom.equalToSuperview() + make.leading.trailing.equalToSuperview().inset(.spacing16) + } + } + + private func bindActions() { + actionButton.tapPublisher.sink { [weak self] in + self?.delegate?.actionButtonDidTap() + }.store(in: &cancellables) + } +} diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell+ViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell/EmptyCell+ViewHolder.swift similarity index 100% rename from Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell+ViewHolder.swift rename to Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell/EmptyCell+ViewHolder.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell/EmptyCell.swift similarity index 100% rename from Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell.swift rename to Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell/EmptyCell.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewCell/ProductDetailReviewCell+ViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell+ViewHolder.swift similarity index 97% rename from Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewCell/ProductDetailReviewCell+ViewHolder.swift rename to Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell+ViewHolder.swift index 92758b8c..cbd2714d 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewCell/ProductDetailReviewCell+ViewHolder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell+ViewHolder.swift @@ -111,6 +111,10 @@ extension ProductDetailReviewCell { make.leading.trailing.equalToSuperview().inset(.spacing16) } + reviewTagListView.snp.makeConstraints { make in + make.height.equalTo(28) + } + reviewLabel.snp.makeConstraints { make in make.top.equalTo(contentStackView.snp.bottom).offset(.spacing12) make.leading.trailing.equalToSuperview().inset(.spacing20) diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewCell/ProductDetailReviewCell.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell.swift similarity index 100% rename from Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewCell/ProductDetailReviewCell.swift rename to Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell.swift diff --git a/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailEntity.swift b/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailEntity.swift index 90254a17..64913bce 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailEntity.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailEntity.swift @@ -9,12 +9,12 @@ import Foundation struct ProductDetailEntity { let id: String - let storeType: ConvenienceStore // + let storeType: ConvenienceStore let imageURL: URL let name: String let price: String - let eventType: EventTag? // - let productType: ProductType // + let eventType: EventTag? + let productType: ProductType let updatedTime: String let description: String? let isNew: Bool? diff --git a/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailSectionItem.swift b/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailSectionItem.swift index 2eb16e8e..e78f7244 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailSectionItem.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailSectionItem.swift @@ -11,5 +11,6 @@ enum ProductDetailSectionItem { case image(imageURL: URL) case information(product: ProductDetailEntity) case reviewWrite(score: Double, reviewsCount: Int, sortItem: FilterItemEntity) + case actionButton case review(productReview: ReviewEntity) } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift index 59e5315c..ecafa742 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewBuilder.swift @@ -13,14 +13,24 @@ protocol MyDetailReviewDependency: Dependency { } final class MyDetailReviewComponent: Component { - - // TODO: Declare 'fileprivate' dependencies that are only used by this RIB. + var productDetail: ProductDetailEntity + var review: ReviewEntity + + init(dependency: MyDetailReviewDependency, productDetail: ProductDetailEntity, review: ReviewEntity) { + self.productDetail = productDetail + self.review = review + super.init(dependency: dependency) + } } // MARK: - Builder protocol MyDetailReviewBuildable: Buildable { - func build(withListener listener: MyDetailReviewListener) -> MyDetailReviewRouting + func build( + withListener listener: MyDetailReviewListener, + productDetail: ProductDetailEntity, + review: ReviewEntity + ) -> MyDetailReviewRouting } final class MyDetailReviewBuilder: Builder, MyDetailReviewBuildable { @@ -29,10 +39,14 @@ final class MyDetailReviewBuilder: Builder, MyDetailRe super.init(dependency: dependency) } - func build(withListener listener: MyDetailReviewListener) -> MyDetailReviewRouting { - let component = MyDetailReviewComponent(dependency: dependency) + func build( + withListener listener: MyDetailReviewListener, + productDetail: ProductDetailEntity, + review: ReviewEntity + ) -> MyDetailReviewRouting { + let component = MyDetailReviewComponent(dependency: dependency, productDetail: productDetail, review: review) let viewController = MyDetailReviewViewController() - let interactor = MyDetailReviewInteractor(presenter: viewController) + let interactor = MyDetailReviewInteractor(presenter: viewController, component: component) interactor.listener = listener return MyDetailReviewRouter(interactor: interactor, viewController: viewController) } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift index bc1e368b..200c943e 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewInteractor.swift @@ -13,7 +13,7 @@ protocol MyDetailReviewRouting: ViewableRouting { protocol MyDetailReviewPresentable: Presentable { var listener: MyDetailReviewPresentableListener? { get set } - // TODO: Declare methods the interactor can invoke the presenter to present data. + func update(with productDetail: ProductDetailEntity, review: ReviewEntity) } protocol MyDetailReviewListener: AnyObject { @@ -24,16 +24,20 @@ final class MyDetailReviewInteractor: PresentableInteractor + private typealias Snapshot = NSDiffableDataSourceSnapshot + + private enum Section { + case main + } + + private enum Item: Hashable { + case productDetail(product: ProductDetailEntity) + case review(review: ReviewEntity) + case landing + } + weak var listener: MyDetailReviewPresentableListener? - let viewHolder: ViewHolder = .init() + // MARK: Private Properties + private let viewHolder: ViewHolder = .init() + private var dataSource: DataSource? + private var snapshot = Snapshot() + private var productDetail: ProductDetailEntity? + private var review: ReviewEntity? + + // MARK: View Life Cycles override func viewDidLoad() { super.viewDidLoad() viewHolder.place(in: view) viewHolder.configureConstraints(for: view) + self.configureUI() self.bindActions() + self.configureCollectionView() + self.configureDataSource() + if let productDetail, let review { + self.applySnapshot(with: productDetail, review: review) + } } + func update(with productDetail: ProductDetailEntity, review: ReviewEntity) { + self.productDetail = productDetail + self.review = review + self.applySnapshot(with: productDetail, review: review) + } + + // MARK: Private Methods private func configureUI() { self.view.backgroundColor = .white } - private func bindActions() { self.viewHolder.backNavigationView.delegate = self } + private func configureCollectionView() { + self.registerCollectionViewCells() + self.viewHolder.collectionView.delegate = self + } + + private func registerCollectionViewCells() { + self.viewHolder.collectionView.register(ProductDetailReviewCell.self) + self.viewHolder.collectionView.register( + UICollectionViewCell.self, + forCellWithReuseIdentifier: MyReviewContentView.identifier + ) + self.viewHolder.collectionView.register(ActionButtonCell.self) + } + + private func configureDataSource() { + dataSource = DataSource(collectionView: self.viewHolder.collectionView) { collectionView, indexPath, itemIdentifier in + switch itemIdentifier { + case .productDetail(let product): + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyReviewContentView.identifier, for: indexPath) + cell.contentConfiguration = MyReviewContentConfiguration( + storeImageIcon: product.storeType, + imageUrl: product.imageURL, + title: product.name + ) + return cell + case .review(let review): + let cell: ProductDetailReviewCell = collectionView.dequeueReusableCell(for: indexPath) + cell.payload = .init(review: review) + return cell + case .landing: + let cell: ActionButtonCell = collectionView.dequeueReusableCell(for: indexPath) + cell.actionButton.setText(with: ActionButtonCell.Constants.Text.showProduct) + return cell + } + } + } + + private func applySnapshot(with productDetail: ProductDetailEntity, review: ReviewEntity) { + var snapshot = Snapshot() + snapshot.appendSections([.main]) + snapshot.appendItems([.productDetail(product: productDetail)]) + snapshot.appendItems([.review(review: review)]) + snapshot.appendItems([.landing]) + dataSource?.apply(snapshot, animatingDifferences: false) + } +} + +extension MyDetailReviewViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + guard let item = dataSource?.itemIdentifier(for: indexPath) else { return CGSize.zero } + let screenWidth = collectionView.bounds.width + switch item { + case .productDetail: + return .init(width: screenWidth, height: 136) + case .review(let review): + let estimateHeight: CGFloat = 1000 + let cell = ProductDetailReviewCell() + cell.frame = .init( + origin: .zero, + size: .init(width: screenWidth, height: estimateHeight) + ) + cell.payload = .init(review: review) + cell.layoutIfNeeded() + let estimateSize = cell.systemLayoutSizeFitting( + .init(width: screenWidth, height: UIView.layoutFittingCompressedSize.height), + withHorizontalFittingPriority: .required, + verticalFittingPriority: .defaultLow + ) + return estimateSize + case .landing: + return .init(width: screenWidth, height: 40) + } + } } extension MyDetailReviewViewController: BackNavigationViewDelegate { diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift index a6034a8d..dbd67b4a 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewHolder.swift @@ -26,23 +26,15 @@ extension MyDetailReviewViewController { return navigationView }() - let productInfoStackView: ProductInfoStackView = { - let infoStackView = ProductInfoStackView(mode: .taste) - return infoStackView + let collectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + return UICollectionView(frame: .zero, collectionViewLayout: layout) }() - let dividerView: UIView = { - let view = UIView() - view.backgroundColor = .gray200 - return view - }() - - // TODO: 아무래도 scrollView ..?? - // TODO: productDetailReviewCell func place(in view: UIView) { view.addSubview(backNavigationView) - view.addSubview(productInfoStackView) - view.addSubview(dividerView) + view.addSubview(collectionView) } func configureConstraints(for view: UIView) { @@ -51,16 +43,10 @@ extension MyDetailReviewViewController { $0.leading.trailing.equalTo(view) } - productInfoStackView.snp.makeConstraints { + collectionView.snp.makeConstraints { $0.top.equalTo(backNavigationView.snp.bottom) $0.leading.trailing.equalToSuperview() - $0.height.equalTo(Size.dividerHeight) - } - - dividerView.snp.makeConstraints { - $0.leading.equalToSuperview().offset(.spacing24) - $0.trailing.equalToSuperview().inset(.spacing24) - $0.height.equalTo(Size.dividerHeight) + $0.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) } } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift index 35761bb7..f363a27b 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift @@ -8,7 +8,7 @@ import ModernRIBs protocol MyReviewRouting: ViewableRouting { - func attachMyDetailReview() + func attachMyDetailReview(productDetail: ProductDetailEntity, review: ReviewEntity) func detachMyDetailReview() } @@ -43,8 +43,10 @@ final class MyReviewInteractor: PresentableInteractor, MyRe // TODO: Pause any business logic. } - func didTapMyDetailReview(with reviewId: String) { - router?.attachMyDetailReview() + func didTapMyDetailReview(with productDetail: ProductDetailEntity, reviewId: String) { + // TODO: 받아온 값으로 수정 +// guard let review = productDetail.reviews.first(where: { $0.reviewId == reviewId }) else { return } + router?.attachMyDetailReview(productDetail: productDetail, review: .init(reviewId: "", taste: .good, quality: .bad, valueForMoney: .normal, score: 0, contents: "", image: nil, writerId: nil, writerName: "", createdTime: "", updatedTime: "", likeCount: .init(writerIds: [], likeCount: 0), hateCount: .init(writerIds: [], hateCount: 0))) } func didTapBackButton() { diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift index 846f9a09..927c785b 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewRouter.swift @@ -33,10 +33,13 @@ final class MyReviewRouter: ViewableRouter CGFloat { @@ -77,7 +79,7 @@ extension MyReviewViewController: UITableViewDataSource { cell.selectionStyle = .none // TODO: interactor로부터 받아온 값으로 변경 cell.contentConfiguration = MyReviewContentConfiguration( storeImageIcon: .sevenEleven, - imageUrl: "", + imageUrl: URL(string: "www.naver.com")!, title: "테스트", date: "2024.05.19" ) diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift index c4edf423..89841f13 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift @@ -9,11 +9,11 @@ import UIKit struct MyReviewContentConfiguration: UIContentConfiguration { var storeImageIcon: ConvenienceStore - var imageUrl: String + var imageUrl: URL var title: String var date: String? - init(storeImageIcon: ConvenienceStore, imageUrl: String, title: String, date: String? = nil) { + init(storeImageIcon: ConvenienceStore, imageUrl: URL, title: String, date: String? = nil) { self.storeImageIcon = storeImageIcon self.imageUrl = imageUrl self.title = title diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift index c59a4b55..88d0fd4e 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift @@ -36,12 +36,8 @@ class MyReviewContentView: UIView, UIContentView { private func configureUI() { guard let configuration = configuration as? MyReviewContentConfiguration else { return } - if let imageUrl = URL(string: configuration.imageUrl) { - self.productInfoStackView.productImageView.setImage(with: imageUrl) - } - + self.productInfoStackView.productImageView.setImage(with: configuration.imageUrl) self.productInfoStackView.productNameLabel.text = configuration.title - self.productInfoStackView.storeImageView.setImage(configuration.storeImageIcon.storeIcon) self.productInfoStackView.storeImageView.snp.makeConstraints { make in guard let storeIcon = configuration.storeImageIcon.storeIcon.image else { return } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/ProductDetailViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/ProductDetailViewController.swift index 5109227a..7a730884 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/ProductDetailViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/ProductDetailViewController.swift @@ -180,6 +180,10 @@ extension ProductDetailViewController: UICollectionViewDataSource { ) reviewWriteCell.delegate = self return reviewWriteCell + case .actionButton: + let actionButtonCell: ActionButtonCell = collectionView.dequeueReusableCell(for: indexPath) + actionButtonCell.actionButton.setText(with: ActionButtonCell.Constants.Text.writeReview) + return actionButtonCell case let .review(entity): let reviewCell: ProductDetailReviewCell = collectionView.dequeueReusableCell( for: indexPath @@ -236,7 +240,9 @@ extension ProductDetailViewController: UICollectionViewDelegateFlowLayout { ) return .init(width: screenWidth, height: estimateSize.height) case .reviewWrite: - return .init(width: screenWidth, height: 300) + return .init(width: screenWidth, height: 114) + case .actionButton: + return .init(width: screenWidth, height: 96) case let .review(entity): let width = collectionView.bounds.size.width let estimateHeight: CGFloat = 1000 diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewEvaluationLabelView/ReviewEvaluationLabelView.swift b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewEvaluationLabelView/ReviewEvaluationLabelView.swift index ad323ba3..328e8146 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewEvaluationLabelView/ReviewEvaluationLabelView.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewEvaluationLabelView/ReviewEvaluationLabelView.swift @@ -81,7 +81,6 @@ final class ReviewEvaluationLabelView: UIView { contentStackView.addArrangedSubview(evaluationLabel) contentView.snp.makeConstraints { make in - make.height.equalTo(28) make.edges.equalToSuperview() } @@ -91,12 +90,10 @@ final class ReviewEvaluationLabelView: UIView { } categoryLabel.snp.makeConstraints { make in - make.height.equalTo(20) make.top.bottom.equalToSuperview() } evaluationLabel.snp.makeConstraints { make in - make.height.equalTo(20) make.top.bottom.equalToSuperview() } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell+ViewHolder.swift b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell+ViewHolder.swift index 0fa6721c..ce60ad62 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell+ViewHolder.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell+ViewHolder.swift @@ -81,15 +81,6 @@ extension ProductDetailReviewWriteCell { return starRatedView }() - let reviewWriteButton: UIButton = { - let button = UIButton(frame: .zero) - button.makeRounded(with: Size.writeButtonRadius) - button.backgroundColor = .black - button.titleLabel?.textColor = .white - button.titleLabel?.font = .body2m - return button - }() - // MARK: - Interface func place(in view: UIView) { view.addSubview(contentView) @@ -97,7 +88,6 @@ extension ProductDetailReviewWriteCell { contentView.addSubview(reviewCountLabel) contentView.addSubview(sortButton) contentView.addSubview(ratingBackgroundView) - contentView.addSubview(reviewWriteButton) ratingBackgroundView.addSubview(ratingScoreStackView) ratingBackgroundView.addSubview(starRatedView) @@ -140,12 +130,6 @@ extension ProductDetailReviewWriteCell { make.bottom.equalToSuperview().inset(.spacing24) } - reviewWriteButton.snp.makeConstraints { make in - make.height.equalTo(40) - make.top.equalTo(ratingBackgroundView.snp.bottom).offset(.spacing16) - make.leading.trailing.equalToSuperview().inset(.spacing16) - make.bottom.equalToSuperview().inset(.spacing40) - } } } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell.swift b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell.swift index 5292578f..ee07fd42 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCell.swift @@ -49,10 +49,6 @@ final class ProductDetailReviewWriteCell: UICollectionViewCell { } private func configureAction() { - viewHolder.reviewWriteButton.addTapGesture( - target: self, - action: #selector(reviewWriteButtonAction(_:)) - ) viewHolder.sortButton.addTapGesture( target: self, @@ -68,14 +64,9 @@ final class ProductDetailReviewWriteCell: UICollectionViewCell { viewHolder.reviewCountLabel.text = "리뷰 \(payload.reviewsCount)개" viewHolder.ratingScoreLabel.text = "\(round(payload.score * 10) / 10)" viewHolder.starRatedView.payload = .init(score: payload.score) - viewHolder.reviewWriteButton.setText(with: "상품 리뷰 작성 하기") viewHolder.sortButton.setText(with: payload.sortItem.name) } - @objc private func reviewWriteButtonAction(_ sender: UITapGestureRecognizer) { - delegate?.writeButtonDidTap() - } - @objc private func reviewSortButtonAction(_ sender: UITapGestureRecognizer) { delegate?.sortButtonDidTap() } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCellDelegate.swift b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCellDelegate.swift index d1a19e7e..b32f6828 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCellDelegate.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCellDelegate.swift @@ -6,6 +6,5 @@ // protocol ProductDetailReviewWriteCellDelegate: AnyObject { - func writeButtonDidTap() func sortButtonDidTap() } From d24eadc3883a8ce06389f7d232e03ac04d8b8347 Mon Sep 17 00:00:00 2001 From: Jouureee Date: Sun, 2 Jun 2024 18:20:26 +0900 Subject: [PATCH 8/8] =?UTF-8?q?Etc:=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83?= =?UTF-8?q?=20=EC=88=98=EC=A0=95,=20myReview=20detach=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/Cell/ProductCell/ProductCell.swift | 2 +- .../ReviewCell/ProductDetailReviewCell.swift | 13 ++++- .../Common/Review/ProductInfoStackView.swift | 47 ++++++++++++------- .../MyDetailReviewViewController.swift | 19 ++++---- .../MyReview/MyReviewInteractor.swift | 8 +++- .../MyReview/MyReviewViewController.swift | 5 +- .../View/MyReviewContentConfiguration.swift | 15 +++++- .../MyReview/View/MyReviewContentView.swift | 12 +++-- .../ProfileHome/ProfileHomeInteractor.swift | 4 ++ .../ProfileHome/ProfileHomeRouter.swift | 2 +- 10 files changed, 87 insertions(+), 40 deletions(-) diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ProductCell/ProductCell.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ProductCell/ProductCell.swift index 65a1bd9c..4a7524bc 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ProductCell/ProductCell.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ProductCell/ProductCell.swift @@ -52,7 +52,7 @@ final class ProductCell: UICollectionViewCell { }.store(in: &cancellable) } - func updateCell(with product: (ProductDetailEntity)?) { + func updateCell(with product: ProductDetailEntity?) { guard let product else { return } self.product = product viewHolder.titleLabel.text = product.name diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell.swift index d012fcd1..71eab0ea 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/ReviewCell/ProductDetailReviewCell.swift @@ -16,6 +16,7 @@ final class ProductDetailReviewCell: UICollectionViewCell { // MARK: - Declaration struct Payload { + var hasEvaluateView: Bool = true let review: ReviewEntity } @@ -92,7 +93,6 @@ final class ProductDetailReviewCell: UICollectionViewCell { } else { viewHolder.reviewLabel.isHidden = false - viewHolder.reviewLabel.snp.makeConstraints { make in make.top.equalTo(viewHolder.contentStackView.snp.bottom).offset(.spacing12) make.leading.trailing.equalToSuperview().inset(.spacing20) @@ -114,6 +114,17 @@ final class ProductDetailReviewCell: UICollectionViewCell { isSelected: review.hateCount.writerIds.contains(UserInfoService.shared.memberID ?? 0), count: review.hateCount.hateCount ) + + if !payload.hasEvaluateView { + viewHolder.goodButton.isHidden = true + viewHolder.badButton.isHidden = true + viewHolder.goodButton.snp.remakeConstraints { + $0.height.equalTo(0) + } + viewHolder.badButton.snp.remakeConstraints { + $0.height.equalTo(0) + } + } } @objc private func goodButtonAction(_ sender: UITapGestureRecognizer) { diff --git a/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift index 005e5a09..768dabf8 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/Common/Review/ProductInfoStackView.swift @@ -10,9 +10,9 @@ import SnapKit class ProductInfoStackView: UIStackView { enum Mode { - case starRating - case date - case taste + case starRating // 별점 + case date // 날짜 + case tastes // 취향 태그 } let productImageView: UIImageView = { @@ -40,11 +40,11 @@ class ProductInfoStackView: UIStackView { let productNameLabel: UILabel = { let label = UILabel() label.font = .body3m - label.numberOfLines = 1 + label.numberOfLines = 2 return label }() - let starRatedView = StarRatedView(score: 0) + lazy var starRatedView = StarRatedView(score: 0) let dateLabel: UILabel = { let label = UILabel() @@ -53,23 +53,30 @@ class ProductInfoStackView: UIStackView { return label }() - let tasteLabel: UILabel = { + let tastesLabel: UILabel = { let label = UILabel() label.font = .body3r label.textColor = .red500 + label.numberOfLines = 2 return label }() init(mode: Mode) { super.init(frame: .zero) self.initialize() - self.configureView(with: mode) + self.configureView() + self.addArrangedSubview(with: mode) } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + func setTastes(tastesTag: [String]) { + let tastes = tastesTag.map { "# \($0)"}.joined(separator: " ") + self.tastesLabel.text = tastes + } + private func initialize() { self.axis = .horizontal self.alignment = .center @@ -79,25 +86,18 @@ class ProductInfoStackView: UIStackView { top: .spacing24, left: .spacing16, bottom: .spacing24, - right: 0 + right: .spacing16 ) } - private func configureView(with mode: Mode) { + private func configureView() { self.addArrangedSubview(productImageView) self.addArrangedSubview(productInformationStackView) self.productInformationStackView.addArrangedSubview(storeImageView) self.productInformationStackView.addArrangedSubview(productNameLabel) - - switch mode { - case .starRating: - self.productInformationStackView.addArrangedSubview(starRatedView) - case .date: - self.productInformationStackView.addArrangedSubview(dateLabel) - case .taste: - self.productInformationStackView.addArrangedSubview(tasteLabel) - } + self.productNameLabel.setContentCompressionResistancePriority(.defaultHigh, for: .vertical) + self.tastesLabel.setContentCompressionResistancePriority(.defaultLow, for: .vertical) self.productImageView.snp.makeConstraints { $0.width.height.equalTo(100) @@ -107,4 +107,15 @@ class ProductInfoStackView: UIStackView { $0.height.equalTo(20) } } + + private func addArrangedSubview(with mode: Mode) { + switch mode { + case .starRating: + self.productInformationStackView.addArrangedSubview(starRatedView) + case .date: + self.productInformationStackView.addArrangedSubview(dateLabel) + case .tastes: + self.productInformationStackView.addArrangedSubview(tastesLabel) + } + } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift index 0e0da1ae..776077e2 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyDetailReview/MyDetailReviewViewController.swift @@ -34,7 +34,6 @@ final class MyDetailReviewViewController: UIViewController, // MARK: Private Properties private let viewHolder: ViewHolder = .init() private var dataSource: DataSource? - private var snapshot = Snapshot() private var productDetail: ProductDetailEntity? private var review: ReviewEntity? @@ -47,15 +46,12 @@ final class MyDetailReviewViewController: UIViewController, self.bindActions() self.configureCollectionView() self.configureDataSource() - if let productDetail, let review { - self.applySnapshot(with: productDetail, review: review) - } + self.applySnapshot(with: productDetail, review: review) } func update(with productDetail: ProductDetailEntity, review: ReviewEntity) { self.productDetail = productDetail self.review = review - self.applySnapshot(with: productDetail, review: review) } // MARK: Private Methods @@ -87,14 +83,16 @@ final class MyDetailReviewViewController: UIViewController, case .productDetail(let product): let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyReviewContentView.identifier, for: indexPath) cell.contentConfiguration = MyReviewContentConfiguration( + mode: .tastes, storeImageIcon: product.storeType, imageUrl: product.imageURL, - title: product.name + title: "프링글스) 매콤한맛(대) 프링글스) 매콤한맛(대)프링글스) 매콤한맛(대)프링글스) 매콤한맛", + tastesTag: ["카페인 러버", "헬창", "캐릭터컬렉터", "캐릭터컬렉터"] ) return cell case .review(let review): let cell: ProductDetailReviewCell = collectionView.dequeueReusableCell(for: indexPath) - cell.payload = .init(review: review) + cell.payload = .init(hasEvaluateView: false, review: review) return cell case .landing: let cell: ActionButtonCell = collectionView.dequeueReusableCell(for: indexPath) @@ -104,7 +102,8 @@ final class MyDetailReviewViewController: UIViewController, } } - private func applySnapshot(with productDetail: ProductDetailEntity, review: ReviewEntity) { + private func applySnapshot(with productDetail: ProductDetailEntity?, review: ReviewEntity?) { + guard let productDetail, let review else { return } var snapshot = Snapshot() snapshot.appendSections([.main]) snapshot.appendItems([.productDetail(product: productDetail)]) @@ -114,6 +113,7 @@ final class MyDetailReviewViewController: UIViewController, } } +// MARK: - UICollectionViewDelegateFlowLayout extension MyDetailReviewViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { guard let item = dataSource?.itemIdentifier(for: indexPath) else { return CGSize.zero } @@ -128,7 +128,7 @@ extension MyDetailReviewViewController: UICollectionViewDelegateFlowLayout { origin: .zero, size: .init(width: screenWidth, height: estimateHeight) ) - cell.payload = .init(review: review) + cell.payload = .init(hasEvaluateView: false, review: review) cell.layoutIfNeeded() let estimateSize = cell.systemLayoutSizeFitting( .init(width: screenWidth, height: UIView.layoutFittingCompressedSize.height), @@ -142,6 +142,7 @@ extension MyDetailReviewViewController: UICollectionViewDelegateFlowLayout { } } +// MARK: - BackNavigationViewDelegate extension MyDetailReviewViewController: BackNavigationViewDelegate { func didTapBackButton() { listener?.didTapBackButton() diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift index f363a27b..5380c48d 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewInteractor.swift @@ -18,7 +18,7 @@ protocol MyReviewPresentable: Presentable { } protocol MyReviewListener: AnyObject { - // TODO: Declare methods the interactor can invoke to communicate with other RIBs. + func detachMyReview() } final class MyReviewInteractor: PresentableInteractor, MyReviewInteractable, MyReviewPresentableListener { @@ -46,10 +46,14 @@ final class MyReviewInteractor: PresentableInteractor, MyRe func didTapMyDetailReview(with productDetail: ProductDetailEntity, reviewId: String) { // TODO: 받아온 값으로 수정 // guard let review = productDetail.reviews.first(where: { $0.reviewId == reviewId }) else { return } - router?.attachMyDetailReview(productDetail: productDetail, review: .init(reviewId: "", taste: .good, quality: .bad, valueForMoney: .normal, score: 0, contents: "", image: nil, writerId: nil, writerName: "", createdTime: "", updatedTime: "", likeCount: .init(writerIds: [], likeCount: 0), hateCount: .init(writerIds: [], hateCount: 0))) + router?.attachMyDetailReview(productDetail: productDetail, review: .init(reviewId: "", taste: .good, quality: .bad, valueForMoney: .normal, score: 0, contents: "설명입니다 설명입니다 설명입니다 설명입니다 설명입니다 설명입니다설명입니다 설명입니다 설명입니다", image: nil, writerId: nil, writerName: "양볼 빵빵 다람쥐", createdTime: "", updatedTime: "", likeCount: .init(writerIds: [], likeCount: 0), hateCount: .init(writerIds: [], hateCount: 0))) } func didTapBackButton() { router?.detachMyDetailReview() } + + func didTapMyReviewBackButton() { + listener?.detachMyReview() + } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift index 65be7fca..02b4d01e 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/MyReviewViewController.swift @@ -9,7 +9,7 @@ import ModernRIBs import UIKit protocol MyReviewPresentableListener: AnyObject { - func didTapBackButton() + func didTapMyReviewBackButton() func didTapMyDetailReview(with productDetail: ProductDetailEntity, reviewId: String) } @@ -78,6 +78,7 @@ extension MyReviewViewController: UITableViewDataSource { let cell = tableView.dequeueReusableCell(withIdentifier: MyReviewContentView.identifier, for: indexPath) cell.selectionStyle = .none // TODO: interactor로부터 받아온 값으로 변경 cell.contentConfiguration = MyReviewContentConfiguration( + mode: .date, storeImageIcon: .sevenEleven, imageUrl: URL(string: "www.naver.com")!, title: "테스트", @@ -90,6 +91,6 @@ extension MyReviewViewController: UITableViewDataSource { // MARK: - BackNavigationViewDelegate extension MyReviewViewController: BackNavigationViewDelegate { func didTapBackButton() { - listener?.didTapBackButton() + listener?.didTapMyReviewBackButton() } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift index 89841f13..a50b274e 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentConfiguration.swift @@ -12,16 +12,27 @@ struct MyReviewContentConfiguration: UIContentConfiguration { var imageUrl: URL var title: String var date: String? + var mode: ProductInfoStackView.Mode + var tastesTag: [String]? - init(storeImageIcon: ConvenienceStore, imageUrl: URL, title: String, date: String? = nil) { + init( + mode: ProductInfoStackView.Mode, + storeImageIcon: ConvenienceStore, + imageUrl: URL, + title: String, + date: String? = nil, + tastesTag: [String]? = nil + ) { + self.mode = mode self.storeImageIcon = storeImageIcon self.imageUrl = imageUrl self.title = title self.date = date + self.tastesTag = tastesTag } func makeContentView() -> any UIView & UIContentView { - return MyReviewContentView(configuration: self) + return MyReviewContentView(configuration: self, mode: mode) } func updated(for state: any UIConfigurationState) -> MyReviewContentConfiguration { diff --git a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift index 88d0fd4e..31fd3179 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/MyReview/View/MyReviewContentView.swift @@ -14,10 +14,11 @@ class MyReviewContentView: UIView, UIContentView { var configuration: any UIContentConfiguration private let storeImageViewHeight: CGFloat = 20 - private var productInfoStackView = ProductInfoStackView(mode: .date) + private var productInfoStackView: ProductInfoStackView - init(configuration: any UIContentConfiguration) { + init(configuration: any UIContentConfiguration, mode: ProductInfoStackView.Mode) { self.configuration = configuration + self.productInfoStackView = ProductInfoStackView(mode: mode) super.init(frame: .zero) configureView() configureUI() @@ -47,8 +48,11 @@ class MyReviewContentView: UIView, UIContentView { } if let date = configuration.date { - let dateString = DateFormatter.productLastUpdateFormatter.date(from: date)?.toString() - self.productInfoStackView.dateLabel.text = dateString + self.productInfoStackView.dateLabel.text = configuration.date + } + + if let tastesTag = configuration.tastesTag { + self.productInfoStackView.setTastes(tastesTag: tastesTag) } } } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift index 682062b3..c9675fe4 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeInteractor.swift @@ -118,4 +118,8 @@ final class ProfileHomeInteractor: PresentableInteractor router?.detachLoggedOut() } + func detachMyReview() { + router?.detachMyReview() + } + } diff --git a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift index 2a90f365..4ecf4d9b 100644 --- a/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift +++ b/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/ProfileHomeRouter.swift @@ -126,7 +126,7 @@ final class ProfileHomeRouter: ViewableRouter