From 9dd0d104fa823d8f9f457c6588f88873b26d7d7a Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:12:15 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[feat]=20Quest=20State=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EB=90=A0=20=EB=95=8C=20NotificationCenter=20=EB=85=B8=ED=8B=B0?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/UseCases/Home/DefaultQuestUseCase.swift | 5 +++++ DailyQuest/DailyQuest/Utils/Notification+.swift | 1 + 2 files changed, 6 insertions(+) diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultQuestUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultQuestUseCase.swift index 6faa9ac..974e063 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultQuestUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultQuestUseCase.swift @@ -25,6 +25,11 @@ extension DefaultQuestUseCase: QuestUseCase { func update(with quest: Quest) -> Observable { return questsRepository .update(with: quest) + .do(onSuccess: { quest in + if quest.state { + NotificationCenter.default.post(name: .questStateChanged, object: quest.date) + } + }) .map { _ in true } .catchAndReturn(false) .asObservable() diff --git a/DailyQuest/DailyQuest/Utils/Notification+.swift b/DailyQuest/DailyQuest/Utils/Notification+.swift index df4c79f..2de4d3b 100644 --- a/DailyQuest/DailyQuest/Utils/Notification+.swift +++ b/DailyQuest/DailyQuest/Utils/Notification+.swift @@ -9,4 +9,5 @@ import Foundation extension Notification.Name { static let updated = Notification.Name("updated") + static let questStateChanged = Notification.Name("questStateChanged") } From 21c7301bd1aea97f2f02007da871a2a0a66acab7 Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:15:12 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[feat]=20calculateDailyState=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UseCases/Home/HomeCalendarUseCase.swift | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift index dbc9714..e9cc567 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift @@ -69,22 +69,6 @@ final class HomeCalendarUseCase: CalendarUseCase { extension HomeCalendarUseCase { - private func calculateDailyState(_ quests: [Quest]) -> DailyQuestCompletion.State { - guard !quests.isEmpty else { - return .normal - } - - let result = quests.reduce(0) { partialResult, quest in - partialResult + (quest.state ? 1 : 0) - } - - if result == quests.count { - return .done - } else { - return .notDone(result) - } - } - func setupMonths() { let currentMonth = try? currentMonth.value() let startDayOfLastMonth = currentMonth?.startDayOfLastMonth @@ -106,6 +90,20 @@ extension HomeCalendarUseCase { .disposed(by: disposeBag) } + private func calculateDailyState(_ quests: [Quest]) -> DailyQuestCompletion.State { + guard !quests.isEmpty else { + return .normal + } + + let filteredQuests = quests.filter { !$0.state } + + if filteredQuests.isEmpty { + return .done + } else { + return .notDone(filteredQuests.count) + } + } + private func fetchAMontlyCompletion(_ month: Date?) -> Observable<[DailyQuestCompletion]> { guard let month = month else { return .empty() } From a48dc331fe58382bcae47e58bed89c1f8fba57c1 Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:17:03 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[feat]=20CalendarUseCase=20Protocol?= =?UTF-8?q?=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20=EB=B3=80=EC=88=98,?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/UseCases/Home/Protocols/CalendarUseCase.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/CalendarUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/CalendarUseCase.swift index a1199d4..5adfdbf 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/CalendarUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/CalendarUseCase.swift @@ -13,8 +13,12 @@ protocol CalendarUseCase { var currentMonth: BehaviorSubject { get } var completionOfMonths: BehaviorSubject<[[DailyQuestCompletion]]> { get } + var selectedDate: BehaviorSubject { get } + var selectedDateCompletion: BehaviorSubject { get } func fetchNextMontlyCompletion() func fetchLastMontlyCompletion() func setupMonths() + func refreshMontlyCompletion(for date: Date) + func selectDate(_ date: Date) } From 087da983df2df728aaf3becbec1e0df1d07f7d2d Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:17:58 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[feat]=20HomeCalendarUseCase=EB=A5=BC=20Cal?= =?UTF-8?q?endarUseCase=20protocol=EC=9D=84=20=EB=94=B0=EB=A5=B4=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UseCases/Home/HomeCalendarUseCase.swift | 51 +++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift index e9cc567..d4eb06e 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift @@ -15,6 +15,8 @@ final class HomeCalendarUseCase: CalendarUseCase { let currentMonth = BehaviorSubject(value: Date()) let completionOfMonths = BehaviorSubject<[[DailyQuestCompletion]]>(value: [[], [], []]) + let selectedDate = BehaviorSubject(value: Date()) + let selectedDateCompletion = BehaviorSubject(value: nil) init(questsRepository: QuestsRepository) { self.questsRepository = questsRepository @@ -65,9 +67,6 @@ final class HomeCalendarUseCase: CalendarUseCase { }) .disposed(by: disposeBag) } -} - -extension HomeCalendarUseCase { func setupMonths() { let currentMonth = try? currentMonth.value() @@ -90,6 +89,43 @@ extension HomeCalendarUseCase { .disposed(by: disposeBag) } + func refreshMontlyCompletion(for date: Date) { + guard + let months = try? self.completionOfMonths.value(), + let index = months.firstIndex(where: { month in + month.contains { dailyQuestCompletion in + (dailyQuestCompletion.state != .hidden) + && (dailyQuestCompletion.day.startOfDay == date.startOfDay) + } + }), + let reloadMonth = months[index].last?.day.startDayOfCurrentMonth + else { + return + } + + fetchAMontlyCompletion(reloadMonth) + .subscribe(onNext: { [weak self] monthlyCompletion in + guard + let self, + var values = try? self.completionOfMonths.value() + else { + return + } + + values[index] = monthlyCompletion + + self.completionOfMonths.onNext(values) + }) + .disposed(by: disposeBag) + } + + func selectDate(_ date: Date) { + selectedDate.onNext(date) + } +} + +extension HomeCalendarUseCase { + private func calculateDailyState(_ quests: [Quest]) -> DailyQuestCompletion.State { guard !quests.isEmpty else { return .normal @@ -114,7 +150,14 @@ extension HomeCalendarUseCase { return self.questsRepository .fetch(by: date) .map { quests -> DailyQuestCompletion in - return DailyQuestCompletion(day: date, state: self.calculateDailyState(quests)) + let completion = DailyQuestCompletion(day: date, state: self.calculateDailyState(quests)) + + if let selectedDate = try? self.selectedDate.value(), + selectedDate.startOfDay == date { + self.selectedDateCompletion.onNext(completion) + } + + return completion } } .toArray() From 82507c4d3b3ba4712f8ad00fadbd0957c0259540 Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:19:15 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[feat]=20Date+=20extension=EC=97=90=20start?= =?UTF-8?q?OfDay=20=EA=B3=84=EC=82=B0=20=EB=B3=80=EC=88=98=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 --- DailyQuest/DailyQuest/Utils/Date+.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DailyQuest/DailyQuest/Utils/Date+.swift b/DailyQuest/DailyQuest/Utils/Date+.swift index dc783f9..e9afae1 100644 --- a/DailyQuest/DailyQuest/Utils/Date+.swift +++ b/DailyQuest/DailyQuest/Utils/Date+.swift @@ -39,6 +39,10 @@ extension Date { return Calendar.current.component(.weekday, from: self) } + var startOfDay: Date { + return Calendar.current.startOfDay(for: self) + } + var nextMonthOfCurrentDay: Date? { return Calendar.current.date(byAdding: .month, value: 1, to: self) } From d4da0eeceaac4b4668233a9e53b6e21ec746b381 Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:20:26 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[feat]=20CalendarCell=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=EB=90=98=EC=97=88=EC=9D=84=20=EB=95=8C=20=EC=99=B8=ED=98=95=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Common/Cells/CalendarCell.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/DailyQuest/DailyQuest/Presentation/Common/Cells/CalendarCell.swift b/DailyQuest/DailyQuest/Presentation/Common/Cells/CalendarCell.swift index 741273b..2969bb6 100644 --- a/DailyQuest/DailyQuest/Presentation/Common/Cells/CalendarCell.swift +++ b/DailyQuest/DailyQuest/Presentation/Common/Cells/CalendarCell.swift @@ -28,6 +28,18 @@ final class CalendarCell: UICollectionViewCell { return view }() + override var isSelected: Bool { + didSet { + if isSelected { + self.circleCheckView.layer.borderWidth = 3.0 + self.circleCheckView.layer.borderColor = UIColor.maxDarkYellow.cgColor + } else { + self.circleCheckView.layer.borderWidth = 0.0 + self.circleCheckView.layer.borderColor = nil + } + } + } + override init(frame: CGRect) { super.init(frame: frame) From 7345d8defd5b3e83ac12c6201fbed279e853d61b Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:27:42 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[feat]=20Quest=EC=9D=98=20State=EA=B0=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EB=90=98=EC=97=88=EC=9D=84=20=EB=95=8C=20Cel?= =?UTF-8?q?l=20=EB=B3=80=EA=B2=BD=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Home/ViewModel/HomeViewModel.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift index 3e695a6..de44edf 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift @@ -116,6 +116,15 @@ final class HomeViewModel { .completionOfMonths .asDriver(onErrorJustReturn: [[], [], []]) + NotificationCenter + .default + .rx + .notification(.questStateChanged) + .compactMap({ $0.object as? Date }) + .subscribe(onNext: { [weak self] date in + self?.calendarUseCase.refreshMontlyCompletion(for: date) + }) + .disposed(by: disposeBag) return Output(data: data, userData: userData, profileTapResult: profileTapResult, From 5a32b9837ffc75211286960318f628ba0ed2225a Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:28:44 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[feat]=20CalendarCell=EC=9D=B4=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=EB=90=98=EC=97=88=EC=9D=84=20=EB=95=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Home/ViewModel/HomeViewModel.swift | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift index de44edf..739d5a2 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/HomeViewModel.swift @@ -36,6 +36,7 @@ final class HomeViewModel { let profileTapResult: Observable let currentMonth: Observable let displayDays: Driver<[[DailyQuestCompletion]]> + let selectedDateCompletion: Driver } func transform(input: Input, disposeBag: DisposeBag) -> Output { @@ -72,7 +73,6 @@ final class HomeViewModel { ) .do(onNext: { [weak self] date in self?.currentDate = date - print("fetched ❄️❄️❄️") }) .flatMap(questUseCase.fetch(by:)) .asDriver(onErrorJustReturn: []) @@ -107,7 +107,13 @@ final class HomeViewModel { } }) .disposed(by: disposeBag) - + + input.daySelected + .bind { [weak self] date in + self?.calendarUseCase.selectDate(date) + } + .disposed(by: disposeBag) + let currentMonth = calendarUseCase .currentMonth .asObserver() @@ -115,7 +121,17 @@ final class HomeViewModel { let displayDays = calendarUseCase .completionOfMonths .asDriver(onErrorJustReturn: [[], [], []]) - + + let selectedDateCompletion = calendarUseCase + .selectedDateCompletion + .asDriver(onErrorJustReturn: nil) + + notification + .subscribe(onNext: { [weak self] date in + self?.calendarUseCase.setupMonths() + }) + .disposed(by: disposeBag) + NotificationCenter .default .rx @@ -125,10 +141,12 @@ final class HomeViewModel { self?.calendarUseCase.refreshMontlyCompletion(for: date) }) .disposed(by: disposeBag) + return Output(data: data, userData: userData, profileTapResult: profileTapResult, currentMonth: currentMonth, - displayDays: displayDays) + displayDays: displayDays, + selectedDateCompletion: selectedDateCompletion) } } From 402a799a438454e0ce4a7dff45470a356a8a4170 Mon Sep 17 00:00:00 2001 From: wickedRun Date: Thu, 8 Dec 2022 14:30:03 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[feat]=20HomeViewModel=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=ED=95=9C=20=EA=B8=B0=EB=8A=A5=20=EB=B0=94?= =?UTF-8?q?=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Home/ViewController/HomeViewController.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift b/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift index 3281bdf..de9c3a7 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift @@ -194,6 +194,17 @@ final class HomeViewController: UIViewController { .compactMap({ $0?.toFormat }) .bind(to: calendarView.yearMonthLabel.rx.text) .disposed(by: disposableBag) + + output + .selectedDateCompletion + .drive(onNext: { [weak self] dailyQuestCompletion in + guard let dailyQuestCompletion else { return } + + let indexPath = self?.calendarView.dataSource.indexPath(for: dailyQuestCompletion) + self?.calendarView.monthCollectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally) + }) + .disposed(by: disposableBag) + } private func bindToQuestHeaderButton() {