14 KiB
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 |
|
|
true |
|
|
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.mdFrom 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"
}
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>