@@ -22,6 +22,14 @@ final class TodayViewModel: Store {
2222 let items : [ TodayTodoItem ]
2323 }
2424
25+ struct SectionBuckets {
26+ var focused : [ TodayTodoItem ] = [ ]
27+ var overdue : [ TodayTodoItem ] = [ ]
28+ var dueSoon : [ TodayTodoItem ] = [ ]
29+ var later : [ TodayTodoItem ] = [ ]
30+ var unscheduled : [ TodayTodoItem ] = [ ]
31+ }
32+
2533 struct State : Equatable {
2634 var todos : [ TodayTodoItem ] = [ ]
2735 var isLoading : Bool = false
@@ -78,12 +86,13 @@ final class TodayViewModel: Store {
7886 }
7987
8088 var sections : [ SectionContent ] {
89+ let groupedItems = groupedSectionItems ( from: displayedTodos)
8190 let allSections : [ SectionContent ] = [
82- SectionContent ( title: " 집중할 일 " , items: displayedTodos . filter ( \ . isPinned ) ) ,
83- SectionContent ( title: " 지난 마감 " , items: displayedTodos . filter { !$0 . isPinned && isOverdue ( $0 ) } ) ,
84- SectionContent ( title: " \( upcomingWindowDays) 일 내 일정 " , items: displayedTodos . filter { !$0 . isPinned && isDueSoon ( $0 ) } ) ,
85- SectionContent ( title: " 나중 일정 " , items: displayedTodos . filter { !$0 . isPinned && isScheduledLater ( $0 ) } ) ,
86- SectionContent ( title: " 일정 미정 " , items: displayedTodos . filter { !$0 . isPinned && $0 . dueDate == nil } )
91+ SectionContent ( title: " 집중할 일 " , items: groupedItems . focused ) ,
92+ SectionContent ( title: " 지난 마감 " , items: groupedItems . overdue ) ,
93+ SectionContent ( title: " \( upcomingWindowDays) 일 내 일정 " , items: groupedItems . dueSoon ) ,
94+ SectionContent ( title: " 나중 일정 " , items: groupedItems . later ) ,
95+ SectionContent ( title: " 일정 미정 " , items: groupedItems . unscheduled )
8796 ]
8897
8998 switch state. selectedSummaryScope {
@@ -289,6 +298,43 @@ private extension TodayViewModel {
289298 }
290299 }
291300
301+ func groupedSectionItems(
302+ from items: [ TodayTodoItem ]
303+ ) -> SectionBuckets {
304+ let startOfToday = calendar. startOfDay ( for: Date ( ) )
305+ guard let windowEnd = calendar. date ( byAdding: . day, value: upcomingWindowDays, to: startOfToday) else {
306+ return SectionBuckets (
307+ focused: items. filter ( \. isPinned) ,
308+ unscheduled: items. filter { !$0. isPinned && $0. dueDate == nil }
309+ )
310+ }
311+
312+ var buckets = SectionBuckets ( )
313+
314+ for item in items {
315+ if item. isPinned {
316+ buckets. focused. append ( item)
317+ continue
318+ }
319+
320+ guard let dueDate = item. dueDate else {
321+ buckets. unscheduled. append ( item)
322+ continue
323+ }
324+
325+ let dueDay = calendar. startOfDay ( for: dueDate)
326+ if dueDay < startOfToday {
327+ buckets. overdue. append ( item)
328+ } else if dueDay <= windowEnd {
329+ buckets. dueSoon. append ( item)
330+ } else {
331+ buckets. later. append ( item)
332+ }
333+ }
334+
335+ return buckets
336+ }
337+
292338 func isOverdue( _ item: TodayTodoItem ) -> Bool {
293339 guard let dueDate = item. dueDate else { return false }
294340 return calendar. startOfDay ( for: dueDate) < calendar. startOfDay ( for: Date ( ) )
@@ -303,14 +349,4 @@ private extension TodayViewModel {
303349 let dueDay = calendar. startOfDay ( for: dueDate)
304350 return startOfToday <= dueDay && dueDay <= windowEnd
305351 }
306-
307- func isScheduledLater( _ item: TodayTodoItem ) -> Bool {
308- guard let dueDate = item. dueDate else { return false }
309- let startOfToday = calendar. startOfDay ( for: Date ( ) )
310- guard let windowEnd = calendar. date ( byAdding: . day, value: upcomingWindowDays, to: startOfToday) else {
311- return false
312- }
313- let dueDay = calendar. startOfDay ( for: dueDate)
314- return windowEnd < dueDay
315- }
316352}
0 commit comments