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
|
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 →
|
widget area → Add Widgets → Wenza → Progress Dots → long-press → Edit Widget →
|
||||||
set Mode to This Day / This Week / This Year (This Month already configured).
|
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 cal = Calendar.current
|
||||||
let start = cal.startOfDay(for: now)
|
let start = cal.startOfDay(for: now)
|
||||||
let end = cal.date(byAdding: .day, value: 1, to: start)!
|
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 {
|
return activeRows().filter {
|
||||||
guard let d = $0.dueDate else { return false }
|
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
|
return d >= start && d < end
|
||||||
}
|
}
|
||||||
.sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) }
|
.sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) }
|
||||||
|
|||||||
Reference in New Issue
Block a user