diff --git a/KisaniCal/Models/TaskItem.swift b/KisaniCal/Models/TaskItem.swift index 8b38076..d1ca5e2 100644 --- a/KisaniCal/Models/TaskItem.swift +++ b/KisaniCal/Models/TaskItem.swift @@ -238,12 +238,29 @@ class TaskViewModel: ObservableObject { } var overdueTasks: [TaskItem] { - let today = Calendar.current.startOfDay(for: Date()) - // Non-recurring past-due only — recurring surfaces its next occurrence instead. - return tasks.filter { !recurs($0) && !$0.isComplete && ($0.dueDate ?? .distantFuture) < today } - .sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) } + let now = Date() + let today = Calendar.current.startOfDay(for: now) + // TickTick rule: timed tasks become overdue the moment the clock passes; + // date-only tasks become overdue at the start of the next day (midnight). + return tasks.filter { + guard !recurs($0) && !$0.isComplete, let due = $0.dueDate else { return false } + return $0.hasTime ? due < now : due < today + } + .sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) } + } + var todayTasks: [TaskItem] { + let now = Date() + 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. + return activeRows().filter { + guard let d = $0.dueDate else { return false } + if $0.hasTime && d < now { return false } + return d >= start && d < end + } + .sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) } } - var todayTasks: [TaskItem] { bucket(from: 0, to: 1) } // due today var tomorrowTasks: [TaskItem] { bucket(from: 1, to: 2) } // due tomorrow var next7DaysTasks: [TaskItem] { bucket(from: 2, to: 8) } // due in 2–7 days var laterTasks: [TaskItem] { bucket(from: 8, to: nil) } // beyond 7 days