@bdayadev/flutter-ultra-mcp 1.12.0 → 1.14.0

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.
Files changed (33) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +41 -13
  4. package/dart/ultra_flutter/pubspec.yaml +1 -1
  5. package/dart/ultra_flutter_devtools/pubspec.yaml +1 -1
  6. package/package.json +1 -1
  7. package/packages/flutter-ultra-native-desktop/package.json +2 -0
  8. package/packages/flutter-ultra-native-mobile/package.json +2 -0
  9. package/skills/add-integration-test/SKILL.md +72 -20
  10. package/skills/add-unit-test/SKILL.md +1 -0
  11. package/skills/add-widget-preview/SKILL.md +75 -26
  12. package/skills/add-widget-test/SKILL.md +51 -22
  13. package/skills/apply-architecture-best-practices/SKILL.md +55 -29
  14. package/skills/build-cli-app/SKILL.md +36 -9
  15. package/skills/build-responsive-layout/SKILL.md +65 -31
  16. package/skills/collect-coverage/SKILL.md +12 -1
  17. package/skills/debug/SKILL.md +19 -2
  18. package/skills/drive/SKILL.md +30 -15
  19. package/skills/fix-layout-issues/SKILL.md +71 -20
  20. package/skills/fix-runtime-errors/SKILL.md +79 -20
  21. package/skills/generate-test-mocks/SKILL.md +43 -13
  22. package/skills/implement-json-serialization/SKILL.md +82 -17
  23. package/skills/migrate-to-checks-package/SKILL.md +46 -14
  24. package/skills/record-demo/SKILL.md +20 -0
  25. package/skills/resolve-package-conflicts/SKILL.md +41 -12
  26. package/skills/run-static-analysis/SKILL.md +29 -16
  27. package/skills/setup/SKILL.md +1 -0
  28. package/skills/setup-declarative-routing/SKILL.md +166 -30
  29. package/skills/setup-localization/SKILL.md +90 -20
  30. package/skills/test/SKILL.md +2 -1
  31. package/skills/tour/SKILL.md +31 -22
  32. package/skills/use-http-package/SKILL.md +61 -23
  33. package/skills/use-pattern-matching/SKILL.md +63 -26
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: setup-localization
3
3
  description: Add `flutter_localizations` and `intl` dependencies, enable "generate true" in `pubspec.yaml`, and create an `l10n.yaml` configuration file. Use when initializing localization support for a new Flutter project.
4
+ last_modified: Tue, 21 Apr 2026 21:27:35 GMT
4
5
  ---
5
6
 
6
7
  # Internationalizing Flutter Applications
@@ -15,46 +16,67 @@ description: Add `flutter_localizations` and `intl` dependencies, enable "genera
15
16
 
16
17
  ## Core Concepts
17
18
 
18
- Flutter handles i18n/l10n via `flutter_localizations` and `intl`. Uses App Resource Bundle (`.arb`) files compiled into a generated `AppLocalizations` class for type-safe access.
19
+ Flutter handles internationalization (i18n) and localization (l10n) via the `flutter_localizations` and `intl` packages. The standard approach uses App Resource Bundle (`.arb`) files to define localized strings, which are then compiled into a generated `AppLocalizations` class for type-safe access within the widget tree.
19
20
 
20
21
  ## Setup Workflow
21
22
 
22
- - [ ] 1. Add dependencies to `pubspec.yaml`.
23
- - [ ] 2. Enable the `generate` flag.
24
- - [ ] 3. Create the `l10n.yaml` configuration file.
25
- - [ ] 4. Configure `MaterialApp` or `CupertinoApp`.
23
+ Copy and track this checklist when initializing internationalization in a Flutter project:
24
+
25
+ - [ ] **Task Progress**
26
+ - [ ] 1. Add dependencies to `pubspec.yaml`.
27
+ - [ ] 2. Enable the `generate` flag.
28
+ - [ ] 3. Create the `l10n.yaml` configuration file.
29
+ - [ ] 4. Configure `MaterialApp` or `CupertinoApp`.
26
30
 
27
31
  ### 1. Add Dependencies
28
32
 
33
+ Add the required localization packages to the project. Execute the following commands in the terminal:
34
+
29
35
  ```bash
30
36
  flutter pub add flutter_localizations --sdk=flutter
31
37
  flutter pub add intl:any
32
38
  ```
33
39
 
40
+ Verify your `pubspec.yaml` includes the following under `dependencies`:
41
+
42
+ ```yaml
43
+ dependencies:
44
+ flutter:
45
+ sdk: flutter
46
+ flutter_localizations:
47
+ sdk: flutter
48
+ intl: any
49
+ ```
50
+
34
51
  ### 2. Enable Code Generation
35
52
 
53
+ Open `pubspec.yaml` and enable the `generate` flag within the `flutter` section to automate localization tasks:
54
+
36
55
  ```yaml
37
- # pubspec.yaml
38
56
  flutter:
39
57
  generate: true
40
58
  ```
