Merge develop -> main: full session (KC-51 through KC-71) #28
@@ -1790,3 +1790,40 @@ Files: `KisaniCalWidgets/KisaniCalWidgets.swift`.
|
||||
Not build-verified (no iOS runtime here). To use: on the Lock Screen, tap the
|
||||
widget area → Add Widgets → Wenza → Progress Dots → long-press → Edit Widget →
|
||||
set Mode to This Day / This Week / This Year (This Month already configured).
|
||||
|
||||
---
|
||||
|
||||
## KC-54 — Timed recurring tasks vanish from Today once their time passes
|
||||
|
||||
**Status:** Fixed (not build-verified)
|
||||
**Reported by:** User (screenshots: Calendar day view showed "Look into DPO
|
||||
certificate" 11 AM and "Read Azure 104" 5 PM; neither appeared anywhere in the
|
||||
Today tab — not in Today, not in Overdue, not in Completed)
|
||||
|
||||
### Root cause
|
||||
Two rules interacted badly for **recurring** tasks:
|
||||
- `todayTasks` deliberately excludes timed tasks whose time has passed today
|
||||
("belongs in overdue, not today").
|
||||
- `overdueTasks` deliberately excludes ALL recurring tasks (`!recurs($0)`),
|
||||
because it feeds `postpone`/`postponeAllOverdue`, which mutate a task's
|
||||
`dueDate` directly by id — for a recurring task that field is the
|
||||
**recurrence rule's anchor date**, not just "today's occurrence." Including
|
||||
recurring occurrences there would let "Postpone All" shift/corrupt the whole
|
||||
series.
|
||||
|
||||
Net effect: once a recurring task's today-occurrence time passed, it was
|
||||
excluded from Today (rule 1) but never picked up by Overdue (rule 2) — it fell
|
||||
into a gap and disappeared from the Today tab entirely, while Calendar's day
|
||||
view (`occurrences(on:)`, which has no time-of-day gating) kept showing it
|
||||
normally. Not a display bug — real data was correctly stored, just not
|
||||
surfaced.
|
||||
|
||||
### Fix
|
||||
`todayTasks`' "past time → excluded" rule now only applies to non-recurring
|
||||
tasks (`!$0.isRecurring`). A recurring task's today-occurrence always stays in
|
||||
Today regardless of time — matching what Calendar already shows, and avoiding
|
||||
the postpone/recurrence-anchor risk entirely (recurring rows are never routed
|
||||
through `overdueTasks`). One-line, additive filter change; `activeRows()` /
|
||||
`occurrenceCopy` already preserve `isRecurring` on the occurrence copy.
|
||||
|
||||
Files: `TaskItem.swift`.
|
||||
|
||||
@@ -253,10 +253,15 @@ class TaskViewModel: ObservableObject {
|
||||
let cal = Calendar.current
|
||||
let start = cal.startOfDay(for: now)
|
||||
let end = cal.date(byAdding: .day, value: 1, to: start)!
|
||||
// Timed tasks whose time has already passed belong in overdue, not today.
|
||||
// Timed ONE-OFF tasks whose time has already passed belong in overdue,
|
||||
// not today. Recurring occurrences always stay in Today regardless of
|
||||
// time: overdueTasks intentionally excludes recurring tasks (postponing
|
||||
// one would shift the recurrence rule's anchor date, not just today's
|
||||
// occurrence), so without this a past-time recurring task would vanish
|
||||
// from the app entirely instead of showing here like Calendar shows it.
|
||||
return activeRows().filter {
|
||||
guard let d = $0.dueDate else { return false }
|
||||
if $0.hasTime && d < now { return false }
|
||||
if $0.hasTime && d < now && !$0.isRecurring { return false }
|
||||
return d >= start && d < end
|
||||
}
|
||||
.sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) }
|
||||
|
||||
Reference in New Issue
Block a user