--- phase: 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks plan: 01 type: execute wave: 1 depends_on: [] files_modified: - lib/features/home/presentation/calendar_day_list.dart - lib/features/home/presentation/calendar_task_row.dart - lib/features/tasks/presentation/task_row.dart - lib/features/tasks/data/tasks_dao.dart - test/features/tasks/data/tasks_dao_test.dart autonomous: true requirements: - TM-01 - TM-02 must_haves: truths: - "User can check off a task on any calendar day including future days" - "When completing a task on a non-due day, nextDueDate recalculates from today not from the original due date" - "Overdue tasks remain completable (no regression)" artifacts: - path: "lib/features/home/presentation/calendar_day_list.dart" provides: "Checkbox always enabled for all day tasks" contains: "canComplete: true" - path: "lib/features/home/presentation/calendar_task_row.dart" provides: "CalendarTaskRow with always-enabled checkbox" contains: "canComplete" - path: "lib/features/tasks/presentation/task_row.dart" provides: "TaskRow with always-enabled checkbox" - path: "lib/features/tasks/data/tasks_dao.dart" provides: "completeTask with today-based recalculation" contains: "calculateNextDueDate" key_links: - from: "lib/features/home/presentation/calendar_day_list.dart" to: "CalendarTaskRow" via: "canComplete: true always passed" pattern: "canComplete: true" - from: "lib/features/tasks/data/tasks_dao.dart" to: "scheduling.dart" via: "calculateNextDueDate uses today as base when completing on non-due day" pattern: "calculateNextDueDate" --- Enable anytime task completion: remove all checkbox-disable restrictions so users can mark tasks done on any calendar day (past, today, or future). When completing a task on a non-due day, recalculate nextDueDate from today (per D-02). Purpose: Users should never be blocked from marking a task as done. The current behavior of disabling checkboxes for future tasks creates friction and confusion. Output: All checkboxes always enabled. completeTask() uses today as base for nextDueDate calculation when task is completed on a non-due day. @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks/11-CONTEXT.md From lib/features/home/presentation/calendar_task_row.dart: ```dart class CalendarTaskRow extends StatelessWidget { const CalendarTaskRow({ super.key, required this.taskWithRoom, required this.onCompleted, this.isOverdue = false, this.showRoomTag = true, this.canComplete = true, // Currently defaults to true but overridden with !isFuture }); final bool canComplete; // When false, checkbox is disabled } ``` From lib/features/tasks/data/tasks_dao.dart: ```dart Future completeTask(int taskId, {DateTime? now}) { // Step 3: calculates next due from task.nextDueDate (original due date) var nextDue = calculateNextDueDate( currentDueDate: task.nextDueDate, // <-- This is the line to change for non-due-day ... ); } ``` From lib/features/tasks/domain/scheduling.dart: ```dart DateTime calculateNextDueDate({ required DateTime currentDueDate, required IntervalType intervalType, required int intervalDays, int? anchorDay, }); DateTime catchUpToPresent({ required DateTime nextDue, required DateTime today, required IntervalType intervalType, required int intervalDays, int? anchorDay, }); ``` Task 1: Remove checkbox-disable restrictions in all three UI files lib/features/home/presentation/calendar_day_list.dart lib/features/home/presentation/calendar_task_row.dart lib/features/tasks/presentation/task_row.dart lib/features/home/presentation/calendar_day_list.dart lib/features/home/presentation/calendar_task_row.dart lib/features/tasks/presentation/task_row.dart **Per D-01: Remove isFuture / canComplete restrictions.** 1. **calendar_day_list.dart** (line ~271): In the `_buildTaskList` method, change the day tasks loop to always pass `canComplete: true`: - Remove the line `final isFuture = state.selectedDate.isAfter(today);` (line ~245) - Change `canComplete: !isFuture` (line ~271) to `canComplete: true` - The `isFuture` variable can be removed entirely since it is only used for `canComplete` - Keep the `today` variable — it is still used for `isToday` check in _buildContent 2. **calendar_task_row.dart**: No changes needed. The `canComplete` parameter already defaults to `true` and the widget itself has no internal disable logic. The restriction was applied by the caller (calendar_day_list.dart). 3. **task_row.dart** (lines ~45, ~60-62): Remove the `isFuture` check that disables the checkbox: - Remove line `final isFuture = dueDate.isAfter(today);` (line ~45) - Change the `onChanged` from the ternary `isFuture ? null : (_) { ... }` to always-enabled: ```dart onChanged: (_) { ref.read(taskActionsProvider.notifier).completeTask(task.id); }, ``` - The `dueDate` and `isOverdue` variables remain — they are used for styling the relative date text color grep -n "isFuture" lib/features/home/presentation/calendar_day_list.dart lib/features/tasks/presentation/task_row.dart; echo "---"; grep -n "canComplete: true" lib/features/home/presentation/calendar_day_list.dart - calendar_day_list.dart does NOT contain the string `isFuture` - calendar_day_list.dart contains `canComplete: true` in the _buildAnimatedTaskRow call for dayTasks - task_row.dart does NOT contain the string `isFuture` - task_row.dart does NOT contain `? null` in the Checkbox onChanged handler - calendar_task_row.dart is unchanged (canComplete param still exists with default true) All checkboxes are always enabled across calendar and task list views. No isFuture guard remains in UI code. Task 2: Update completeTask to recalculate nextDueDate from today on non-due-day completion lib/features/tasks/data/tasks_dao.dart test/features/tasks/data/tasks_dao_test.dart lib/features/tasks/data/tasks_dao.dart lib/features/tasks/domain/scheduling.dart test/features/tasks/data/tasks_dao_test.dart - Test: Completing a task ON its due date recalculates nextDueDate from the original due date (existing behavior preserved) - Test: Completing a weekly task 3 days BEFORE its due date recalculates nextDueDate from today (not original due date) — e.g., task due Friday, completed Tuesday, next due = next Tuesday - Test: Completing a daily task on a non-due day still produces tomorrow as next due - Test: Completing a monthly task early recalculates from today with anchor day preserved **Per D-02 and D-03: When completing a task on a non-due day, recalculate nextDueDate from today.** In `lib/features/tasks/data/tasks_dao.dart`, method `completeTask()`: Change step 3 from: ```dart // 3. Calculate next due date (from original due date, not today) var nextDue = calculateNextDueDate( currentDueDate: task.nextDueDate, intervalType: task.intervalType, intervalDays: task.intervalDays, anchorDay: task.anchorDay, ); ``` To: ```dart // 3. Calculate next due date // If completing on the due date, use original due date as base (keeps rhythm). // If completing on a different day (early or late), use today as base (per D-02). final todayStart = DateTime(currentTime.year, currentTime.month, currentTime.day); final taskDueDay = DateTime(task.nextDueDate.year, task.nextDueDate.month, task.nextDueDate.day); final baseDate = todayStart == taskDueDay ? task.nextDueDate : todayStart; var nextDue = calculateNextDueDate( currentDueDate: baseDate, intervalType: task.intervalType, intervalDays: task.intervalDays, anchorDay: task.anchorDay, ); ``` Note: The existing `todayDateOnly` variable (line 66-70) can be replaced by `todayStart` since they are the same. Rename to avoid duplication. The catch-up step (step 4) remains unchanged — it still ensures nextDue is not in the past. Write 4 new test cases in `test/features/tasks/data/tasks_dao_test.dart`: 1. `completeTask on due date preserves rhythm` — weekly task due 2026-03-24, complete on 2026-03-24, next due = 2026-03-31 2. `completeTask before due date recalculates from today` — weekly task due 2026-03-28, complete on 2026-03-24, next due = 2026-03-31 (7 days from today) 3. `completeTask daily task on non-due day` — daily task due 2026-03-26, complete on 2026-03-24, next due = 2026-03-25 (tomorrow) 4. `completeTask monthly task early preserves anchor` — monthly task due 2026-03-28 anchorDay=28, complete on 2026-03-24, next due = 2026-04-28 cd /home/jean-luc-makiola/Development/projects/HouseHoldKeaper && flutter test test/features/tasks/data/tasks_dao_test.dart --reporter compact - tasks_dao.dart completeTask() contains `final baseDate = todayStart == taskDueDay ? task.nextDueDate : todayStart;` - tasks_dao.dart completeTask() passes `currentDueDate: baseDate` to calculateNextDueDate - tasks_dao_test.dart contains test with name matching `completeTask.*before due date.*recalculates from today` - tasks_dao_test.dart contains test with name matching `completeTask.*on due date.*preserves rhythm` - All tests in tasks_dao_test.dart pass (exit code 0) completeTask() uses today as base for non-due-day completions. 4 new tests verify the behavior for on-due-day, before-due-day, daily, and monthly scenarios. All existing tests still pass. 1. `flutter test` — all existing + new tests pass 2. `dart analyze` — zero issues 3. `grep -rn "isFuture" lib/features/home/presentation/calendar_day_list.dart lib/features/tasks/presentation/task_row.dart` — no matches 4. `grep -n "canComplete: true" lib/features/home/presentation/calendar_day_list.dart` — found in dayTasks loop - Checkboxes are always enabled on all calendar days (past, today, future) - Checkboxes are always enabled in room task list view - Completing a task on its due date preserves the original interval rhythm - Completing a task on a non-due day recalculates from today - All existing tests pass with zero regressions - dart analyze reports zero issues After completion, create `.planning/phases/11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks/11-01-SUMMARY.md`