docs: document widget API fix and add architectural patterns to CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -63,6 +63,12 @@ assets/
|
|||||||
|
|
||||||
API base URL: `http://localhost:8090/api/v1/`
|
API base URL: `http://localhost:8090/api/v1/`
|
||||||
|
|
||||||
|
## Widget API Patterns
|
||||||
|
- **Dual-param widgets**: `shared/widgets/` accept both entity param (e.g. `task: TaskEntity?`) AND individual raw params — private getters resolve which to use. Keep backward compat when extending.
|
||||||
|
- **`PetType` canonical location**: `domain/entities/pet_type.dart` — never redeclare locally.
|
||||||
|
- **`todayTasksProvider`** is a top-level alias for `tasksProvider` (no date filter in MVP).
|
||||||
|
- **Pet identity vs. pet state**: `petType`/`petName` belong to `userProvider`; `petStateProvider` tracks energy/streak/rewards only.
|
||||||
|
|
||||||
## Naming Conventions
|
## Naming Conventions
|
||||||
- **Files**: `snake_case.dart`
|
- **Files**: `snake_case.dart`
|
||||||
- **Classes**: `PascalCase`
|
- **Classes**: `PascalCase`
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
# Widget API Mismatches — Fix
|
||||||
|
|
||||||
|
**Branch:** `NDM-App-221-fix-widget-api-mismatches-build-errors-after-merge`
|
||||||
|
**Commits:** `371e826`, `adc2f72`
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
After multiple feature branches were merged independently, the shared widgets and domain entities had diverged APIs causing 8 compilation errors. This fix aligns widget constructors with how `TasksScreen` and `ZenScreen` use them, adds missing entity properties, and resolves provider reference errors.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problems Fixed
|
||||||
|
|
||||||
|
| # | Error | Location |
|
||||||
|
|---|-------|----------|
|
||||||
|
| 1 | `EnergyBar` has no param `energyLevel` | `TasksScreen:65` |
|
||||||
|
| 2 | `PetBubble` missing required param `petName` | `TasksScreen:69` |
|
||||||
|
| 3 | `StreakDots` has no param `streakDays` | `TasksScreen:77` |
|
||||||
|
| 4 | `TaskCard` has no param `task` | `TasksScreen:118,132` |
|
||||||
|
| 5 | `todayTasksProvider` not defined | `TasksScreen:24` |
|
||||||
|
| 6 | `PetStateEntity` missing `petType` getter | `TasksScreen:35` |
|
||||||
|
| 7 | `EnergyBadge` has no param `energyLevel` | `ZenScreen:132` |
|
||||||
|
| 8 | `PetStateEntity` constructor missing `updatedAt` | `pet_providers.dart:43` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files Changed
|
||||||
|
|
||||||
|
### `lib/shared/widgets/energy_bar.dart`
|
||||||
|
Added optional `energyLevel: int?` parameter alongside the existing `fraction: double?`.
|
||||||
|
Both are now nullable; an `assert` ensures exactly one is provided.
|
||||||
|
Private getter `_effectiveFraction` converts `energyLevel` → fraction via `(level / 3.0).clamp(0.0, 1.0)`.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
EnergyBar(energyLevel: petState.energyToday) // new usage
|
||||||
|
EnergyBar(fraction: 0.66) // existing usage still works
|
||||||
|
```
|
||||||
|
|
||||||
|
### `lib/shared/widgets/energy_badge.dart`
|
||||||
|
Added optional `energyLevel: int?` parameter alongside the existing `level: EnergyLevel?`.
|
||||||
|
Private getter `_effectiveLevel` falls back to `EnergyLevel.fromInt(energyLevel ?? 1)`.
|
||||||
|
Also added `EnergyLevel.fromInt()` static factory (maps 1→low, 2→medium, 3→high).
|
||||||
|
|
||||||
|
```dart
|
||||||
|
EnergyBadge(energyLevel: task.energyLevel) // new usage
|
||||||
|
EnergyBadge(level: EnergyLevel.medium) // existing usage still works
|
||||||
|
EnergyBadge.fromInt(2) // factory convenience
|
||||||
|
```
|
||||||
|
|
||||||
|
### `lib/shared/widgets/streak_dots.dart`
|
||||||
|
Added optional `streakDays: int?` parameter.
|
||||||
|
`_generateDays(int streak)` computes a `List<DayStatus>` from today's weekday index and streak count.
|
||||||
|
Both `days` and `streakCount` are now optional (default to empty/0 when `streakDays` is provided).
|
||||||
|
|
||||||
|
```dart
|
||||||
|
StreakDots(streakDays: petState.streakDays) // new
|
||||||
|
StreakDots(days: myList, streakCount: 3) // existing
|
||||||
|
```
|
||||||
|
|
||||||
|
### `lib/shared/widgets/task_card.dart`
|
||||||
|
Added optional `task: TaskEntity?` and `onComplete: VoidCallback?` parameters.
|
||||||
|
Private getters (`_title`, `_energyLevel`, `_isDone`, `_isSelfCare`, `_isOverdue`, `_toggleCallback`) delegate to `task` fields when set, falling back to individual params.
|
||||||
|
`_isOverdue` computes from `task.deadline` when a task is provided.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
TaskCard(task: entity, onComplete: () => ref.read(...).completeTask(id)) // new
|
||||||
|
TaskCard(title: 'Buy milk', energyLevel: 1, isDone: false) // existing
|
||||||
|
```
|
||||||
|
|
||||||
|
### `lib/shared/widgets/pet_bubble.dart`
|
||||||
|
Removed local `PetType` enum (was duplicated here and in `domain/entities/pet_type.dart`).
|
||||||
|
Now imports `PetType` from the domain layer — single source of truth.
|
||||||
|
|
||||||
|
### `lib/domain/entities/task_entity.dart`
|
||||||
|
Added computed getter:
|
||||||
|
```dart
|
||||||
|
bool get isCompleted => status == TaskStatus.done;
|
||||||
|
```
|
||||||
|
Widgets and screens use this instead of manually comparing `status == TaskStatus.done`.
|
||||||
|
|
||||||
|
### `lib/features/tasks/providers/task_providers.dart`
|
||||||
|
Added `uncompleteTask(int id)` method to `TasksNotifier` — sets status back to `pending`.
|
||||||
|
Added top-level alias:
|
||||||
|
```dart
|
||||||
|
final todayTasksProvider = tasksProvider;
|
||||||
|
```
|
||||||
|
MVP does not filter by date; screens watch `todayTasksProvider` and split pending/completed themselves.
|
||||||
|
|
||||||
|
### `lib/features/tasks/providers/pet_providers.dart`
|
||||||
|
Fixed `PetStateEntity` constructor: `id`/`userId` are `String` (`'1'`), `updatedAt` is required.
|
||||||
|
Added `onTaskCompleted()` method as a public alias for `incrementTasksDone()`.
|
||||||
|
|
||||||
|
### `lib/features/tasks/screens/tasks_screen.dart`
|
||||||
|
- Watches `userProvider` (for `petType`, `petName`) and `petMoodProvider` (for mood string).
|
||||||
|
- `PetBubble` now receives `petName` from `userState` and `mood` from `petMoodProvider`.
|
||||||
|
- `_EmptyState` now accepts `PetType` (enum) instead of `String`, uses `petType.emoji`.
|
||||||
|
- Pet type resolved from `userState.petType`, not `petState.petType` (pet state doesn't own identity).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
|
||||||
|
**Dual-param widget pattern**: Widgets accept both an entity param (`task: TaskEntity?`) and individual params (`title`, `energyLevel`, etc.). Private getters resolve which to use. This keeps backward compatibility for any callers passing raw values while enabling entity-driven usage from screens.
|
||||||
|
|
||||||
|
**`PetType` canonical location**: `domain/entities/pet_type.dart` is the single source. `PetBubble` used to redeclare it locally — that local copy is removed.
|
||||||
|
|
||||||
|
**`todayTasksProvider` is an alias**: Not a filtered provider. In MVP all tasks are "today" tasks. Screens handle the pending/completed split via `.where()`. If date-filtering is needed later, only this alias needs to change.
|
||||||
|
|
||||||
|
**Pet identity vs. pet state**: `petType` and `petName` belong to the `User` entity (`userProvider`), not `PetStateEntity`. `PetStateEntity` tracks energy/streak/rewards only.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tests Added
|
||||||
|
|
||||||
|
83 new tests across 6 files:
|
||||||
|
|
||||||
|
| File | Tests |
|
||||||
|
|------|-------|
|
||||||
|
| `test/domain/entities/task_entity_test.dart` | 12 |
|
||||||
|
| `test/domain/entities/pet_type_test.dart` | 12 |
|
||||||
|
| `test/domain/entities/pet_state_entity_test.dart` | 8 |
|
||||||
|
| `test/features/tasks/providers/task_providers_test.dart` | 16 |
|
||||||
|
| `test/features/tasks/providers/pet_providers_test.dart` | 24 |
|
||||||
|
| `test/shared/widgets/energy_badge_test.dart` | 13 |
|
||||||
|
|
||||||
|
All 83 new tests pass. 2 pre-existing failures in `test/data/repositories/` require `build_runner` regeneration and are unrelated to this fix.
|
||||||
Reference in New Issue
Block a user