From 673f27ad38e0f12fd86c50c474abb93ca5ac8ccc Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Fri, 3 Apr 2026 21:28:23 +0200 Subject: [PATCH] =?UTF-8?q?docs(11-02):=20complete=20pre-populate-recurrin?= =?UTF-8?q?g-tasks=20plan=20=E2=80=94=20interval-window=20pre-population?= =?UTF-8?q?=20with=20muted=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .planning/REQUIREMENTS.md | 6 +- .planning/ROADMAP.md | 8 +- .planning/STATE.md | 18 ++- .../11-02-SUMMARY.md | 151 ++++++++++++++++++ 4 files changed, 169 insertions(+), 14 deletions(-) create mode 100644 .planning/phases/11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks/11-02-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 2154027..44c472a 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -29,9 +29,9 @@ Requirements for milestone v1.2 Polish & Task Management. Each maps to roadmap p - [x] **TM-01**: User can check off (complete) a task on any calendar day — checkboxes are never disabled for future dates - [x] **TM-02**: When completing a task on a non-due day, nextDueDate is recalculated from today (not from the original due date) -- [ ] **TM-03**: Recurring tasks are pre-populated on all applicable days within their current interval window (e.g., a weekly task shows every day in the 7-day window leading up to its due date) -- [ ] **TM-04**: Pre-populated tasks that have already been completed in the current interval period are hidden from the calendar view -- [ ] **TM-05**: Pre-populated tasks not yet due have a muted visual distinction (reduced opacity) compared to due-today and overdue tasks +- [x] **TM-03**: Recurring tasks are pre-populated on all applicable days within their current interval window (e.g., a weekly task shows every day in the 7-day window leading up to its due date) +- [x] **TM-04**: Pre-populated tasks that have already been completed in the current interval period are hidden from the calendar view +- [x] **TM-05**: Pre-populated tasks not yet due have a muted visual distinction (reduced opacity) compared to due-today and overdue tasks ## Future Requirements diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index b3fcd01..9442a14 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -36,7 +36,7 @@ See `milestones/v1.1-ROADMAP.md` for full phase details. - [x] **Phase 8: Task Delete** - Add smart delete action to tasks — hard delete if never completed, soft delete (deactivate) if completed at least once (completed 2026-03-18) - [x] **Phase 9: Task Creation UX** - Rework the frequency picker from flat preset chips to an intuitive "Every N units" interface with quick-select shortcuts (completed 2026-03-18) - [x] **Phase 10: Dead Code Cleanup** - Remove orphaned v1.0 daily plan files and verify no regressions (completed 2026-03-19) -- [ ] **Phase 11: Tasks Management** - Allow task checking anytime and pre-populate recurring tasks within their interval window +- [x] **Phase 11: Tasks Management** - Allow task checking anytime and pre-populate recurring tasks within their interval window (completed 2026-04-03) ## Phase Details @@ -86,10 +86,10 @@ Plans: **Goal**: Users can complete tasks on any day regardless of schedule, and recurring tasks appear on all applicable days within their interval window — making the app feel like a consistent checklist rather than a rigid scheduler **Depends on**: Phase 10 **Requirements**: TM-01, TM-02, TM-03, TM-04, TM-05 -**Plans:** 1/2 plans executed +**Plans:** 2/2 plans complete Plans: - [x] 11-01-PLAN.md — Anytime completion: remove checkbox restrictions, recalculate nextDueDate from today on non-due-day completion -- [ ] 11-02-PLAN.md — Pre-population: virtual task instances in provider layer, period-completion filtering, muted visual styling +- [x] 11-02-PLAN.md — Pre-population: virtual task instances in provider layer, period-completion filtering, muted visual styling **Success Criteria** (what must be TRUE): 1. Checkboxes are always enabled on all calendar days (past, today, future) and in room task lists 2. Completing a task on a non-due day recalculates nextDueDate from today, not the original due date @@ -114,4 +114,4 @@ Plans: | 8. Task Delete | v1.2 | 2/2 | Complete | 2026-03-18 | | 9. Task Creation UX | v1.2 | 1/1 | Complete | 2026-03-18 | | 10. Dead Code Cleanup | v1.2 | 1/1 | Complete | 2026-03-19 | -| 11. Tasks Management | v1.2 | 1/2 | In Progress| | +| 11. Tasks Management | v1.2 | 2/2 | Complete | 2026-04-03 | diff --git a/.planning/STATE.md b/.planning/STATE.md index d07ddaa..d0f6f4e 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,14 +2,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone -status: Ready to execute -stopped_at: Completed 11-01-PLAN.md -last_updated: "2026-03-24T08:49:28.728Z" +status: Phase complete — ready for verification +stopped_at: Completed 11-02-PLAN.md +last_updated: "2026-04-03T19:28:12.418Z" progress: total_phases: 4 - completed_phases: 3 + completed_phases: 4 total_plans: 6 - completed_plans: 5 + completed_plans: 6 --- # Project State @@ -39,6 +39,7 @@ Plan: 2 of 2 | Phase 09-task-creation-ux P01 | 2 | 1 tasks | 4 files | | Phase 10-dead-code-cleanup P01 | 5 | 2 tasks | 4 files | | Phase 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks P01 | 219 | 2 tasks | 4 files | +| Phase 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks P02 | 15 | 2 tasks | 6 files | ## Accumulated Context @@ -56,6 +57,9 @@ Decisions archived to PROJECT.md Key Decisions table. - [Phase 10-dead-code-cleanup]: TaskWithRoom retained in daily_plan_models.dart — actively used by calendar_dao.dart, calendar_providers.dart, and related calendar files - [Phase 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks]: D-01: Remove isFuture/canComplete restrictions — checkboxes always enabled across all UI; calendar_task_row.dart unchanged (caller was applying restriction) - [Phase 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks]: D-02: When completing on non-due day, use today as baseDate for nextDueDate calculation (todayStart == taskDueDay pattern) +- [Phase 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks]: D-03: Pre-population via query-time virtual instances — no schema migration +- [Phase 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks]: D-04: _subtractMonths uses total-month arithmetic to handle January-boundary year crossings correctly +- [Phase 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks]: D-05: Pre-populated tasks rendered in Demnächst section below day tasks with 0.55 Opacity ### Pending Todos @@ -71,7 +75,7 @@ None. ## Session Continuity -Last session: 2026-03-24T08:49:28.726Z -Stopped at: Completed 11-01-PLAN.md +Last session: 2026-04-03T19:28:12.416Z +Stopped at: Completed 11-02-PLAN.md Resume file: None Next action: Phase 10 complete diff --git a/.planning/phases/11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks/11-02-SUMMARY.md b/.planning/phases/11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks/11-02-SUMMARY.md new file mode 100644 index 0000000..9d4ace7 --- /dev/null +++ b/.planning/phases/11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks/11-02-SUMMARY.md @@ -0,0 +1,151 @@ +--- +phase: 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks +plan: 02 +subsystem: ui, database, domain +tags: [flutter, drift, riverpod, pre-population, recurring-tasks, calendar, interval-window] + +# Dependency graph +requires: + - phase: 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks + plan: 11-01 + provides: Always-enabled checkboxes and today-base completeTask behavior + +provides: + - watchAllActiveRecurringTasks and watchAllActiveRecurringTasksInRoom DAO queries + - watchCompletionsInRange DAO query for period-completion filtering + - CalendarDayState.prePopulatedTasks field + - _isInCurrentIntervalWindow and _calculatePreviousDueDate pre-population helpers + - calendarDayProvider and roomCalendarDayProvider pre-population logic + - "Demnächst" section with 0.55 opacity rendering in CalendarDayList + +affects: + - Home screen calendar day view (pre-populated tasks now visible) + - Room-scoped calendar view (same pre-population logic) + - Celebration state (now checks prePopulatedTasks.isEmpty too) + +# Tech tracking +tech-stack: + added: [] + patterns: + - "Interval window pre-population: query-time virtual instances, no schema migration" + - "Period-completion filtering: watchCompletionsInRange excludes already-completed tasks" + - "Total-month arithmetic for _subtractMonths: avoids year-boundary bugs with negative months" + - "0.55 opacity for pre-populated task rows via Opacity widget wrapper" + +key-files: + created: [] + modified: + - lib/features/home/data/calendar_dao.dart + - lib/features/home/domain/calendar_models.dart + - lib/features/home/presentation/calendar_providers.dart + - lib/features/home/presentation/calendar_day_list.dart + - lib/features/home/presentation/calendar_task_row.dart + - test/features/home/data/calendar_dao_test.dart + +key-decisions: + - "D-03: Pre-population via query-time virtual instances — no schema migration, no stored virtual rows" + - "D-04: _subtractMonths uses total-month arithmetic (year*12+month-1) to correctly handle January-boundary crossings" + - "D-05: Pre-populated tasks rendered in 'Demnächst' section below day tasks with 0.55 Opacity" + - "D-06: Celebration state now includes prePopulatedTasks.isEmpty — pre-populated tasks prevent celebration" + +patterns-established: + - "Interval window: selected date AFTER previousDue (exclusive) AND BEFORE nextDueDate (exclusive)" + - "Period completion filter: watchCompletionsInRange(taskId, prevDue, nextDue+1day)" + - "Muted pre-population UI: Opacity(0.55) wrapping ListTile, isPrePopulated flag propagated through widget tree" + +requirements-completed: + - TM-03 + - TM-04 + - TM-05 + +# Metrics +duration: ~15min +completed: 2026-04-03 +--- + +# Phase 11 Plan 02: Pre-populate Recurring Tasks on Interval Window Summary + +**Interval-window pre-population via query-time virtual instances with period-completion filtering and 0.55 opacity muted visual distinction** + +## Performance + +- **Duration:** ~15 min +- **Started:** 2026-04-03 +- **Completed:** 2026-04-03 +- **Tasks:** 2 +- **Files modified:** 6 + +## Accomplishments + +- Added `watchAllActiveRecurringTasks()` and `watchAllActiveRecurringTasksInRoom(roomId)` to `CalendarDao` — fetch all active tasks for pre-population source data +- Added `watchCompletionsInRange(taskId, start, end)` to `CalendarDao` — check if a task was completed in the current interval period (prevents re-showing completed tasks) +- Extended `CalendarDayState` with `prePopulatedTasks` field (default empty for backward compatibility); updated `isEmpty` getter to include `prePopulatedTasks.isEmpty` +- Added `_isInCurrentIntervalWindow()` helper: determines if a task's current interval window includes `selectedDate` (selected is after previousDue and before nextDueDate) +- Added `_calculatePreviousDueDate()` helper: reverse-calculates start of current interval window by subtracting one interval +- Rewrote `calendarDayProvider` and `roomCalendarDayProvider` to combine three streams: due-today, overdue, and pre-populated virtual instances with period-completion exclusion +- Added `isPrePopulated` parameter to `CalendarTaskRow` with `Opacity(0.55)` wrapper for muted visual style +- Rendered "Demnächst" section in `CalendarDayList` below day tasks, with muted section header and `isPrePopulated: true` rows +- Added 9 new DAO tests for `watchAllActiveRecurringTasks`, `watchAllActiveRecurringTasksInRoom`, `watchCompletionsInRange` + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: DAO queries, CalendarDayState model, pre-population provider** - `9a67c51` (feat) +2. **Task 2: UI rendering with muted visual distinction** - `8cbe989` (feat) + +## Files Created/Modified + +- `lib/features/home/data/calendar_dao.dart` — Added `watchAllActiveRecurringTasks()`, `watchAllActiveRecurringTasksInRoom()`, `watchCompletionsInRange()` +- `lib/features/home/domain/calendar_models.dart` — Added `prePopulatedTasks` field with default empty, updated `isEmpty` +- `lib/features/home/presentation/calendar_providers.dart` — Added `_isInCurrentIntervalWindow`, `_calculatePreviousDueDate`, `_subtractMonths` helpers; rewrote both providers with pre-population logic; added `IntervalType` and `database.dart` imports +- `lib/features/home/presentation/calendar_day_list.dart` — Added "Demnächst" section, updated `_buildAnimatedTaskRow` with `isPrePopulated`, updated `_CompletingTaskRow`, updated celebration check, updated cleanup loop +- `lib/features/home/presentation/calendar_task_row.dart` — Added `isPrePopulated` parameter and `Opacity(0.55)` wrapper +- `test/features/home/data/calendar_dao_test.dart` — Added 9 tests across 3 new test groups; added `drift/drift.dart` import for `Value` + +## Decisions Made + +- Pre-population uses query-time virtual instances — no schema migration, no stored virtual rows. Provider layer computes which tasks appear on a given day by checking their interval window. +- `_subtractMonths` uses total-month arithmetic (`year*12 + month - 1 - months`) instead of the plan's proposed formula, which had a year-boundary bug for months <= 0 (e.g. January - 1 month would incorrectly stay in the same year with Dart's truncation division). +- Celebration state updated to check `prePopulatedTasks.isEmpty` — a day with only pre-populated tasks does not show the celebration screen (tasks still need doing). + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Fixed _subtractMonths year-boundary arithmetic** + +- **Found during:** Task 1 +- **Issue:** The plan's proposed `_subtractMonths` formula used `(targetMonth - 1) ~/ 12` for year calculation. In Dart, `~/` is truncation-toward-zero division, so `(-1) ~/ 12 = 0` (not `-1`). This means subtracting 1 month from January 2026 would produce year 2026 instead of 2025. +- **Fix:** Replaced with total-month arithmetic: `totalMonths = date.year * 12 + (date.month - 1) - months`, then `targetYear = totalMonths ~/ 12`, `normalizedMonth = (totalMonths % 12) + 1`. This is always correct for any combination of year and months. +- **Files modified:** `lib/features/home/presentation/calendar_providers.dart` +- **Commit:** `9a67c51` + +## Known Stubs + +None. + +## User Setup Required + +None — no external service configuration required. + +## Next Phase Readiness + +- Pre-population of recurring tasks fully implemented +- Phase 11 (Issue #3) complete — both plans executed +- No blockers + +## Self-Check: PASSED + +- FOUND: lib/features/home/data/calendar_dao.dart +- FOUND: lib/features/home/domain/calendar_models.dart +- FOUND: lib/features/home/presentation/calendar_providers.dart +- FOUND: lib/features/home/presentation/calendar_day_list.dart +- FOUND: lib/features/home/presentation/calendar_task_row.dart +- FOUND: test/features/home/data/calendar_dao_test.dart +- FOUND: commit 9a67c51 (Task 1 - DAO queries + provider logic) +- FOUND: commit 8cbe989 (Task 2 - UI rendering) + +--- +*Phase: 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks* +*Completed: 2026-04-03*