11 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks | 01 | execute | 1 |
|
true |
|
|
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.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.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.mdFrom lib/features/home/presentation/calendar_task_row.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:
Future<void> 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:
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,
});
-
calendar_day_list.dart (line ~271): In the
_buildTaskListmethod, change the day tasks loop to always passcanComplete: true:- Remove the line
final isFuture = state.selectedDate.isAfter(today);(line ~245) - Change
canComplete: !isFuture(line ~271) tocanComplete: true - The
isFuturevariable can be removed entirely since it is only used forcanComplete - Keep the
todayvariable — it is still used forisTodaycheck in _buildContent
- Remove the line
-
calendar_task_row.dart: No changes needed. The
canCompleteparameter already defaults totrueand the widget itself has no internal disable logic. The restriction was applied by the caller (calendar_day_list.dart). -
task_row.dart (lines ~45, ~60-62): Remove the
isFuturecheck that disables the checkbox:- Remove line
final isFuture = dueDate.isAfter(today);(line ~45) - Change the
onChangedfrom the ternaryisFuture ? null : (_) { ... }to always-enabled:onChanged: (_) { ref.read(taskActionsProvider.notifier).completeTask(task.id); }, - The
dueDateandisOverduevariables 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 <acceptance_criteria> - calendar_day_list.dart does NOT contain the string
isFuture - calendar_day_list.dart contains
canComplete: truein the _buildAnimatedTaskRow call for dayTasks - task_row.dart does NOT contain the string
isFuture - task_row.dart does NOT contain
? nullin the Checkbox onChanged handler - calendar_task_row.dart is unchanged (canComplete param still exists with default true) </acceptance_criteria> All checkboxes are always enabled across calendar and task list views. No isFuture guard remains in UI code.
- Remove line
In lib/features/tasks/data/tasks_dao.dart, method completeTask():
Change step 3 from:
// 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:
// 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:
completeTask on due date preserves rhythm— weekly task due 2026-03-24, complete on 2026-03-24, next due = 2026-03-31completeTask 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)completeTask daily task on non-due day— daily task due 2026-03-26, complete on 2026-03-24, next due = 2026-03-25 (tomorrow)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 <acceptance_criteria>- tasks_dao.dart completeTask() contains
final baseDate = todayStart == taskDueDay ? task.nextDueDate : todayStart; - tasks_dao.dart completeTask() passes
currentDueDate: baseDateto 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) </acceptance_criteria> 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.
- tasks_dao.dart completeTask() contains
<success_criteria>
- 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 </success_criteria>