Recurring tasks: occurrence engine on calendar + lists (KC-12)
Recurring tasks only ever showed on their single dueDate. Add a recurrence engine that expands occurrences per-date with independent per-occurrence completion. - TaskItem: recurrenceEnd + completedOccurrences (optional, safe decode). - TaskViewModel: isOccurrence/occurrenceComplete/toggleOccurrence/ occurrenceCopy/nextOccurrence/occurrences(on:); Daily/Weekly/Monthly/ Yearly/Every-Weekday; respects recurrenceEnd; works across years. - toggle() routes recurring rows to per-occurrence completion. - Date filters re-inject per-date occurrence copies; recurring excluded from overdue. Calendar dots + day detail use occurrences(on:). Also log KC-11 (year display) + KC-12. Pending: "repeat until" date UI (engine already honors recurrenceEnd). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -463,9 +463,9 @@ struct CalendarView: View {
|
||||
dots.append(calColor)
|
||||
}
|
||||
}
|
||||
let taskDots = taskVM.tasks
|
||||
// Includes recurring occurrences that land on this date.
|
||||
let taskDots = taskVM.occurrences(on: date)
|
||||
.filter { !$0.isComplete }
|
||||
.filter { guard let d = $0.dueDate else { return false }; return cal.isDate(d, inSameDayAs: date) }
|
||||
.prefix(max(0, 3 - dots.count))
|
||||
.map { $0.quadrant.color }
|
||||
dots.append(contentsOf: taskDots)
|
||||
@@ -581,10 +581,7 @@ struct CalendarView: View {
|
||||
ScrollView(showsIndicators: false) {
|
||||
DayTimelineView(
|
||||
date: selectedDate,
|
||||
tasks: taskVM.tasks.filter { t in
|
||||
guard let d = t.dueDate else { return false }
|
||||
return cal.isDate(d, inSameDayAs: selectedDate)
|
||||
},
|
||||
tasks: taskVM.occurrences(on: selectedDate),
|
||||
calEvents: calStore.isAuthorized ? calStore.events(for: selectedDate) : [],
|
||||
workout: workoutVM.program(for: selectedDate),
|
||||
workoutDone: workoutVM.isWorkoutComplete(on: selectedDate),
|
||||
|
||||
Reference in New Issue
Block a user