41
59
 
42
60
  ### 3. Create Configuration File
43
61
 
62
+ Create a new file named `l10n.yaml` in the root directory of the Flutter project. Define the input directory, template file, and output file:
63
+
44
64
  ```yaml
45
- # l10n.yaml
46
65
  arb-dir: lib/l10n
47
66
  template-arb-file: app_en.arb
48
67
  output-localization-file: app_localizations.dart
49
68
  synthetic-package: true
50
69
  ```
51
70
 
52
- ### 4. Configure App Entry Point
71
+ ### 4. Configure the App Entry Point
72
+
73
+ Import the generated localizations and the `flutter_localizations` library in your `main.dart`. Inject the delegates and supported locales into your `MaterialApp` or `CupertinoApp`.
53
74
 
54
75
  ```dart
55
76
  import 'package:flutter_localizations/flutter_localizations.dart';
56
- import 'package:flutter_gen/gen_l10n/app_localizations.dart';
77
+ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // Adjust path if synthetic-package is false
57
78
 
79
+ // ... inside build method
58
80
  return MaterialApp(
59
81
  localizationsDelegates: const [
60
82
  AppLocalizations.delegate,
@@ -62,16 +84,22 @@ return MaterialApp(
62
84
  GlobalWidgetsLocalizations.delegate,
63
85
  GlobalCupertinoLocalizations.delegate,
64
86
  ],
65
- supportedLocales: const [Locale('en'), Locale('es')],
87
+ supportedLocales: const [
88
+ Locale('en'), // English
89
+ Locale('es'), // Spanish
90
+ ],
66
91
  home: const MyHomePage(),
67
92
  );
68
93
  ```
69
94
 
70
95
  ## Implementation Workflow
71
96
 
97
+ Follow this workflow when adding or modifying localized content.
98
+
72
99
  ### 1. Define ARB Files
73
100
 
74
- **Template (`lib/l10n/app_en.arb`):**
101
+ - **If creating NEW content:** Add the base string to the template file (`lib/l10n/app_en.arb`). Include a description for context.
102
+ - **If EDITING existing content:** Locate the key in all supported `.arb` files and update the values.
75
103
 
76
104
  ```json
77
105
  {
@@ -82,59 +110,98 @@ return MaterialApp(
82
110
  }
83
111
  ```
84
112
 
85
- **Other locales (`lib/l10n/app_es.arb`):**
113
+ Create corresponding files for other locales (e.g., `app_es.arb`):
86
114
 
87
115
  ```json
88
116
  {
89
- "helloWorld": "!Hola Mundo!"
117
+ "helloWorld": "¡Hola Mundo!"
90
118
  }
91
119
  ```
92
120
 
93
121
  ### 2. Generate Localization Classes
94
122
 
123
+ Run the following command to trigger code generation:
124
+
95
125
  ```bash
96
126
  flutter pub get
97
127
  ```
98
128
 
129
+ _Feedback Loop:_ Run validator -> review terminal output for ARB syntax errors -> fix missing commas or mismatched placeholders -> re-run `flutter pub get`.
130
+
99
131
  ### 3. Consume Localized Strings
100
132
 
133
+ Access the localized strings in your widget tree using `AppLocalizations.of(context)`. Ensure the widget calling this is a descendant of `MaterialApp`.
134
+
101
135
  ```dart
102
136
  Text(AppLocalizations.of(context)!.helloWorld)
103
137
  ```
104
138
 
105
139
  ## Advanced Formatting
106
140
 
141
+ Use placeholders for dynamic data, plurals, and conditional selects.
142
+
107
143
  ### Placeholders
108
144
 
145
+ Define parameters within curly braces and specify their type in the metadata object.
146
+
109
147
  ```json
110
148
  "hello": "Hello {userName}",
111
149
  "@hello": {
150
+ "description": "A message with a single parameter",
112
151
  "placeholders": {
113
- "userName": { "type": "String", "example": "Bob" }
152
+ "userName": {
153
+ "type": "String",
154
+ "example": "Bob"
155
+ }
114
156
  }
115
157
  }
116
158
  ```
117
159
 
118
160
  ### Plurals
119
161
 
162
+ Use the `plural` syntax to handle quantity-based string variations. The `other` case is mandatory.
163
+
120
164
  ```json
121
165
  "nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
122
166
  "@nWombats": {
123
- "placeholders": { "count": { "type": "num", "format": "compact" } }
167
+ "description": "A plural message",
168
+ "placeholders": {
169
+ "count": {
170
+ "type": "num",
171
+ "format": "compact"
172
+ }
173
+ }
124
174
  }
125
175
  ```
126
176
 
127
177
  ### Selects
128
178
 
179
+ Use the `select` syntax for conditional strings, such as gendered text.
180
+
129
181
  ```json
130
182
  "pronoun": "{gender, select, male{he} female{she} other{they}}",
131
183
  "@pronoun": {
132
- "placeholders": { "gender": { "type": "String" } }
184
+ "description": "A gendered message",
185
+ "placeholders": {
186
+ "gender": {
187
+ "type": "String"
188
+ }
189
+ }
133
190
  }
134
191
  ```
