Merge develop -> main: full session (KC-51 through KC-71) #28
@@ -2250,3 +2250,45 @@ non-deprecated overload: `activity.end(nil, dismissalPolicy: .immediate)`.
|
||||
|
||||
Files: `KisaniCal/Managers/LiveActivityManager.swift`,
|
||||
`KisaniCalWidgets/StopCountdownIntent.swift`.
|
||||
|
||||
## KC-65 — TaskItem never actually stored a creation date
|
||||
|
||||
Status: Implemented (not build-verified — no iOS runtime here)
|
||||
Reported by: User, from a Track Countdown lock-screen widget stuck at 0%
|
||||
Area: Model / widgets (Track Countdown progress dots)
|
||||
|
||||
### Description
|
||||
The countdown-dots widget (`KisaniCalWidgets.swift`'s `eventStartDate`) was
|
||||
already written to prefer `task.createdAt` as the progress bar's start
|
||||
date — but `TaskItem` never had a `createdAt` property at all, so it always
|
||||
decoded to `nil` and every task fell through to a fallback chain: a
|
||||
per-task "first render" anchor persisted in `UserDefaults.kisani`
|
||||
(`kisani.widget.progressDots.anchor.<id>`), or failing that, an inferred
|
||||
legacy start (`remainingDays * 2`, capped 30–365 days). That anchor can
|
||||
reset to "now" under several conditions (widget re-added, storage cleared,
|
||||
the `looksLikeUpgradeAnchor` heuristic firing) — which is exactly the
|
||||
"starting from scratch on every update" behavior the user was seeing.
|
||||
|
||||
### Change
|
||||
Added `var createdAt: Date? = Date()` to `TaskItem` (`Models/TaskItem.swift`)
|
||||
— optional so existing saved tasks decode safely (missing key → `nil`,
|
||||
same pattern as `recurrenceEnd`), but the `Date()` default is evaluated
|
||||
fresh at each construction site, so every newly created task now genuinely
|
||||
records its creation moment. No call sites needed updating: `addTask` uses
|
||||
the compiler-synthesized memberwise init and doesn't pass `createdAt`
|
||||
explicitly, so it gets the live default; `occurrenceCopy` copies the
|
||||
struct (`var c = t`), so recurring-task instances correctly inherit the
|
||||
series' original `createdAt` rather than getting a fresh one.
|
||||
|
||||
The widget-side plumbing (`WidgetData.swift`'s `RawTask`/`WidgetTask`
|
||||
decode, `eventStartDate`'s preference order) already existed and needed no
|
||||
change — it was just never being fed a real value.
|
||||
|
||||
Files: `KisaniCal/Models/TaskItem.swift`.
|
||||
|
||||
### Note
|
||||
Not build-verified (no iOS runtime here). Self-reviewed: balanced braces/
|
||||
parens (one pre-existing stray `(` predates this change, confirmed earlier
|
||||
in KC-62). Existing tasks (created before this fix) still have no real
|
||||
creation date and will keep using the anchor/inferred fallback — there's
|
||||
no way to retroactively know when they were actually created.
|
||||
|
||||
@@ -5,6 +5,10 @@ import WidgetKit
|
||||
struct TaskItem: Identifiable, Codable, Equatable {
|
||||
var id = UUID()
|
||||
var title: String
|
||||
// Optional so existing saved tasks decode safely (missing key → nil); the
|
||||
// `Date()` default only fires for genuinely new tasks constructed after
|
||||
// this field existed — it's evaluated fresh at each construction site.
|
||||
var createdAt: Date? = Date()
|
||||
var dueDate: Date?
|
||||
var hasTime: Bool = false
|
||||
var isComplete: Bool = false
|
||||
|
||||
Reference in New Issue
Block a user