Skip to content

Commit

Permalink
Merge pull request #117 from boostcampwm-2022/feature/CalendarView
Browse files Browse the repository at this point in the history
Feature/calendar view cell 선택 기능 추가
  • Loading branch information
jinwoong16 committed Dec 8, 2022
2 parents 4727a84 + 763f98f commit 2644cea
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ extension DefaultQuestUseCase: QuestUseCase {
func update(with quest: Quest) -> Observable<Bool> {
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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ final class HomeCalendarUseCase: CalendarUseCase {

let currentMonth = BehaviorSubject<Date?>(value: Date())
let completionOfMonths = BehaviorSubject<[[DailyQuestCompletion]]>(value: [[], [], []])
let selectedDate = BehaviorSubject<Date>(value: Date())
let selectedDateCompletion = BehaviorSubject<DailyQuestCompletion?>(value: nil)

init(questsRepository: QuestsRepository) {
self.questsRepository = questsRepository
Expand Down Expand Up @@ -65,25 +67,6 @@ final class HomeCalendarUseCase: CalendarUseCase {
})
.disposed(by: disposeBag)
}
}

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()
Expand All @@ -106,6 +89,57 @@ 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
}

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() }

Expand All @@ -116,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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ protocol CalendarUseCase {

var currentMonth: BehaviorSubject<Date?> { get }
var completionOfMonths: BehaviorSubject<[[DailyQuestCompletion]]> { get }
var selectedDate: BehaviorSubject<Date> { get }
var selectedDateCompletion: BehaviorSubject<DailyQuestCompletion?> { get }

func fetchNextMontlyCompletion()
func fetchLastMontlyCompletion()
func setupMonths()
func refreshMontlyCompletion(for date: Date)
func selectDate(_ date: Date)
}
12 changes: 12 additions & 0 deletions DailyQuest/DailyQuest/Presentation/Common/Cells/CalendarCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ final class HomeViewModel {
let profileTapResult: Observable<Bool>
let currentMonth: Observable<Date?>
let displayDays: Driver<[[DailyQuestCompletion]]>
let selectedDateCompletion: Driver<DailyQuestCompletion?>
}

func transform(input: Input, disposeBag: DisposeBag) -> Output {
Expand Down Expand Up @@ -142,6 +143,12 @@ 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()
Expand All @@ -150,11 +157,32 @@ final class HomeViewModel {
.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
.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,
questStatus: questStatus,
profileTapResult: profileTapResult,
currentMonth: currentMonth,
displayDays: displayDays)
displayDays: displayDays,
selectedDateCompletion: selectedDateCompletion)
}
}
4 changes: 4 additions & 0 deletions DailyQuest/DailyQuest/Utils/Date+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
1 change: 1 addition & 0 deletions DailyQuest/DailyQuest/Utils/Notification+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ import Foundation
extension Notification.Name {
static let updated = Notification.Name("updated")
static let userUpdated = Notification.Name("userUpdated")
static let questStateChanged = Notification.Name("questStateChanged")
}

0 comments on commit 2644cea

Please sign in to comment.