135
192
 
136
193
  ## Examples
137
194
 
195
+ ### Complete `l10n.yaml`
196
+
197
+ ```yaml
198
+ arb-dir: lib/l10n
199
+ template-arb-file: app_en.arb
200
+ output-localization-file: app_localizations.dart
201
+ synthetic-package: true
202
+ use-escaping: true
203
+ ```
204
+
138
205
  ### Complete Widget Implementation
139
206
 
140
207
  ```dart
@@ -154,10 +221,13 @@ class GreetingWidget extends StatelessWidget {
154
221
  @override
155
222
  Widget build(BuildContext context) {
156
223
  final l10n = AppLocalizations.of(context)!;
157
- return Column(children: [
158
- Text(l10n.hello(userName)),
159
- Text(l10n.nWombats(notificationCount)),
160
- ]);
224
+
225
+ return Column(
226
+ children: [
227
+ Text(l10n.hello(userName)),
228
+ Text(l10n.nWombats(notificationCount)),
229
+ ],
230
+ );
161
231
  }
162
232
  }
163
233
  ```
@@ -11,7 +11,7 @@ Covers all Flutter test layers: unit, widget, golden, and patrol E2E. For ad-hoc
11
11
 
12
12
  ### 1. Identify project and scope
13
13
 
14
- - `mcp__plugin_flutter_flutter-ultra-build__list_projects` to find available projects.
14
+ - `mcp__plugin_flutter_flutter-ultra-build__list_projects` to find available projects. If the target project does not yet exist, use `mcp__plugin_flutter_flutter-ultra-build__create_project` to scaffold it before proceeding.
15
15
  - `mcp__plugin_flutter_flutter-ultra-build__project_info` for the target project path, flavors, and entry points.
16
16
  - `mcp__plugin_flutter_flutter-ultra-build__test_filter` to discover test files matching a name pattern before running.
17
17
  - Determine scope from the user's request: unit only, widget only, patrol E2E only, golden only, full suite, or coverage.
@@ -107,6 +107,7 @@ After unit tests with `coverage: true`:
107
107
  4. **Patrol E2E failures**: read `logContext` from `get_patrol_result`. Cross-reference with `get_patrol_browser_errors` for web.
108
108
  5. **Screenshot on failure**: patrol captures screenshots automatically. For unit/widget failures, call `mcp__plugin_flutter_flutter-ultra-runtime__screenshot` if the app is running.
109
109
  6. **Network issues during E2E**: use `mcp__plugin_flutter_flutter-ultra-runtime__start_http_capture` + `mcp__plugin_flutter_flutter-ultra-runtime__get_http_events` to check API calls.
110
+ 7. **Flaky tests due to external API responses**: use `mcp__plugin_flutter_flutter-ultra-browser__mock_network_route` before running patrol web tests to stub non-deterministic endpoints and isolate the test from network variance.
110
111
 
111
112
  ## Output format
112
113
 
@@ -49,6 +49,7 @@ If the user supplied a route list, use that directly.
49
49
  - Browser screenshot (web): `mcp__plugin_flutter_flutter-ultra-browser__screenshot`
50
50
  - Device screenshot (mobile): `mcp__plugin_flutter_flutter-ultra-native-mobile__take_device_screenshot`
51
51
  - Desktop screenshot: `mcp__plugin_flutter_flutter-ultra-native-desktop__desktop_screenshot`
52
+ - For auth-gated mobile routes that open a CCT/SVC: call `mcp__plugin_flutter_flutter-ultra-native-mobile__detect_in_app_browser` first; if detected, screenshot the in-app browser before dismissing it.
52
53
  5. **Responsive captures** (when requested): `mcp__plugin_flutter_flutter-ultra-gesture__take_responsive_screenshots` to capture at phone/tablet/desktop breakpoints in one call.
53
54
  6. Record `{ route, file, timestamp }` for the report.
54
55
 
@@ -68,12 +69,15 @@ Push live progress to a connected DevTools panel:
68
69
 
69
70
  ### 6. Handle edge cases
70
71
 
71
- - **Auth-gated routes**: after navigation, check for a login widget via `mcp__plugin_flutter_flutter-ultra-runtime__find_widget`. Authenticate via `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` or gesture tools, then retry.
72
+ - **Auth-gated routes**: after navigation, check for a login widget via `mcp__plugin_flutter_flutter-ultra-runtime__find_widget`. Authenticate via `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` or gesture tools, then retry. For CCT/SVC-based auth on mobile, use `mcp__plugin_flutter_flutter-ultra-native-mobile__detect_in_app_browser` to detect the Custom Tab and interact with it before returning to the app.
72
73
  - **Parameterized routes** (`/item/:id`): substitute a known test ID. Ask the user for sample IDs if none are obvious.
