From d03dc89c79667bcd59a1f87228d34929b2a06d51 Mon Sep 17 00:00:00 2001 From: eung7 Date: Sat, 22 Jul 2023 20:54:23 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[Feat]=20FavorTabBarController,=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EC=A4=91=EC=95=99=20=EC=84=A0=EB=AC=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20GiftManagement=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Favor/Favor.xcodeproj/project.pbxproj | 14 +---- .../xcshareddata/swiftpm/Package.resolved | 9 --- Favor/Favor/Sources/Flows/AppFlow.swift | 26 +++++++- Favor/Favor/Sources/Flows/DashboardFlow.swift | 60 ------------------- .../FavorTabBarController.swift | 12 ++-- .../Scenes/Dashboard/Views/FavorTabBar.swift | 8 ++- 6 files changed, 39 insertions(+), 90 deletions(-) delete mode 100644 Favor/Favor/Sources/Flows/DashboardFlow.swift diff --git a/Favor/Favor.xcodeproj/project.pbxproj b/Favor/Favor.xcodeproj/project.pbxproj index e6b7f3fa..b0360e93 100644 --- a/Favor/Favor.xcodeproj/project.pbxproj +++ b/Favor/Favor.xcodeproj/project.pbxproj @@ -200,8 +200,8 @@ 2EFF672E2A5058E50097A664 /* BaseSettingsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EFF672D2A5058E50097A664 /* BaseSettingsCell.swift */; }; 2EFF67302A5059450097A664 /* SettingsTappableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EFF672F2A5059450097A664 /* SettingsTappableCell.swift */; }; 2EFF67322A5059570097A664 /* SettingsSwitchableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EFF67312A5059570097A664 /* SettingsSwitchableCell.swift */; }; - DDA780DB2A57BCBF000B6E26 /* Photo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA780DA2A57BCBF000B6E26 /* Photo.swift */; }; DD30D6BE2A53E34A0043F1BE /* ReminderDatePopup.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51A21F22A51C7AC003E676F /* ReminderDatePopup.swift */; }; + DDA780DB2A57BCBF000B6E26 /* Photo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA780DA2A57BCBF000B6E26 /* Photo.swift */; }; E51F55842A4036650002EADB /* FavorTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51F55832A4036650002EADB /* FavorTabBar.swift */; }; E523F63E2A22EBDB007A6317 /* FirendPageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = E523F63D2A22EBDB007A6317 /* FirendPageVC.swift */; }; E523F6472A231B17007A6317 /* FriendPageViewReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E523F6462A231B17007A6317 /* FriendPageViewReactor.swift */; }; @@ -218,7 +218,6 @@ E52F565B29D5698A004E85A6 /* NewGiftFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E52F565A29D5698A004E85A6 /* NewGiftFlow.swift */; }; E55CF7BA298A743B002940D1 /* AuthFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55CF7B9298A743B002940D1 /* AuthFlow.swift */; }; E55CF7C1298B5631002940D1 /* OnboardingFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55CF7C0298B5631002940D1 /* OnboardingFlow.swift */; }; - E55CF7C6298B8EBB002940D1 /* DashboardFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55CF7C5298B8EBB002940D1 /* DashboardFlow.swift */; }; E56260FC2991E4EA00D14020 /* RSKPlaceholderTextView in Frameworks */ = {isa = PBXBuildFile; productRef = E56260FB2991E4EA00D14020 /* RSKPlaceholderTextView */; }; E57F313D2970004D00E3D449 /* OnboardingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E57F313C2970004D00E3D449 /* OnboardingCell.swift */; }; E583C58F2A1E619F00DC219A /* AnniversaryBottomSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E583C58E2A1E619F00DC219A /* AnniversaryBottomSheetView.swift */; }; @@ -452,7 +451,6 @@ E52F565A29D5698A004E85A6 /* NewGiftFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGiftFlow.swift; sourceTree = ""; }; E55CF7B9298A743B002940D1 /* AuthFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFlow.swift; sourceTree = ""; }; E55CF7C0298B5631002940D1 /* OnboardingFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFlow.swift; sourceTree = ""; }; - E55CF7C5298B8EBB002940D1 /* DashboardFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardFlow.swift; sourceTree = ""; }; E57F313C2970004D00E3D449 /* OnboardingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingCell.swift; sourceTree = ""; }; E583C58E2A1E619F00DC219A /* AnniversaryBottomSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnniversaryBottomSheetView.swift; sourceTree = ""; }; E583C5902A1E627800DC219A /* FilterBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterBottomSheet.swift; sourceTree = ""; }; @@ -1566,7 +1564,6 @@ E5CFF72A298404F700E11D9A /* AppStep.swift */, 2EAC60A42A49F68B0047A572 /* AppStepper.swift */, E55CF7B9298A743B002940D1 /* AuthFlow.swift */, - E55CF7C5298B8EBB002940D1 /* DashboardFlow.swift */, E59AB0992A17858C00F0AC7D /* FriendFlow.swift */, 2E9B4CB92A1277BC00C7E31E /* FriendListFlow.swift */, E523F64D2A24DC04007A6317 /* FriendPageFlow.swift */, @@ -1833,7 +1830,6 @@ 2ED8CB4729B0C30400E7B547 /* AuthTermCell.swift in Sources */, 2ED326C329B327DE001963D0 /* AuthValidateEmailViewReactor.swift in Sources */, E583C5952A1E62A400DC219A /* MemoBottomSheet.swift in Sources */, - E51A21F52A51C7AC003E676F /* ReminderDatePopup.swift in Sources */, E524C19629EAA50C004CCC40 /* FriendSelectorHeaderView.swift in Sources */, 2E00561E29A8B131006CF302 /* ProfileSectionFooter.swift in Sources */, 2EC939E32998C63200C8C47F /* ProfileSetupHelperCell.swift in Sources */, @@ -1888,9 +1884,8 @@ 2E8FFDE02A3AAAFD00C7D254 /* SearchTagSection.swift in Sources */, 2EB3E71B29D5EB77008D10A0 /* PastSectionBackgroundView.swift in Sources */, 2EC939E12998BEAD00C8C47F /* ProfileGiftStatsCollectionHeader.swift in Sources */, - 2E7330972A52D7DB009682D2 /* BasePopup.swift in Sources */, 2E3FA75129F713A7003342CA /* EditMyPageProfileHeader.swift in Sources */, - 2E3FA75129F713A7003342CA /* EditMyPageCollectionHeaderView.swift in Sources */, + 2E3FA75129F713A7003342CA /* EditMyPageProfileHeader.swift in Sources */, 2E95E4B729E8FB8000A46C38 /* SearchUserResultCell.swift in Sources */, 2E76F58529601CD6002FF001 /* SplashVC.swift in Sources */, 2EC358E32A1E786B000313BB /* GiftDetailViewReactor.swift in Sources */, @@ -1980,7 +1975,6 @@ 2EB3E71129D4356A008D10A0 /* ReminderViewReactor.swift in Sources */, 2EC6E11F29BC6656006FBC11 /* ReminderFlow.swift in Sources */, 2E1C81B22A1EEC3100D4128E /* GiftDetailSection.swift in Sources */, - E55CF7C6298B8EBB002940D1 /* DashboardFlow.swift in Sources */, 2E6E28E42A246C6600E25DB6 /* GiftManagementPinCell.swift in Sources */, 2EC939F1299CF67E00C8C47F /* ProfileGiftStatsCollectionHeaderReactor.swift in Sources */, 2EE07ECF296E8DB500048A3C /* ReminderVC.swift in Sources */, @@ -2187,8 +2181,6 @@ OTHER_LIBTOOLFLAGS = "-WLinkingC true -XCBuildForPre true -XCExpApple true"; PRODUCT_BUNDLE_IDENTIFIER = com.favor.Favor.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "Favor GitHubActions Deploy"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Favor-iOS-Development-Provision"; PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Favor-Apple-Development-Provision"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -2231,8 +2223,6 @@ OTHER_LIBTOOLFLAGS = "-WLinkingC true -XCBuildForPre true -XCExpApple true"; PRODUCT_BUNDLE_IDENTIFIER = com.favor.Favor.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "Favor GitHubActions Deploy"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Favor-iOS-Development-Provision"; PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Favor-Apple-Development-Provision"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; diff --git a/Favor/Favor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Favor/Favor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c7fdaa3c..31509a7a 100644 --- a/Favor/Favor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Favor/Favor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -27,15 +27,6 @@ "version" : "5.0.0" } }, - { - "identity" : "hero", - "kind" : "remoteSourceControl", - "location" : "https://github.com/HeroTransitions/Hero.git", - "state" : { - "revision" : "66a554b21116fccf61b3aa2205a86f6b0cdc9766", - "version" : "1.6.2" - } - }, { "identity" : "kakao-ios-sdk", "kind" : "remoteSourceControl", diff --git a/Favor/Favor/Sources/Flows/AppFlow.swift b/Favor/Favor/Sources/Flows/AppFlow.swift index 0f3f5e12..471ba96f 100644 --- a/Favor/Favor/Sources/Flows/AppFlow.swift +++ b/Favor/Favor/Sources/Flows/AppFlow.swift @@ -46,7 +46,7 @@ public final class AppFlow: Flow { case .authIsRequired: return self.navigateToAuth() - + case .localAuthIsRequired(let location): return self.navigateToLocalAuth(request: location) @@ -55,7 +55,10 @@ public final class AppFlow: Flow { case .wayBackToRootIsRequired: return self.navigateWayBackToRoot() - + + case .giftManagementIsRequired: + return self.navigateToGiftManagement() + default: return .none } @@ -166,6 +169,22 @@ private extension AppFlow { func navigateWayBackToRoot() -> FlowContributors { return .one(flowContributor: .forwardToCurrentFlow(withStep: AppStep.authIsRequired)) } + + func navigateToGiftManagement() -> FlowContributors { + let newGiftFlow = NewGiftFlow() + + Flows.use(newGiftFlow, when: .ready) { [unowned self] root in + DispatchQueue.main.async { + root.modalPresentationStyle = .overFullScreen + self.rootViewController.present(root, animated: true) + } + } + + return .one(flowContributor: .contribute( + withNextPresentable: newGiftFlow, + withNextStepper: OneStepper(withSingleStep: AppStep.giftManagementIsRequired()) + )) + } } // MARK: - Contributors @@ -192,7 +211,8 @@ private extension AppFlow { .contribute( withNextPresentable: myPageFlow, withNextStepper: OneStepper(withSingleStep: AppStep.myPageIsRequired) - ) + ), + .contribute(withNext: self.rootViewController) ] } } diff --git a/Favor/Favor/Sources/Flows/DashboardFlow.swift b/Favor/Favor/Sources/Flows/DashboardFlow.swift deleted file mode 100644 index e47eac86..00000000 --- a/Favor/Favor/Sources/Flows/DashboardFlow.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// DashboardFlow.swift -// Favor -// -// Created by 김응철 on 2023/02/02. -// - -import UIKit - -import FavorKit -import RxFlow - -@MainActor -public final class DashboardFlow: Flow { - - // MARK: - Properties - - public var root: Presentable { self.rootViewController } - - let rootViewController: BaseNavigationController - - // MARK: - Initializer - - init(_ rootViewController: BaseNavigationController) { - self.rootViewController = rootViewController - } - - // MARK: - Navigate - - public func navigate(to step: Step) -> FlowContributors { - guard let step = step as? AppStep else { return .none } - - switch step { - case .giftManagementIsRequired: - return self.navigateToNewGift() - default: - return .none - } - } -} - -// MARK: - Navigates - -private extension DashboardFlow { - func navigateToNewGift() -> FlowContributors { - let newGiftFlow = NewGiftFlow() - - Flows.use(newGiftFlow, when: .ready) { [unowned self] root in - DispatchQueue.main.async { - root.modalPresentationStyle = .overFullScreen - self.rootViewController.present(root, animated: true) - } - } - - return .one(flowContributor: .contribute( - withNextPresentable: newGiftFlow, - withNextStepper: OneStepper(withSingleStep: AppStep.giftManagementIsRequired()) - )) - } -} diff --git a/Favor/Favor/Sources/Scenes/Dashboard/ViewControllers/FavorTabBarController.swift b/Favor/Favor/Sources/Scenes/Dashboard/ViewControllers/FavorTabBarController.swift index 25692a58..9ead6ec2 100644 --- a/Favor/Favor/Sources/Scenes/Dashboard/ViewControllers/FavorTabBarController.swift +++ b/Favor/Favor/Sources/Scenes/Dashboard/ViewControllers/FavorTabBarController.swift @@ -51,10 +51,7 @@ final class FavorTabBarController: UITabBarController, Stepper { self.delegate = self self.setValue(self.favorTabBar, forKey: "tabBar") self.favorTabBar.selectedIndex = 0 - - self.favorTabBar.middleButtonObserver = { - // TODO: GiftManagement페이지로 이동합니다. - } + self.favorTabBar.eventDelegate = self } /// 탭 바의 높이를 조정해주는 메서드입니다. @@ -73,3 +70,10 @@ extension FavorTabBarController: UITabBarControllerDelegate { HapticManager.haptic(style: .soft) } } + +extension FavorTabBarController: FavorTabBarDelegate { + /// 중앙의 선물 추가 버튼을 누르면 실행되는 메서드입니다. + func didTapAddGiftButton() { + self.steps.accept(AppStep.giftManagementIsRequired()) + } +} diff --git a/Favor/Favor/Sources/Scenes/Dashboard/Views/FavorTabBar.swift b/Favor/Favor/Sources/Scenes/Dashboard/Views/FavorTabBar.swift index 64b92697..57e0f25c 100644 --- a/Favor/Favor/Sources/Scenes/Dashboard/Views/FavorTabBar.swift +++ b/Favor/Favor/Sources/Scenes/Dashboard/Views/FavorTabBar.swift @@ -11,6 +11,10 @@ import FavorKit import RxSwift import SnapKit +protocol FavorTabBarDelegate: AnyObject { + func didTapAddGiftButton() +} + final class FavorTabBar: UITabBar { // MARK: - UI Components @@ -35,7 +39,7 @@ final class FavorTabBar: UITabBar { } var isDrawn: Bool = false - var middleButtonObserver: (() -> Void)? + weak var eventDelegate: FavorTabBarDelegate? // MARK: - DrawCycle @@ -201,7 +205,7 @@ final class FavorTabBar: UITabBar { /// 중앙 버튼이 터치될 때 불려지는 메서드입니다. @objc private func didTapMiddleButton() { - self.middleButtonObserver?() + self.eventDelegate?.didTapAddGiftButton() } } From 2fd19fb66c8e4aa138c57ebe63b515ffe249faa0 Mon Sep 17 00:00:00 2001 From: eung7 Date: Sun, 23 Jul 2023 13:17:16 +0900 Subject: [PATCH 2/6] =?UTF-8?q?GiftDetailVC=20=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=84=A0=EB=AC=BC=20=EA=B3=A0=EC=A0=95=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?API=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20UI=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EC=95=88=20=EB=90=98=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Favor/Favor/Sources/Flows/AppFlow.swift | 6 ++--- Favor/Favor/Sources/Flows/HomeFlow.swift | 2 +- Favor/Favor/Sources/Flows/NewGiftFlow.swift | 4 +-- .../Gift/Reactors/GiftDetailViewReactor.swift | 26 +++++++++---------- .../Views/Cells/GiftDetailTitleCell.swift | 14 +++++----- .../Home/Reactors/HomeViewReactor.swift | 14 +++++++--- .../Scenes/Home/ViewControllers/HomeVC.swift | 12 ++++----- .../Home/Views/Cells/HomeTimelineCell.swift | 2 +- .../Managers/Realm/Realm+Transaction.swift | 4 +-- .../Managers/Realm/Realm+Workbench.swift | 4 +-- 10 files changed, 46 insertions(+), 42 deletions(-) diff --git a/Favor/Favor/Sources/Flows/AppFlow.swift b/Favor/Favor/Sources/Flows/AppFlow.swift index 471ba96f..798f564b 100644 --- a/Favor/Favor/Sources/Flows/AppFlow.swift +++ b/Favor/Favor/Sources/Flows/AppFlow.swift @@ -165,17 +165,17 @@ private extension AppFlow { return .none } - + func navigateWayBackToRoot() -> FlowContributors { return .one(flowContributor: .forwardToCurrentFlow(withStep: AppStep.authIsRequired)) } func navigateToGiftManagement() -> FlowContributors { let newGiftFlow = NewGiftFlow() - + Flows.use(newGiftFlow, when: .ready) { [unowned self] root in DispatchQueue.main.async { - root.modalPresentationStyle = .overFullScreen + root.modalPresentationStyle = .fullScreen self.rootViewController.present(root, animated: true) } } diff --git a/Favor/Favor/Sources/Flows/HomeFlow.swift b/Favor/Favor/Sources/Flows/HomeFlow.swift index b8f41b5f..12d997e0 100644 --- a/Favor/Favor/Sources/Flows/HomeFlow.swift +++ b/Favor/Favor/Sources/Flows/HomeFlow.swift @@ -62,7 +62,7 @@ private extension HomeFlow { withNextStepper: homeReactor )) } - + func navigateToSearch() -> FlowContributors { let searchFlow = SearchFlow(rootViewController: self.rootViewController) diff --git a/Favor/Favor/Sources/Flows/NewGiftFlow.swift b/Favor/Favor/Sources/Flows/NewGiftFlow.swift index 79062a89..a7106856 100644 --- a/Favor/Favor/Sources/Flows/NewGiftFlow.swift +++ b/Favor/Favor/Sources/Flows/NewGiftFlow.swift @@ -36,10 +36,10 @@ final class NewGiftFlow: Flow { case .friendManagementIsRequired: return self.navigateToFriendManagement() - + case .giftManagementIsCompleteWithNoChanges: return self.popToTabBar() - + case .newGiftIsComplete(let gift): return self.popToTabBar(with: gift) diff --git a/Favor/Favor/Sources/Scenes/Gift/Reactors/GiftDetailViewReactor.swift b/Favor/Favor/Sources/Scenes/Gift/Reactors/GiftDetailViewReactor.swift index 2eab53c6..faa6ea74 100644 --- a/Favor/Favor/Sources/Scenes/Gift/Reactors/GiftDetailViewReactor.swift +++ b/Favor/Favor/Sources/Scenes/Gift/Reactors/GiftDetailViewReactor.swift @@ -17,10 +17,10 @@ final class GiftDetailViewReactor: Reactor, Stepper { typealias Item = GiftDetailSectionItem // MARK: - Properties - + var initialState: State var steps = PublishRelay() - + enum Action { case editButtonDidTap case deleteButtonDidTap @@ -34,7 +34,7 @@ final class GiftDetailViewReactor: Reactor, Stepper { case friendsTagDidTap([Friend]) case doNothing } - + enum Mutation { case updateGift(Gift) } @@ -46,21 +46,21 @@ final class GiftDetailViewReactor: Reactor, Stepper { } // MARK: - Initializer - + init(gift: Gift) { self.initialState = State( gift: gift ) } - + // MARK: - Functions - + func mutate(action: Action) -> Observable { switch action { case .editButtonDidTap: self.steps.accept(AppStep.giftManagementIsRequired(self.currentState.gift)) return .empty() - + case .deleteButtonDidTap: return self.requestDeleteGift(self.currentState.gift) .asObservable() @@ -82,9 +82,7 @@ final class GiftDetailViewReactor: Reactor, Stepper { return .empty() case .isPinnedButtonDidTap: - var updatedGift = self.currentState.gift - updatedGift.isPinned.toggle() - return self.requestToggleIsPinned(updatedGift) + return self.requestToggleIsPinned(self.currentState.gift) .asObservable() .flatMap { gift -> Observable in return .just(.updateGift(gift)) @@ -93,7 +91,7 @@ final class GiftDetailViewReactor: Reactor, Stepper { print(error) return .empty() } - + case .emotionTagDidTap(let emotion): self.steps.accept(AppStep.searchEmotionResultIsRequired(emotion)) return .empty() @@ -101,7 +99,7 @@ final class GiftDetailViewReactor: Reactor, Stepper { case .categoryTagDidTap(let category): self.steps.accept(AppStep.searchCategoryResultIsRequired(category)) return .empty() - + case .isGivenTagDidTap(let isGiven): // TODO: 타임라인 단독 화면 만든 후 연결 os_log(.debug, "IsGiven tag did tap: \(isGiven).") @@ -168,11 +166,11 @@ private extension GiftDetailViewReactor { } } } - + func requestToggleIsPinned(_ gift: Gift) -> Single { return Single.create { single in let networking = GiftNetworking() - let disposable = networking.request(.patchGift(gift.updateRequestDTO(), giftNo: gift.identifier)) + let disposable = networking.request(.patchPinGift(giftNo: gift.identifier)) .take(1) .asSingle() .subscribe(onSuccess: { response in diff --git a/Favor/Favor/Sources/Scenes/Gift/Views/Cells/GiftDetailTitleCell.swift b/Favor/Favor/Sources/Scenes/Gift/Views/Cells/GiftDetailTitleCell.swift index 55c7a74d..810e69bc 100644 --- a/Favor/Favor/Sources/Scenes/Gift/Views/Cells/GiftDetailTitleCell.swift +++ b/Favor/Favor/Sources/Scenes/Gift/Views/Cells/GiftDetailTitleCell.swift @@ -39,23 +39,23 @@ final class GiftDetailTitleCell: BaseCollectionViewCell { private let pinButton: UIButton = { var config = UIButton.Configuration.plain() config.background.backgroundColor = .clear - config.image = .favorIcon(.pin)?.withRenderingMode(.alwaysTemplate) + let pinImage: UIImage? = .favorIcon(.pin) config.contentInsets = .zero - + let button = UIButton(configuration: config) button.configurationUpdateHandler = { button in switch button.state { case .normal: - button.configuration?.baseForegroundColor = .favorColor(.line2) + button.configuration?.image = pinImage?.withTintColor(.favorColor(.line2)) case .selected: - button.configuration?.baseForegroundColor = .favorColor(.icon) + button.configuration?.image = pinImage?.withTintColor(.favorColor(.icon)) default: break } } return button }() - + private let titleStack: UIStackView = { let stackView = UIStackView() stackView.axis = .horizontal @@ -77,7 +77,7 @@ final class GiftDetailTitleCell: BaseCollectionViewCell { stackView.alignment = .leading return stackView }() - + // MARK: - Initializer override init(frame: CGRect) { @@ -104,7 +104,7 @@ final class GiftDetailTitleCell: BaseCollectionViewCell { } // MARK: - Functions - + private func updateGift() { self.titleLabel.text = self.gift.name self.pinButton.isSelected = self.gift.isPinned diff --git a/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift b/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift index 19feb774..518933f7 100644 --- a/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift +++ b/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift @@ -174,10 +174,10 @@ final class HomeViewReactor: Reactor, Stepper { case .updateTimelineLoading(let isLoading): newState.isTimelineLoading = isLoading } - + return newState } - + // transform(state:)는 State stream에 영향을 주지 않습니다. // 단지 View에 최종적으로 전달되는 State에 변형을 줄 뿐입니다. = 저장되어있는 State는 변하지 않습니다. func transform(state: Observable) -> Observable { @@ -252,7 +252,7 @@ private extension HomeViewReactor { } } } - + func setupGiftFetcher() { // onRemote self.giftFetcher.onRemote = { @@ -277,8 +277,14 @@ private extension HomeViewReactor { .map { Gift(realmObject: $0) } } // onLocalUpdate - self.giftFetcher.onLocalUpdate = { _, remoteGifts in + self.giftFetcher.onLocalUpdate = { localGifts, remoteGifts in + // 삭제시킬 선물을 찾습니다. + let deleteGifts = localGifts.filter { localGift in + !remoteGifts.map { $0.identifier }.contains(localGift.identifier) + } + try await self.workbench.write { transaction in + deleteGifts.forEach { transaction.delete($0.realmObject()) } transaction.update(remoteGifts.map { $0.realmObject() }) } } diff --git a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift index 8764aade..4c19168a 100644 --- a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift +++ b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift @@ -28,7 +28,7 @@ final class HomeViewController: BaseViewController, View { private let searchButton: UIButton = { var config = UIButton.Configuration.plain() config.image = .favorIcon(.search) - + let button = UIButton(configuration: config) return button }() @@ -62,7 +62,7 @@ final class HomeViewController: BaseViewController, View { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + self.setupNavigationBar() } @@ -93,7 +93,7 @@ final class HomeViewController: BaseViewController, View { .map { Reactor.Action.searchButtonDidTap } .bind(to: reactor.action) .disposed(by: self.disposeBag) - + self.collectionView.rx.itemSelected .map { indexPath in guard let dataSource = self.dataSource else { fatalError() } @@ -184,7 +184,7 @@ private extension HomeViewController { cell.bindEmptyData(image: image, text: title) } } - + let upcomingCellRegistration = UICollectionView.CellRegistration { [weak self] cell, _, item in guard @@ -193,7 +193,7 @@ private extension HomeViewController { else { return } cell.bind(with: reminder) } - + let timelineCellRegistration = UICollectionView.CellRegistration { [weak self] cell, _, item in guard @@ -202,7 +202,7 @@ private extension HomeViewController { else { return } cell.bind(with: gift) } - + self.dataSource = HomeDataSource( collectionView: self.collectionView, cellProvider: { collectionView, indexPath, item in diff --git a/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift b/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift index 4e111acf..2a831839 100644 --- a/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift +++ b/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift @@ -51,7 +51,7 @@ final class HomeTimelineCell: BaseCollectionViewCell { } // MARK: - Functions - + public func bind(with gift: Gift) { // Image // TODO: 테스트 코드 삭제 diff --git a/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Transaction.swift b/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Transaction.swift index 03c6c8d7..44a92b85 100644 --- a/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Transaction.swift +++ b/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Transaction.swift @@ -51,7 +51,7 @@ public final class Transaction { ) where T: Object { self.realm.add(value, update: update) } - + /// `RealmObject` 인스턴스를 여러개 받아 직접 `update` 합니다. public func update( _ values: [T], @@ -59,7 +59,7 @@ public final class Transaction { ) where T: Object { self.realm.add(values, update: update) } - + /// `RealmObject` 인스턴스를 받아 직접 `delete`합니다. public func delete( _ value: T diff --git a/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Workbench.swift b/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Workbench.swift index a1c6f66b..efb37ab4 100644 --- a/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Workbench.swift +++ b/Favor/FavorKit/Sources/FavorKit/Managers/Realm/Realm+Workbench.swift @@ -26,7 +26,7 @@ public final class RealmWorkbench { queue: DispatchQueue = DispatchQueue.realmThread ) { self.realmQueue = queue - + do { let config = Realm.Configuration( schemaVersion: RealmMigration.version, @@ -47,7 +47,7 @@ public final class RealmWorkbench { public func locateRealm() { os_log(.debug, "💽 RealmDB is located at \(self.realm.configuration.fileURL!)") } - + public func write( _ block: @escaping (_ transaction: Transaction) throws -> Void ) async throws { From 1f52770301da5dc4f949df4bf9fe79ccaa6acabe Mon Sep 17 00:00:00 2001 From: eung7 Date: Sun, 23 Jul 2023 13:54:53 +0900 Subject: [PATCH 3/6] =?UTF-8?q?HomeVC=20=ED=95=80=20=EC=97=AC=EB=B6=80=20U?= =?UTF-8?q?I=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=95=88=20?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Favor/Favor/Sources/Scenes/Home/HomeSection.swift | 2 +- .../Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift | 6 +++++- .../Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Favor/Favor/Sources/Scenes/Home/HomeSection.swift b/Favor/Favor/Sources/Scenes/Home/HomeSection.swift index 72347016..a84e19af 100644 --- a/Favor/Favor/Sources/Scenes/Home/HomeSection.swift +++ b/Favor/Favor/Sources/Scenes/Home/HomeSection.swift @@ -20,7 +20,7 @@ enum HomeSectionItem: ComposableItem { case empty(UIImage?, String) case reminder(Reminder) } - + enum Timeline: Hashable { case empty(UIImage?, String) case gift(Gift) diff --git a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift index 4c19168a..83ac723e 100644 --- a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift +++ b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift @@ -155,7 +155,7 @@ final class HomeViewController: BaseViewController, View { } DispatchQueue.main.async { - dataSource.apply(snapshot) + dataSource.applySnapshotUsingReloadData(snapshot) } }) .disposed(by: self.disposeBag) @@ -201,6 +201,10 @@ private extension HomeViewController { case let HomeSectionItem.timeline(.gift(gift)) = item else { return } cell.bind(with: gift) + + cell.configurationUpdateHandler = { cell, _ in + print(item) + } } self.dataSource = HomeDataSource( diff --git a/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift b/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift index 2a831839..1c08006d 100644 --- a/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift +++ b/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift @@ -53,6 +53,7 @@ final class HomeTimelineCell: BaseCollectionViewCell { // MARK: - Functions public func bind(with gift: Gift) { + print("PINSTATUS: \(gift.isPinned)") // Image // TODO: 테스트 코드 삭제 let url = URL(string: "https://picsum.photos/1200/1200")! From 61b8803a0b2869ef645b82089849c5ba9ab86f44 Mon Sep 17 00:00:00 2001 From: eung7 Date: Sun, 23 Jul 2023 17:36:32 +0900 Subject: [PATCH 4/6] =?UTF-8?q?HomeVC=20=EC=84=A0=EB=AC=BC=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Favor/Favor/Sources/Flows/HomeFlow.swift | 51 +++++++++---------- .../Sources/Scenes/FilterBottomSheet.swift | 23 ++++++--- .../Gift/ViewControllers/GiftDetailVC.swift | 6 +-- .../Sources/Scenes/Home/HomeSection.swift | 24 --------- .../Home/Reactors/HomeViewReactor.swift | 31 +++++++---- .../Scenes/Home/ViewControllers/HomeVC.swift | 28 +++++++--- .../Home/Views/Cells/HomeTimelineCell.swift | 5 +- 7 files changed, 86 insertions(+), 82 deletions(-) diff --git a/Favor/Favor/Sources/Flows/HomeFlow.swift b/Favor/Favor/Sources/Flows/HomeFlow.swift index 12d997e0..7184f746 100644 --- a/Favor/Favor/Sources/Flows/HomeFlow.swift +++ b/Favor/Favor/Sources/Flows/HomeFlow.swift @@ -37,9 +37,6 @@ final class HomeFlow: Flow { case .reminderIsRequired: return self.navigateToReminder() - case .filterBottomSheetIsRequired(let sortType): - return self.navigateToFilter(sortedBy: sortType) - case .giftDetailIsRequired(let gift): return self.navigateToGift(with: gift) @@ -90,29 +87,29 @@ private extension HomeFlow { )) } - func navigateToFilter(sortedBy sortType: SortType) -> FlowContributors { - let filterBottomSheet = FilterBottomSheet() - filterBottomSheet.currentSortType = sortType - filterBottomSheet.modalPresentationStyle = .overFullScreen - self.rootViewController.present(filterBottomSheet, animated: false) - self.filterBottomSheet = filterBottomSheet - - return .one(flowContributor: .contribute( - withNextPresentable: filterBottomSheet, - withNextStepper: filterBottomSheet - )) - } +// func navigateToFilter(sortedBy sortType: SortType) -> FlowContributors { +// let filterBottomSheet = FilterBottomSheet() +// filterBottomSheet.currentSortType = sortType +// filterBottomSheet.modalPresentationStyle = .overFullScreen +// self.rootViewController.present(filterBottomSheet, animated: false) +// self.filterBottomSheet = filterBottomSheet +// +// return .one(flowContributor: .contribute( +// withNextPresentable: filterBottomSheet, +// withNextStepper: filterBottomSheet +// )) +// } - func dismissFilter(sortedBy sortType: SortType) -> FlowContributors { - self.filterBottomSheet?.animateDismissView() - self.filterBottomSheet = nil - - guard let homeVC = self.rootViewController.topViewController as? HomeViewController else { - return .none - } - // TODO: Realm DB 구현하며 Sort, Filter 방식 변경 -// homeVC.reactor?.currentSortType.accept(sortType) -// homeVC.filterDidEnded() - return .none - } +// func dismissFilter(sortedBy sortType: SortType) -> FlowContributors { +// self.filterBottomSheet?.animateDismissView() +// self.filterBottomSheet = nil +// +// guard let homeVC = self.rootViewController.topViewController as? HomeViewController else { +// return .none +// } +// // TODO: Realm DB 구현하며 Sort, Filter 방식 변경 +//// homeVC.reactor?.currentSortType.accept(sortType) +//// homeVC.filterDidEnded() +// return .none +// } } diff --git a/Favor/Favor/Sources/Scenes/FilterBottomSheet.swift b/Favor/Favor/Sources/Scenes/FilterBottomSheet.swift index 21653016..45fdaa20 100644 --- a/Favor/Favor/Sources/Scenes/FilterBottomSheet.swift +++ b/Favor/Favor/Sources/Scenes/FilterBottomSheet.swift @@ -12,26 +12,31 @@ import RxCocoa import RxFlow import RxSwift -final class FilterBottomSheet: BaseBottomSheet, Stepper { +protocol FilterBottomSheetDelegate: AnyObject { + func didTapSortButton(_ sortType: SortType) +} + +final class FilterBottomSheet: BaseBottomSheet { // MARK: - Properties private lazy var latestButton = self.makeSelectionButton(title: "최신순") private lazy var oldestButton = self.makeSelectionButton(title: "과거순") private lazy var buttons: [UIButton] = [] - - var steps = PublishRelay() - + public var currentSortType: SortType = .latest { didSet { self.updateButton() } } + weak var delegate: FilterBottomSheetDelegate? + // MARK: - Setup override func setupStyles() { super.setupStyles() self.updateTitle("필터") self.cancelButton.isHidden = true + self.finishButton.isHidden = true self.buttons = [latestButton, oldestButton] self.updateButton() } @@ -70,15 +75,17 @@ final class FilterBottomSheet: BaseBottomSheet, Stepper { .asDriver(onErrorRecover: { _ in return .empty()}) .drive(with: self, onNext: { owner, _ in owner.currentSortType = .latest -// owner.steps.accept(AppStep.filterBottomSheetIsComplete(.latest)) + owner.delegate?.didTapSortButton(.latest) + owner.dismissBottomSheet() }) .disposed(by: self.disposeBag) - + self.oldestButton.rx.tap .asDriver(onErrorRecover: { _ in return .empty()}) .drive(with: self, onNext: { owner, _ in owner.currentSortType = .oldest -// owner.steps.accept(AppStep.filterBottomSheetIsComplete(.oldest)) + owner.delegate?.didTapSortButton(.oldest) + owner.dismissBottomSheet() }) .disposed(by: self.disposeBag) } @@ -105,7 +112,7 @@ private extension FilterBottomSheet { config.imagePlacement = .leading config.imagePadding = 20 config.baseBackgroundColor = .clear - + let button = UIButton(configuration: config) button.configurationUpdateHandler = { button in var config = button.configuration diff --git a/Favor/Favor/Sources/Scenes/Gift/ViewControllers/GiftDetailVC.swift b/Favor/Favor/Sources/Scenes/Gift/ViewControllers/GiftDetailVC.swift index 330805fa..0deb2f6a 100644 --- a/Favor/Favor/Sources/Scenes/Gift/ViewControllers/GiftDetailVC.swift +++ b/Favor/Favor/Sources/Scenes/Gift/ViewControllers/GiftDetailVC.swift @@ -205,13 +205,13 @@ private extension GiftDetailViewController { else { return } // Image } - + let titleCellRegistration = UICollectionView.CellRegistration { [weak self] cell, _, _ in guard let self = self, let reactor = self.reactor else { return } cell.delegate = self cell.gift = reactor.currentState.gift - + cell.configurationUpdateHandler = { cell, _ in guard let cell = cell as? GiftDetailTitleCell, @@ -220,7 +220,7 @@ private extension GiftDetailViewController { cell.gift = reactor.currentState.gift } } - + let tagsCellRegistration = UICollectionView.CellRegistration { [weak self] cell, _, _ in guard let self = self, let reactor = self.reactor else { return } diff --git a/Favor/Favor/Sources/Scenes/Home/HomeSection.swift b/Favor/Favor/Sources/Scenes/Home/HomeSection.swift index a84e19af..2af4a329 100644 --- a/Favor/Favor/Sources/Scenes/Home/HomeSection.swift +++ b/Favor/Favor/Sources/Scenes/Home/HomeSection.swift @@ -34,30 +34,6 @@ public enum HomeSection: ComposableSection { case timeline(isEmpty: Bool) } -// MARK: - Hashable - -extension HomeSection { - public static func == (lhs: Self, rhs: Self) -> Bool { - switch (lhs, rhs) { - case (.upcoming, .upcoming): - return true - case (.timeline, .timeline): - return true - default: - return false - } - } - - public func hash(into hasher: inout Hasher) { - switch self { - case .upcoming: - hasher.combine("upcoming") - case .timeline: - hasher.combine("timeline") - } - } -} - // MARK: - Composer extension HomeSection: Composable { diff --git a/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift b/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift index 518933f7..61d8e0f5 100644 --- a/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift +++ b/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift @@ -32,6 +32,7 @@ final class HomeViewReactor: Reactor, Stepper { enum Action { case viewNeedsLoaded + case didChangeSortType(SortType) case searchButtonDidTap case rightButtonDidTap(HomeSection) case filterButtonDidSelected(GiftFilterType) @@ -50,6 +51,7 @@ final class HomeViewReactor: Reactor, Stepper { case updateFilterType(GiftFilterType) case updateLoading(Bool) case updateTimelineLoading(Bool) + case updateSortType(SortType) } struct State { @@ -108,17 +110,15 @@ final class HomeViewReactor: Reactor, Stepper { ]) } } - + case .searchButtonDidTap: os_log(.debug, "Search button did tap.") self.steps.accept(AppStep.searchIsRequired) return .empty() - + case .rightButtonDidTap(let section): if case Section.upcoming = section { self.steps.accept(AppStep.reminderIsRequired) - } else if case Section.timeline = section { - self.steps.accept(AppStep.filterBottomSheetIsRequired(self.currentSortType.value)) } return .empty() @@ -127,11 +127,10 @@ final class HomeViewReactor: Reactor, Stepper { case let .updateMaxTimelineItems((currentMaxItems, unit)): return .just(.updateMaxTimelineItems((current: currentMaxItems, unit: unit))) - + case .itemSelected(let item): if case let Item.upcoming(upcoming) = item { guard case let Item.Upcoming.reminder(reminder) = upcoming else { return .empty() } - print(reminder) } else if case let Item.timeline(timeline) = item { guard case let Item.Timeline.gift(gift) = timeline else { return .empty() } self.steps.accept(AppStep.giftDetailIsRequired(gift)) @@ -140,6 +139,9 @@ final class HomeViewReactor: Reactor, Stepper { case .timelineNeedsLoaded(let isLoading): return .just(.updateTimelineLoading(isLoading)) + + case .didChangeSortType(let sortType): + return .just(.updateSortType(sortType)) } } @@ -173,6 +175,9 @@ final class HomeViewReactor: Reactor, Stepper { case .updateTimelineLoading(let isLoading): newState.isTimelineLoading = isLoading + + case .updateSortType(let sortType): + newState.currentSortType = sortType } return newState @@ -195,12 +200,18 @@ final class HomeViewReactor: Reactor, Stepper { } else { newState.upcomingItems = upcomingItems } - + // Timeline 데이터를 조건에 따라 Item으로 변환합니다. let filteredGifts = state.gifts.filter(by: state.filterType) let (pinnedGifts, unpinnedGifts) = filteredGifts.sort(by: .isPinned) - let pinnedTimelines: [Item] = pinnedGifts.map { .timeline(.gift($0)) } - let unpinnedTimelines: [Item] = unpinnedGifts.map { .timeline(.gift($0)) } + var pinnedTimelines: [Item] = pinnedGifts.map { .timeline(.gift($0)) } + var unpinnedTimelines: [Item] = unpinnedGifts.map { .timeline(.gift($0)) } + + if self.currentState.currentSortType == .latest { + pinnedTimelines.reverse() + unpinnedTimelines.reverse() + } + let totalTimelines: [Item] = pinnedTimelines + unpinnedTimelines // Load 최대 개수 만큼만 반환 let croppedTimelines = totalTimelines.prefix(self.currentState.maxTimelineItems.current).wrap() @@ -211,7 +222,7 @@ final class HomeViewReactor: Reactor, Stepper { } else { newState.timelineItems = croppedTimelines } - + newState.items = [newState.upcomingItems, newState.timelineItems] return newState diff --git a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift index 83ac723e..9d99b2ed 100644 --- a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift +++ b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift @@ -152,14 +152,15 @@ final class HomeViewController: BaseViewController, View { snapshot.appendSections(sectionData.sections) sectionData.items.enumerated().forEach { idx, item in snapshot.appendItems(item, toSection: sectionData.sections[idx]) + snapshot.reconfigureItems(item) } DispatchQueue.main.async { - dataSource.applySnapshotUsingReloadData(snapshot) + dataSource.apply(snapshot) } }) .disposed(by: self.disposeBag) - + reactor.state.map { $0.isLoading } .bind(to: self.rx.isLoading) .disposed(by: self.disposeBag) @@ -201,10 +202,6 @@ private extension HomeViewController { case let HomeSectionItem.timeline(.gift(gift)) = item else { return } cell.bind(with: gift) - - cell.configurationUpdateHandler = { cell, _ in - print(item) - } } self.dataSource = HomeDataSource( @@ -271,7 +268,16 @@ private extension HomeViewController { extension HomeViewController: HomeHeaderViewDelegate { func rightButtonDidTap(from view: HomeHeaderView, for section: HomeSection) { guard let reactor = self.reactor else { return } - reactor.action.onNext(.rightButtonDidTap(section)) + switch section { + case .upcoming: + reactor.action.onNext(.rightButtonDidTap(section)) + case .timeline: + let filterBottomSheet = FilterBottomSheet() + filterBottomSheet.currentSortType = reactor.currentState.currentSortType + filterBottomSheet.modalPresentationStyle = .overFullScreen + filterBottomSheet.delegate = self + self.present(filterBottomSheet, animated: false) + } } func filterDidSelected(from view: HomeHeaderView, to filterType: GiftFilterType) { @@ -279,3 +285,11 @@ extension HomeViewController: HomeHeaderViewDelegate { reactor.action.onNext(.filterButtonDidSelected(filterType)) } } + +extension HomeViewController: FilterBottomSheetDelegate { + func didTapSortButton(_ sortType: SortType) { + guard let reactor = self.reactor else { return } + reactor.action.onNext(.didChangeSortType(sortType)) + reactor.action.onNext(.viewNeedsLoaded) + } +} diff --git a/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift b/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift index 1c08006d..668a676c 100644 --- a/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift +++ b/Favor/Favor/Sources/Scenes/Home/Views/Cells/HomeTimelineCell.swift @@ -22,14 +22,14 @@ final class HomeTimelineCell: BaseCollectionViewCell { // MARK: - Properties // MARK: - UI Components - + private lazy var imageView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFill imageView.backgroundColor = .favorColor(.background) return imageView }() - + private lazy var pinnedIconView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .center @@ -53,7 +53,6 @@ final class HomeTimelineCell: BaseCollectionViewCell { // MARK: - Functions public func bind(with gift: Gift) { - print("PINSTATUS: \(gift.isPinned)") // Image // TODO: 테스트 코드 삭제 let url = URL(string: "https://picsum.photos/1200/1200")! From eedb29e2a3031e42cfd7139a1676b82eab8f90e9 Mon Sep 17 00:00:00 2001 From: eung7 Date: Sun, 23 Jul 2023 21:13:27 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[Fix]=20HomeVC=20GiftSortSection=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=84=A0=ED=83=9D=20=EC=8B=9C,=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EC=A0=84=EC=9C=BC=EB=A1=9C=20=EB=8B=A4?= =?UTF-8?q?=EC=8B=9C=20=EB=90=98=EB=8F=8C=EC=95=84=EA=B0=80=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Home/Reactors/HomeViewReactor.swift | 2 +- .../Scenes/Home/ViewControllers/HomeVC.swift | 16 +++--- .../Scenes/Home/Views/HomeHeaderView.swift | 54 ++++++++++--------- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift b/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift index 61d8e0f5..1f6957b2 100644 --- a/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift +++ b/Favor/Favor/Sources/Scenes/Home/Reactors/HomeViewReactor.swift @@ -188,7 +188,7 @@ final class HomeViewReactor: Reactor, Stepper { func transform(state: Observable) -> Observable { return state.map { state in var newState = state - + // Upcoming 데이터를 조건에 따라 Item으로 변환합니다. let (futureReminders, _) = state.reminders.sort() let upcomingThreeReminders: [Reminder] = futureReminders.prefix(3).wrap() diff --git a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift index 9d99b2ed..cefc0631 100644 --- a/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift +++ b/Favor/Favor/Sources/Scenes/Home/ViewControllers/HomeVC.swift @@ -228,25 +228,25 @@ private extension HomeViewController { } } }) - + let headerRegistration = UICollectionView.SupplementaryRegistration( elementKind: UICollectionView.elementKindSectionHeader ) { [weak self] header, _, indexPath in guard let self = self, - let dataSource = self.dataSource + let section = self.dataSource?.sectionIdentifier(for: indexPath.section) else { return } header.delegate = self - let currentSnapshot = dataSource.snapshot() - header.section = currentSnapshot.sectionIdentifiers[indexPath.section] + header.section = section + header.toggleButton(self.reactor?.currentState.filterType ?? .all) } - + let footerRegistration = UICollectionView.SupplementaryRegistration( elementKind: UICollectionView.elementKindSectionFooter ) { [weak self] _, _, _ in guard self != nil else { return } } - + self.dataSource?.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in guard self != nil else { return UICollectionReusableView() } switch kind { @@ -279,13 +279,15 @@ extension HomeViewController: HomeHeaderViewDelegate { self.present(filterBottomSheet, animated: false) } } - + func filterDidSelected(from view: HomeHeaderView, to filterType: GiftFilterType) { guard let reactor = self.reactor else { return } reactor.action.onNext(.filterButtonDidSelected(filterType)) } } +// MARK: - FilterBottomSheet + extension HomeViewController: FilterBottomSheetDelegate { func didTapSortButton(_ sortType: SortType) { guard let reactor = self.reactor else { return } diff --git a/Favor/Favor/Sources/Scenes/Home/Views/HomeHeaderView.swift b/Favor/Favor/Sources/Scenes/Home/Views/HomeHeaderView.swift index 01490584..eb46195e 100644 --- a/Favor/Favor/Sources/Scenes/Home/Views/HomeHeaderView.swift +++ b/Favor/Favor/Sources/Scenes/Home/Views/HomeHeaderView.swift @@ -28,14 +28,18 @@ public class HomeHeaderView: UICollectionReusableView { // MARK: - Properties public var disposeBag = DisposeBag() - + public weak var delegate: HomeHeaderViewDelegate? public var section: HomeSection { didSet { self.updateToSection() } } - private let selectedFilter = PublishRelay() + private var selectedFilter: GiftFilterType = .all { + didSet { + self.delegate?.filterDidSelected(from: self, to: self.selectedFilter) + } + } // MARK: - UI Components @@ -45,12 +49,12 @@ public class HomeHeaderView: UICollectionReusableView { label.text = "헤더 타이틀" return label }() - + private let rightButton: UIButton = { var config = UIButton.Configuration.plain() config.background.backgroundColor = .clear config.baseForegroundColor = .favorColor(.icon) - + let button = UIButton(configuration: config) return button }() @@ -96,7 +100,7 @@ public class HomeHeaderView: UICollectionReusableView { } // MARK: - Binding - + public func bind() { // Action self.rightButton.rx.tap @@ -105,31 +109,23 @@ public class HomeHeaderView: UICollectionReusableView { owner.delegate?.rightButtonDidTap(from: owner, for: owner.section) }) .disposed(by: self.disposeBag) - + self.allButton.rx.tap .map { .all } - .bind(to: self.selectedFilter) + .asDriver(onErrorRecover: { _ in return .empty() }) + .drive(with: self) { $0.toggleButton($1) } .disposed(by: self.disposeBag) - + self.receivedButton.rx.tap .map { .received } - .bind(to: self.selectedFilter) + .asDriver(onErrorRecover: { _ in return .empty() }) + .drive(with: self) { $0.toggleButton($1) } .disposed(by: self.disposeBag) - + self.givenButton.rx.tap .map { .given } - .bind(to: self.selectedFilter) - .disposed(by: self.disposeBag) - - self.selectedFilter - .distinctUntilChanged() - .asDriver(onErrorRecover: { _ in return .empty()}) - .drive(with: self, onNext: { owner, selectedFilter in - owner.allButton.isSelected = owner.allButton == owner.buttons[selectedFilter.rawValue] - owner.receivedButton.isSelected = owner.receivedButton == owner.buttons[selectedFilter.rawValue] - owner.givenButton.isSelected = owner.givenButton == owner.buttons[selectedFilter.rawValue] - owner.delegate?.filterDidSelected(from: owner, to: selectedFilter) - }) + .asDriver(onErrorRecover: { _ in return .empty() }) + .drive(with: self) { $0.toggleButton($1) } .disposed(by: self.disposeBag) } } @@ -156,7 +152,7 @@ extension HomeHeaderView: BaseView { ].forEach { self.buttons.append($0) } - + [ self.allButton, self.receivedButton, @@ -179,13 +175,13 @@ extension HomeHeaderView: BaseView { make.directionalHorizontalEdges.equalToSuperview() make.height.equalTo(Metric.rightButtonSize) } - + self.secondLineStack.snp.makeConstraints { make in make.centerY.equalTo(self.firstLineStack.snp.bottom).offset(25) make.leading.equalToSuperview() make.height.greaterThanOrEqualTo(44) } - + self.rightButton.snp.makeConstraints { make in make.width.height.equalTo(Metric.rightButtonSize) } @@ -195,6 +191,12 @@ extension HomeHeaderView: BaseView { $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) } } + + func toggleButton(_ filterType: GiftFilterType) { + self.buttons.forEach { $0.isSelected = false } + self.buttons[filterType.rawValue].isSelected = true + self.selectedFilter = filterType + } } // MARK: - Private Functions @@ -222,7 +224,7 @@ private extension HomeHeaderView { button.configuration = config } } - + func makeFilterButton(title: String) -> UIButton { var configuration = UIButton.Configuration.plain() var attributedTitle = AttributedString(title) From f728f3db9c7fcb50afaa943eddbef9015d6cbc13 Mon Sep 17 00:00:00 2001 From: eung7 Date: Mon, 24 Jul 2023 16:39:52 +0900 Subject: [PATCH 6/6] [Git] TEST --- Favor/Favor/Sources/Models/Storables/Reminder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Favor/Favor/Sources/Models/Storables/Reminder.swift b/Favor/Favor/Sources/Models/Storables/Reminder.swift index e0714bd1..c66f12e1 100644 --- a/Favor/Favor/Sources/Models/Storables/Reminder.swift +++ b/Favor/Favor/Sources/Models/Storables/Reminder.swift @@ -37,7 +37,7 @@ public struct Reminder: Storable, Receivable { self.notifyDate = realmObject.notifyTime self.relatedFriend = realmObject.friendNo } - + public func realmObject() -> ReminderObject { ReminderObject( reminderNo: self.identifier,