-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #103 from boostcampwm-2022/feature/CalendarView
Feature/calendar view
- Loading branch information
Showing
12 changed files
with
372 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
DailyQuest/DailyQuest/Domain/Entities/DailyQuestCompletion.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// DailyQuestCompletion.swift | ||
// DailyQuest | ||
// | ||
// Created by wickedRun on 2022/12/06. | ||
// | ||
|
||
import Foundation | ||
|
||
struct DailyQuestCompletion: Hashable { | ||
|
||
enum State: Hashable { | ||
case hidden | ||
case normal | ||
case notDone(Int) | ||
case done | ||
} | ||
|
||
let day: Date | ||
let state: State | ||
} |
28 changes: 28 additions & 0 deletions
28
DailyQuest/DailyQuest/Domain/Entities/MonthlyQuestCompletion.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// MonthlyQuestCompletion.swift | ||
// DailyQuest | ||
// | ||
// Created by wickedRun on 2022/12/06. | ||
// | ||
|
||
import Foundation | ||
|
||
struct MonthlyQuestCompletion { | ||
|
||
let month: Date | ||
let states: [DailyQuestCompletion] | ||
} | ||
|
||
extension MonthlyQuestCompletion: Comparable { | ||
|
||
static func < (lhs: MonthlyQuestCompletion, rhs: MonthlyQuestCompletion) -> Bool { | ||
return lhs.month < rhs.month | ||
} | ||
} | ||
|
||
extension MonthlyQuestCompletion: Equatable { | ||
|
||
static func == (lhs: MonthlyQuestCompletion, rhs: MonthlyQuestCompletion) -> Bool { | ||
return lhs.month == rhs.month | ||
} | ||
} |
133 changes: 133 additions & 0 deletions
133
DailyQuest/DailyQuest/Domain/UseCases/Home/HomeCalendarUseCase.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// | ||
// HomeCalendarUseCase.swift | ||
// DailyQuest | ||
// | ||
// Created by wickedRun on 2022/12/05. | ||
// | ||
|
||
import Foundation | ||
|
||
import RxSwift | ||
|
||
final class HomeCalendarUseCase: CalendarUseCase { | ||
private let questsRepository: QuestsRepository | ||
private let disposeBag = DisposeBag() | ||
|
||
let currentMonth = BehaviorSubject<Date?>(value: Date()) | ||
let completionOfMonths = BehaviorSubject<[[DailyQuestCompletion]]>(value: [[], [], []]) | ||
|
||
init(questsRepository: QuestsRepository) { | ||
self.questsRepository = questsRepository | ||
} | ||
|
||
func fetchNextMontlyCompletion() { | ||
guard let nextMonth = try? currentMonth.value()?.startDayOfNextMonth else { return } | ||
currentMonth.onNext(nextMonth) | ||
|
||
let monthAfterNext = nextMonth.startDayOfNextMonth | ||
|
||
fetchAMontlyCompletion(monthAfterNext) | ||
.subscribe(onNext: { [weak self] monthlyCompletion in | ||
guard | ||
let self, | ||
var values = try? self.completionOfMonths.value() | ||
else { | ||
return | ||
} | ||
|
||
values.removeFirst() | ||
values.append(monthlyCompletion) | ||
|
||
self.completionOfMonths.onNext(values) | ||
}) | ||
.disposed(by: disposeBag) | ||
} | ||
|
||
func fetchLastMontlyCompletion() { | ||
guard let lastMonth = try? currentMonth.value()?.startDayOfLastMonth else { return } | ||
currentMonth.onNext(lastMonth) | ||
|
||
let monthBeforeLast = lastMonth.startDayOfLastMonth | ||
|
||
fetchAMontlyCompletion(monthBeforeLast) | ||
.subscribe(onNext: { [weak self] monthlyCompletion in | ||
guard | ||
let self, | ||
var values = try? self.completionOfMonths.value() | ||
else { | ||
return | ||
} | ||
|
||
values.removeLast() | ||
values.insert(monthlyCompletion, at: 0) | ||
|
||
self.completionOfMonths.onNext(values) | ||
}) | ||
.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() | ||
let startDayOfLastMonth = currentMonth?.startDayOfLastMonth | ||
let startDayOfCurrentMonth = currentMonth?.startDayOfCurrentMonth | ||
let startDayOfNextMonth = currentMonth?.startDayOfNextMonth | ||
|
||
let months = [startDayOfLastMonth, startDayOfCurrentMonth, startDayOfNextMonth] | ||
|
||
Observable.from(months) | ||
.concatMap { [weak self] monthDate in | ||
guard let self else { return Observable<[DailyQuestCompletion]>.empty() } | ||
|
||
return self.fetchAMontlyCompletion(monthDate) | ||
} | ||
.toArray() | ||
.subscribe(onSuccess: { [weak self] completionOfMonths in | ||
self?.completionOfMonths.onNext(completionOfMonths) | ||
}) | ||
.disposed(by: disposeBag) | ||
} | ||
|
||
private func fetchAMontlyCompletion(_ month: Date?) -> Observable<[DailyQuestCompletion]> { | ||
guard let month = month else { return .empty() } | ||
|
||
return Observable.from(month.rangeDaysOfMonth) | ||
.concatMap { [weak self] date -> Observable<DailyQuestCompletion> in | ||
guard let self else { return Observable.empty() } | ||
|
||
return self.questsRepository | ||
.fetch(by: date) | ||
.map { quests -> DailyQuestCompletion in | ||
return DailyQuestCompletion(day: date, state: self.calculateDailyState(quests)) | ||
} | ||
} | ||
.toArray() | ||
.map { states in | ||
let firstWeekStates = month.rangeFromStartWeekdayOfLastMonthToEndDayOfCurrentMonth | ||
.map { date -> DailyQuestCompletion in | ||
return DailyQuestCompletion(day: date, state: .hidden) | ||
} | ||
|
||
return firstWeekStates + states | ||
} | ||
.asObservable() | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/CalendarUseCase.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// | ||
// CalendarUseCase.swift | ||
// DailyQuest | ||
// | ||
// Created by wickedRun on 2022/12/05. | ||
// | ||
|
||
import Foundation | ||
|
||
import RxSwift | ||
|
||
protocol CalendarUseCase { | ||
|
||
var currentMonth: BehaviorSubject<Date?> { get } | ||
var completionOfMonths: BehaviorSubject<[[DailyQuestCompletion]]> { get } | ||
|
||
func fetchNextMontlyCompletion() | ||
func fetchLastMontlyCompletion() | ||
func setupMonths() | ||
} |
Oops, something went wrong.