73
74
  - **Routes that crash**: catch errors from `mcp__plugin_flutter_flutter-ultra-runtime__get_runtime_errors`, log in the report, continue to the next route.
74
75
  - **Async data loading**: poll `mcp__plugin_flutter_flutter-ultra-runtime__widget_exists` for loading indicators; wait up to 5s in 500ms increments.
75
76
  - **Bottom sheets / dialogs**: trigger via `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` on the parent route, screenshot, dismiss.
77
+ - **Unexpected browser dialogs** (web tours): use `mcp__plugin_flutter_flutter-ultra-browser__handle_dialog` to dismiss alert/confirm/prompt dialogs that block screenshot capture.
76
78
  - **Platform rendering**: use `mcp__plugin_flutter_flutter-ultra-runtime__set_platform_override` to capture iOS-style UI on a non-iOS device.
79
+ - **Notification state screenshots**: use `mcp__plugin_flutter_flutter-ultra-native-mobile__open_notification_tray` to expand the notification shade, then `mcp__plugin_flutter_flutter-ultra-native-mobile__list_notifications` to enumerate visible notifications before capturing a screenshot.
80
+ - **Consistent API responses**: use `mcp__plugin_flutter_flutter-ultra-browser__mock_network_route` (web) to stub API responses before navigating to data-dependent routes, ensuring reproducible screenshots across runs.
77
81
 
78
82
  ### 7. Compile the report
79
83
 
@@ -81,27 +85,32 @@ Write `tour-report.md` with a markdown table of all routes, screenshot paths, an
81
85
 
82
86
  ## Tool reference
83
87
 
84
- | Action | Tool |
85
- | ------------------- | ------------------------------------------------------------------------- |
86
- | Find sessions | `mcp__plugin_flutter_flutter-ultra-runtime__discover_sessions` |
87
- | Launch app | `mcp__plugin_flutter_flutter-ultra-runtime__launch_app` |
88
- | Attach | `mcp__plugin_flutter_flutter-ultra-runtime__attach` |
89
- | Evaluate Dart | `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` |
90
- | VM screenshot | `mcp__plugin_flutter_flutter-ultra-runtime__screenshot` |
91
- | Find widget | `mcp__plugin_flutter_flutter-ultra-runtime__find_widget` |
92
- | Widget exists | `mcp__plugin_flutter_flutter-ultra-runtime__widget_exists` |
93
- | Platform override | `mcp__plugin_flutter_flutter-ultra-runtime__set_platform_override` |
94
- | Runtime errors | `mcp__plugin_flutter_flutter-ultra-runtime__get_runtime_errors` |
95
- | Wait for settle | `mcp__plugin_flutter_flutter-ultra-gesture__wait_for` |
96
- | Responsive shots | `mcp__plugin_flutter_flutter-ultra-gesture__take_responsive_screenshots` |
97
- | Screencast start | `mcp__plugin_flutter_flutter-ultra-gesture__start_screencast` |
98
- | Screencast stop | `mcp__plugin_flutter_flutter-ultra-gesture__stop_screencast` |
99
- | Browser screenshot | `mcp__plugin_flutter_flutter-ultra-browser__screenshot` |
100
- | Browser launch | `mcp__plugin_flutter_flutter-ultra-browser__launch_browser` |
101
- | Connect CDP | `mcp__plugin_flutter_flutter-ultra-browser__connect_over_cdp` |
102
- | Device screenshot | `mcp__plugin_flutter_flutter-ultra-native-mobile__take_device_screenshot` |
103
- | Desktop screenshot | `mcp__plugin_flutter_flutter-ultra-native-desktop__desktop_screenshot` |
104
- | Push DevTools event | `mcp__plugin_flutter_flutter-ultra-devtools__push_event` |
88
+ | Action | Tool |
89
+ | ---------------------- | ------------------------------------------------------------------------- |
90
+ | Find sessions | `mcp__plugin_flutter_flutter-ultra-runtime__discover_sessions` |
91
+ | Launch app | `mcp__plugin_flutter_flutter-ultra-runtime__launch_app` |
92
+ | Attach | `mcp__plugin_flutter_flutter-ultra-runtime__attach` |
93
+ | Evaluate Dart | `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` |
94
+ | VM screenshot | `mcp__plugin_flutter_flutter-ultra-runtime__screenshot` |
95
+ | Find widget | `mcp__plugin_flutter_flutter-ultra-runtime__find_widget` |
96
+ | Widget exists | `mcp__plugin_flutter_flutter-ultra-runtime__widget_exists` |
97
+ | Platform override | `mcp__plugin_flutter_flutter-ultra-runtime__set_platform_override` |
98
+ | Runtime errors | `mcp__plugin_flutter_flutter-ultra-runtime__get_runtime_errors` |
99
+ | Wait for settle | `mcp__plugin_flutter_flutter-ultra-gesture__wait_for` |
100
+ | Responsive shots | `mcp__plugin_flutter_flutter-ultra-gesture__take_responsive_screenshots` |
101
+ | Screencast start | `mcp__plugin_flutter_flutter-ultra-gesture__start_screencast` |
102
+ | Screencast stop | `mcp__plugin_flutter_flutter-ultra-gesture__stop_screencast` |
103
+ | Browser screenshot | `mcp__plugin_flutter_flutter-ultra-browser__screenshot` |
104
+ | Browser launch | `mcp__plugin_flutter_flutter-ultra-browser__launch_browser` |
105
+ | Connect CDP | `mcp__plugin_flutter_flutter-ultra-browser__connect_over_cdp` |
106
+ | Device screenshot | `mcp__plugin_flutter_flutter-ultra-native-mobile__take_device_screenshot` |
107
+ | Desktop screenshot | `mcp__plugin_flutter_flutter-ultra-native-desktop__desktop_screenshot` |
108
+ | Detect CCT/SVC | `mcp__plugin_flutter_flutter-ultra-native-mobile__detect_in_app_browser` |
109
+ | Open notif tray | `mcp__plugin_flutter_flutter-ultra-native-mobile__open_notification_tray` |
110
+ | List notifications | `mcp__plugin_flutter_flutter-ultra-native-mobile__list_notifications` |
111
+ | Dismiss browser dialog | `mcp__plugin_flutter_flutter-ultra-browser__handle_dialog` |
112
+ | Mock API response | `mcp__plugin_flutter_flutter-ultra-browser__mock_network_route` |
113
+ | Push DevTools event | `mcp__plugin_flutter_flutter-ultra-devtools__push_event` |
105
114
 
