7.9 KiB
7.9 KiB
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()andwatchAllActiveRecurringTasksInRoom(roomId)toCalendarDao— fetch all active tasks for pre-population source data - Added
watchCompletionsInRange(taskId, start, end)toCalendarDao— check if a task was completed in the current interval period (prevents re-showing completed tasks) - Extended
CalendarDayStatewithprePopulatedTasksfield (default empty for backward compatibility); updatedisEmptygetter to includeprePopulatedTasks.isEmpty - Added
_isInCurrentIntervalWindow()helper: determines if a task's current interval window includesselectedDate(selected is after previousDue and before nextDueDate) - Added
_calculatePreviousDueDate()helper: reverse-calculates start of current interval window by subtracting one interval - Rewrote
calendarDayProviderandroomCalendarDayProviderto combine three streams: due-today, overdue, and pre-populated virtual instances with period-completion exclusion - Added
isPrePopulatedparameter toCalendarTaskRowwithOpacity(0.55)wrapper for muted visual style - Rendered "Demnächst" section in
CalendarDayListbelow day tasks, with muted section header andisPrePopulated: truerows - Added 9 new DAO tests for
watchAllActiveRecurringTasks,watchAllActiveRecurringTasksInRoom,watchCompletionsInRange
Task Commits
Each task was committed atomically:
- Task 1: DAO queries, CalendarDayState model, pre-population provider -
9a67c51(feat) - Task 2: UI rendering with muted visual distinction -
8cbe989(feat)
Files Created/Modified
lib/features/home/data/calendar_dao.dart— AddedwatchAllActiveRecurringTasks(),watchAllActiveRecurringTasksInRoom(),watchCompletionsInRange()lib/features/home/domain/calendar_models.dart— AddedprePopulatedTasksfield with default empty, updatedisEmptylib/features/home/presentation/calendar_providers.dart— Added_isInCurrentIntervalWindow,_calculatePreviousDueDate,_subtractMonthshelpers; rewrote both providers with pre-population logic; addedIntervalTypeanddatabase.dartimportslib/features/home/presentation/calendar_day_list.dart— Added "Demnächst" section, updated_buildAnimatedTaskRowwithisPrePopulated, updated_CompletingTaskRow, updated celebration check, updated cleanup looplib/features/home/presentation/calendar_task_row.dart— AddedisPrePopulatedparameter andOpacity(0.55)wrappertest/features/home/data/calendar_dao_test.dart— Added 9 tests across 3 new test groups; addeddrift/drift.dartimport forValue
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.
_subtractMonthsuses 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
_subtractMonthsformula used(targetMonth - 1) ~/ 12for 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, thentargetYear = 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