Merge develop -> main: full session (KC-51 through KC-71) #28

Merged
kutesir merged 64 commits from develop into main 2026-07-12 22:57:14 +00:00
2 changed files with 44 additions and 2 deletions
Showing only changes of commit 083a51065b - Show all commits

View File

@@ -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`.

View File

@@ -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) }