106
115
  ## Example
107
116
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: use-http-package
3
3
  description: Use the `http` package to execute GET, POST, PUT, or DELETE requests. Use when you need to fetch from or send data to a REST API.
4
+ last_modified: Tue, 21 Apr 2026 21:36:42 GMT
4
5
  ---
5
6
 
6
7
  # Implementing Flutter Networking
@@ -15,56 +16,82 @@ description: Use the `http` package to execute GET, POST, PUT, or DELETE request
15
16
 
16
17
  ## Configuration & Permissions
17
18
 
18
- 1. Add the `http` package: `flutter pub add http`
19
- 2. Import: `import 'package:http/http.dart' as http;`
20
- 3. **Android**: Add `<uses-permission android:name="android.permission.INTERNET" />` to `AndroidManifest.xml`.
21
- 4. **macOS**: Add `com.apple.security.network.client` = `true` to both entitlements files.
19
+ Configure the environment and platform-specific permissions required for network access.
20
+
21
+ 1. Add the `http` package dependency via the terminal:
22
+ ```bash
23
+ flutter pub add http
24
+ ```
25
+ 2. Import the package in your Dart files:
26
+ ```dart
27
+ import 'package:http/http.dart' as http;
28
+ ```
29
+ 3. Configure Android permissions by adding the Internet permission to `android/app/src/main/AndroidManifest.xml`:
30
+ ```xml
31
+ <uses-permission android:name="android.permission.INTERNET" />
32
+ ```
33
+ 4. Configure macOS entitlements by adding the network client key to both `macos/Runner/DebugProfile.entitlements` and `macos/Runner/Release.entitlements`:
34
+ ```xml
35
+ <key>com.apple.security.network.client</key>
36
+ <true/>
37
+ ```
22
38
 
23
39
  ## Request Execution & Response Handling
24
40
 
25
- - **URIs:** Always use `Uri.parse('your_url')`.
26
- - **Headers:** Inject via the `headers` parameter map.
27
- - **Payloads:** For POST/PUT, encode body with `jsonEncode()`.
28
- - **Status Validation:** Treat `200 OK` (GET/PUT/DELETE) and `201 CREATED` (POST) as success.
29
- - **Error Handling:** Throw explicit exceptions on non-success codes. Never return `null`.
30
- - **Deserialization:** `jsonDecode(response.body)` then map to model's `fromJson`.
41
+ Execute HTTP operations and map responses to strongly typed Dart objects.
42
+
43
+ - **URIs:** Always parse URL strings using `Uri.parse('your_url')`.
44
+ - **Headers:** Inject authorization and content-type headers via the `headers` parameter map. Use `HttpHeaders.authorizationHeader` for auth tokens.
45
+ - **Payloads:** For POST and PUT requests, encode the body using `jsonEncode()` from `dart:convert`.
46
+ - **Status Validation:** Evaluate `response.statusCode`. Treat `200 OK` (GET/PUT/DELETE) and `201 CREATED` (POST) as success.
47
+ - **Error Handling:** Throw explicit exceptions for non-success status codes. Never return `null` on failure, as this prevents `FutureBuilder` from triggering its error state and causes infinite loading indicators.
48
+ - **Deserialization:** Parse the raw string using `jsonDecode(response.body)` and map it to a custom Dart object using a factory constructor (e.g., `fromJson`).
31
49
 
32
50
  ## Background Parsing
33
51
 
