agent-flutter 0.1.1
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.
- package/README.md +57 -0
- package/bin/agent-flutter.js +8 -0
- package/package.json +36 -0
- package/src/cli.js +494 -0
- package/templates/shared/.ignore +24 -0
- package/templates/shared/TEMPLATES.md +54 -0
- package/templates/shared/rules/document-workflow-function.md +98 -0
- package/templates/shared/rules/integration-api.md +3 -0
- package/templates/shared/rules/new-template-project.md +148 -0
- package/templates/shared/rules/ui.md +268 -0
- package/templates/shared/rules/unit-test.md +3 -0
- package/templates/shared/rules/widget-test.md +3 -0
- package/templates/shared/skills/dart-best-practices/SKILL.md +20 -0
- package/templates/shared/skills/dart-language-patterns/SKILL.md +47 -0
- package/templates/shared/skills/dart-model-reuse/SKILL.md +38 -0
- package/templates/shared/skills/dart-tooling-ci/SKILL.md +38 -0
- package/templates/shared/skills/flutter-assets-management/SKILL.md +78 -0
- package/templates/shared/skills/flutter-bloc-state-management/SKILL.md +48 -0
- package/templates/shared/skills/flutter-bloc-state-management/references/REFERENCE.md +19 -0
- package/templates/shared/skills/flutter-bloc-state-management/references/auth-bloc-example.md +96 -0
- package/templates/shared/skills/flutter-bloc-state-management/references/property-based-state.md +103 -0
- package/templates/shared/skills/flutter-dependency-injection-injectable/SKILL.md +64 -0
- package/templates/shared/skills/flutter-dependency-injection-injectable/references/REFERENCE.md +15 -0
- package/templates/shared/skills/flutter-dependency-injection-injectable/references/modules.md +42 -0
- package/templates/shared/skills/flutter-error-handling/SKILL.md +25 -0
- package/templates/shared/skills/flutter-error-handling/references/REFERENCE.md +38 -0
- package/templates/shared/skills/flutter-error-handling/references/error-mapping.md +44 -0
- package/templates/shared/skills/flutter-navigation-manager/SKILL.md +81 -0
- package/templates/shared/skills/flutter-navigation-manager/references/REFERENCE.md +71 -0
- package/templates/shared/skills/flutter-navigation-manager/references/router-config.md +57 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture/SKILL.md +89 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture/references/REFERENCE.md +19 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture/references/folder-structure.md +35 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture/references/modular-injection.md +27 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture/references/shared-core.md +29 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture-dependency-rules/SKILL.md +58 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture-dependency-rules/references/REFERENCE.md +113 -0
- package/templates/shared/skills/flutter-standard-lib-src-architecture-dependency-rules/references/repository-mapping.md +48 -0
- package/templates/shared/skills/flutter-ui-widgets/SKILL.md +152 -0
- package/templates/shared/skills/getx-localization-standard/SKILL.md +101 -0
- package/templates/shared/skills/getx-localization-standard/references/new-page-localization.example.md +61 -0
- package/templates/shared/skills/ui-documentation-workflow/SKILL.md +55 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# GetX Routing Reference
|
|
2
|
+
|
|
3
|
+
Examples for implementing scalable routing with **GetX** and nested **Navigator** stacks.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [Router Configuration](router-config.md) — Standard setup with `AppPages`, `GetPage`, and `CommonRouter`.
|
|
8
|
+
- [Skill: Flutter Navigation Manager](../SKILL.md) — Strategy, prototype mapping, and arguments.
|
|
9
|
+
|
|
10
|
+
## Quick Navigation
|
|
11
|
+
|
|
12
|
+
```dart
|
|
13
|
+
// Full-screen route (hides BottomBar)
|
|
14
|
+
Get.toNamed(AppPages.detail, arguments: {'id': 123});
|
|
15
|
+
// Back
|
|
16
|
+
Navigator.pop(context);
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```dart
|
|
20
|
+
// Nested route under BottomBar (keeps visible)
|
|
21
|
+
Navigator.of(context).pushNamed(
|
|
22
|
+
AppPages.detail,
|
|
23
|
+
arguments: {'id': 123},
|
|
24
|
+
);
|
|
25
|
+
// Back
|
|
26
|
+
Navigator.pop(context);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Arguments
|
|
30
|
+
|
|
31
|
+
```dart
|
|
32
|
+
// GetX: send & receive
|
|
33
|
+
Get.toNamed(AppPages.detail, arguments: {'id': 123, 'mode': 'edit'});
|
|
34
|
+
final args = Get.arguments as Map<String, dynamic>;
|
|
35
|
+
final id = args['id'] as int;
|
|
36
|
+
final mode = args['mode'] as String?;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```dart
|
|
40
|
+
// Navigator: prefer pushNamed with arguments
|
|
41
|
+
Navigator.of(context).pushNamed(
|
|
42
|
+
AppPages.detail,
|
|
43
|
+
arguments: {'id': 123, 'mode': 'edit'},
|
|
44
|
+
);
|
|
45
|
+
// Receive in the destination page
|
|
46
|
+
final args = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;
|
|
47
|
+
final id = args?['id'] as int?;
|
|
48
|
+
final mode = args?['mode'] as String?;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Bindings
|
|
52
|
+
|
|
53
|
+
Use bindings with routes to initialize dependencies:
|
|
54
|
+
|
|
55
|
+
```dart
|
|
56
|
+
// AppPages (GetPage)
|
|
57
|
+
GetPage(
|
|
58
|
+
name: AppPages.notification,
|
|
59
|
+
page: () => const NotificationPage(),
|
|
60
|
+
binding: NotificationBinding(),
|
|
61
|
+
);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```dart
|
|
65
|
+
// CommonRouter (nested/shared) using GetPageRoute
|
|
66
|
+
return GetPageRoute(
|
|
67
|
+
page: () => const NotificationPage(),
|
|
68
|
+
settings: settings,
|
|
69
|
+
binding: NotificationBinding(),
|
|
70
|
+
);
|
|
71
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Router Configuration (GetX)
|
|
2
|
+
|
|
3
|
+
## AppPages Configuration
|
|
4
|
+
Located in `lib/src/utils/app_pages.dart`.
|
|
5
|
+
|
|
6
|
+
```dart
|
|
7
|
+
import 'package:get/get.dart';
|
|
8
|
+
import 'package:link_home/src/ui/home/home_page.dart';
|
|
9
|
+
import 'package:link_home/src/ui/auth/login/login_page.dart';
|
|
10
|
+
import 'package:link_home/src/ui/auth/login/binding/login_binding.dart';
|
|
11
|
+
|
|
12
|
+
class AppPages {
|
|
13
|
+
static const String login = _Paths.login;
|
|
14
|
+
static const String home = _Paths.home;
|
|
15
|
+
|
|
16
|
+
static final pages = [
|
|
17
|
+
GetPage(
|
|
18
|
+
name: _Paths.login,
|
|
19
|
+
page: () => const LoginPage(),
|
|
20
|
+
binding: LoginBinding(), // Attach Binding
|
|
21
|
+
),
|
|
22
|
+
GetPage(
|
|
23
|
+
name: _Paths.home,
|
|
24
|
+
page: () => const HomePage(),
|
|
25
|
+
),
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
abstract class _Paths {
|
|
30
|
+
static const String login = "/login";
|
|
31
|
+
static const String home = "/home";
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Common Router (Nested/Shared)
|
|
36
|
+
Located in `lib/src/ui/routing/common_router.dart`.
|
|
37
|
+
Used for handling routes that might be accessible from multiple entry points or require custom transitions.
|
|
38
|
+
|
|
39
|
+
```dart
|
|
40
|
+
class CommonRouter {
|
|
41
|
+
static Route<dynamic>? onGenerateRoute(RouteSettings settings) {
|
|
42
|
+
switch (settings.name) {
|
|
43
|
+
case AppPages.notification:
|
|
44
|
+
return GetPageRoute(
|
|
45
|
+
page: () => const NotificationPage(),
|
|
46
|
+
settings: settings,
|
|
47
|
+
binding: NotificationBinding(),
|
|
48
|
+
);
|
|
49
|
+
default:
|
|
50
|
+
return GetPageRoute(
|
|
51
|
+
page: () => const NotFoundPage(),
|
|
52
|
+
settings: settings,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Standard lib/src Architecture
|
|
2
|
+
|
|
3
|
+
## **Priority: P0 (CRITICAL)**
|
|
4
|
+
|
|
5
|
+
Standard folder architecture for Flutter apps organized under `lib/src/`.
|
|
6
|
+
|
|
7
|
+
## Structure
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
lib/
|
|
11
|
+
└── src/
|
|
12
|
+
├── api/
|
|
13
|
+
├── core/
|
|
14
|
+
│ ├── model/
|
|
15
|
+
│ │ ├── request/ # API Request Bodies (DTOs)
|
|
16
|
+
│ │ └── response/ # API Response Objects (DTOs)
|
|
17
|
+
├── di/
|
|
18
|
+
├── enums/
|
|
19
|
+
├── extensions/
|
|
20
|
+
├── helper/
|
|
21
|
+
├── locale/
|
|
22
|
+
├── ui/
|
|
23
|
+
│ ├── <page_name>/
|
|
24
|
+
│ │ ├── binding/
|
|
25
|
+
│ │ ├── components/
|
|
26
|
+
│ │ └── interactor/
|
|
27
|
+
│ └── widgets/
|
|
28
|
+
└── utils/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Implementation Guidelines
|
|
32
|
+
|
|
33
|
+
- **Page Modules**: Each screen/flow is a module under `lib/src/ui/<page_name>/`.
|
|
34
|
+
- **Page Naming**: Page file MUST be named `<page_name>_page.dart` (e.g., `page_a_page.dart`).
|
|
35
|
+
- **Folder Roles**:
|
|
36
|
+
- `ui/<page>/binding/`: routing + dependency wiring for that page module.
|
|
37
|
+
- `ui/<page>/interactor/`: state + business logic for that page module.
|
|
38
|
+
- `ui/<page>/components/`: page-specific UI blocks.
|
|
39
|
+
- `ui/widgets/`: shared UI widgets reused across pages.
|
|
40
|
+
- `di/`: global dependency registration (app-level modules).
|
|
41
|
+
- `api/`: networking clients, repositories/services (no UI).
|
|
42
|
+
- `core/model/`: **Data Transfer Objects (DTOs)**.
|
|
43
|
+
- `request/`: Models sent TO the server (e.g., `LoginRequest`).
|
|
44
|
+
- `response/`: Models received FROM the server (e.g., `LoginResponse`).
|
|
45
|
+
- *Note*: Shared domain entities can sit directly in `core/model/`.
|
|
46
|
+
- `core/`: cross-cutting infrastructure (router, theme, localization plumbing, error mapping, etc.).
|
|
47
|
+
- `utils/`: app-wide constants/styles/helpers that are safe to import anywhere.
|
|
48
|
+
|
|
49
|
+
- **Dependency Rule**:
|
|
50
|
+
- `components`/`widgets`/page UI → may depend on `interactor`.
|
|
51
|
+
- `interactor` → may depend on `api`, `core`, and `utils`.
|
|
52
|
+
- `api`/`core` → must not depend on `ui`.
|
|
53
|
+
- `binding` is the only place inside a page module allowed to import `di`.
|
|
54
|
+
|
|
55
|
+
## UI: Component Extraction (P0)
|
|
56
|
+
|
|
57
|
+
Any **visually meaningful UI block** must be extracted into a component file.
|
|
58
|
+
|
|
59
|
+
### What counts as “visually meaningful”
|
|
60
|
+
|
|
61
|
+
- A block users can visually identify as a unit (Header, SearchBar, Card, Section, BottomSheet content).
|
|
62
|
+
- A repeated layout (e.g., list item / card appears 2+ times).
|
|
63
|
+
- A block with its own spacing/background/border/gradient.
|
|
64
|
+
- A block that would make the page widget harder to scan if kept inline.
|
|
65
|
+
|
|
66
|
+
### Folder convention
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
lib/src/ui/<page_name>/
|
|
70
|
+
├── binding/
|
|
71
|
+
├── interactor/
|
|
72
|
+
├── components/
|
|
73
|
+
└── <page_name>_page.dart
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Shared components live in:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
lib/src/ui/widgets/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Reference & Examples
|
|
83
|
+
|
|
84
|
+
For page module blueprints and DI guidance:
|
|
85
|
+
See [references/REFERENCE.md](references/REFERENCE.md).
|
|
86
|
+
|
|
87
|
+
## Related Topics
|
|
88
|
+
|
|
89
|
+
dependency-injection | go-router-navigation | getx-localization | error-handling
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Standard lib/src Architecture Reference
|
|
2
|
+
|
|
3
|
+
Detailed examples for organizing Flutter apps using the standard `lib/src` structure.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Standard Folder Structure**](folder-structure.md) - Deep dive into `lib/src` directory nesting.
|
|
8
|
+
- [**Core vs Shared UI**](shared-core.md) - When to put code in `core`, `ui/widgets`, or keep it page-local.
|
|
9
|
+
- [**Modular Injection**](modular-injection.md) - How to wire dependencies per page module + global DI.
|
|
10
|
+
|
|
11
|
+
## **Quick Implementation Rule**
|
|
12
|
+
|
|
13
|
+
- Page-local code stays page-local:
|
|
14
|
+
- Do not import `lib/src/ui/<page>/components/` from other pages.
|
|
15
|
+
- Do not import `lib/src/ui/<page>/binding/` from other pages.
|
|
16
|
+
- If something is reused by multiple pages, move it to:
|
|
17
|
+
- `lib/src/ui/widgets/` (UI)
|
|
18
|
+
- `lib/src/core/` (infrastructure)
|
|
19
|
+
- `lib/src/utils/` (constants/styles)
|
package/templates/shared/skills/flutter-standard-lib-src-architecture/references/folder-structure.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Standard lib/src Folder Structure
|
|
2
|
+
|
|
3
|
+
A complete blueprint for the standard `lib/src` structure and a single page module.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
lib/src/
|
|
7
|
+
├── api/
|
|
8
|
+
├── core/
|
|
9
|
+
├── di/
|
|
10
|
+
├── enums/
|
|
11
|
+
├── extensions/
|
|
12
|
+
├── helper/
|
|
13
|
+
├── locale/
|
|
14
|
+
├── ui/
|
|
15
|
+
│ ├── authentication/
|
|
16
|
+
│ │ ├── binding/
|
|
17
|
+
│ │ │ └── authentication_binding.dart
|
|
18
|
+
│ │ ├── components/
|
|
19
|
+
│ │ │ └── login_form.dart
|
|
20
|
+
│ │ ├── interactor/
|
|
21
|
+
│ │ │ └── authentication_interactor.dart
|
|
22
|
+
│ │ └── authentication_page.dart
|
|
23
|
+
│ └── widgets/
|
|
24
|
+
│ └── app_button.dart
|
|
25
|
+
└── utils/
|
|
26
|
+
├── app_styles.dart
|
|
27
|
+
├── app_colors.dart
|
|
28
|
+
└── app_pages.dart
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## **Key Constraints**
|
|
32
|
+
|
|
33
|
+
1. **Page Encapsulation**: `ui/<page>/components` and `ui/<page>/binding` are page-private.
|
|
34
|
+
2. **Shared UI**: If reused by multiple pages, move it to `ui/widgets/`.
|
|
35
|
+
3. **No UI in API/Core**: `api/` and `core/` must not import from `ui/`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Modular Injection (Per Page Module)
|
|
2
|
+
|
|
3
|
+
This describes how to keep dependency wiring modular in the standard `lib/src` architecture.
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
- Each page module owns its own bindings (wiring for that module).
|
|
8
|
+
- App composition wires global dependencies in `lib/src/di/`.
|
|
9
|
+
|
|
10
|
+
## Suggested Structure
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
lib/src/
|
|
14
|
+
├── di/
|
|
15
|
+
│ ├── di.dart
|
|
16
|
+
│ └── modules/
|
|
17
|
+
└── ui/
|
|
18
|
+
└── <page>/
|
|
19
|
+
└── binding/
|
|
20
|
+
└── <page>_binding.dart
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Rules
|
|
24
|
+
|
|
25
|
+
- Global DI registers shared services (clients, storage, repositories) in `di/modules/`.
|
|
26
|
+
- Page binding registers only page-scoped objects (interactors/controllers) for that page.
|
|
27
|
+
- UI code must not register dependencies outside `binding/` and `di/`.
|
package/templates/shared/skills/flutter-standard-lib-src-architecture/references/shared-core.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Core vs Shared UI
|
|
2
|
+
|
|
3
|
+
Use this rule to decide where code should live in a standard `lib/src` codebase.
|
|
4
|
+
|
|
5
|
+
## Core (`lib/src/core/`)
|
|
6
|
+
|
|
7
|
+
Put code here when it is:
|
|
8
|
+
- Cross-cutting infrastructure (router, theme, localization, networking base, logging)
|
|
9
|
+
- App-wide and not tied to any specific page
|
|
10
|
+
- Safe to be imported by any page module
|
|
11
|
+
|
|
12
|
+
## Shared UI (`lib/src/ui/widgets/`)
|
|
13
|
+
|
|
14
|
+
Put code here when it is:
|
|
15
|
+
- UI building blocks reused by multiple pages (buttons, form fields, empty states)
|
|
16
|
+
- Design system widgets (app button, app text, skeletons)
|
|
17
|
+
- Not “infrastructure”, but still reusable UI
|
|
18
|
+
|
|
19
|
+
## Page-local (`lib/src/ui/<page>/...`)
|
|
20
|
+
|
|
21
|
+
Default choice. Keep code inside the feature when it is:
|
|
22
|
+
- Only used by one page (UI components, interactor logic, page validators/helpers)
|
|
23
|
+
- Tightly coupled to that page flow
|
|
24
|
+
|
|
25
|
+
## Rule of Thumb
|
|
26
|
+
|
|
27
|
+
- If only one page uses it → keep it in that page.
|
|
28
|
+
- If many pages use it and it’s infrastructure-like → `core/`.
|
|
29
|
+
- If many pages use it and it’s UI → `ui/widgets/`.
|
package/templates/shared/skills/flutter-standard-lib-src-architecture-dependency-rules/SKILL.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Flutter Standard lib/src Architecture (Dependency Rules)
|
|
3
|
+
description: Dependency flow and separation of concerns for the project (UI -> BLoC -> Repository).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Project Architecture & Dependency Rules
|
|
7
|
+
|
|
8
|
+
## **Priority: P0 (CRITICAL)**
|
|
9
|
+
|
|
10
|
+
This project follows a feature-based Clean Architecture adapted for Flutter.
|
|
11
|
+
|
|
12
|
+
## Structure
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
lib/src/
|
|
16
|
+
├── api/ # API definitions & DTOs
|
|
17
|
+
├── core/
|
|
18
|
+
│ └── repository/ # Data Layer (Repositories)
|
|
19
|
+
├── di/ # Dependency Injection Setup
|
|
20
|
+
├── ui/ # Presentation Layer
|
|
21
|
+
│ ├── <feature>/
|
|
22
|
+
│ │ ├── binding/ # DI Bindings
|
|
23
|
+
│ │ ├── bloc/ # OR interactor/ (Business Logic)
|
|
24
|
+
│ │ └── <page>.dart # UI Widget
|
|
25
|
+
│ └── routing/ # Routing Logic
|
|
26
|
+
└── utils/ # Helpers & Constants
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Dependency Flow
|
|
30
|
+
|
|
31
|
+
**UI** (`ui/<feature>`)
|
|
32
|
+
↓ calls
|
|
33
|
+
**BLoC** (`ui/<feature>/bloc` or `interactor`)
|
|
34
|
+
↓ calls
|
|
35
|
+
**Repository** (`core/repository`)
|
|
36
|
+
↓ calls
|
|
37
|
+
**API / Local Storage**
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
|
|
41
|
+
### 1. Presentation Layer (UI)
|
|
42
|
+
- **Responsibility**: Render UI, handle user input, listen to State.
|
|
43
|
+
- **Dependencies**: Can depend on `BLoC` (via `BlocBuilder`/`BlocListener`).
|
|
44
|
+
- **Forbidden**: NO direct API calls. NO direct Repository access.
|
|
45
|
+
|
|
46
|
+
### 2. Business Logic Layer (BLoC/Interactor)
|
|
47
|
+
- **Responsibility**: State management, business logic, calling repositories.
|
|
48
|
+
- **Dependencies**: Can depend on `Repository`.
|
|
49
|
+
- **Forbidden**: NO UI widgets (`BuildContext`, `Scaffold`).
|
|
50
|
+
|
|
51
|
+
### 3. Data Layer (Repository)
|
|
52
|
+
- **Responsibility**: Coordinate data sources (Remote API, Local DB).
|
|
53
|
+
- **Dependencies**: `Api`, `SharedPreference`, etc.
|
|
54
|
+
- **Forbidden**: NO knowledge of UI or BLoC.
|
|
55
|
+
|
|
56
|
+
## Reference & Examples
|
|
57
|
+
|
|
58
|
+
See [references/repository-mapping.md](references/repository-mapping.md).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Reference: Standard lib/src Architecture Examples
|
|
2
|
+
|
|
3
|
+
This reference shows how the standard `lib/src` structure maps to responsibilities:
|
|
4
|
+
|
|
5
|
+
- `ui/<page>/interactor`: state + business logic
|
|
6
|
+
- `api/`: DTOs + repositories + remote data sources
|
|
7
|
+
- `di/` and `ui/<page>/binding`: dependency wiring
|
|
8
|
+
|
|
9
|
+
## Example: Interactor + Repository + DTO mapping
|
|
10
|
+
|
|
11
|
+
### 1) App model (used by Interactors / UI)
|
|
12
|
+
|
|
13
|
+
```dart
|
|
14
|
+
class BankModel {
|
|
15
|
+
final String id;
|
|
16
|
+
final String name;
|
|
17
|
+
final String branchCode;
|
|
18
|
+
|
|
19
|
+
const BankModel({
|
|
20
|
+
required this.id,
|
|
21
|
+
required this.name,
|
|
22
|
+
required this.branchCode,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2) DTO + mapper (in `lib/src/api/`)
|
|
28
|
+
|
|
29
|
+
```dart
|
|
30
|
+
class BankDto {
|
|
31
|
+
final String id;
|
|
32
|
+
final String name;
|
|
33
|
+
final String branchCode;
|
|
34
|
+
|
|
35
|
+
const BankDto({
|
|
36
|
+
required this.id,
|
|
37
|
+
required this.name,
|
|
38
|
+
required this.branchCode,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
factory BankDto.fromJson(Map<String, dynamic> json) => BankDto(
|
|
42
|
+
id: json['bank_id'] as String,
|
|
43
|
+
name: json['bank_name'] as String,
|
|
44
|
+
branchCode: json['code'] as String,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
BankModel toModel() => BankModel(id: id, name: name, branchCode: branchCode);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3) Repository (in `lib/src/api/`)
|
|
52
|
+
|
|
53
|
+
```dart
|
|
54
|
+
abstract class IBankRepository {
|
|
55
|
+
Future<Result<List<BankModel>>> fetchBanks();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class BankRepository implements IBankRepository {
|
|
59
|
+
final BankRemoteDataSource remoteDataSource;
|
|
60
|
+
|
|
61
|
+
BankRepository(this.remoteDataSource);
|
|
62
|
+
|
|
63
|
+
@override
|
|
64
|
+
Future<Result<List<BankModel>>> fetchBanks() async {
|
|
65
|
+
try {
|
|
66
|
+
final dtoList = await remoteDataSource.getBanks();
|
|
67
|
+
final banks = dtoList.map((dto) => dto.toModel()).toList();
|
|
68
|
+
return Success(banks);
|
|
69
|
+
} catch (e) {
|
|
70
|
+
return FailureResult(ApiFailure.fromException(e));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 4) Interactor (in `lib/src/ui/<page>/interactor/`)
|
|
77
|
+
|
|
78
|
+
```dart
|
|
79
|
+
enum BankStatus { initial, loading, loaded, failure }
|
|
80
|
+
|
|
81
|
+
class BankInteractor extends Equatable {
|
|
82
|
+
final IBankRepository repository;
|
|
83
|
+
final BankStatus status;
|
|
84
|
+
final List<BankModel> banks;
|
|
85
|
+
final String? message;
|
|
86
|
+
|
|
87
|
+
const BankInteractor({
|
|
88
|
+
required this.repository,
|
|
89
|
+
this.status = BankStatus.initial,
|
|
90
|
+
this.banks = const [],
|
|
91
|
+
this.message,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
Future<BankInteractor> fetch() async {
|
|
95
|
+
final result = await repository.fetchBanks();
|
|
96
|
+
return switch (result) {
|
|
97
|
+
Success(value: final banks) => BankInteractor(
|
|
98
|
+
repository: repository,
|
|
99
|
+
status: BankStatus.loaded,
|
|
100
|
+
banks: banks,
|
|
101
|
+
),
|
|
102
|
+
FailureResult(failure: final failure) => BankInteractor(
|
|
103
|
+
repository: repository,
|
|
104
|
+
status: BankStatus.failure,
|
|
105
|
+
message: failure.message,
|
|
106
|
+
),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@override
|
|
111
|
+
List<Object?> get props => [status, banks, message];
|
|
112
|
+
}
|
|
113
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Repository & BLoC Mapping
|
|
2
|
+
|
|
3
|
+
## Repository Pattern
|
|
4
|
+
Repositories act as the bridge between Data Sources (API) and the Domain/Business Logic.
|
|
5
|
+
|
|
6
|
+
```dart
|
|
7
|
+
// lib/src/core/repository/auth_repository.dart
|
|
8
|
+
class AuthRepository extends Api {
|
|
9
|
+
final AppShared _appShared;
|
|
10
|
+
final IAuthApiUrl _authUrl;
|
|
11
|
+
|
|
12
|
+
AuthRepository(this._appShared, this._authUrl);
|
|
13
|
+
|
|
14
|
+
Future<void> login(Map<String, dynamic> payload) async {
|
|
15
|
+
final res = await request(
|
|
16
|
+
_authUrl.login,
|
|
17
|
+
Method.post,
|
|
18
|
+
body: payload,
|
|
19
|
+
);
|
|
20
|
+
// Save token, handle data
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## BLoC Implementation
|
|
26
|
+
BLoCs use repositories to fetch data and emit states.
|
|
27
|
+
|
|
28
|
+
```dart
|
|
29
|
+
// lib/src/ui/notification/interactor/notification_bloc.dart
|
|
30
|
+
class NotificationBloc extends Bloc<NotificationEvent, NotificationState> {
|
|
31
|
+
// Inject Repository if needed
|
|
32
|
+
// final NotificationRepository _repo;
|
|
33
|
+
|
|
34
|
+
NotificationBloc() : super(const NotificationState()) {
|
|
35
|
+
on<NotificationInitialized>(_onInitialized);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Future<void> _onInitialized(event, emit) async {
|
|
39
|
+
emit(state.copyWith(pageState: PageState.loading));
|
|
40
|
+
try {
|
|
41
|
+
// await _repo.fetchNotifications();
|
|
42
|
+
emit(state.copyWith(pageState: PageState.success));
|
|
43
|
+
} catch (e) {
|
|
44
|
+
emit(state.copyWith(pageState: PageState.failure));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|