Skip to content

Commit 850f373

Browse files
authored
[#198] 오늘 기준으로 관련이 있는 Todo들을 보여주는 뷰를 구성한다 (#201)
* feat: 오늘 기준으로 Todo의 각종 정보를 모아 한눈에 보여주는 뷰 구현 * refactor: 로컬 정렬 대신 서버에 정렬된 형태로 요청해서 받아오는 형태로 개선 * feat: SummaryCard를 탭이 가능하도록 변경해서 각 카드에 해당하는 Todo를 아래에서 볼 수 있도록 추가 * feat: 우측 상단에 툴바를 추가하여 보고싶은 Todo 데이터만 보도록 추가 * fix: iOS 17에서 동일한 텍스트면 Menu에서 하나만 보이는 현상 해결4 * refactor: dueDate가 사용된 쿼리 생성 시 secondary가 없을 때 에러를 보장하도록 개선 * refactor: 필터링 시 각 조건에 대해 각각 필터링이 아닌, 한번의 순회 동안 각 조건을 검사해서 필터링하도록 개선 * refactor: 리스트에 보이는 타이틀과 메시지를 한 곳에서 수정하도록 개선
1 parent 76ad622 commit 850f373

19 files changed

Lines changed: 987 additions & 21 deletions

DevLog/App/Assembler/DomainAssembler.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,5 +154,13 @@ private extension DomainAssembler {
154154
container.register(UpdateProfileHeatmapActivityTypesUseCase.self) {
155155
UpdateProfileHeatmapActivityTypesUseCaseImpl(container.resolve(UserPreferencesRepository.self))
156156
}
157+
158+
container.register(FetchTodayDisplayOptionsUseCase.self) {
159+
FetchTodayDisplayOptionsUseCaseImpl(container.resolve(UserPreferencesRepository.self))
160+
}
161+
162+
container.register(UpdateTodayDisplayOptionsUseCase.self) {
163+
UpdateTodayDisplayOptionsUseCaseImpl(container.resolve(UserPreferencesRepository.self))
164+
}
157165
}
158166
}

DevLog/Data/DTO/TodoCursorDTO.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import Foundation
99

1010
struct TodoCursorDTO {
11-
let orderedAt: Date
11+
let primarySortDate: Date?
12+
let secondarySortDate: Date?
1213
let documentID: String
1314
}