34
- For large payloads (>16ms parse time), use `compute()` from `package:flutter/foundation.dart` to parse in a background isolate. The parsing function must be top-level or static.
52
+ Offload expensive JSON parsing to a separate Isolate to prevent UI jank (frame drops).
53
+
54
+ - Import `package:flutter/foundation.dart`.
55
+ - Use the `compute()` function to run the parsing logic in a background isolate.
56
+ - Ensure the parsing function passed to `compute()` is a top-level function or a static method, as closures or instance methods cannot be passed across isolates.
35
57
 
36
58
  ## Workflow: Executing Network Operations
37
59
 
60
+ Use the following checklist to implement and validate network operations.
61
+
38
62
  **Task Progress:**
39
63
 
40
- - [ ] 1. Define strongly typed Dart model with `fromJson`.
41
- - [ ] 2. Implement network request method returning `Future<Model>`.
42
- - [ ] 3. Apply conditional logic:
43
- - **GET**: Append query parameters to URI.
44
- - **POST/PUT**: Set `Content-Type: application/json; charset=UTF-8`, attach `jsonEncode` body.
45
- - **DELETE**: Return empty model instance on success.
46
- - [ ] 4. Validate `statusCode` and throw `Exception` on failure.
47
- - [ ] 5. Integrate into UI using `FutureBuilder`.
48
- - [ ] 6. Handle `snapshot.hasData`, `snapshot.hasError`, default to `CircularProgressIndicator`.
49
- - [ ] 7. Run app -> trigger request -> review console for exceptions -> fix.
64
+ - [ ] 1. Define the strongly typed Dart model with a `fromJson` factory constructor.
65
+ - [ ] 2. Implement the network request method returning a `Future<Model>`.
66
+ - [ ] 3. Apply conditional logic based on the operation type:
67
+ - **If fetching data (GET):** Append query parameters to the URI.
68
+ - **If mutating data (POST/PUT):** Set `'Content-Type': 'application/json; charset=UTF-8'` and attach the `jsonEncode` body.
69
+ - **If deleting data (DELETE):** Return an empty model instance on success (`200 OK`).
70
+ - [ ] 4. Validate the `statusCode` and throw an `Exception` on failure.
71
+ - [ ] 5. Integrate the `Future` into the UI using `FutureBuilder`.
72
+ - [ ] 6. Handle `snapshot.hasData`, `snapshot.hasError`, and default to a `CircularProgressIndicator`.
73
+ - [ ] 7. **Feedback Loop:** Run the app -> trigger the network request -> review console for unhandled exceptions -> fix parsing or permission errors.
50
74
 
51
75
  ## Examples
52
76
 
53
- ### Fetching and Parsing in the Background
77
+ ### High-Fidelity Implementation: Fetching and Parsing in the Background
54
78
 
