Files
2026-03-16 20:12:01 +01:00

14 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
02-rooms-and-tasks 02 execute 2
02-01
lib/features/rooms/presentation/rooms_screen.dart
lib/features/rooms/presentation/room_card.dart
lib/features/rooms/presentation/room_form_screen.dart
lib/features/rooms/presentation/icon_picker_sheet.dart
lib/features/rooms/presentation/room_providers.dart
lib/core/router/router.dart
lib/l10n/app_de.arb
pubspec.yaml
true
ROOM-01
ROOM-02
ROOM-03
ROOM-04
ROOM-05
truths artifacts key_links
User can create a room by entering a name and selecting an icon from a curated bottom sheet picker
User can edit a room's name and icon from the room detail screen
User can delete a room with a confirmation dialog warning about cascade deletion
User can reorder rooms via drag-and-drop on the 2-column grid
Rooms screen shows a 2-column card grid with room icon, name, due task count, and thin cleanliness progress bar
Rooms screen shows empty state when no rooms exist, with a create button
path provides min_lines
lib/features/rooms/presentation/rooms_screen.dart 2-column reorderable room card grid with FAB for room creation 50
path provides min_lines
lib/features/rooms/presentation/room_card.dart Room card widget with icon, name, due count, cleanliness bar 40
path provides min_lines
lib/features/rooms/presentation/room_form_screen.dart Full-screen form for room creation and editing 50
path provides min_lines
lib/features/rooms/presentation/icon_picker_sheet.dart Bottom sheet with curated Material Icons grid 30
path provides exports
lib/features/rooms/presentation/room_providers.dart Riverpod providers wrapping RoomsDao stream queries and mutations
roomListProvider
roomWithStatsProvider
roomActionsProvider
path provides contains
lib/core/router/router.dart Nested routes under /rooms for room detail and forms rooms/new
from to via pattern
lib/features/rooms/presentation/room_providers.dart lib/features/rooms/data/rooms_dao.dart providers watch appDatabaseProvider then access roomsDao ref.watch(appDatabaseProvider)
from to via pattern
lib/features/rooms/presentation/rooms_screen.dart lib/features/rooms/presentation/room_providers.dart ConsumerWidget watches roomWithStatsProvider ref.watch(roomWithStats
from to via pattern
lib/features/rooms/presentation/room_card.dart lib/core/router/router.dart InkWell onTap navigates to /rooms/:roomId context.go.*rooms/
Build the complete room management UI: 2-column reorderable card grid, room creation/edit form with icon picker, delete with confirmation, and Riverpod providers connecting to the data layer.

Purpose: Delivers ROOM-01 through ROOM-05 as a working user-facing feature. After this plan, users can create, view, edit, reorder, and delete rooms. Output: Rooms screen with card grid, room form, icon picker, providers, and router updates.

<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/02-rooms-and-tasks/2-CONTEXT.md @.planning/phases/02-rooms-and-tasks/02-RESEARCH.md @.planning/phases/02-rooms-and-tasks/02-01-SUMMARY.md

From lib/features/rooms/data/rooms_dao.dart (created in Plan 01):

class RoomWithStats {
  final Room room;
  final int totalTasks;
  final int dueTasks;
  final int overdueCount;
  final double cleanlinessRatio; // 0.0 to 1.0
}

@DriftAccessor(tables: [Rooms, Tasks, TaskCompletions])
class RoomsDao extends DatabaseAccessor<AppDatabase> with _$RoomsDaoMixin {
  Stream<List<Room>> watchAllRooms();
  Stream<List<RoomWithStats>> watchRoomWithStats();
  Future<int> insertRoom(RoomsCompanion room);
  Future<bool> updateRoom(Room room);
  Future<void> deleteRoom(int roomId);
  Future<void> reorderRooms(List<int> roomIds);
  Future<Room> getRoomById(int id);
}

From lib/features/rooms/domain/room_icons.dart (created in Plan 01):

const List<({String name, IconData icon})> curatedRoomIcons = [...];
IconData mapIconName(String name);

From lib/core/database/database.dart (updated in Plan 01):

@DriftDatabase(tables: [Rooms, Tasks, TaskCompletions], daos: [RoomsDao, TasksDao])
class AppDatabase extends _$AppDatabase {
  RoomsDao get roomsDao => ...; // auto-generated
  TasksDao get tasksDao => ...; // auto-generated
}

From lib/core/providers/database_provider.dart (existing):

@Riverpod(keepAlive: true)
AppDatabase appDatabase(Ref ref) { ... }

From lib/l10n/app_de.arb (existing — 18 keys, needs expansion):

{
  "roomsEmptyTitle": "Hier ist noch alles leer!",
  "roomsEmptyMessage": "Erstelle deinen ersten Raum, um loszulegen.",
  "roomsEmptyAction": "Raum erstellen"
}
Task 1: Create Riverpod providers, room form screen, and icon picker lib/features/rooms/presentation/room_providers.dart, lib/features/rooms/presentation/room_form_screen.dart, lib/features/rooms/presentation/icon_picker_sheet.dart, lib/core/router/router.dart, lib/l10n/app_de.arb, pubspec.yaml 1. **Add flutter_reorderable_grid_view dependency**: Run `flutter pub add flutter_reorderable_grid_view` to add it to pubspec.yaml.
2. **lib/features/rooms/presentation/room_providers.dart**: Create Riverpod providers using @riverpod code generation:

```dart
@riverpod
Stream<List<RoomWithStats>> roomWithStatsList(Ref ref) {
  final db = ref.watch(appDatabaseProvider);
  return db.roomsDao.watchRoomWithStats();
}

@riverpod
class RoomActions extends _$RoomActions {
  @override
  FutureOr<void> build() {}

  Future<int> createRoom(String name, String iconName) async { ... }
  Future<void> updateRoom(Room room) async { ... }
  Future<void> deleteRoom(int roomId) async { ... }
  Future<void> reorderRooms(List<int> roomIds) async { ... }
}
```

3. **lib/features/rooms/presentation/icon_picker_sheet.dart**: Create a bottom sheet widget showing a grid of curated Material Icons from `curatedRoomIcons`. Use a `GridView.count` with crossAxisCount 5. Each icon is an `InkWell` wrapping an `Icon` widget. Selected icon gets a colored circle background using `colorScheme.primaryContainer`. Takes `selectedIconName` and `onIconSelected` callback. Show as modal bottom sheet with `showModalBottomSheet`.

4. **lib/features/rooms/presentation/room_form_screen.dart**: Full-screen Scaffold form for creating and editing rooms. Constructor takes optional `roomId` (null for create, non-null for edit). Uses `ConsumerStatefulWidget`.

Form fields:
- Name: `TextFormField` with autofocus, validator (non-empty, max 100 chars), German label "Raumname"
- Icon: tappable preview showing current selected icon + "Symbol waehlen" label. Tapping opens `IconPickerSheet`. Default to first icon in curated list for new rooms.
- For edit mode: load existing room data via `ref.read(appDatabaseProvider).roomsDao.getRoomById(roomId)` in `initState`.
- Save button in AppBar (check icon). On save: validate form, call `roomActions.createRoom()` or `roomActions.updateRoom()`, then `context.pop()`.
- AppBar title: "Raum erstellen" for new, "Raum bearbeiten" for edit.

5. **lib/core/router/router.dart**: Add nested routes under the `/rooms` branch:
- `/rooms/new` -> `RoomFormScreen()` (create)
- `/rooms/:roomId` -> `TaskListScreen(roomId: roomId)` (will be created in Plan 03, use placeholder for now if needed)
- `/rooms/:roomId/edit` -> `RoomFormScreen(roomId: roomId)` (edit)
- `/rooms/:roomId/tasks/new` -> placeholder (Plan 03)
- `/rooms/:roomId/tasks/:taskId` -> placeholder (Plan 03)

For routes that reference screens from Plan 03 (TaskListScreen, TaskFormScreen), import them. If they don't exist yet, create minimal placeholder files `lib/features/tasks/presentation/task_list_screen.dart` and `lib/features/tasks/presentation/task_form_screen.dart` with a simple `Scaffold(body: Center(child: Text('Coming soon')))` and a `roomId`/`taskId` constructor parameter.

6. **lib/l10n/app_de.arb**: Add new localization keys for room management:
- "roomFormCreateTitle": "Raum erstellen"
- "roomFormEditTitle": "Raum bearbeiten"
- "roomFormNameLabel": "Raumname"
- "roomFormNameHint": "z.B. Kueche, Badezimmer..."
- "roomFormNameRequired": "Bitte einen Namen eingeben"
- "roomFormIconLabel": "Symbol waehlen"
- "roomDeleteConfirmTitle": "Raum loeschen?"
- "roomDeleteConfirmMessage": "Der Raum und alle zugehoerigen Aufgaben werden unwiderruflich geloescht."
- "roomDeleteConfirmAction": "Loeschen"
- "roomCardDueCount": "{count} faellig"
- "cancel": "Abbrechen"

Use proper German umlauts (Unicode escapes in ARB: \u00fc for ue, \u00f6 for oe, \u00e4 for ae, \u00dc for Ue, etc.).

7. Run `dart run build_runner build --delete-conflicting-outputs` to generate provider .g.dart files.
cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze lib/features/rooms/presentation/ lib/core/router/router.dart && flutter test Room providers connect to DAO layer. Room form screen handles create and edit with validation. Icon picker shows curated grid in bottom sheet. Router has nested room routes. New ARB keys added. All code analyzes clean. Task 2: Build rooms screen with reorderable card grid and room card component lib/features/rooms/presentation/rooms_screen.dart, lib/features/rooms/presentation/room_card.dart 1. **lib/features/rooms/presentation/room_card.dart**: Create `RoomCard` StatelessWidget accepting `RoomWithStats` data. Per user decision (2-CONTEXT.md): - Card with `InkWell` wrapping, `onTap` navigates to `/rooms/${room.id}` via `context.go()` - Column layout: Icon (36px, using `mapIconName(room.iconName)`), room name (titleSmall), due task count badge if > 0 (bodySmall, using `colorScheme.error` color, text from `roomCardDueCount` ARB key) - Thin cleanliness progress bar at BOTTOM of card: `LinearProgressIndicator` with `minHeight: 3`, value = `cleanlinessRatio`, color interpolated green->yellow->red using `Color.lerp` with coral `Color(0xFFE07A5F)` (overdue) and sage `Color(0xFF7A9A6D)` (clean), backgroundColor = `surfaceContainerHighest` - Use `ValueKey(room.id)` for drag-and-drop compatibility - Card styling: `surfaceContainerLow` background, rounded corners, subtle elevation
2. **lib/features/rooms/presentation/rooms_screen.dart**: Replace the existing placeholder with a `ConsumerWidget` that:
- Watches `roomWithStatsListProvider` for reactive room data
- Shows the Phase 1 empty state (icon + text + "Raum erstellen" button) when list is empty. The button navigates to `/rooms/new`
- When rooms exist, shows a `ReorderableBuilder` from `flutter_reorderable_grid_view` wrapping a `GridView.count(crossAxisCount: 2)` of `RoomCard` widgets
- Each card has `ValueKey(roomWithStats.room.id)`
- On reorder complete, calls `roomActions.reorderRooms()` with the new ID order
- FAB (FloatingActionButton) at bottom-right with `Icons.add` to navigate to `/rooms/new`
- Uses `AsyncValue.when(data: ..., loading: ..., error: ...)` pattern for the stream provider
- Loading state: `CircularProgressIndicator` centered
- Error state: error message with retry option

Add a `PopupMenuButton` or long-press menu on each card for edit and delete actions:
- Edit: navigates to `/rooms/${room.id}/edit`
- Delete: shows confirmation dialog per user decision. Dialog title from `roomDeleteConfirmTitle`, message from `roomDeleteConfirmMessage` (warns about cascade), cancel and delete buttons. On confirm, calls `roomActions.deleteRoom(roomId)`.
cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze lib/features/rooms/presentation/ && flutter test Rooms screen displays 2-column reorderable card grid with room icon, name, due task count, and cleanliness bar. Empty state shows when no rooms. FAB creates new room. Cards navigate to room detail. Long-press/popup menu offers edit and delete with confirmation dialog. Drag-and-drop reorder persists via DAO. All existing tests still pass. ```bash cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze && flutter test ``` All code analyzes clean. All tests pass. Room creation, editing, deletion, and reorder are functional at the UI level.

<success_criteria>

  • Rooms screen shows 2-column card grid (or empty state)
  • Room cards display: icon, name, due task count, thin cleanliness bar (green->yellow->red)
  • Room form: create and edit with name field + icon picker bottom sheet
  • Icon picker: curated grid of ~25 household Material Icons in bottom sheet
  • Delete: confirmation dialog with cascade warning
  • Drag-and-drop: reorder persists to database
  • FAB for creating new rooms
  • Router: nested routes /rooms/new, /rooms/:roomId, /rooms/:roomId/edit
  • Localization: all room UI strings from ARB </success_criteria>
After completion, create `.planning/phases/02-rooms-and-tasks/02-02-SUMMARY.md`