coregen-cli 3.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coregen.py +1585 -0
- coregen_cli-3.1.6.dist-info/METADATA +1211 -0
- coregen_cli-3.1.6.dist-info/RECORD +172 -0
- coregen_cli-3.1.6.dist-info/WHEEL +5 -0
- coregen_cli-3.1.6.dist-info/entry_points.txt +2 -0
- coregen_cli-3.1.6.dist-info/top_level.txt +2 -0
- generators/__init__.py +1 -0
- generators/assets/__init__.py +1 -0
- generators/assets/assets.py +30 -0
- generators/assets/main.py +4 -0
- generators/config/__init__.py +1 -0
- generators/config/analisy_options.py +42 -0
- generators/config/main.py +11 -0
- generators/config/pubspec.py +139 -0
- generators/cursor/__init__.py +3 -0
- generators/cursor/setup.py +87 -0
- generators/helpers/__init__.py +56 -0
- generators/helpers/component.py +1030 -0
- generators/helpers/config.py +255 -0
- generators/helpers/data_source.py +180 -0
- generators/helpers/domain.py +469 -0
- generators/helpers/feature.py +654 -0
- generators/helpers/navigation.py +274 -0
- generators/helpers/page.py +63 -0
- generators/helpers/project.py +33 -0
- generators/helpers/utils.py +338 -0
- generators/helpers/validation.py +364 -0
- generators/initializator.py +68 -0
- generators/main.py +81 -0
- generators/static/assets/logo.png +0 -0
- generators/static/assets/mock/auth_user.json +5 -0
- generators/static/assets/svgs/apple.svg +4 -0
- generators/static/assets/svgs/google.svg +2 -0
- generators/static/cursor/AGENTS.md.jinja +37 -0
- generators/static/cursor/agents/doc-writer.md +20 -0
- generators/static/cursor/agents/epic-orchestrator.md +28 -0
- generators/static/cursor/agents/feature-implementer.md +29 -0
- generators/static/cursor/agents/integration-wiring.md +30 -0
- generators/static/cursor/agents/layer-application.md +21 -0
- generators/static/cursor/agents/layer-guardian.md +21 -0
- generators/static/cursor/agents/layer-infrastructure.md +31 -0
- generators/static/cursor/agents/layer-model.md +24 -0
- generators/static/cursor/agents/layer-presentation.md +33 -0
- generators/static/cursor/docs/architecture/APIS_AND_INTEGRATION.md.jinja +42 -0
- generators/static/cursor/docs/architecture/CARAVAGGIO_COMPONENTS.md.jinja +317 -0
- generators/static/cursor/docs/architecture/DDD_LAYERS.md.jinja +32 -0
- generators/static/cursor/docs/architecture/FILE_TEMPLATES.md.jinja +76 -0
- generators/static/cursor/docs/architecture/MOCK_AND_REMOTE_DATA.md.jinja +87 -0
- generators/static/cursor/docs/architecture/REFERENCE_IMPLEMENTATIONS.md.jinja +48 -0
- generators/static/cursor/docs/architecture/WIDGETS_AND_CARAVAGGIO.md.jinja +76 -0
- generators/static/cursor/docs/epics/README.md +17 -0
- generators/static/cursor/lib/domain/AGENTS.md +23 -0
- generators/static/cursor/lib/features/AGENTS.md +23 -0
- generators/static/cursor/lib/widgets/AGENTS.md +21 -0
- generators/static/cursor/rules/apis-layer.mdc.jinja +21 -0
- generators/static/cursor/rules/application-layer.mdc.jinja +12 -0
- generators/static/cursor/rules/architecture-core.mdc.jinja +43 -0
- generators/static/cursor/rules/dart-conventions.mdc.jinja +14 -0
- generators/static/cursor/rules/domain-layer.mdc.jinja +24 -0
- generators/static/cursor/rules/login-context.mdc.jinja +16 -0
- generators/static/cursor/rules/presentation-layer.mdc.jinja +15 -0
- generators/static/cursor/rules/quality-gate.mdc.jinja +14 -0
- generators/static/cursor/rules/ui-caravaggio.mdc.jinja +22 -0
- generators/static/cursor/skills/caravaggio-ui/SKILL.md +138 -0
- generators/static/cursor/skills/epic-delivery/SKILL.md +74 -0
- generators/static/cursor/skills/epic-delivery/templates/epic-status.md +14 -0
- generators/static/cursor/skills/epic-delivery/templates/epic.md +36 -0
- generators/static/templates/apis/common/constants_template.jinja +48 -0
- generators/static/templates/apis/common/data_source_config_template.jinja +47 -0
- generators/static/templates/apis/core/api_injectable_module_template.jinja +14 -0
- generators/static/templates/apis/interceptors/api_logger_template.jinja +135 -0
- generators/static/templates/apis/interceptors/auth_interceptor_template.jinja +207 -0
- generators/static/templates/auth/application/auth_bloc_template.jinja +36 -0
- generators/static/templates/auth/application/auth_event_template.jinja +7 -0
- generators/static/templates/auth/application/auth_state_template.jinja +8 -0
- generators/static/templates/auth/infrastructure/auth_facade_module_template.jinja +16 -0
- generators/static/templates/auth/infrastructure/auth_facade_template.jinja +288 -0
- generators/static/templates/auth/infrastructure/mock_auth_facade_template.jinja +106 -0
- generators/static/templates/auth/model/auth_failure_template.jinja +11 -0
- generators/static/templates/auth/model/i_auth_facade_template.jinja +24 -0
- generators/static/templates/auth/model/user_template.jinja +34 -0
- generators/static/templates/auth/model/value_objects_template.jinja +54 -0
- generators/static/templates/auth/presentation/login_screen_template.jinja +24 -0
- generators/static/templates/auth/sign_in_form/application/sign_in_form_bloc_template.jinja +139 -0
- generators/static/templates/auth/sign_in_form/application/sign_in_form_event_template.jinja +15 -0
- generators/static/templates/auth/sign_in_form/application/sign_in_form_state_template.jinja +26 -0
- generators/static/templates/auth/sign_in_form/presentation/apple_form_template.jinja +16 -0
- generators/static/templates/auth/sign_in_form/presentation/email_password_form_template_INACTIVE.jinja +94 -0
- generators/static/templates/auth/sign_in_form/presentation/google_form_template.jinja +15 -0
- generators/static/templates/auth/sign_in_form/presentation/sign_in_form_template.jinja +381 -0
- generators/static/templates/component/component_bloc_template.jinja +49 -0
- generators/static/templates/component/component_event_template.jinja +7 -0
- generators/static/templates/component/component_form_bloc_template.jinja +56 -0
- generators/static/templates/component/component_form_event_template.jinja +7 -0
- generators/static/templates/component/component_form_state_template.jinja +18 -0
- generators/static/templates/component/component_form_widget_template.jinja +130 -0
- generators/static/templates/component/component_list_widget_template.jinja +95 -0
- generators/static/templates/component/component_state_template.jinja +9 -0
- generators/static/templates/component/component_widget_template.jinja +113 -0
- generators/static/templates/core/bloc/base_form_bloc_template.jinja +32 -0
- generators/static/templates/core/errors/error_localizer_template.jinja +61 -0
- generators/static/templates/core/infrastructure/base_mapper_template.jinja +21 -0
- generators/static/templates/core/infrastructure/base_repository_mixin_template.jinja +78 -0
- generators/static/templates/core/infrastructure/firebase_injectable_module_template.jinja +11 -0
- generators/static/templates/core/infrastructure/firestore_helpers_template.jinja +22 -0
- generators/static/templates/core/infrastructure/repository_error_handler_template.jinja +44 -0
- generators/static/templates/core/model/common_interfaces_template.jinja +3 -0
- generators/static/templates/core/model/entity_template.jinja +5 -0
- generators/static/templates/core/model/errors_template.jinja +15 -0
- generators/static/templates/core/model/failures_template.jinja +97 -0
- generators/static/templates/core/model/value_objects_template.jinja +135 -0
- generators/static/templates/core/model/value_validators_template.jinja +105 -0
- generators/static/templates/core/presentation/app_drawer_template.jinja +52 -0
- generators/static/templates/core/presentation/app_widget_template.jinja +41 -0
- generators/static/templates/core/presentation/bottom_nav_bar_template.jinja +32 -0
- generators/static/templates/domain/domain_mapper_template.jinja +39 -0
- generators/static/templates/domain/domain_remote_service_template.jinja +46 -0
- generators/static/templates/domain/domain_repository_template.jinja +90 -0
- generators/static/templates/domain/domain_service_module_template.jinja +23 -0
- generators/static/templates/domain/enum_template.jinja +3 -0
- generators/static/templates/domain/i_domain_service_template.jinja +18 -0
- generators/static/templates/domain/mock_domain_service_template.jinja +73 -0
- generators/static/templates/feature/feature_bloc_template.jinja +104 -0
- generators/static/templates/feature/feature_dto_template.jinja +26 -0
- generators/static/templates/feature/feature_entity_template.jinja +23 -0
- generators/static/templates/feature/feature_event_template.jinja +20 -0
- generators/static/templates/feature/feature_extensions_template.jinja +25 -0
- generators/static/templates/feature/feature_failure_template.jinja +11 -0
- generators/static/templates/feature/feature_page_template.jinja +113 -0
- generators/static/templates/feature/feature_repository_template.jinja +112 -0
- generators/static/templates/feature/feature_state_template.jinja +20 -0
- generators/static/templates/feature/i_feature_repository_template.jinja +21 -0
- generators/static/templates/feature/value_object_field_template.jinja +0 -0
- generators/static/templates/feature/value_object_template.jinja +0 -0
- generators/static/templates/feature/value_validators_template.jinja +57 -0
- generators/static/templates/home/home_screen_template.jinja +68 -0
- generators/static/templates/home/presentation/home_screen_template.jinja +52 -0
- generators/static/templates/home/screen_template.jinja +12 -0
- generators/static/templates/injection_template.jinja +8 -0
- generators/static/templates/logging/analytics_logging_template.jinja +42 -0
- generators/static/templates/logging/console_template.jinja +50 -0
- generators/static/templates/logging/logger_injectable_module_template.jinja +24 -0
- generators/static/templates/logging/logger_template.jinja +118 -0
- generators/static/templates/main_template.jinja +43 -0
- generators/static/templates/page_template.jinja +29 -0
- generators/static/templates/router_template.jinja +26 -0
- generators/static/templates/splash/presentation/splash_screen_auth_template.jinja +97 -0
- generators/static/templates/splash/presentation/splash_screen_template.jinja +51 -0
- generators/static/templates/storage/storage_repository_template.jinja +80 -0
- generators/static/templates/user_profile/infrastructure/user_profile_dto_template.jinja +27 -0
- generators/static/templates/user_profile/infrastructure/user_profile_mapper_template.jinja +43 -0
- generators/static/templates/user_profile/infrastructure/user_profile_repository_template.jinja +82 -0
- generators/static/templates/user_profile/infrastructure/user_profile_service_template.jinja +27 -0
- generators/static/templates/user_profile/model/i_user_profile_repository_template.jinja +34 -0
- generators/static/templates/user_profile/model/user_profile_failure_template.jinja +11 -0
- generators/static/templates/user_profile/model/user_profile_template.jinja +31 -0
- generators/static/templates/widgets/common/custom_scaffold_template.jinja +52 -0
- generators/static/templates/widgets/common/error_widget_template.jinja +22 -0
- generators/static/templates/widgets/common/loading_widget_template.jinja +14 -0
- generators/static/templates/widgets/common/unknown_state_widget_template.jinja +23 -0
- generators/templates/__init__.py +1 -0
- generators/templates/_core/core_generator.py +121 -0
- generators/templates/apis/apis_generator.py +50 -0
- generators/templates/auth/auth_generator.py +40 -0
- generators/templates/auth/sign_in_form_generator.py +22 -0
- generators/templates/copier.py +51 -0
- generators/templates/home/home_generator.py +26 -0
- generators/templates/lib/lib_generator.py +40 -0
- generators/templates/logging/logging_generator.py +28 -0
- generators/templates/main.py +75 -0
- generators/templates/splash/splash_generator.py +20 -0
- generators/templates/storage/storage_generator.py +5 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Mock and remote data sources — [[project_name]]
|
|
2
|
+
|
|
3
|
+
## Why mock by default
|
|
4
|
+
|
|
5
|
+
New entities use **mock** data so the app runs immediately without `Constants.apiUrl` or a live backend. Switch individual entities to **remote** when their API is ready.
|
|
6
|
+
|
|
7
|
+
## Registry — `DataSourceConfig`
|
|
8
|
+
|
|
9
|
+
File: `lib/apis/common/data_source_config.dart`
|
|
10
|
+
|
|
11
|
+
```dart
|
|
12
|
+
static const Map<String, DataSource> entities = {
|
|
13
|
+
'auth': DataSource.mock, // when login enabled
|
|
14
|
+
'task': DataSource.mock,
|
|
15
|
+
'user': DataSource.remote, // example after API is ready
|
|
16
|
+
};
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- Keys: **snake_case** entity folder name; `'auth'` for authentication.
|
|
20
|
+
- Change one line: `DataSource.mock` → `DataSource.remote`.
|
|
21
|
+
- New entities from `add-domain` are added as `mock` automatically (existing `remote` entries are preserved).
|
|
22
|
+
|
|
23
|
+
Startup calls `DataSourceConfig.validateRemoteRequiresApiUrl()` in `main.dart`. Any **non-auth** entity set to `remote` without a configured `Constants.apiUrl` throws a clear `StateError`. Placeholder strings like `INSERT YOUR LOCAL URL HERE` do **not** count as configured.
|
|
24
|
+
|
|
25
|
+
`Constants.apiUrl` defaults to **empty** in `main.dart` for mock-only development. Dio uses `Constants.dioBaseUrl` (`http://127.0.0.1` when unset) so DI starts without network calls.
|
|
26
|
+
|
|
27
|
+
## Infrastructure layout (per domain entity)
|
|
28
|
+
|
|
29
|
+
| File | Role |
|
|
30
|
+
|------|------|
|
|
31
|
+
| `i_<entity>_service.dart` | Service interface |
|
|
32
|
+
| `<entity>_remote_service.dart` | Retrofit REST client |
|
|
33
|
+
| `mock_<entity>_service.dart` | Loads `assets/mock/<entity>.json`, in-memory CRUD |
|
|
34
|
+
| `<entity>_service_module.dart` | DI: picks mock or remote via `DataSourceConfig` |
|
|
35
|
+
| `<entity>_repository.dart` | Single repository; injects `I<Entity>Service` |
|
|
36
|
+
|
|
37
|
+
Auth (`--login`):
|
|
38
|
+
|
|
39
|
+
| File | Role |
|
|
40
|
+
|------|------|
|
|
41
|
+
| `auth_facade.dart` | Remote skeleton (Firebase/API — developer implements) |
|
|
42
|
+
| `mock_auth_facade.dart` | Mock sign-in from `assets/mock/auth_user.json` |
|
|
43
|
+
| `auth_facade_module.dart` | DI for `IAuthFacade` |
|
|
44
|
+
|
|
45
|
+
## Mock JSON format
|
|
46
|
+
|
|
47
|
+
Path: `assets/mock/<entity_snake_case>.json`
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"items": [
|
|
52
|
+
{ "id": "1", "title": "Sample task", "done": false }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Field names and types must match `<entity>_dto.dart` JSON serialization.
|
|
58
|
+
- Include **at least 2–3 realistic records**.
|
|
59
|
+
- `coregen add-domain` generates a starter file; **agents must update it** when adding entities manually or extending fields.
|
|
60
|
+
|
|
61
|
+
Auth seed: `assets/mock/auth_user.json`
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"id": "mock-user-1",
|
|
66
|
+
"name": "Demo User",
|
|
67
|
+
"emailAddress": "demo@example.com"
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Developer checklist — API ready
|
|
72
|
+
|
|
73
|
+
1. Implement / verify `<entity>_remote_service.dart` endpoints.
|
|
74
|
+
2. Set `'entity_key': DataSource.remote` in `DataSourceConfig.entities`.
|
|
75
|
+
3. Set `Constants.apiUrl` in `initEnvironment()` in `main.dart`.
|
|
76
|
+
4. Run `dart run build_runner build --delete-conflicting-outputs`.
|
|
77
|
+
|
|
78
|
+
## AI obligation
|
|
79
|
+
|
|
80
|
+
When implementing a **new domain entity** (epic or manual):
|
|
81
|
+
|
|
82
|
+
1. Create `i_<entity>_service.dart`, `mock_<entity>_service.dart`, `<entity>_remote_service.dart`, `<entity>_service_module.dart`.
|
|
83
|
+
2. **Create or update** `assets/mock/<entity>.json` with 2–3 coherent sample rows.
|
|
84
|
+
3. Register the entity in `DataSourceConfig.entities` as `DataSource.mock` unless remote is explicitly required.
|
|
85
|
+
4. Repository injects `I<Entity>Service` only — never Retrofit directly.
|
|
86
|
+
|
|
87
|
+
See also: `docs/architecture/APIS_AND_INTEGRATION.md`.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Reference implementations — [[project_name]]
|
|
2
|
+
|
|
3
|
+
Use these generated files as canonical examples when implementing new code.
|
|
4
|
+
|
|
5
|
+
## Shell
|
|
6
|
+
|
|
7
|
+
| Area | Path |
|
|
8
|
+
|------|------|
|
|
9
|
+
| Entry | `lib/main.dart` |
|
|
10
|
+
| DI | `lib/injection.dart` |
|
|
11
|
+
| Routing | `lib/router.dart` |
|
|
12
|
+
| App widget | `lib/core/presentation/app_widget.dart` |
|
|
13
|
+
| Error messages | `lib/core/errors/error_localizer.dart` |
|
|
14
|
+
|
|
15
|
+
## Features (generated at create)
|
|
16
|
+
|
|
17
|
+
| Feature | Application | Presentation |
|
|
18
|
+
|---------|-------------|--------------|
|
|
19
|
+
| Splash | — | `lib/features/splash/splash_page.dart` — `CustomScaffold`, `showBackButton: false` |
|
|
20
|
+
| Home | — | `lib/features/home/home_page.dart` — `CustomScaffold`, `showBackButton: false` |
|
|
21
|
+
|
|
22
|
+
{% if login %}
|
|
23
|
+
## Auth (login enabled)
|
|
24
|
+
|
|
25
|
+
| Layer | Path |
|
|
26
|
+
|-------|------|
|
|
27
|
+
| Domain | `lib/domain/auth/model/`, `lib/domain/auth/infrastructure/` |
|
|
28
|
+
| Feature | `lib/features/auth/application/`, `lib/features/auth/presentation/` |
|
|
29
|
+
| Sign-in form | `lib/features/auth/sign_in_form/application/`, `.../presentation/` |
|
|
30
|
+
| Login page | `lib/features/auth/presentation/login_page.dart` — `CustomScaffold`, `showBackButton: false` |
|
|
31
|
+
{% endif %}
|
|
32
|
+
|
|
33
|
+
## Shared widgets
|
|
34
|
+
|
|
35
|
+
- `lib/widgets/common/custom_scaffold.dart` — page shell (wraps `CScaffold`)
|
|
36
|
+
- `lib/widgets/common/loading_widget.dart` — `CLoader.bouncing()`
|
|
37
|
+
- `lib/widgets/common/error_widget.dart` — `CText.body`
|
|
38
|
+
- `lib/widgets/common/unknown_state_widget.dart` — fallback BLoC state
|
|
39
|
+
|
|
40
|
+
## APIs and data sources
|
|
41
|
+
|
|
42
|
+
- `lib/apis/common/data_source_config.dart` — per-entity mock vs remote
|
|
43
|
+
- `lib/apis/common/constants.dart` — `apiUrl`
|
|
44
|
+
- `assets/mock/` — JSON seed data per entity
|
|
45
|
+
|
|
46
|
+
See `docs/architecture/MOCK_AND_REMOTE_DATA.md`.
|
|
47
|
+
|
|
48
|
+
When adding new code, match naming, imports, and patterns from the closest reference above. For UI components see `docs/architecture/CARAVAGGIO_COMPONENTS.md`.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Widgets and CaravaggioUI — [[project_name]]
|
|
2
|
+
|
|
3
|
+
## CaravaggioUI (required)
|
|
4
|
+
|
|
5
|
+
This project uses `caravaggio_ui` **1.0.6**. Initialize in `main.dart` via `CaravaggioUI.initialize(...)`.
|
|
6
|
+
|
|
7
|
+
```dart
|
|
8
|
+
import 'package:caravaggio_ui/caravaggio_ui.dart';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Component catalog:** read `docs/architecture/CARAVAGGIO_COMPONENTS.md` before creating or editing presentation UI.
|
|
12
|
+
|
|
13
|
+
Prefer CaravaggioUI components over raw Material widgets when equivalents exist (see catalog mapping table).
|
|
14
|
+
|
|
15
|
+
## Pages — CustomScaffold (required)
|
|
16
|
+
|
|
17
|
+
All routed pages **must** use `CustomScaffold` from `lib/widgets/common/custom_scaffold.dart`.
|
|
18
|
+
|
|
19
|
+
- Do **not** use Material `Scaffold` + `AppBar` on pages.
|
|
20
|
+
- `showBackButton: false` on root routes: Home, Splash, Login.
|
|
21
|
+
- `showBackButton: true` on all other pages (add-page, feature pages, nested routes).
|
|
22
|
+
- Use `bodyBuilder` with `topPadding` for scrollable content.
|
|
23
|
+
- Move toolbar actions (add, refresh) to the `action` slot — no `FloatingActionButton`.
|
|
24
|
+
|
|
25
|
+
```dart
|
|
26
|
+
import 'package:caravaggio_ui/caravaggio_ui.dart';
|
|
27
|
+
import 'package:[[project_name]]/widgets/common/custom_scaffold.dart';
|
|
28
|
+
|
|
29
|
+
CustomScaffold(
|
|
30
|
+
title: CText.title('Title', size: TextSize.small),
|
|
31
|
+
showBackButton: true,
|
|
32
|
+
body: ...,
|
|
33
|
+
);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Reusable BLoC **components** (`*_component.dart`) do **not** include a scaffold — the parent page provides `CustomScaffold` and `BlocProvider`.
|
|
37
|
+
|
|
38
|
+
## Widget locations
|
|
39
|
+
|
|
40
|
+
| Type | Path | Use when |
|
|
41
|
+
|------|------|----------|
|
|
42
|
+
| App-wide shared | `lib/widgets/common/` | Scaffold, loading, error, empty states — **reuse first** |
|
|
43
|
+
| Cross-feature component | `lib/features/components/<name>/` | Reusable UI with its own BLoC (list/single/form) |
|
|
44
|
+
| Feature-local | `lib/features/<feature>/presentation/widgets/` | Widget used only in one feature |
|
|
45
|
+
| Pages | `lib/features/<feature>/presentation/*_page.dart` or `lib/features/<name>/<name>_page.dart` | Routed screens |
|
|
46
|
+
|
|
47
|
+
## Existing shared widgets
|
|
48
|
+
|
|
49
|
+
| Widget | Path | Implementation |
|
|
50
|
+
|--------|------|----------------|
|
|
51
|
+
| `CustomScaffold` | `lib/widgets/common/custom_scaffold.dart` | Wraps `CScaffold` |
|
|
52
|
+
| `LoadingWidget` | `lib/widgets/common/loading_widget.dart` | `CLoader.bouncing()` |
|
|
53
|
+
| `ErrorWidget` | `lib/widgets/common/error_widget.dart` | `CText.body` |
|
|
54
|
+
| `UnknownStateWidget` | `lib/widgets/common/unknown_state_widget.dart` | `CText.body` |
|
|
55
|
+
|
|
56
|
+
Import with `package:[[project_name]]/widgets/common/...`.
|
|
57
|
+
|
|
58
|
+
## Reuse policy
|
|
59
|
+
|
|
60
|
+
1. Check `lib/widgets/common/` before creating loading/error UI or page shells.
|
|
61
|
+
2. Check `lib/features/components/` before building similar list/form UIs.
|
|
62
|
+
3. Extract to `features/components/` when a second feature needs the same UI.
|
|
63
|
+
4. Keep feature-specific layout in `presentation/widgets/`.
|
|
64
|
+
5. Consult `CARAVAGGIO_COMPONENTS.md` before introducing new Material widgets.
|
|
65
|
+
|
|
66
|
+
## Presentation patterns
|
|
67
|
+
|
|
68
|
+
- `BlocBuilder` with typed `switch` on Freezed states.
|
|
69
|
+
- Use `ErrorLocalizer` for failure messages.
|
|
70
|
+
- `MultiBlocProvider` with explicit `List<SingleChildWidget>` typing.
|
|
71
|
+
- Lists: `CTile.simple` instead of `ListTile`.
|
|
72
|
+
- Loading: `LoadingWidget` or `CLoader` instead of `CircularProgressIndicator`.
|
|
73
|
+
|
|
74
|
+
## Cursor skill
|
|
75
|
+
|
|
76
|
+
For UI implementation patterns use skill **`/caravaggio-ui`** (page, form, list).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Epics
|
|
2
|
+
|
|
3
|
+
Track feature delivery as epics under `EPIC-NNN-<slug>.md`.
|
|
4
|
+
|
|
5
|
+
## Workflow
|
|
6
|
+
|
|
7
|
+
1. Invoke skill `/epic-delivery` with a high-level product description.
|
|
8
|
+
2. Skill creates epic files from `.cursor/skills/epic-delivery/templates/epic.md`.
|
|
9
|
+
3. Each epic is implemented via `epic-orchestrator` subagent.
|
|
10
|
+
4. Status updated on completion; `layer-guardian` audits DDD boundaries.
|
|
11
|
+
|
|
12
|
+
## Complexity
|
|
13
|
+
|
|
14
|
+
- **small** — 1 entity + 1 UI use case → `feature-implementer`
|
|
15
|
+
- **large** — multiple entities/screens/API → layer pipeline
|
|
16
|
+
|
|
17
|
+
See root `AGENTS.md` and `docs/architecture/`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Domain layer
|
|
2
|
+
|
|
3
|
+
## Structure
|
|
4
|
+
|
|
5
|
+
- `model/` — entity, failure, repository interface, value objects
|
|
6
|
+
- `infrastructure/` — DTO, `I*Service`, mock/remote services, service module, mapper, repository
|
|
7
|
+
|
|
8
|
+
## Mock vs remote
|
|
9
|
+
|
|
10
|
+
Per-entity switch in `lib/apis/common/data_source_config.dart`. Default: **mock**.
|
|
11
|
+
|
|
12
|
+
When adding entities manually:
|
|
13
|
+
|
|
14
|
+
1. Create full infrastructure including `mock_<entity>_service.dart` and `<entity>_service_module.dart`.
|
|
15
|
+
2. Add `assets/mock/<entity>.json` with 2–3 sample items.
|
|
16
|
+
3. Register in `DataSourceConfig.entities`.
|
|
17
|
+
|
|
18
|
+
See `docs/architecture/MOCK_AND_REMOTE_DATA.md`.
|
|
19
|
+
|
|
20
|
+
## Rules
|
|
21
|
+
|
|
22
|
+
- No UI or BLoC in domain.
|
|
23
|
+
- Repository interface in `model/`; implementation uses `I*Service`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Features layer
|
|
2
|
+
|
|
3
|
+
Vertical use cases under `lib/features/<name>/`.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
- `application/` — BLoC, events, states (Freezed)
|
|
8
|
+
- `presentation/` — pages, components, feature-local widgets
|
|
9
|
+
|
|
10
|
+
## Reusable components
|
|
11
|
+
|
|
12
|
+
Cross-feature UI with its own BLoC: `lib/features/components/<name>/` (same application + presentation layout).
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
- Application depends on domain interfaces, not infrastructure implementations.
|
|
17
|
+
- **Pages** use `CustomScaffold` from `lib/widgets/common/custom_scaffold.dart` (never Material `Scaffold`).
|
|
18
|
+
- **Components** (`*_component.dart`) have no scaffold — parent page provides it.
|
|
19
|
+
- Presentation uses CaravaggioUI — see `docs/architecture/CARAVAGGIO_COMPONENTS.md`.
|
|
20
|
+
- Reuse `lib/widgets/common/` shared widgets.
|
|
21
|
+
- Routes go in `lib/router.dart` via integration-wiring.
|
|
22
|
+
|
|
23
|
+
See `docs/architecture/WIDGETS_AND_CARAVAGGIO.md`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Widgets
|
|
2
|
+
|
|
3
|
+
## App-wide (`lib/widgets/common/`)
|
|
4
|
+
|
|
5
|
+
Shared across the app:
|
|
6
|
+
|
|
7
|
+
- `custom_scaffold.dart` — **required** for all routed pages (wraps `CScaffold`)
|
|
8
|
+
- `loading_widget.dart` — `CLoader.bouncing()`
|
|
9
|
+
- `error_widget.dart` — localized error display
|
|
10
|
+
- `unknown_state_widget.dart` — unhandled BLoC states
|
|
11
|
+
|
|
12
|
+
Always check here before creating new page shells or loading/error UI.
|
|
13
|
+
|
|
14
|
+
## Feature components
|
|
15
|
+
|
|
16
|
+
Reusable UI with BLoC: `lib/features/components/` — not under `widgets/`.
|
|
17
|
+
|
|
18
|
+
## Policy
|
|
19
|
+
|
|
20
|
+
- `docs/architecture/WIDGETS_AND_CARAVAGGIO.md` — locations, CustomScaffold rules
|
|
21
|
+
- `docs/architecture/CARAVAGGIO_COMPONENTS.md` — full CaravaggioUI catalog
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: lib/apis/**
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# APIs layer
|
|
7
|
+
|
|
8
|
+
- `lib/apis/common/constants.dart` — `apiUrl`, headers
|
|
9
|
+
- `lib/apis/common/data_source_config.dart` — per-entity `DataSource.mock` / `DataSource.remote`
|
|
10
|
+
- `lib/apis/interceptors/` — Dio interceptors (auth token, logging)
|
|
11
|
+
- `lib/apis/core/` — Dio injectable module
|
|
12
|
+
|
|
13
|
+
Read `docs/architecture/MOCK_AND_REMOTE_DATA.md` before adding or switching data sources.
|
|
14
|
+
|
|
15
|
+
## Rules
|
|
16
|
+
|
|
17
|
+
- No UI in `lib/apis/`.
|
|
18
|
+
- Register services via `@injectable` modules; run `build_runner` after changes.
|
|
19
|
+
- Non-auth entities set to `remote` require non-empty `Constants.apiUrl` (validated in `main.dart`).
|
|
20
|
+
- New entities: add `assets/mock/<entity>.json` and register in `DataSourceConfig`.
|
|
21
|
+
- Coordinate router/DI/mock JSON with `integration-wiring` subagent when adding endpoints for a new epic.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: lib/features/**/application/**
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Application layer (BLoC)
|
|
7
|
+
|
|
8
|
+
- Location: `lib/features/<feature>/application/`
|
|
9
|
+
- Files: `<name>_bloc.dart`, `<name>_event.dart`, `<name>_state.dart` (Freezed).
|
|
10
|
+
- BLoC depends on `I*Repository` from domain — never on infrastructure implementations directly.
|
|
11
|
+
- No Flutter widgets or `BuildContext` in application layer.
|
|
12
|
+
- Use explicit types in `BlocBuilder` and state `switch` expressions.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: true
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# [[project_name]] — CoreGen DDD architecture
|
|
6
|
+
|
|
7
|
+
## lib/ layout
|
|
8
|
+
|
|
9
|
+
| Path | Role |
|
|
10
|
+
|------|------|
|
|
11
|
+
| `lib/core/` | Shared kernel: model (failures, VOs), infrastructure mixins, `app_widget`, `error_localizer` |
|
|
12
|
+
| `lib/domain/<entity>/` | Shared domain: `model/` + `infrastructure/` only — no UI, no BLoC |
|
|
13
|
+
| `lib/domain/enums/` | Domain enums |
|
|
14
|
+
| `lib/features/<feature>/` | Vertical features: `application/` (BLoC) + `presentation/` (UI) |
|
|
15
|
+
| `lib/features/components/` | Reusable UI components with their own BLoC |
|
|
16
|
+
| `lib/apis/` | HTTP, Dio, `DataSourceConfig`, interceptors |
|
|
17
|
+
| `lib/logging/`, `lib/storage/` | Cross-cutting infrastructure |
|
|
18
|
+
| `lib/widgets/common/` | App-wide widgets (CustomScaffold, Loading, Error, UnknownState) |
|
|
19
|
+
|
|
20
|
+
Mock seed data: `assets/mock/<entity>.json` (per-entity mock services). See `docs/architecture/MOCK_AND_REMOTE_DATA.md`.
|
|
21
|
+
|
|
22
|
+
Entry points: `lib/main.dart`, `lib/injection.dart`, `lib/router.dart`.
|
|
23
|
+
|
|
24
|
+
{% if login %}
|
|
25
|
+
With login enabled: `lib/domain/auth/`, `lib/features/auth/`, `lib/features/auth/sign_in_form/`.
|
|
26
|
+
{% endif %}
|
|
27
|
+
|
|
28
|
+
## Layer boundaries
|
|
29
|
+
|
|
30
|
+
- `domain/` must not import from `features/` or Flutter widgets.
|
|
31
|
+
- `features/*/application/` must not import presentation widgets.
|
|
32
|
+
- `presentation/` uses repositories via interfaces in `domain/*/model/i_*_repository.dart`.
|
|
33
|
+
- Use `@injectable` / `get_it` — do not instantiate repositories in widgets.
|
|
34
|
+
|
|
35
|
+
## How to add code
|
|
36
|
+
|
|
37
|
+
Write Dart files manually following `docs/architecture/FILE_TEMPLATES.md` and `docs/architecture/REFERENCE_IMPLEMENTATIONS.md`.
|
|
38
|
+
|
|
39
|
+
**Never run `coregen` CLI commands** (`coregen create`, `coregen add-*`). Agents implement code directly.
|
|
40
|
+
|
|
41
|
+
## Epic workflow
|
|
42
|
+
|
|
43
|
+
Use skill `/epic-delivery` for high-level features. See `docs/epics/README.md`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: lib/**/*.dart
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Dart conventions
|
|
7
|
+
|
|
8
|
+
- File names: `snake_case.dart`. Classes: `PascalCase`.
|
|
9
|
+
- Suffixes: `*_page.dart`, `*_bloc.dart`, `*_event.dart`, `*_state.dart`, `*_failure.dart`, `*_repository.dart`, `*_dto.dart`, `*_mapper.dart`, `*_service.dart`.
|
|
10
|
+
- Use `package:[[project_name]]/...` imports (`always_use_package_imports`).
|
|
11
|
+
- Specify types explicitly in `fold`, `catch`, `BlocBuilder`, and `switch` on Freezed states.
|
|
12
|
+
- Freezed + json_serializable + injectable: after editing annotated files run:
|
|
13
|
+
`dart run build_runner build --delete-conflicting-outputs`
|
|
14
|
+
- Respect `analysis_options.yaml` in project root.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: lib/domain/**
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Domain layer
|
|
7
|
+
|
|
8
|
+
Domain entities live under `lib/domain/<entity>/`:
|
|
9
|
+
|
|
10
|
+
**model/** — `<entity>.dart`, `<entity>_failure.dart`, `i_<entity>_repository.dart`, `value_objects.dart`, `value_validators.dart`
|
|
11
|
+
|
|
12
|
+
**infrastructure/** — `<entity>_dto.dart`, `i_<entity>_service.dart`, `<entity>_remote_service.dart`, `mock_<entity>_service.dart`, `<entity>_service_module.dart`, `<entity>_mapper.dart`, `<entity>_repository.dart`
|
|
13
|
+
|
|
14
|
+
Enums: `lib/domain/enums/<enum_snake>.dart`
|
|
15
|
+
|
|
16
|
+
Mock JSON: `assets/mock/<entity>.json` — see `docs/architecture/MOCK_AND_REMOTE_DATA.md`.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
|
|
20
|
+
- No widgets, no BLoC, no `BuildContext` in domain.
|
|
21
|
+
- Repository interface in `model/`; implementation in `infrastructure/`.
|
|
22
|
+
- Repository injects `I*Service`; service module selects mock vs remote via `DataSourceConfig`.
|
|
23
|
+
- When adding an entity, create/update `assets/mock/<entity>.json` with 2–3 sample rows.
|
|
24
|
+
- After adding a new `*_failure.dart`, update `lib/core/errors/error_localizer.dart` with a `localize*Failure` method (or delegate to `integration-wiring` subagent).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: lib/domain/auth/**,lib/features/auth/**
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Login / auth context
|
|
7
|
+
|
|
8
|
+
This project was created with `--login`. Auth-related paths:
|
|
9
|
+
|
|
10
|
+
- Domain: `lib/domain/auth/model/`, `lib/domain/auth/infrastructure/`
|
|
11
|
+
- Feature: `lib/features/auth/application/`, `lib/features/auth/presentation/`
|
|
12
|
+
- Sign-in form: `lib/features/auth/sign_in_form/application/`, `.../presentation/`
|
|
13
|
+
- API interceptor: `lib/apis/interceptors/`
|
|
14
|
+
- `ErrorLocalizer.localizeAuthFailure` in `lib/core/errors/error_localizer.dart`
|
|
15
|
+
|
|
16
|
+
Follow existing auth patterns when extending authentication flows.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: lib/features/**/presentation/**
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Presentation layer
|
|
7
|
+
|
|
8
|
+
- Location: `lib/features/<feature>/presentation/` or `lib/features/components/<name>/presentation/`
|
|
9
|
+
- Pages: `<name>_page.dart`. Components: `<name>_component.dart`.
|
|
10
|
+
- Pages use `CustomScaffold` — see `docs/architecture/WIDGETS_AND_CARAVAGGIO.md`.
|
|
11
|
+
- UI components: see `docs/architecture/CARAVAGGIO_COMPONENTS.md`.
|
|
12
|
+
- Use `MultiBlocProvider` with typed `providers` list.
|
|
13
|
+
- Import shared states from `lib/widgets/common/` (LoadingWidget, ErrorWidget, UnknownStateWidget).
|
|
14
|
+
- Map failures via `ErrorLocalizer` from `lib/core/errors/error_localizer.dart`.
|
|
15
|
+
- New routes: update `lib/router.dart` (prefer `integration-wiring` subagent).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: After substantial Dart changes, run quality checks — flutter analyze, build_runner when codegen files changed, dart format.
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Quality gate
|
|
7
|
+
|
|
8
|
+
Before marking work complete:
|
|
9
|
+
|
|
10
|
+
1. Run `flutter analyze` (or `dart analyze`) in project root and fix relevant issues.
|
|
11
|
+
2. If Freezed, Injectable, Retrofit, or json_serializable files changed, run:
|
|
12
|
+
`dart run build_runner build --delete-conflicting-outputs`
|
|
13
|
+
3. Optionally run `dart format .`
|
|
14
|
+
4. Do not leave analyzer errors in files you modified.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: lib/**/presentation/**,lib/widgets/**
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UI — CaravaggioUI and widget reuse
|
|
7
|
+
|
|
8
|
+
Read before creating or editing UI:
|
|
9
|
+
|
|
10
|
+
1. `docs/architecture/WIDGETS_AND_CARAVAGGIO.md` — app policy, widget locations, CustomScaffold rules
|
|
11
|
+
2. `docs/architecture/CARAVAGGIO_COMPONENTS.md` — full component catalog (caravaggio_ui 1.0.6)
|
|
12
|
+
|
|
13
|
+
## Hard rules
|
|
14
|
+
|
|
15
|
+
- **Pages:** use `CustomScaffold` from `lib/widgets/common/custom_scaffold.dart`. Never Material `Scaffold` + `AppBar` on pages.
|
|
16
|
+
- **Root pages** (Home, Splash, Login): `showBackButton: false`.
|
|
17
|
+
- **Components** (`*_component.dart`): no scaffold — parent page provides shell.
|
|
18
|
+
- Prefer cataloged CaravaggioUI components over Material equivalents (`CTile`, `CLoader`, `CButton`, `CText`, etc.).
|
|
19
|
+
- Reuse `LoadingWidget`, `ErrorWidget`, `UnknownStateWidget` from `lib/widgets/common/` before creating new states.
|
|
20
|
+
- Cross-feature reusable components: `lib/features/components/<name>/` with `application/` + `presentation/`.
|
|
21
|
+
- Feature-local widgets: `lib/features/<feature>/presentation/widgets/`.
|
|
22
|
+
- Do not duplicate widget policy in comments — follow the architecture docs.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: caravaggio-ui
|
|
3
|
+
description: Implement Flutter presentation UI with CaravaggioUI components and CustomScaffold. Use when creating pages, forms, lists, dialogs, or any presentation layer UI in this project.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CaravaggioUI — presentation patterns
|
|
7
|
+
|
|
8
|
+
Implement UI using `caravaggio_ui` **1.0.6** and project wrappers.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
Read `docs/architecture/CARAVAGGIO_COMPONENTS.md` (full component catalog).
|
|
13
|
+
|
|
14
|
+
Policy and locations: `docs/architecture/WIDGETS_AND_CARAVAGGIO.md`.
|
|
15
|
+
|
|
16
|
+
```dart
|
|
17
|
+
import 'package:caravaggio_ui/caravaggio_ui.dart';
|
|
18
|
+
import 'package:<project>/widgets/common/custom_scaffold.dart';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Pattern 1 — Page with scrollable content
|
|
24
|
+
|
|
25
|
+
Use `CustomScaffold` + `bodyBuilder` for lists and scroll views.
|
|
26
|
+
|
|
27
|
+
```dart
|
|
28
|
+
class ItemsPage extends StatelessWidget {
|
|
29
|
+
static const String routeName = '/items';
|
|
30
|
+
|
|
31
|
+
const ItemsPage({super.key});
|
|
32
|
+
|
|
33
|
+
@override
|
|
34
|
+
Widget build(BuildContext context) {
|
|
35
|
+
return CustomScaffold(
|
|
36
|
+
title: CText.title('Items', size: TextSize.small),
|
|
37
|
+
showBackButton: true,
|
|
38
|
+
action: IconButton(
|
|
39
|
+
icon: const Icon(Icons.add),
|
|
40
|
+
onPressed: () { /* navigate to create */ },
|
|
41
|
+
),
|
|
42
|
+
bodyBuilder: (context, topPadding) {
|
|
43
|
+
return BlocBuilder<ItemsBloc, ItemsState>(
|
|
44
|
+
builder: (context, state) => switch (state) {
|
|
45
|
+
Loading() => Padding(
|
|
46
|
+
padding: EdgeInsets.only(top: topPadding),
|
|
47
|
+
child: const LoadingWidget(),
|
|
48
|
+
),
|
|
49
|
+
Loaded(:final items) => ListView.builder(
|
|
50
|
+
padding: EdgeInsets.only(top: topPadding, left: 16, right: 16),
|
|
51
|
+
itemCount: items.length,
|
|
52
|
+
itemBuilder: (context, index) => CTile.simple(
|
|
53
|
+
title: items[index].name,
|
|
54
|
+
onTap: () { /* detail */ },
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
_ => const SizedBox.shrink(),
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Root pages** (Home, Splash, Login): `showBackButton: false`, no title if not needed.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Pattern 2 — Form
|
|
71
|
+
|
|
72
|
+
Forms live inside a page shell or component — no scaffold in reusable form components.
|
|
73
|
+
|
|
74
|
+
```dart
|
|
75
|
+
CTextField.bordered(
|
|
76
|
+
decoration: CFieldDecoration(label: 'Email'),
|
|
77
|
+
onChanged: (value) => bloc.add(EmailChanged(value)),
|
|
78
|
+
),
|
|
79
|
+
const SizedBox(height: 16),
|
|
80
|
+
CButton.elevated(
|
|
81
|
+
radius: AppRadius.s,
|
|
82
|
+
onPressed: isSubmitting ? null : onSubmit,
|
|
83
|
+
child: isSubmitting
|
|
84
|
+
? SizedBox(
|
|
85
|
+
width: 20,
|
|
86
|
+
height: 20,
|
|
87
|
+
child: CCircularProgressIndicator.primary(),
|
|
88
|
+
)
|
|
89
|
+
: CText.label('Submit'),
|
|
90
|
+
),
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Use `CDatePicker`, `CDropdown`, `CCheckbox`, `CRadioGroup` as needed — see catalog.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Pattern 3 — List component (no scaffold)
|
|
98
|
+
|
|
99
|
+
Reusable BLoC components omit scaffold; parent page wraps with `CustomScaffold`.
|
|
100
|
+
|
|
101
|
+
```dart
|
|
102
|
+
class TaskListComponent extends StatelessWidget {
|
|
103
|
+
const TaskListComponent({super.key});
|
|
104
|
+
|
|
105
|
+
@override
|
|
106
|
+
Widget build(BuildContext context) {
|
|
107
|
+
return BlocBuilder<TaskListBloc, TaskListState>(
|
|
108
|
+
builder: (context, state) => switch (state) {
|
|
109
|
+
Loading() => const LoadingWidget(),
|
|
110
|
+
Loaded(:final items) => ListView.builder(
|
|
111
|
+
itemCount: items.length,
|
|
112
|
+
itemBuilder: (context, index) => CTile.simple(
|
|
113
|
+
title: items[index].title,
|
|
114
|
+
trailing: IconButton(
|
|
115
|
+
icon: const Icon(Icons.delete),
|
|
116
|
+
onPressed: () => context.read<TaskListBloc>().add(
|
|
117
|
+
TaskListEvent.deleteRequested(items[index].id),
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
),
|
|
121
|
+
),
|
|
122
|
+
Error(:final message) => ErrorWidget(message: message),
|
|
123
|
+
_ => const UnknownStateWidget(),
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Checklist
|
|
133
|
+
|
|
134
|
+
- [ ] Page uses `CustomScaffold`, not Material `Scaffold`
|
|
135
|
+
- [ ] Caravaggio components from catalog, not raw Material equivalents
|
|
136
|
+
- [ ] Shared widgets reused from `lib/widgets/common/`
|
|
137
|
+
- [ ] Failures via `ErrorLocalizer`
|
|
138
|
+
- [ ] `flutter analyze` passes
|