55
79
  ```dart
80
+ import 'dart:async';
56
81
  import 'dart:convert';
57
82
  import 'dart:io';
58
83
  import 'package:flutter/foundation.dart';
59
84
  import 'package:flutter/material.dart';
60
85
  import 'package:http/http.dart' as http;
61
86
 
87
+ // 1. Top-level parsing function for Isolate
62
88
  List<Photo> parsePhotos(String responseBody) {
63
89
  final parsed = (jsonDecode(responseBody) as List<Object?>)
64
90
  .cast<Map<String, Object?>>();
65
91
  return parsed.map<Photo>(Photo.fromJson).toList();
66
92
  }
67
93
 
94
+ // 2. Network execution with background parsing
68
95
  Future<List<Photo>> fetchPhotos() async {
69
96
  final response = await http.get(
70
97
  Uri.parse('https://jsonplaceholder.typicode.com/photos'),
@@ -75,18 +102,24 @@ Future<List<Photo>> fetchPhotos() async {
75
102
  );
76
103
 
77
104
  if (response.statusCode == 200) {
105
+ // Offload heavy parsing to a background isolate
78
106
  return compute(parsePhotos, response.body);
79
107
  } else {
80
108
  throw Exception('Failed to load photos. Status: ${response.statusCode}');
81
109
  }
82
110
  }
83
111
 
112
+ // 3. Strongly typed model
84
113
  class Photo {
85
114
  final int id;
86
115
  final String title;
87
116
  final String thumbnailUrl;
88
117
 
89
- const Photo({required this.id, required this.title, required this.thumbnailUrl});
118
+ const Photo({
119
+ required this.id,
120
+ required this.title,
121
+ required this.thumbnailUrl,
122
+ });
90
123
 
91
124
  factory Photo.fromJson(Map<String, dynamic> json) {
92
125
  return Photo(
@@ -97,8 +130,10 @@ class Photo {
97
130
  }
98
131
  }
99
132
 
133
+ // 4. UI Integration
100
134
  class PhotoGallery extends StatefulWidget {
101
135
  const PhotoGallery({super.key});
136
+
102
137
  @override
103
138
  State<PhotoGallery> createState() => _PhotoGalleryState();
104
139
  }
@@ -109,6 +144,7 @@ class _PhotoGalleryState extends State<PhotoGallery> {
109
144
  @override
110
145
  void initState() {
111
146
  super.initState();
147
+ // Initialize Future once to prevent re-fetching on rebuilds
112
148
  _futurePhotos = fetchPhotos();
113
149
  }
114
150
 
@@ -129,6 +165,8 @@ class _PhotoGalleryState extends State<PhotoGallery> {
129
165
  } else if (snapshot.hasError) {
130
166
  return Center(child: Text('Error: ${snapshot.error}'));
131
167
  }
168
+
169
+ // Default loading state
132
170
  return const Center(child: CircularProgressIndicator());
133
171
  },
134
172
  );
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: use-pattern-matching
3
3
  description: Use switch expressions and pattern matching where appropriate
4
+ last_modified: Fri, 24 Apr 2026 15:08:55 GMT
4
5
  ---
5
6
 
6
7
  # Implementing Dart Patterns
@@ -15,60 +16,82 @@ description: Use switch expressions and pattern matching where appropriate
15
16
 
16
17
  ## Pattern Selection Strategy
17
18
 
18
- - **If validating and extracting from deserialized data (e.g., JSON):** Use Map and List patterns.
19
- - **If handling multiple return values:** Use Record patterns.
20
- - **If executing type-specific behavior (Algebraic Data Types):** Use Object patterns with `sealed` classes.
21
- - **If matching numeric ranges or conditions:** Use Relational and Logical-and patterns.
22
- - **If multiple cases share logic:** Use Logical-or (`||`) patterns.
23
- - **If ignoring specific values:** Use the Wildcard pattern (`_`).
19
+ Apply specific pattern types based on the data structure and desired outcome. Follow these conditional guidelines:
20
+
21
+ - **If validating and extracting from deserialized data (e.g., JSON):** Use Map and List patterns to simultaneously check structure and destructure key-value pairs.
22
+ - **If handling multiple return values:** Use Record patterns to destructure fields directly into local variables.
23
+ - **If executing type-specific behavior (Algebraic Data Types):** Use Object patterns combined with `sealed` classes to ensure exhaustiveness.
24
+ - **If matching numeric ranges or conditions:** Use Relational (`>=`, `<=`) and Logical-and (`&&`) patterns.
25
+ - **If multiple cases share logic:** Use Logical-or (`||`) patterns to share a single case body or guard clause.
26
+ - **If ignoring specific values:** Use the Wildcard pattern (`_`) or a non-matching Rest element (`...`) in collections.
24
27
 
25
28
  ## Switch Statements vs. Expressions
26
29
 
27
- - **If producing a value:** Use a **switch expression**. Syntax: `switch (value) { pattern => expression, }`. Must be exhaustive.
28
- - **If executing statements or side effects:** Use a **switch statement**. Empty cases fall through. Non-empty cases implicitly break.
30
+ Select the appropriate switch construct based on the execution context:
31
+
32
+ - **If producing a value:** Use a **switch expression**.
33
+ - Syntax: `switch (value) { pattern => expression, }`
34
+ - Rule: Each case must be a single expression. No implicit fallthrough. Must be exhaustive.
35
+ - **If executing statements or side effects:** Use a **switch statement**.
36
+ - Syntax: `switch (value) { case pattern: statements; }`
37
+ - Rule: Empty cases fall through to the next case. Non-empty cases implicitly break (no `break` keyword required).
29
38
 
30
39
  ## Core Pattern Implementations
31
40
 
32
- - **Logical-or (`||`):** Both branches must define the exact same set of variables.
33
- - **Logical-and (`&&`):** Branches must _not_ define overlapping variables.
41
+ Implement patterns using the following syntax and rules:
42
+
43
+ - **Logical-or (`||`):** `pattern1 || pattern2`. Both branches must define the exact same set of variables.
44
+ - **Logical-and (`&&`):** `pattern1 && pattern2`. Branches must _not_ define overlapping variables.
34
45
  - **Relational:** `==`, `!=`, `<`, `>`, `<=`, `>=` followed by a constant expression.
35
- - **Cast (`as`):** Throws if the value does not match the type.
36
- - **Null-check (`?`):** Fails the match if the value is null.
37
- - **Null-assert (`!`):** Throws if the value is null.
38
- - **Variable:** `var name` or `Type name`. Binds the matched value.
46
+ - **Cast (`as`):** `pattern as Type`. Throws if the value does not match the type. Use to forcibly assert types during destructuring.
47
+ - **Null-check (`?`):** `pattern?`. Fails the match if the value is null. Binds the variable to the non-nullable base type.
48
+ - **Null-assert (`!`):** `pattern!`. Throws if the value is null.
49
+ - **Variable:** `var name` or `Type name`. Binds the matched value to a new local variable.
39
50
  - **Wildcard (`_`):** Matches any value and discards it.
40
- - **List:** `[pattern1, pattern2]`. Matches lists of exact length unless a Rest element (`...`) is used.
41
- - **Map:** `{"key": pattern}`. Matches maps containing the specified keys.
42
- - **Record:** `(pattern1, named: pattern2)`. Use `:var name` to infer the getter name.
43
- - **Object:** `ClassName(field: pattern)`. Use `:var field` to infer the getter name.
51
+ - **List:** `[pattern1, pattern2]`. Matches lists of exact length unless a Rest element (`...` or `...var rest`) is used.
52
+ - **Map:** `{"key": pattern}`. Matches maps containing the specified keys. Ignores unmatched keys.
53
+ - **Record:** `(pattern1, named: pattern2)`. Matches records of the exact shape. Use `:var name` to infer the getter name.
54
+ - **Object:** `ClassName(field: pattern)`. Matches instances of `ClassName`. Use `:var field` to infer the getter name.
44
55
 
45
56
  ## Workflows
46
57
 
47
58
  ### Task Progress: Implementing Pattern Matching
48
59
 
49
- - [ ] Identify the data structure being evaluated.
50
- - [ ] Select the appropriate switch construct.
51
- - [ ] Define the required patterns.
52
- - [ ] Extract required data using Variable patterns.
60
+ Copy this checklist to track progress when implementing complex pattern matching logic:
61
+
62
+ - [ ] Identify the data structure being evaluated (JSON, Record, Class, Enum).
63
+ - [ ] Select the appropriate switch construct (Expression for values, Statement for side-effects).
64
+ - [ ] Define the required patterns (Object, Map, List, Record).
65
+ - [ ] Extract required data using Variable patterns (`var x`, `:var y`).
53
66
  - [ ] Apply Guard clauses (`when condition`) for logic that cannot be expressed via patterns.
54
- - [ ] Handle unmatched cases using a Wildcard (`_`) or `default`.
67
+ - [ ] Handle unmatched cases using a Wildcard (`_`) or `default` clause (if not using a sealed class).
55
68
  - [ ] Run exhaustiveness validator.
56
69
 
57
70
  ### Feedback Loop: Exhaustiveness Checking
58
71
 
59
- 1. Execute `dart analyze`.
60
- 2. Look for "The type 'X' is not exhaustively matched" errors.
61
- 3. Add the missing Object patterns for unhandled subtypes, or add a Wildcard case.
72
+ When switching over `sealed` classes or enums, you must ensure all subtypes are handled.
73
+
74
+ 1. **Run validator:** Execute `dart analyze`.
75
+ 2. **Review errors:** Look for "The type 'X' is not exhaustively matched by the switch cases" errors.
76
+ 3. **Fix:** Add the missing Object patterns for the unhandled subtypes, or add a Wildcard (`_`) case if a default fallback is acceptable.
62
77
 
63
78
  ## Examples
64
79
 
65
80
  ### JSON Validation and Destructuring
66
81
 
82
+ Use Map and List patterns to validate structure and extract data in a single step.
83
+
84
+ **Input:**
85
+
67
86
  ```dart
