tasks: add "every N weeks/months/days/years" recurrence (KC-70)

Recurrence previously only supported 5 fixed rules with no interval.
Adds TaskItem.recurrenceInterval (optional, nil = 1, so every existing
task is unaffected), a stepper in the shared create/edit sheet, quick-add
NLP for phrases like "every 2 weeks"/"biweekly"/"fortnightly", and
threads the interval through both countdown widgets so their progress
bars size correctly for biweekly/etc tasks too.

Built on KC-69's consolidated RecurrenceRule engine. Verified two things
by actually compiling and running standalone swiftc drivers rather than
just reading: the core interval math (44/44, unchanged from KC-69) and
the new quick-add regex patterns against realistic phrases including
"look into tru housing options every two weeks" (11/11 passing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
kutesir
2026-07-12 00:15:45 +03:00
committed by kutesir
parent f6a9358a86
commit b7af2dd76b
8 changed files with 225 additions and 22 deletions

View File

@@ -12,6 +12,7 @@ struct WidgetTask: Codable, Identifiable {
let category: String
var isRecurring: Bool = false
var recurrenceLabel: String? = nil
var recurrenceInterval: Int? = nil
var createdAt: Date? = nil
var reminderDate: Date? = nil
var progress: Double? = nil
@@ -67,6 +68,7 @@ func loadWidgetTasks() -> [WidgetTask] {
WidgetTask(id: $0.id, title: $0.title, dueDate: $0.dueDate,
isComplete: $0.isComplete, quadrant: $0.quadrant, category: $0.category,
isRecurring: $0.isRecurring ?? false, recurrenceLabel: $0.recurrenceLabel,
recurrenceInterval: $0.recurrenceInterval,
createdAt: $0.createdAt, reminderDate: $0.reminderDate,
progress: $0.countdownProgress ?? $0.progress)
}
@@ -82,13 +84,14 @@ private struct RawTask: Codable {
var category: String = "reminder"
var isRecurring: Bool? = nil
var recurrenceLabel: String? = nil
var recurrenceInterval: Int? = nil
var createdAt: Date? = nil
var reminderDate: Date? = nil
var progress: Double? = nil
var countdownProgress: Double? = nil
enum CodingKeys: String, CodingKey {
case id, title, dueDate, isComplete, quadrant, category, isRecurring, recurrenceLabel
case createdAt, reminderDate, progress, countdownProgress
case recurrenceInterval, createdAt, reminderDate, progress, countdownProgress
}
}