diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 2dc09f0..5f2c8fc 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -37,7 +37,10 @@ See `milestones/v1.0-ROADMAP.md` for full phase details. 3. On app launch the strip auto-scrolls so today's card is centered and selected by default 4. When two adjacent day cards span a month boundary, a subtle color shift or divider makes the boundary visible without extra chrome 5. Tasks that were not completed on their due date appear in subsequent days' lists with a red/orange accent marking them as overdue -**Plans**: TBD +**Plans:** 2 plans +Plans: +- [ ] 05-01-PLAN.md — Data layer: CalendarDao, CalendarDayState model, Riverpod providers, localization, DAO tests +- [ ] 05-02-PLAN.md — UI: CalendarStrip, CalendarDayList, CalendarTaskRow widgets, HomeScreen replacement ### Phase 6: Task History **Goal**: Users can see exactly when each task was completed in the past, building trust that the scheduling loop is working correctly @@ -68,6 +71,6 @@ See `milestones/v1.0-ROADMAP.md` for full phase details. | 2. Rooms and Tasks | v1.0 | 5/5 | Complete | 2026-03-15 | | 3. Daily Plan and Cleanliness | v1.0 | 3/3 | Complete | 2026-03-16 | | 4. Notifications | v1.0 | 3/3 | Complete | 2026-03-16 | -| 5. Calendar Strip | v1.1 | 0/? | Not started | - | +| 5. Calendar Strip | v1.1 | 0/2 | Planned | - | | 6. Task History | v1.1 | 0/? | Not started | - | | 7. Task Sorting | v1.1 | 0/? | Not started | - | diff --git a/.planning/phases/05-calendar-strip/05-01-PLAN.md b/.planning/phases/05-calendar-strip/05-01-PLAN.md new file mode 100644 index 0000000..bf4ffdd --- /dev/null +++ b/.planning/phases/05-calendar-strip/05-01-PLAN.md @@ -0,0 +1,262 @@ +--- +phase: 05-calendar-strip +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - lib/features/home/data/calendar_dao.dart + - lib/features/home/data/calendar_dao.g.dart + - lib/features/home/domain/calendar_models.dart + - lib/features/home/presentation/calendar_providers.dart + - lib/core/database/database.dart + - lib/core/database/database.g.dart + - lib/l10n/app_de.arb + - lib/l10n/app_localizations_de.dart + - lib/l10n/app_localizations.dart + - test/features/home/data/calendar_dao_test.dart +autonomous: true +requirements: + - CAL-02 + - CAL-05 + +must_haves: + truths: + - "Querying tasks for any arbitrary date returns exactly the tasks whose nextDueDate falls on that day" + - "Querying overdue tasks for today returns all tasks whose nextDueDate is strictly before today" + - "Querying a future date returns only tasks due that day, no overdue carry-over" + - "CalendarState model holds selectedDate, overdue tasks, and day tasks as separate lists" + - "Localization strings for calendar UI exist in ARB and generated files" + artifacts: + - path: "lib/features/home/data/calendar_dao.dart" + provides: "Date-parameterized task queries" + exports: ["CalendarDao"] + - path: "lib/features/home/domain/calendar_models.dart" + provides: "CalendarState and reuse of TaskWithRoom" + exports: ["CalendarState"] + - path: "lib/features/home/presentation/calendar_providers.dart" + provides: "Riverpod provider for calendar state" + exports: ["calendarProvider", "selectedDateProvider"] + - path: "test/features/home/data/calendar_dao_test.dart" + provides: "DAO unit tests" + min_lines: 50 + key_links: + - from: "lib/features/home/data/calendar_dao.dart" + to: "lib/core/database/database.dart" + via: "DAO registered in @DriftDatabase annotation" + pattern: "CalendarDao" + - from: "lib/features/home/presentation/calendar_providers.dart" + to: "lib/features/home/data/calendar_dao.dart" + via: "Provider reads CalendarDao from AppDatabase" + pattern: "db\\.calendarDao" +--- + + +Create the data layer, domain models, Riverpod providers, and localization strings for the calendar strip feature. + +Purpose: The calendar strip UI (Plan 02) needs a data foundation that can answer "what tasks are due on date X?" and "what tasks are overdue relative to today?" without the old overdue/today/tomorrow bucketing. This plan builds that foundation and tests it. + +Output: CalendarDao with date-parameterized queries, CalendarState model, Riverpod providers (selectedDateProvider + calendarProvider), new l10n strings, DAO unit tests. + + + +@/home/jlmak/.claude/get-shit-done/workflows/execute-plan.md +@/home/jlmak/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/05-calendar-strip/5-CONTEXT.md + + + + +From lib/core/database/database.dart: +```dart +// Tables: Rooms, Tasks, TaskCompletions +// Existing DAOs: RoomsDao, TasksDao, DailyPlanDao +// CalendarDao must be added to the @DriftDatabase annotation daos list +// and imported at the top of database.dart + +@DriftDatabase( + tables: [Rooms, Tasks, TaskCompletions], + daos: [RoomsDao, TasksDao, DailyPlanDao], // ADD CalendarDao here +) +class AppDatabase extends _$AppDatabase { ... } +``` + +From lib/features/home/domain/daily_plan_models.dart: +```dart +class TaskWithRoom { + final Task task; + final String roomName; + final int roomId; + const TaskWithRoom({required this.task, required this.roomName, required this.roomId}); +} +``` + +From lib/features/home/presentation/daily_plan_providers.dart: +```dart +// Pattern to follow: StreamProvider.autoDispose, manual (not @riverpod) +// because of drift's generated Task type +final dailyPlanProvider = StreamProvider.autoDispose((ref) { + final db = ref.watch(appDatabaseProvider); + ... +}); +``` + +From lib/features/home/data/daily_plan_dao.dart: +```dart +// Pattern: @DriftAccessor with tables, extends DatabaseAccessor +// Uses query.watch() for reactive streams +@DriftAccessor(tables: [Tasks, Rooms, TaskCompletions]) +class DailyPlanDao extends DatabaseAccessor with _$DailyPlanDaoMixin { ... } +``` + +From lib/core/providers/database_provider.dart: +```dart +// appDatabaseProvider gives access to the database singleton +``` + + + + + + + Task 1: Create CalendarDao with date-parameterized queries and tests + + lib/features/home/data/calendar_dao.dart, + lib/core/database/database.dart, + test/features/home/data/calendar_dao_test.dart + + + - watchTasksForDate(date): returns tasks whose nextDueDate falls on the given calendar day (same year/month/day), joined with room name, sorted by task name alphabetically + - watchOverdueTasks(referenceDate): returns tasks whose nextDueDate is strictly before referenceDate (start of day), joined with room name, sorted by nextDueDate ascending + - watchTasksForDate for a date with no tasks returns empty list + - watchOverdueTasks returns empty when no tasks are overdue + - watchOverdueTasks does NOT include tasks due on the referenceDate itself + - watchTasksForDate for a past date returns only tasks originally due that day (does NOT include overdue carry-over) + + + 1. Create `lib/features/home/data/calendar_dao.dart`: + - Class `CalendarDao` extends `DatabaseAccessor` with `_$CalendarDaoMixin` + - Annotated `@DriftAccessor(tables: [Tasks, Rooms, TaskCompletions])` + - `part 'calendar_dao.g.dart';` + - Method `Stream> watchTasksForDate(DateTime date)`: + Compute startOfDay and endOfDay (startOfDay + 1 day). Join tasks with rooms. Filter `tasks.nextDueDate >= startOfDay AND tasks.nextDueDate < endOfDay`. Order by `tasks.name` ascending. Map to `TaskWithRoom`. + - Method `Stream> watchOverdueTasks(DateTime referenceDate)`: + Compute startOfReferenceDay. Join tasks with rooms. Filter `tasks.nextDueDate < startOfReferenceDay`. Order by `tasks.nextDueDate` ascending. Map to `TaskWithRoom`. + - Import `daily_plan_models.dart` for `TaskWithRoom` (reuse, don't duplicate). + + 2. Register CalendarDao in `lib/core/database/database.dart`: + - Add import: `import '../../features/home/data/calendar_dao.dart';` + - Add `CalendarDao` to the `daos:` list in `@DriftDatabase` + + 3. Run `dart run build_runner build --delete-conflicting-outputs` to generate `calendar_dao.g.dart` and updated `database.g.dart`. + + 4. Write `test/features/home/data/calendar_dao_test.dart` following the pattern in `test/features/home/data/daily_plan_dao_test.dart`: + - Use in-memory database: `AppDatabase(NativeDatabase.memory())` + - Create test rooms in setUp + - Test group for watchTasksForDate: + - Empty when no tasks + - Returns only tasks due on the queried date (not before, not after) + - Returns tasks from multiple rooms + - Sorted alphabetically by name + - Test group for watchOverdueTasks: + - Empty when no overdue tasks + - Returns tasks due before reference date + - Does NOT include tasks due ON the reference date + - Sorted by nextDueDate ascending + + + cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter test test/features/home/data/calendar_dao_test.dart + + CalendarDao registered in AppDatabase, both query methods return correct results for arbitrary dates, all DAO tests pass + + + + Task 2: Create CalendarState model, Riverpod providers, and localization strings + + lib/features/home/domain/calendar_models.dart, + lib/features/home/presentation/calendar_providers.dart, + lib/l10n/app_de.arb + + + 1. Create `lib/features/home/domain/calendar_models.dart`: + ```dart + import 'package:household_keeper/features/home/domain/daily_plan_models.dart'; + + /// State for the calendar day view: tasks for the selected date + overdue tasks. + class CalendarDayState { + final DateTime selectedDate; + final List dayTasks; + final List overdueTasks; + + const CalendarDayState({ + required this.selectedDate, + required this.dayTasks, + required this.overdueTasks, + }); + + /// True when viewing today and all tasks (day + overdue) have been completed + /// (lists are empty but completions exist). Determined by the UI layer. + bool get isEmpty => dayTasks.isEmpty && overdueTasks.isEmpty; + } + ``` + + 2. Create `lib/features/home/presentation/calendar_providers.dart`: + - Import Riverpod, database_provider, calendar_dao, calendar_models, daily_plan_models + - `final selectedDateProvider = StateProvider((ref) { final now = DateTime.now(); return DateTime(now.year, now.month, now.day); });` + This is NOT autoDispose -- the selected date persists as long as the app is alive (resets on restart naturally). + - `final calendarDayProvider = StreamProvider.autoDispose((ref) { ... });` + Manual definition (not @riverpod) following dailyPlanProvider pattern. + Reads `selectedDateProvider` to get the current date. + Reads `appDatabaseProvider` to get the DB. + Determines if selectedDate is today: `isToday = selectedDate == DateTime(now.year, now.month, now.day)`. + Determines if selectedDate is in the future: `isFuture = selectedDate.isAfter(today)`. + Watches `db.calendarDao.watchTasksForDate(selectedDate)`. + For overdue: if `isToday`, also watch `db.calendarDao.watchOverdueTasks(selectedDate)`. + If viewing a past date or future date, overdueTasks = empty. + Per user decision: "When viewing past days: show what was due that day. When viewing future days: show only tasks due that day, no overdue carry-over." + Combine both streams using `Rx.combineLatest2` or simply use `asyncMap` on the day tasks stream and fetch overdue as a secondary query. + + Implementation approach: Use the dayTasks stream as the primary, and inside asyncMap call the overdue stream's `.first` when isToday. This keeps it simple and follows the existing `dailyPlanProvider` pattern of `stream.asyncMap()`. + + 3. Add new l10n strings to `lib/l10n/app_de.arb` (add before the closing `}`): + - `"calendarNoTasks": "Keine Aufgaben"` — shown when a day has no tasks at all + - `"calendarAllDone": "Alles erledigt!"` — celebration when all tasks for a day are done + - `"calendarOverdueSection": "Uberfaellig"` — No, reuse existing `dailyPlanSectionOverdue` ("Uberfaellig") for the overdue section header + - `"calendarTodayButton": "Heute"` — floating today button label + + Actually, we can reuse `dailyPlanSectionOverdue` for the overdue header, `dailyPlanNoTasks` for no-tasks-at-all, and `dailyPlanAllClearTitle`/`dailyPlanAllClearMessage` for celebration. The only truly new string needed is for the Today button: + - Add `"calendarTodayButton": "Heute"` to the ARB file + + 4. Run `flutter gen-l10n` to regenerate localization files. + + + cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter analyze --no-fatal-infos + + CalendarDayState model exists with selectedDate/dayTasks/overdueTasks fields. selectedDateProvider and calendarDayProvider are defined. calendarDayProvider returns overdue tasks only when viewing today. New l10n string "calendarTodayButton" exists. No analysis errors. + + + + + +- `flutter test test/features/home/data/calendar_dao_test.dart` — all DAO tests pass +- `flutter analyze --no-fatal-infos` — no errors in new or modified files +- `flutter test` — full test suite still passes (existing tests not broken by database.dart changes) + + + +- CalendarDao is registered in AppDatabase and has two working query methods +- CalendarDayState model correctly separates day tasks from overdue tasks +- calendarDayProvider returns overdue only for today, not for past/future dates +- All existing tests still pass after database.dart modification +- New DAO tests cover core query behaviors + + + +After completion, create `.planning/phases/05-calendar-strip/05-01-SUMMARY.md` + diff --git a/.planning/phases/05-calendar-strip/05-02-PLAN.md b/.planning/phases/05-calendar-strip/05-02-PLAN.md new file mode 100644 index 0000000..8346bbb --- /dev/null +++ b/.planning/phases/05-calendar-strip/05-02-PLAN.md @@ -0,0 +1,316 @@ +--- +phase: 05-calendar-strip +plan: 02 +type: execute +wave: 2 +depends_on: ["05-01"] +files_modified: + - lib/features/home/presentation/home_screen.dart + - lib/features/home/presentation/calendar_strip.dart + - lib/features/home/presentation/calendar_task_row.dart + - lib/features/home/presentation/calendar_day_list.dart +autonomous: false +requirements: + - CAL-01 + - CAL-03 + - CAL-04 + - CAL-05 + +must_haves: + truths: + - "Home screen shows a horizontal scrollable strip of day cards with German abbreviation (Mo, Di, Mi...) and date number" + - "Tapping a day card updates the task list below to show that day's tasks" + - "On app launch the strip auto-scrolls so today's card is centered" + - "A subtle wider gap and month label appears at month boundaries" + - "Overdue tasks appear in a separate coral-accented section when viewing today" + - "Overdue tasks do NOT appear when viewing past or future days" + - "Completing a task via checkbox triggers slide-out animation" + - "Floating Today button appears when scrolled away from today, hidden when today is visible" + - "First-run empty state (no rooms/tasks) still shows the create-room prompt" + - "Celebration state shows when all tasks for the selected day are done" + artifacts: + - path: "lib/features/home/presentation/calendar_strip.dart" + provides: "Horizontal scrollable date strip widget" + min_lines: 100 + - path: "lib/features/home/presentation/calendar_day_list.dart" + provides: "Day task list with overdue section, empty, and celebration states" + min_lines: 80 + - path: "lib/features/home/presentation/calendar_task_row.dart" + provides: "Task row adapted for calendar (no relative date, has room tag + checkbox)" + min_lines: 30 + - path: "lib/features/home/presentation/home_screen.dart" + provides: "Rewritten HomeScreen composing strip + day list" + min_lines: 40 + key_links: + - from: "lib/features/home/presentation/home_screen.dart" + to: "lib/features/home/presentation/calendar_strip.dart" + via: "HomeScreen composes CalendarStrip widget" + pattern: "CalendarStrip" + - from: "lib/features/home/presentation/home_screen.dart" + to: "lib/features/home/presentation/calendar_day_list.dart" + via: "HomeScreen composes CalendarDayList widget" + pattern: "CalendarDayList" + - from: "lib/features/home/presentation/calendar_strip.dart" + to: "lib/features/home/presentation/calendar_providers.dart" + via: "Strip reads and writes selectedDateProvider" + pattern: "selectedDateProvider" + - from: "lib/features/home/presentation/calendar_day_list.dart" + to: "lib/features/home/presentation/calendar_providers.dart" + via: "Day list watches calendarDayProvider for reactive task data" + pattern: "calendarDayProvider" + - from: "lib/features/home/presentation/calendar_day_list.dart" + to: "lib/features/tasks/presentation/task_providers.dart" + via: "Task completion uses taskActionsProvider.completeTask()" + pattern: "taskActionsProvider" +--- + + +Build the complete calendar strip UI and replace the old HomeScreen with it. + +Purpose: This is the user-facing deliverable of Phase 5 -- the horizontal date strip with day-task list that replaces the stacked overdue/today/tomorrow daily plan. + +Output: CalendarStrip widget, CalendarDayList widget, CalendarTaskRow widget, rewritten HomeScreen that composes them. + + + +@/home/jlmak/.claude/get-shit-done/workflows/execute-plan.md +@/home/jlmak/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/05-calendar-strip/5-CONTEXT.md +@.planning/phases/05-calendar-strip/05-01-SUMMARY.md + + + + +From lib/features/home/domain/calendar_models.dart: +```dart +class CalendarDayState { + final DateTime selectedDate; + final List dayTasks; + final List overdueTasks; + const CalendarDayState({required this.selectedDate, required this.dayTasks, required this.overdueTasks}); + bool get isEmpty => dayTasks.isEmpty && overdueTasks.isEmpty; +} +``` + +From lib/features/home/presentation/calendar_providers.dart: +```dart +final selectedDateProvider = StateProvider(...); // read/write selected date +final calendarDayProvider = StreamProvider.autoDispose(...); // reactive day data +``` + +From lib/features/home/domain/daily_plan_models.dart: +```dart +class TaskWithRoom { + final Task task; + final String roomName; + final int roomId; +} +``` + +From lib/features/tasks/presentation/task_providers.dart: +```dart +// Use to complete tasks: +ref.read(taskActionsProvider.notifier).completeTask(taskId); +``` + +From lib/core/theme/app_theme.dart: +```dart +// Seed color: Color(0xFF7A9A6D) -- sage green +// The "light sage/green tint" for day cards should derive from the theme's primary/seed +``` + +Existing reusable constants: +```dart +const _overdueColor = Color(0xFFE07A5F); // warm coral for overdue +``` + +Existing l10n strings to reuse: +```dart +l10n.dailyPlanSectionOverdue // "Uberfaellig" +l10n.dailyPlanNoTasks // "Noch keine Aufgaben angelegt" +l10n.dailyPlanAllClearTitle // "Alles erledigt!" +l10n.dailyPlanAllClearMessage // "Keine Aufgaben fuer heute..." +l10n.homeEmptyMessage // "Lege zuerst einen Raum an..." +l10n.homeEmptyAction // "Raum erstellen" +l10n.calendarTodayButton // "Heute" (added in Plan 01) +``` + + + + + + + Task 1: Build CalendarStrip, CalendarTaskRow, CalendarDayList widgets + + lib/features/home/presentation/calendar_strip.dart, + lib/features/home/presentation/calendar_task_row.dart, + lib/features/home/presentation/calendar_day_list.dart + + + **CalendarStrip** (`lib/features/home/presentation/calendar_strip.dart`): + + A ConsumerStatefulWidget that renders a horizontal scrollable row of day cards. + + Scroll range: 90 days in the past and 90 days in the future (181 total items). This gives enough past for review and future for planning without performance concerns. + + Layout: + - Uses a `ScrollController` with `initialScrollOffset` calculated to center today's card on first build. + - Each day card is a fixed-width container (~56px wide, ~72px tall). Cards show: + - Top: German day abbreviation using `DateFormat('E', 'de').format(date)` which gives "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So". Import `package:intl/intl.dart`. + - Bottom: Date number (day of month) as text. + - Card styling per user decisions: + - All cards: light sage/green tint background. Use `theme.colorScheme.primaryContainer.withValues(alpha: 0.3)` or similar to get a subtle green wash. + - Selected card: stronger green (`theme.colorScheme.primaryContainer`) and border with `theme.colorScheme.primary`. The strip scrolls to center the selected card using `animateTo()`. + - Today's card (when not selected): bold text + a small accent underline bar below the date number (2px, primary color). + - Today + selected: both treatments combined. + - Spacing: cards have 4px horizontal margin by default. At month boundaries (where card N is the last day of a month and card N+1 is the first of the next month), the gap is 16px, and a small Text widget showing the new month abbreviation (e.g., "Apr") in `theme.textTheme.labelSmall` is inserted between them. + - On tap: update `ref.read(selectedDateProvider.notifier).state = tappedDate` and animate the scroll to center the tapped card. + - Auto-scroll on init: In `initState`, after the first frame (using `WidgetsBinding.instance.addPostFrameCallback`), animate to center today's card with a 200ms duration using `Curves.easeOut`. + + Controller pattern for scroll-to-today: + ```dart + class CalendarStripController { + VoidCallback? _scrollToToday; + void scrollToToday() => _scrollToToday?.call(); + } + ``` + CalendarStrip takes `CalendarStripController controller` parameter and sets `controller._scrollToToday` in initState. Parent calls `controller.scrollToToday()` from the Today button. + + Today visibility callback: Expose `onTodayVisibilityChanged(bool isVisible)`. Determine visibility by checking if today's card offset is within the viewport bounds during scroll events. + + **CalendarTaskRow** (`lib/features/home/presentation/calendar_task_row.dart`): + + Adapted from `DailyPlanTaskRow` but simplified per user decisions: + - Shows: task name, tappable room tag (navigates to room via `context.go('/rooms/$roomId')`), checkbox + - Does NOT show relative date (strip already communicates which day) + - Same room tag styling as DailyPlanTaskRow (secondaryContainer chip with borderRadius 4) + - Checkbox visible, onChanged triggers `onCompleted` callback + - Overdue variant: if `isOverdue` flag is true, task name text color uses `_overdueColor` for visual distinction + + **CalendarDayList** (`lib/features/home/presentation/calendar_day_list.dart`): + + A ConsumerStatefulWidget that shows the task list for the selected day. + + Watches `calendarDayProvider`. Manages `Set _completingTaskIds` for animation state. + + Handles these states: + + a) **Loading**: `CircularProgressIndicator` centered. + + b) **Error**: Error text centered. + + c) **First-run empty** (no rooms/tasks at all): Same pattern as current `_buildNoTasksState` -- checklist icon, "Noch keine Aufgaben angelegt" message, "Lege zuerst einen Raum an" subtitle, "Raum erstellen" FilledButton.tonal navigating to `/rooms`. Detect by checking if `state.isEmpty && state.totalTaskCount == 0` (requires adding `totalTaskCount` field to CalendarDayState and computing it in the provider -- see NOTE below). + + d) **Empty day** (tasks exist elsewhere but not this day, and not today): show centered subtle icon (Icons.event_available) + "Keine Aufgaben" text. + + e) **Celebration** (today is selected, tasks exist elsewhere, but today's tasks are all done): show celebration icon + "Alles erledigt!" title + "Keine Aufgaben fuer heute. Geniesse den Moment!" message. Compact layout (no ProgressCard). + + f) **Has tasks**: Render a ListView with: + - If overdue tasks exist (only present when viewing today): Section header "Uberfaellig" in coral color (`_overdueColor`), followed by overdue CalendarTaskRow items with `isOverdue: true` and interactive checkboxes. + - Day tasks: CalendarTaskRow items with interactive checkboxes. + - Task completion: on checkbox tap, add taskId to `_completingTaskIds`, call `ref.read(taskActionsProvider.notifier).completeTask(taskId)`. Render completing tasks with the `_CompletingTaskRow` animation (SizeTransition + SlideTransition, 300ms, Curves.easeInOut) -- recreate this private widget in calendar_day_list.dart. + + NOTE for executor: Plan 01 creates CalendarDayState with selectedDate, dayTasks, overdueTasks. This task needs a `totalTaskCount` int field on CalendarDayState to distinguish first-run from celebration. When implementing, add `final int totalTaskCount` to CalendarDayState in calendar_models.dart and compute it in the calendarDayProvider via a simple `SELECT COUNT(*) FROM tasks` query (one line in CalendarDao: `Future getTaskCount() async { final r = await (selectOnly(tasks)..addColumns([tasks.id.count()])).getSingle(); return r.read(tasks.id.count()) ?? 0; }`). + + + cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter analyze --no-fatal-infos + + CalendarStrip renders 181 day cards with German abbreviations, highlights selected/today cards, shows month boundary labels. CalendarTaskRow shows name + room tag + checkbox without relative date. CalendarDayList shows overdue section (today only), day tasks, empty states, and celebration state. All compile without analysis errors. + + + + Task 2: Replace HomeScreen with calendar composition and floating Today button + + lib/features/home/presentation/home_screen.dart + + + Rewrite `lib/features/home/presentation/home_screen.dart` entirely. The old content (DailyPlanState, overdue/today/tomorrow sections, ProgressCard) is fully replaced. + + New HomeScreen is a `ConsumerStatefulWidget`: + + State fields: + - `late final CalendarStripController _stripController = CalendarStripController();` + - `bool _showTodayButton = false;` + + Build method returns a Stack with: + 1. A Column containing: + - `CalendarStrip(controller: _stripController, onTodayVisibilityChanged: (visible) { setState(() => _showTodayButton = !visible); })` + - `Expanded(child: CalendarDayList())` + 2. Conditionally, a Positioned floating "Heute" button at bottom-center: + - `FloatingActionButton.extended` with `Icons.today` icon and `l10n.calendarTodayButton` label + - onPressed: set `selectedDateProvider` to today's date-only DateTime, call `_stripController.scrollToToday()` + + Imports needed: + - `flutter/material.dart` + - `flutter_riverpod/flutter_riverpod.dart` + - `calendar_strip.dart` + - `calendar_day_list.dart` + - `calendar_providers.dart` (for selectedDateProvider) + - `app_localizations.dart` + + Do NOT delete old files (`daily_plan_providers.dart`, `daily_plan_task_row.dart`, `progress_card.dart`, `daily_plan_dao.dart`). DailyPlanDao is still used by the notification service. Old presentation files become dead code -- safe to clean up in a future phase. + + + cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter analyze --no-fatal-infos && flutter test + + HomeScreen renders CalendarStrip at top and CalendarDayList below. Floating Today button appears when scrolled away from today. Old overdue/today/tomorrow sections are gone. Full test suite passes. No analysis errors. + + + + Task 3: Verify calendar strip home screen visually and functionally + lib/features/home/presentation/home_screen.dart + + Human verifies the complete calendar strip experience on a running device/emulator. + + Launch the app with `flutter run` (or hot-restart). Walk through all key behaviors: + 1. Strip appearance: day cards with German abbreviations and date numbers + 2. Today highlighting: centered, stronger green, bold + underline + 3. Day selection: tap a card, task list updates + 4. Month boundaries: wider gap with month label + 5. Today button: appears when scrolled away, snaps back on tap + 6. Overdue section: coral header on today only + 7. Task completion: checkbox triggers slide-out animation + 8. Empty/celebration states + + + cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter analyze --no-fatal-infos + + User has confirmed the calendar strip looks correct, day selection works, overdue behavior is right, and all states render properly. + + + + + +- `flutter analyze --no-fatal-infos` -- zero errors +- `flutter test` -- full test suite passes (existing + new DAO tests) +- Visual: calendar strip is horizontally scrollable with day cards +- Visual: selected day highlighted, today has bold + underline treatment +- Visual: month boundaries have wider gaps and month name labels +- Functional: tapping a day card updates the task list below +- Functional: overdue tasks appear only when viewing today +- Functional: floating Today button appears/disappears correctly +- Functional: task completion animation works + + + +- Home screen replaced: no more stacked overdue/today/tomorrow sections +- Horizontal date strip scrolls smoothly with 181 day range +- Day cards show German abbreviations and date numbers +- Tapping a card selects it and shows that day's tasks +- Today auto-centers on launch with smooth animation +- Month boundaries visually distinct with labels +- Overdue carry-over only on today's view with coral accent +- Floating Today button for quick navigation +- Empty and celebration states work correctly +- All existing tests pass, no regressions + + + +After completion, create `.planning/phases/05-calendar-strip/05-02-SUMMARY.md` +