68
87
  var data = {
69
88
  'user': ['Lily', 13],
70
89
  };
90
+ ```
71
91
 
92
+ **Implementation:**
93
+
94
+ ```dart
72
95
  if (data case {'user': [String name, int age]}) {
73
96
  print('User $name is $age years old.');
74
97
  } else {
@@ -78,6 +101,10 @@ if (data case {'user': [String name, int age]}) {
78
101
 
79
102
  ### Algebraic Data Types (Sealed Classes)
80
103
 
104
+ Use Object patterns with switch expressions to handle family types exhaustively.
105
+
106
+ **Implementation:**
107
+
81
108
  ```dart
82
109
  sealed class Shape {}
83
110
 
@@ -91,6 +118,7 @@ class Circle implements Shape {
91
118
  Circle(this.radius);
92
119
  }
93
120
 
121
+ // Switch expression guarantees exhaustiveness due to `sealed` modifier.
94
122
  double calculateArea(Shape shape) => switch (shape) {
95
123
  Square(length: var l) => l * l,
96
124
  Circle(:var radius) => math.pi * radius * radius,
@@ -99,15 +127,24 @@ double calculateArea(Shape shape) => switch (shape) {
99
127
 
100
128
  ### Variable Swapping and Destructuring
101
129
 
130
+ Use variable assignment patterns to swap values or extract record fields without temporary variables.
131
+
132
+ **Implementation:**
133
+
102
134
  ```dart
103
135
  var (a, b) = ('left', 'right');
104
136
  (b, a) = (a, b); // Swap values
105
137
 
138
+ // Destructuring a function return
106
139
  var (name, age) = getUserInfo();
107
140
  ```
108
141
 
109
142
  ### Guard Clauses and Logical-or
110
143
 
144
+ Use `when` to evaluate arbitrary conditions after a pattern matches.
145
+
146
+ **Implementation:**
147
+
111
148
  ```dart
112
149
  switch (shape) {
113
150
  case Square(size: var s) || Circle(size: var s) when s > 0: