Files
HouseHoldKeaper/.planning/phases/03-daily-plan-and-cleanliness/03-02-PLAN.md

15 KiB

phase: 03-daily-plan-and-cleanliness plan: 02 type: execute wave: 2 depends_on: - 03-01 files_modified: - lib/features/home/presentation/home_screen.dart - lib/features/home/presentation/daily_plan_task_row.dart - lib/features/home/presentation/progress_card.dart - test/features/home/presentation/home_screen_test.dart autonomous: true requirements: - PLAN-04 - PLAN-06 - CLEAN-01 must_haves: truths: - "User sees progress card at top of daily plan showing 'X von Y erledigt' with linear progress bar" - "User sees overdue tasks in a highlighted section (warm coral) that only appears when overdue tasks exist" - "User sees today's tasks in a section below overdue" - "User sees tomorrow's tasks in a collapsed 'Demnachst (N)' section that expands on tap" - "User can check a checkbox on an overdue or today task, which animates the task out and increments progress" - "When no overdue or today tasks are due, user sees 'Alles erledigt!' empty state with celebration icon" - "Room name tag on each task row navigates to that room's task list on tap" - "Task rows have NO row-tap navigation -- only checkbox and room tag are interactive" - "CLEAN-01 cleanliness indicator already visible on room cards (Phase 2 -- no new work)" artifacts: - path: "lib/features/home/presentation/home_screen.dart" provides: "Complete daily plan screen replacing placeholder" min_lines: 100 - path: "lib/features/home/presentation/daily_plan_task_row.dart" provides: "Task row variant with room name tag, optional checkbox, no row-tap" min_lines: 50 - path: "lib/features/home/presentation/progress_card.dart" provides: "Progress banner card with linear progress bar" min_lines: 30 - path: "test/features/home/presentation/home_screen_test.dart" provides: "Widget tests for empty state, section rendering" min_lines: 40 key_links: - from: "lib/features/home/presentation/home_screen.dart" to: "lib/features/home/presentation/daily_plan_providers.dart" via: "ref.watch(dailyPlanProvider)" pattern: "dailyPlanProvider" - from: "lib/features/home/presentation/home_screen.dart" to: "lib/features/tasks/presentation/task_providers.dart" via: "ref.read(taskActionsProvider.notifier).completeTask()" pattern: "taskActionsProvider" - from: "lib/features/home/presentation/daily_plan_task_row.dart" to: "go_router" via: "context.go('/rooms/$roomId') on room tag tap" pattern: "context\.go" Build the daily plan UI: replace the HomeScreen placeholder with the full daily plan screen featuring a progress card, overdue/today/tomorrow sections, animated task completion, and "all clear" empty state.

Purpose: This is the app's primary screen -- the first thing users see. It transforms the placeholder Home tab into the core daily workflow: see what's due, check it off, feel progress. Output: Complete HomeScreen rewrite, DailyPlanTaskRow widget, ProgressCard widget, and widget tests.

<execution_context> @/home/jlmak/.claude/get-shit-done/workflows/execute-plan.md @/home/jlmak/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-daily-plan-and-cleanliness/3-CONTEXT.md @.planning/phases/03-daily-plan-and-cleanliness/03-RESEARCH.md @.planning/phases/03-daily-plan-and-cleanliness/03-01-SUMMARY.md

@lib/features/home/presentation/home_screen.dart @lib/features/tasks/presentation/task_row.dart @lib/features/tasks/presentation/task_providers.dart @lib/features/tasks/domain/relative_date.dart @lib/core/router/router.dart @lib/l10n/app_de.arb

From lib/features/home/domain/daily_plan_models.dart:

class TaskWithRoom {
  final Task task;
  final String roomName;
  final int roomId;
  const TaskWithRoom({required this.task, required this.roomName, required this.roomId});
}

class DailyPlanState {
  final List<TaskWithRoom> overdueTasks;
  final List<TaskWithRoom> todayTasks;
  final List<TaskWithRoom> tomorrowTasks;
  final int completedTodayCount;
  final int totalTodayCount; // overdue + today + completedTodayCount
  const DailyPlanState({...});
}

From lib/features/home/presentation/daily_plan_providers.dart:

final dailyPlanProvider = StreamProvider.autoDispose<DailyPlanState>((ref) { ... });

From lib/features/tasks/presentation/task_providers.dart:

@riverpod
class TaskActions extends _$TaskActions {
  Future<void> completeTask(int taskId) async { ... }
}

From lib/features/tasks/domain/relative_date.dart:

String formatRelativeDate(DateTime dueDate, DateTime today);
// Returns: "Heute", "Morgen", "in X Tagen", "Uberfaellig seit X Tagen"

From lib/l10n/app_de.arb (Plan 01 additions):