DevLog/Data/Mapper/TodoMapping.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,16 @@ extension TodoResponse {
5050
extension TodoCursorDTO {
5151
func toDomain() -> TodoCursor {
5252
TodoCursor(
53-
orderedAt: orderedAt,
53+
primarySortDate: primarySortDate,
54+
secondarySortDate: secondarySortDate,
5455
documentID: documentID
5556
)
5657
}
5758

5859
static func fromDomain(_ cursor: TodoCursor) -> Self {
5960
TodoCursorDTO(
60-
orderedAt: cursor.orderedAt,
61+
primarySortDate: cursor.primarySortDate,
62+
secondarySortDate: cursor.secondarySortDate,
6163
documentID: cursor.documentID
6264
)
6365
}

DevLog/Data/Repository/UserPreferencesRepositoryImpl.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ final class UserPreferencesRepositoryImpl: UserPreferencesRepository {
1717
static let pushTimeFilter = "PushNotification.timeFilter"
1818
static let pushUnreadOnly = "PushNotification.showUnreadOnly"
1919
static let profileHeatmapActivityTypes = "Profile.heatmap.activityTypes"
20+
static let todayDueDateVisibility = "Today.dueDateVisibility"
21+
static let todayFocusVisibility = "Today.focusVisibility"
2022
}
2123

2224
private let store: UserDefaultsStore
@@ -101,4 +103,23 @@ final class UserPreferencesRepositoryImpl: UserPreferencesRepository {
101103
func setProfileHeatmapActivityTypes(_ activityTypes: [String]) {
102104
store.setStringArray(activityTypes, forKey: Key.profileHeatmapActivityTypes)
103105
}
106+
107+
func todayDisplayOptions() -> TodayDisplayOptions {
108+
let dueDateVisibilityRawValue = store.string(forKey: Key.todayDueDateVisibility)
109+
let focusVisibilityRawValue = store.string(forKey: Key.todayFocusVisibility)
110+
111+
return TodayDisplayOptions(
112+
dueDateVisibility: TodayDisplayOptions.DueDateVisibility(
113+
rawValue: dueDateVisibilityRawValue ?? ""
114+
) ?? .all,
115+
focusVisibility: TodayDisplayOptions.FocusVisibility(
116+
rawValue: focusVisibilityRawValue ?? ""
117+
) ?? .all
118+
)
119+
}
120+
121+
func setTodayDisplayOptions(_ options: TodayDisplayOptions) {
122+
store.setString(options.dueDateVisibility.rawValue, forKey: Key.todayDueDateVisibility)
123+
store.setString(options.focusVisibility.rawValue, forKey: Key.todayFocusVisibility)
124+
}
104125
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// TodayDisplayOptions.swift
3+
// DevLog
4+
//
5+
// Created by opfic on 3/6/26.
6+
//
7+
8+
import Foundation
9+
10+
struct TodayDisplayOptions: Equatable {
11+
enum DueDateVisibility: String, CaseIterable, Equatable {
12+
case all
13+
case withDueDateOnly
14+
case withoutDueDateOnly
15+
}
16+
17+
enum FocusVisibility: String, CaseIterable, Equatable {
18+
case all
19+
case focusedOnly
20+
}
21+
22+
var dueDateVisibility: DueDateVisibility
23+
var focusVisibility: FocusVisibility
24+
25+
static let `default` = TodayDisplayOptions(
26+
dueDateVisibility: .all,
27+
focusVisibility: .all
28+
)
29+
}

DevLog/Domain/Entity/TodoCursor.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import Foundation
99

1010
struct TodoCursor {
11-
let orderedAt: Date
11+
let primarySortDate: Date?
12+
let secondarySortDate: Date?
1213
let documentID: String
1314
}

DevLog/Domain/Entity/TodoQuery.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ struct TodoQuery: Equatable {
1111
enum SortTarget: Equatable, Hashable {
1212
case createdAt
1313
case updatedAt
14+
case dueDate
1415

1516
var fieldName: String {
1617
switch self {
1718
case .createdAt:
1819
return "createdAt"
1920
case .updatedAt:
2021
return "updatedAt"
22+
case .dueDate:
23+
return "dueDate"
2124
}
2225
}
2326
}
@@ -48,10 +51,17 @@ struct TodoQuery: Equatable {
4851
}
4952
}
5053

54+
enum DueDateFilter: Equatable, Hashable {
55+
case all
56+
case withDueDate
57+
case withoutDueDate
58+
}
59+
5160
var kind: TodoKind?
5261
var keyword: String?
5362
var isPinned: Bool?
5463
var completionFilter: CompletionFilter
64+
var dueDateFilter: DueDateFilter
5565
var createdAtFrom: Date?
5666
var createdAtTo: Date?
5767
var sortTarget: SortTarget
@@ -64,6 +74,7 @@ struct TodoQuery: Equatable {
6474
keyword: String? = nil,
6575
isPinned: Bool? = nil,
6676
completionFilter: CompletionFilter = .all,
77+
dueDateFilter: DueDateFilter = .all,
6778
createdAtFrom: Date? = nil,
6879
createdAtTo: Date? = nil,
6980
sortTarget: SortTarget = .createdAt,
@@ -75,6 +86,7 @@ struct TodoQuery: Equatable {
7586
self.keyword = keyword
7687
self.isPinned = isPinned
7788
self.completionFilter = completionFilter
89+
self.dueDateFilter = dueDateFilter
7890
self.createdAtFrom = createdAtFrom
7991
self.createdAtTo = createdAtTo
8092
self.sortTarget = sortTarget

DevLog/Domain/Protocol/UserPreferencesRepository.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,7 @@ protocol UserPreferencesRepository {
3030

3131
func profileHeatmapActivityTypes() -> [String]
3232
func setProfileHeatmapActivityTypes(_ activityTypes: [String])
33+
34+
func todayDisplayOptions() -> TodayDisplayOptions
35+
func setTodayDisplayOptions(_ options: TodayDisplayOptions)
3336
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//
2+
// FetchTodayDisplayOptionsUseCase.swift
3+
// DevLog
4+
//
5+
// Created by opfic on 3/6/26.
6+
//
7+
8+
protocol FetchTodayDisplayOptionsUseCase {
9+
func execute() -> TodayDisplayOptions
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// FetchTodayDisplayOptionsUseCaseImpl.swift
3+
// DevLog
4+
//
5+
// Created by opfic on 3/6/26.
6+
//
7+
8+
final class FetchTodayDisplayOptionsUseCaseImpl: FetchTodayDisplayOptionsUseCase {
9+
private let repository: UserPreferencesRepository
10+
11+
init(_ repository: UserPreferencesRepository) {
12+
self.repository = repository
13+
}
14+
15+
func execute() -> TodayDisplayOptions {
16+
repository.todayDisplayOptions()
17+
}
18+
}

0 commit comments

Comments
 (0)