dailyPlanProgress(completed, total) -> "{completed} von {total} erledigt"
dailyPlanSectionOverdue -> "Uberfaellig"
dailyPlanSectionToday -> "Heute"
dailyPlanSectionUpcoming -> "Demnachst"
dailyPlanUpcomingCount(count) -> "Demnachst ({count})"
dailyPlanAllClearTitle -> "Alles erledigt!"
dailyPlanAllClearMessage -> "Keine Aufgaben fuer heute. Geniesse den Moment!"
dailyPlanNoTasks -> "Noch keine Aufgaben angelegt"
Task 1: DailyPlanTaskRow and ProgressCard widgets lib/features/home/presentation/daily_plan_task_row.dart, lib/features/home/presentation/progress_card.dart 1. Create `lib/features/home/presentation/daily_plan_task_row.dart`: - `class DailyPlanTaskRow extends StatelessWidget` (NOT ConsumerWidget -- no ref needed; completion callback passed in) - Constructor params: `required TaskWithRoom taskWithRoom`, `required bool showCheckbox`, `VoidCallback? onCompleted` - Build a `ListTile` with: - `leading`: If showCheckbox, a `Checkbox(value: false, onChanged: (_) => onCompleted?.call())`. If not showCheckbox, null (tomorrow tasks are read-only) - `title`: `Text(task.name)` with titleMedium, maxLines 1, ellipsis overflow - `subtitle`: A `Row` containing: a. Room name tag: `GestureDetector` wrapping a `Container` with `secondaryContainer` background, rounded corners (4px), containing `Text(roomName)` in `labelSmall` with `onSecondaryContainer` color. `onTap: () => context.go('/rooms/${taskWithRoom.roomId}')` b. `SizedBox(width: 8)` c. Relative date text via `formatRelativeDate(task.nextDueDate, DateTime.now())`. Color: `_overdueColor` (0xFFE07A5F) if overdue, `onSurfaceVariant` otherwise. Overdue check: dueDate (date-only) < today (date-only) - NO `onTap` -- per user decision, daily plan task rows have no row-tap navigation. Only checkbox and room tag are interactive - NO `onLongPress` -- no edit/delete from daily plan
2. Create `lib/features/home/presentation/progress_card.dart`:
   - `class ProgressCard extends StatelessWidget`
   - Constructor: `required int completed`, `required int total`
   - Build a `Card` with `margin: EdgeInsets.all(16)`:
     - `Text(l10n.dailyPlanProgress(completed, total))` in `titleMedium` with `fontWeight: FontWeight.bold`
     - `SizedBox(height: 12)`
     - `ClipRRect(borderRadius: 4)` wrapping `LinearProgressIndicator`:
       - `value: total > 0 ? completed / total : 0.0`
       - `minHeight: 8`
       - `backgroundColor: colorScheme.surfaceContainerHighest`
       - `color: colorScheme.primary`
   - When total is 0 and completed is 0 (no tasks at all), the progress card should still render gracefully (0.0 progress, "0 von 0 erledigt")
cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze lib/features/home/presentation/daily_plan_task_row.dart lib/features/home/presentation/progress_card.dart - DailyPlanTaskRow renders task name, room name tag (tappable, navigates to room), relative date (coral if overdue) - DailyPlanTaskRow has checkbox only when showCheckbox=true (overdue/today), hidden for tomorrow - DailyPlanTaskRow has NO onTap or onLongPress on the row itself - ProgressCard shows "X von Y erledigt" text with linear progress bar - Both widgets pass dart analyze Task 2: HomeScreen rewrite with daily plan sections, animated completion, empty state, and tests lib/features/home/presentation/home_screen.dart, test/features/home/presentation/home_screen_test.dart 1. COMPLETE REWRITE of `lib/features/home/presentation/home_screen.dart`: - Change from `StatelessWidget` to `ConsumerStatefulWidget` (needs ref for providers AND state for AnimatedList keys) - `ref.watch(dailyPlanProvider)` in build method - Use `AsyncValue.when(loading: ..., error: ..., data: ...)` pattern: - `loading`: Center(child: CircularProgressIndicator()) - `error`: Center(child: Text(error.toString())) - `data`: Build the daily plan UI
   DAILY PLAN UI STRUCTURE (data case):

   a. **"No tasks at all" state**: If totalTodayCount == 0 AND tomorrowTasks.isEmpty AND completedTodayCount == 0, show the existing empty state pattern (homeEmptyTitle / homeEmptyMessage / homeEmptyAction button navigating to /rooms). This covers the case where the user has not created any rooms/tasks yet. Use `dailyPlanNoTasks` localization key for this.

   b. **"All clear" state** (PLAN-06): If overdueTasks.isEmpty AND todayTasks.isEmpty AND completedTodayCount > 0, show celebration empty state: `Icons.celebration_outlined` (size 80, onSurface alpha 0.4), `dailyPlanAllClearTitle`, `dailyPlanAllClearMessage`. This means there WERE tasks today but they're all done.

   c. **"Also all clear but nothing was ever due today"**: If overdueTasks.isEmpty AND todayTasks.isEmpty AND completedTodayCount == 0 AND tomorrowTasks.isNotEmpty, show same celebration empty state but with the progress card showing 0/0 and then the tomorrow section. (Edge case: nothing today, but stuff tomorrow.)

   d. **Normal state** (tasks exist): `ListView` with:
     1. `ProgressCard(completed: completedTodayCount, total: totalTodayCount)` -- always first
     2. If overdueTasks.isNotEmpty: Section header "Uberfaellig" (titleMedium, warm coral color 0xFFE07A5F) with `Padding(horizontal: 16, vertical: 8)`, followed by `DailyPlanTaskRow` for each overdue task with `showCheckbox: true`
     3. Section header "Heute" (titleMedium, primary color) with same padding, followed by `DailyPlanTaskRow` for each today task with `showCheckbox: true`
     4. If tomorrowTasks.isNotEmpty: `ExpansionTile` with `initiallyExpanded: false`, title: `dailyPlanUpcomingCount(count)` in titleMedium. Children: `DailyPlanTaskRow` for each tomorrow task with `showCheckbox: false`

   COMPLETION ANIMATION (PLAN-04):
   - For the simplicity-first approach (avoiding AnimatedList desync pitfalls from research): When checkbox is tapped, call `ref.read(taskActionsProvider.notifier).completeTask(taskId)`. The Drift stream will naturally re-emit without the completed task (its nextDueDate moves to the future). This provides a seamless removal.
   - To add visual feedback: Wrap each DailyPlanTaskRow in the overdue and today sections with an `AnimatedSwitcher` (or use `AnimatedList` if confident). The simplest approach: maintain a local `Set<int> _completingTaskIds` in state. When checkbox tapped, add taskId to set, triggering a rebuild that wraps the row in `SizeTransition` animating to zero height over 300ms. After animation, the stream re-emission removes it permanently.
   - Alternative simpler approach: Use a plain ListView. On checkbox tap, fire completeTask(). The stream re-emission rebuilds the list without the task. No explicit animation, but the progress counter updates immediately giving visual feedback. This is acceptable for v1.
   - RECOMMENDED: Use `AnimatedList` with `GlobalKey<AnimatedListState>` for overdue+today section. On completion, call `removeItem()` with `SizeTransition + SlideTransition` (slide right, 300ms, easeInOut). Fire `completeTask()` simultaneously. When the stream re-emits, compare with local list and reconcile. See research Pattern 3 for exact code. BUT if this proves complex during implementation, fall back to the simpler "let stream handle it" approach.

2. Create `test/features/home/presentation/home_screen_test.dart`:
   - Use provider override pattern (same as app_shell_test.dart):
     - Override `dailyPlanProvider` with a `StreamProvider` returning test data
     - Override `appDatabaseProvider` if needed
   - Test cases:
     a. Empty state: When no tasks exist, shows homeEmptyTitle text and action button
     b. All clear state: When overdue=[], today=[], completedTodayCount > 0, shows "Alles erledigt!" text
     c. Normal state: When tasks exist, shows progress card with correct counts
     d. Overdue section: When overdue tasks exist, shows "Uberfaellig" header
     e. Tomorrow section: Shows collapsed "Demnachst" header with count

3. Run `flutter test` to confirm all tests pass (existing + new).
cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter test test/features/home/presentation/home_screen_test.dart && flutter test - HomeScreen fully replaced with daily plan: progress card at top, overdue section (conditional), today section, tomorrow section (collapsed ExpansionTile) - Checkbox on overdue/today tasks triggers completion via taskActionsProvider, task animates out or disappears on stream re-emission - Tomorrow tasks are read-only (no checkbox) - Room name tags navigate to room task list via context.go - "All clear" empty state shown when all today's tasks are done - "No tasks" empty state shown when no tasks exist at all - Widget tests cover empty state, all clear state, normal state with sections - Full test suite passes - CLEAN-01 verified: room cards already show cleanliness indicator (no new work needed) - `flutter test test/features/home/` -- all home feature tests pass - `flutter test` -- full suite passes (no regressions) - `dart analyze` -- clean analysis - HomeScreen shows daily plan with all three sections - CLEAN-01 confirmed via existing room card cleanliness indicator

<success_criteria>

  • HomeScreen replaced with complete daily plan (no more placeholder)
  • Progress card shows "X von Y erledigt" with accurate counts
  • Overdue tasks highlighted with warm coral section header, only shown when overdue tasks exist
  • Today tasks shown in dedicated section with checkboxes
  • Tomorrow tasks in collapsed ExpansionTile, read-only
  • Checkbox completion triggers database update and task disappears
  • "All clear" empty state displays when all tasks done
  • Room name tags navigate to room task list
  • No row-tap navigation on task rows (daily plan is focused action screen)
  • CLEAN-01 verified on room cards </success_criteria>
After completion, create `.planning/phases/03-daily-plan-and-cleanliness/03-02-SUMMARY.md`