@bdayadev/flutter-ultra-mcp 1.11.7 → 1.12.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dart/ultra_flutter/pubspec.yaml +1 -1
- package/dart/ultra_flutter_devtools/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/skills/UPSTREAM-LICENSES +75 -0
- package/skills/add-integration-test/SKILL.md +127 -0
- package/skills/add-unit-test/SKILL.md +140 -0
- package/skills/add-widget-preview/SKILL.md +117 -0
- package/skills/add-widget-test/SKILL.md +142 -0
- package/skills/apply-architecture-best-practices/SKILL.md +156 -0
- package/skills/build-cli-app/SKILL.md +173 -0
- package/skills/build-responsive-layout/SKILL.md +126 -0
- package/skills/collect-coverage/SKILL.md +157 -0
- package/skills/fix-layout-issues/SKILL.md +101 -0
- package/skills/fix-runtime-errors/SKILL.md +138 -0
- package/skills/generate-test-mocks/SKILL.md +147 -0
- package/skills/implement-json-serialization/SKILL.md +103 -0
- package/skills/migrate-to-checks-package/SKILL.md +124 -0
- package/skills/resolve-package-conflicts/SKILL.md +111 -0
- package/skills/run-static-analysis/SKILL.md +107 -0
- package/skills/setup-declarative-routing/SKILL.md +157 -0
- package/skills/setup-localization/SKILL.md +177 -0
- package/skills/use-http-package/SKILL.md +151 -0
- package/skills/use-pattern-matching/SKILL.md +132 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apply-architecture-best-practices
|
|
3
|
+
description: Architects a Flutter application using the recommended layered approach (UI, Logic, Data). Use when structuring a new project or refactoring for scalability.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Architecting Flutter Applications
|
|
7
|
+
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Architectural Layers](#architectural-layers)
|
|
11
|
+
- [Project Structure](#project-structure)
|
|
12
|
+
- [Workflow: Implementing a New Feature](#workflow-implementing-a-new-feature)
|
|
13
|
+
- [Examples](#examples)
|
|
14
|
+
|
|
15
|
+
## Architectural Layers
|
|
16
|
+
|
|
17
|
+
Enforce strict Separation of Concerns by dividing the application into distinct layers.
|
|
18
|
+
|
|
19
|
+
### UI Layer (Presentation)
|
|
20
|
+
|
|
21
|
+
Implement the MVVM (Model-View-ViewModel) pattern.
|
|
22
|
+
|
|
23
|
+
- **Views:** Reusable, lean widgets. Restrict logic to UI-specific operations.
|
|
24
|
+
- **ViewModels:** Manage UI state. Extend `ChangeNotifier`. Expose immutable state snapshots. Inject Repositories via constructor.
|
|
25
|
+
|
|
26
|
+
### Data Layer
|
|
27
|
+
|
|
28
|
+
Implement the Repository pattern for a single source of truth.
|
|
29
|
+
|
|
30
|
+
- **Services:** Stateless classes wrapping external APIs. Return raw API models or `Result` wrappers.
|
|
31
|
+
- **Repositories:** Consume Services. Transform raw models into Domain Models. Handle caching and retry logic.
|
|
32
|
+
|
|
33
|
+
### Logic Layer (Domain - Optional)
|
|
34
|
+
|
|
35
|
+
- **Use Cases:** Only if complex business logic clutters the ViewModel, or logic must be reused across ViewModels.
|
|
36
|
+
|
|
37
|
+
## Project Structure
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
lib/
|
|
41
|
+
├── data/
|
|
42
|
+
│ ├── models/ # API models
|
|
43
|
+
│ ├── repositories/ # Repository implementations
|
|
44
|
+
│ └── services/ # API clients, local storage wrappers
|
|
45
|
+
├── domain/
|
|
46
|
+
│ ├── models/ # Clean domain models
|
|
47
|
+
│ └── use_cases/ # Optional business logic classes
|
|
48
|
+
└── ui/
|
|
49
|
+
├── core/ # Shared widgets, themes, typography
|
|
50
|
+
└── features/
|
|
51
|
+
└── [feature_name]/
|
|
52
|
+
├── view_models/
|
|
53
|
+
└── views/
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Workflow: Implementing a New Feature
|
|
57
|
+
|
|
58
|
+
### Task Progress
|
|
59
|
+
|
|
60
|
+
- [ ] **Step 1:** Define Domain Models (immutable data classes).
|
|
61
|
+
- [ ] **Step 2:** Implement Services (external API communication).
|
|
62
|
+
- [ ] **Step 3:** Implement Repositories (consume Services, return Domain Models).
|
|
63
|
+
- [ ] **Step 4:** Apply Conditional Logic:
|
|
64
|
+
- Complex data transformation or cross-repository logic: Create a Use Case.
|
|
65
|
+
- Simple CRUD: Skip to Step 5.
|
|
66
|
+
- [ ] **Step 5:** Implement the ViewModel (extend `ChangeNotifier`, inject Repositories).
|
|
67
|
+
- [ ] **Step 6:** Implement the View (use `ListenableBuilder` to listen to ViewModel).
|
|
68
|
+
- [ ] **Step 7:** Inject Dependencies (register in DI container).
|
|
69
|
+
- [ ] **Step 8:** Run tests. Feedback Loop: Run -> Review -> Fix -> Re-run.
|
|
70
|
+
|
|
71
|
+
## Examples
|
|
72
|
+
|
|
73
|
+
### Data Layer: Service and Repository
|
|
74
|
+
|
|
75
|
+
```dart
|
|
76
|
+
class ApiClient {
|
|
77
|
+
Future<UserApiModel> fetchUser(String id) async { /* ... */ }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class UserRepository {
|
|
81
|
+
UserRepository({required ApiClient apiClient}) : _apiClient = apiClient;
|
|
82
|
+
final ApiClient _apiClient;
|
|
83
|
+
User? _cachedUser;
|
|
84
|
+
|
|
85
|
+
Future<User> getUser(String id) async {
|
|
86
|
+
if (_cachedUser != null) return _cachedUser!;
|
|
87
|
+
final apiModel = await _apiClient.fetchUser(id);
|
|
88
|
+
_cachedUser = User(id: apiModel.id, name: apiModel.fullName);
|
|
89
|
+
return _cachedUser!;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### UI Layer: ViewModel and View
|
|
95
|
+
|
|
96
|
+
```dart
|
|
97
|
+
class ProfileViewModel extends ChangeNotifier {
|
|
98
|
+
ProfileViewModel({required UserRepository userRepository})
|
|
99
|
+
: _userRepository = userRepository;
|
|
100
|
+
final UserRepository _userRepository;
|
|
101
|
+
|
|
102
|
+
User? _user;
|
|
103
|
+
User? get user => _user;
|
|
104
|
+
bool _isLoading = false;
|
|
105
|
+
bool get isLoading => _isLoading;
|
|
106
|
+
|
|
107
|
+
Future<void> loadProfile(String id) async {
|
|
108
|
+
_isLoading = true;
|
|
109
|
+
notifyListeners();
|
|
110
|
+
try {
|
|
111
|
+
_user = await _userRepository.getUser(id);
|
|
112
|
+
} finally {
|
|
113
|
+
_isLoading = false;
|
|
114
|
+
notifyListeners();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
class ProfileView extends StatelessWidget {
|
|
120
|
+
const ProfileView({super.key, required this.viewModel});
|
|
121
|
+
final ProfileViewModel viewModel;
|
|
122
|
+
|
|
123
|
+
@override
|
|
124
|
+
Widget build(BuildContext context) {
|
|
125
|
+
return ListenableBuilder(
|
|
126
|
+
listenable: viewModel,
|
|
127
|
+
builder: (context, _) {
|
|
128
|
+
if (viewModel.isLoading) return const Center(child: CircularProgressIndicator());
|
|
129
|
+
final user = viewModel.user;
|
|
130
|
+
if (user == null) return const Center(child: Text('User not found'));
|
|
131
|
+
return Column(children: [
|
|
132
|
+
Text(user.name),
|
|
133
|
+
ElevatedButton(
|
|
134
|
+
onPressed: () => viewModel.loadProfile(user.id),
|
|
135
|
+
child: const Text('Refresh'),
|
|
136
|
+
),
|
|
137
|
+
]);
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Flutter Ultra Integration
|
|
145
|
+
|
|
146
|
+
Use these tools to audit and validate architectural decisions:
|
|
147
|
+
|
|
148
|
+
- `mcp__plugin_flutter_flutter-ultra-build__list_projects` — Discover all projects in the workspace
|
|
149
|
+
- `mcp__plugin_flutter_flutter-ultra-build__project_info` — Get project structure, dependencies, and entry points
|
|
150
|
+
- `mcp__plugin_flutter_flutter-ultra-build__analyze` — Run static analysis to catch architectural violations
|
|
151
|
+
- `mcp__plugin_flutter_flutter-ultra-build__pub_deps` — Review dependency graph for layering issues
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
> **Attribution:** This skill is vendored from [flutter/skills](https://github.com/flutter/skills) (BSD-3-Clause).
|
|
156
|
+
> Synced by `scripts/sync-upstream-skills.mjs`. Do not edit manually — changes will be overwritten on next sync.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-cli-app
|
|
3
|
+
description: Entrypoint structure, exit codes, cross-platform scripts. Use when building command line utilities, scripts, or applications.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Building Dart CLI Applications
|
|
7
|
+
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Project Setup & Architecture](#project-setup--architecture)
|
|
11
|
+
- [Argument Parsing & Command Routing](#argument-parsing--command-routing)
|
|
12
|
+
- [Execution & Error Handling](#execution--error-handling)
|
|
13
|
+
- [Testing CLI Applications](#testing-cli-applications)
|
|
14
|
+
- [Compilation & Distribution](#compilation--distribution)
|
|
15
|
+
- [Workflows](#workflows)
|
|
16
|
+
- [Examples](#examples)
|
|
17
|
+
|
|
18
|
+
## Project Setup & Architecture
|
|
19
|
+
|
|
20
|
+
Initialize new CLI projects using the official Dart template to ensure standard directory structures.
|
|
21
|
+
|
|
22
|
+
- Run `dart create -t cli <project_name>` to scaffold a console application with basic argument parsing.
|
|
23
|
+
- Place executable entry points (files containing `main()`) exclusively in the `bin/` directory.
|
|
24
|
+
- Place internal implementation logic in `lib/src/` and expose public APIs via `lib/<project_name>.dart`.
|
|
25
|
+
- Enforce formatting in CI environments by running `dart format . --set-exit-if-changed`. This returns exit code 1 if formatting violations exist.
|
|
26
|
+
|
|
27
|
+
## Argument Parsing & Command Routing
|
|
28
|
+
|
|
29
|
+
Import the `args` package to manage command-line arguments, flags, and subcommands.
|
|
30
|
+
|
|
31
|
+
- If building a simple script: Use `ArgParser` directly to define flags (`addFlag`) and options (`addOption`).
|
|
32
|
+
- If building a complex, multi-command CLI (like `git`): Implement `CommandRunner` and extend `Command` for each subcommand.
|
|
33
|
+
- Define global arguments on the `CommandRunner.argParser` and command-specific arguments on the individual `Command.argParser`.
|
|
34
|
+
- Catch `UsageException` to gracefully handle invalid arguments and display the automatically generated help text.
|
|
35
|
+
- **Validate Help Text Accuracy**: Ensure the help text provides all necessary information to run the tool.
|
|
36
|
+
|
|
37
|
+
## Execution & Error Handling
|
|
38
|
+
|
|
39
|
+
Leverage the `io` and `stack_trace` packages to build robust, production-ready CLI tools.
|
|
40
|
+
|
|
41
|
+
- Use the `io` package's `ExitCode` enum to return standard POSIX exit codes (e.g., `ExitCode.success.code`, `ExitCode.usage.code`).
|
|
42
|
+
- Use `sharedStdIn` from the `io` package if multiple asynchronous listeners need sequential access to standard input.
|
|
43
|
+
- Wrap the application execution in `Chain.capture()` from the `stack_trace` package to track asynchronous stack chains.
|
|
44
|
+
- Format output stack traces using `Trace.terse` or `Chain.terse` to strip noisy core library frames and present readable errors to the user.
|
|
45
|
+
- **Do not swallow exceptions** in lower-level logic unless recovery is possible. Let them bubble up.
|
|
46
|
+
- **Fail fast and with non-zero exit codes**: Ensure operation failures result in descriptive error messages to `stderr` and appropriate non-zero exit codes.
|
|
47
|
+
|
|
48
|
+
## Testing CLI Applications
|
|
49
|
+
|
|
50
|
+
Use `test_process` and `test_descriptor` to write high-fidelity integration tests for your CLI.
|
|
51
|
+
|
|
52
|
+
- Define expected filesystem states using `test_descriptor` (`d.dir`, `d.file`).
|
|
53
|
+
- Create the mock filesystem before execution using `await d.Descriptor.create()`.
|
|
54
|
+
- Spawn the CLI process using `TestProcess.start('dart', ['run', 'bin/cli.dart', ...args])`.
|
|
55
|
+
- Validate standard output and error streams using `StreamQueue` matchers (e.g., `emitsThrough`, `emits`).
|
|
56
|
+
- Assert the final exit code using `await process.shouldExit(0)`.
|
|
57
|
+
- Validate resulting filesystem mutations using `await d.Descriptor.validate()`.
|
|
58
|
+
|
|
59
|
+
## Compilation & Distribution
|
|
60
|
+
|
|
61
|
+
Select the appropriate compilation target based on your distribution requirements.
|
|
62
|
+
|
|
63
|
+
- **If testing locally during development:** Use `dart run bin/cli.dart`. This uses the JIT compiler for rapid iteration.
|
|
64
|
+
- **If bundling code assets and dynamic libraries:** Use `dart build cli`.
|
|
65
|
+
- **If distributing a standalone native executable:** Use `dart compile exe bin/cli.dart -o <output_path>`.
|
|
66
|
+
- **If distributing multiple apps with strict disk space limits:** Use `dart compile aot-snapshot bin/cli.dart`.
|
|
67
|
+
|
|
68
|
+
## Workflows
|
|
69
|
+
|
|
70
|
+
### Task Progress: Implement a New CLI Command
|
|
71
|
+
|
|
72
|
+
- [ ] Create a new class extending `Command` in `lib/src/commands/`.
|
|
73
|
+
- [ ] Define the `name` and `description` properties.
|
|
74
|
+
- [ ] Register command-specific flags in the constructor using `argParser.addFlag()` or `argParser.addOption()`.
|
|
75
|
+
- [ ] Implement the `run()` method with the core logic.
|
|
76
|
+
- [ ] Register the new command in the `CommandRunner` instance in `bin/cli.dart` using `addCommand()`.
|
|
77
|
+
- [ ] Create tests for the new command in the `test/` directory.
|
|
78
|
+
- [ ] Run validator -> Execute `dart run bin/cli.dart help <command_name>` to verify help text generation.
|
|
79
|
+
- [ ] Verify final UX: Compile the application using `dart compile exe` and run the resulting executable.
|
|
80
|
+
|
|
81
|
+
### Task Progress: Compile and Release Native Executable
|
|
82
|
+
|
|
83
|
+
- [ ] Run validator -> Execute `dart format . --set-exit-if-changed` to ensure code formatting.
|
|
84
|
+
- [ ] Run validator -> Execute `dart analyze` to ensure no static analysis errors.
|
|
85
|
+
- [ ] Run validator -> Execute `dart test` to pass all integration tests.
|
|
86
|
+
- [ ] Compile for host OS: `dart compile exe bin/cli.dart -o build/cli-host`
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
### Example: CommandRunner Implementation
|
|
91
|
+
|
|
92
|
+
```dart
|
|
93
|
+
import 'dart:io';
|
|
94
|
+
import 'package:args/command_runner.dart';
|
|
95
|
+
import 'package:stack_trace/stack_trace.dart';
|
|
96
|
+
|
|
97
|
+
class CommitCommand extends Command {
|
|
98
|
+
@override
|
|
99
|
+
final String name = 'commit';
|
|
100
|
+
@override
|
|
101
|
+
final String description = 'Record changes to the repository.';
|
|
102
|
+
|
|
103
|
+
CommitCommand() {
|
|
104
|
+
argParser.addFlag('all', abbr: 'a', help: 'Commit all changed files.');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@override
|
|
108
|
+
Future<void> run() async {
|
|
109
|
+
final commitAll = argResults?['all'] as bool? ?? false;
|
|
110
|
+
print('Committing... (All: $commitAll)');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
void main(List<String> args) {
|
|
115
|
+
Chain.capture(() async {
|
|
116
|
+
final runner = CommandRunner('dgit', 'Distributed version control.')
|
|
117
|
+
..addCommand(CommitCommand());
|
|
118
|
+
|
|
119
|
+
await runner.run(args);
|
|
120
|
+
}, onError: (error, chain) {
|
|
121
|
+
if (error is UsageException) {
|
|
122
|
+
stderr.writeln(error.message);
|
|
123
|
+
stderr.writeln(error.usage);
|
|
124
|
+
exit(64);
|
|
125
|
+
} else {
|
|
126
|
+
stderr.writeln('Fatal error: $error');
|
|
127
|
+
stderr.writeln(chain.terse);
|
|
128
|
+
exit(1);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Example: Integration Testing with Subprocesses
|
|
135
|
+
|
|
136
|
+
```dart
|
|
137
|
+
import 'package:test/test.dart';
|
|
138
|
+
import 'package:test_process/test_process.dart';
|
|
139
|
+
import 'package:test_descriptor/test_descriptor.dart' as d;
|
|
140
|
+
|
|
141
|
+
void main() {
|
|
142
|
+
test('CLI formats output correctly and modifies filesystem', () async {
|
|
143
|
+
await d.dir('project', [
|
|
144
|
+
d.file('config.json', '{"key": "value"}')
|
|
145
|
+
]).create();
|
|
146
|
+
|
|
147
|
+
final process = await TestProcess.start(
|
|
148
|
+
'dart',
|
|
149
|
+
['run', 'bin/cli.dart', 'process', '--path', '${d.sandbox}/project']
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
await expectLater(process.stdout, emitsThrough('Processing complete.'));
|
|
153
|
+
await process.shouldExit(0);
|
|
154
|
+
|
|
155
|
+
await d.dir('project', [
|
|
156
|
+
d.file('config.json', '{"key": "value"}'),
|
|
157
|
+
d.file('output.log', 'Success')
|
|
158
|
+
]).validate();
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Flutter Ultra Integration
|
|
164
|
+
|
|
165
|
+
Use these tools to validate the CLI app structure:
|
|
166
|
+
|
|
167
|
+
- `mcp__plugin_flutter_flutter-ultra-build__analyze` — Static analysis on the CLI project
|
|
168
|
+
- `mcp__plugin_flutter_flutter-ultra-build__pub_deps` — Review dependency tree
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
> **Attribution:** This skill is vendored from [dart-lang/skills](https://github.com/dart-lang/skills) (BSD-3-Clause).
|
|
173
|
+
> Synced by `scripts/sync-upstream-skills.mjs`. Do not edit manually — changes will be overwritten on next sync.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-responsive-layout
|
|
3
|
+
description: Use `LayoutBuilder`, `MediaQuery`, or `Expanded/Flexible` to create a layout that adapts to different screen sizes. Use when you need the UI to look good on both mobile and tablet/desktop form factors.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Implementing Adaptive Layouts
|
|
7
|
+
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Space Measurement Guidelines](#space-measurement-guidelines)
|
|
11
|
+
- [Widget Sizing and Constraints](#widget-sizing-and-constraints)
|
|
12
|
+
- [Device and Orientation Behaviors](#device-and-orientation-behaviors)
|
|
13
|
+
- [Workflow: Constructing an Adaptive Layout](#workflow-constructing-an-adaptive-layout)
|
|
14
|
+
- [Workflow: Optimizing for Large Screens](#workflow-optimizing-for-large-screens)
|
|
15
|
+
- [Examples](#examples)
|
|
16
|
+
|
|
17
|
+
## Space Measurement Guidelines
|
|
18
|
+
|
|
19
|
+
- **Use `MediaQuery.sizeOf(context)`** to get the size of the entire app window.
|
|
20
|
+
- **Use `LayoutBuilder`** to make layout decisions based on the parent widget's allocated space.
|
|
21
|
+
- **Do not use `MediaQuery.orientationOf` or `OrientationBuilder`** near the top of the widget tree. Device orientation does not accurately reflect available space.
|
|
22
|
+
- **Do not check for hardware types** ("phone" vs. "tablet"). Base all decisions strictly on available window space.
|
|
23
|
+
|
|
24
|
+
## Widget Sizing and Constraints
|
|
25
|
+
|
|
26
|
+
- **`Expanded`**: Force a child to fill all remaining available space.
|
|
27
|
+
- **`Flexible`**: Allow a child to size itself up to a limit while expanding/contracting. Use `flex` factor for sibling ratios.
|
|
28
|
+
- **Constrain Width**: Wrap widgets in `ConstrainedBox` with `maxWidth` on large screens.
|
|
29
|
+
- **Lazy Rendering**: Use `ListView.builder` or `GridView.builder` for long/unknown-length lists.
|
|
30
|
+
|
|
31
|
+
## Device and Orientation Behaviors
|
|
32
|
+
|
|
33
|
+
- **Do not lock screen orientation.** Causes severe layout issues on foldable devices.
|
|
34
|
+
- **Support Multiple Inputs:** Implement support for mice, trackpads, and keyboard shortcuts.
|
|
35
|
+
|
|
36
|
+
## Workflow: Constructing an Adaptive Layout
|
|
37
|
+
|
|
38
|
+
**Task Progress:**
|
|
39
|
+
|
|
40
|
+
- [ ] Identify the target widget.
|
|
41
|
+
- [ ] Wrap in a `LayoutBuilder`.
|
|
42
|
+
- [ ] Extract `constraints.maxWidth`.
|
|
43
|
+
- [ ] Define breakpoint (e.g., `600`).
|
|
44
|
+
- [ ] If `maxWidth > breakpoint`: Return large-screen layout (e.g., `Row` with sidebar).
|
|
45
|
+
- [ ] If `maxWidth <= breakpoint`: Return small-screen layout.
|
|
46
|
+
- [ ] Resize the app window -> review transitions -> fix overflow errors.
|
|
47
|
+
|
|
48
|
+
## Workflow: Optimizing for Large Screens
|
|
49
|
+
|
|
50
|
+
**Task Progress:**
|
|
51
|
+
|
|
52
|
+
- [ ] Identify full-width components.
|
|
53
|
+
- [ ] **Lists**: Convert `ListView.builder` to `GridView.builder` with `SliverGridDelegateWithMaxCrossAxisExtent`.
|
|
54
|
+
- [ ] **Forms/text**: Wrap in `ConstrainedBox` with `BoxConstraints(maxWidth: ...)`.
|
|
55
|
+
- [ ] Wrap in `Center` to keep constrained content centered.
|
|
56
|
+
- [ ] Test on desktop/tablet -> review horizontal stretching.
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
### Adaptive Layout using LayoutBuilder
|
|
61
|
+
|
|
62
|
+
```dart
|
|
63
|
+
import 'package:flutter/material.dart';
|
|
64
|
+
|
|
65
|
+
const double largeScreenMinWidth = 600.0;
|
|
66
|
+
|
|
67
|
+
class AdaptiveLayout extends StatelessWidget {
|
|
68
|
+
const AdaptiveLayout({super.key});
|
|
69
|
+
|
|
70
|
+
@override
|
|
71
|
+
Widget build(BuildContext context) {
|
|
72
|
+
return LayoutBuilder(
|
|
73
|
+
builder: (context, constraints) {
|
|
74
|
+
if (constraints.maxWidth > largeScreenMinWidth) {
|
|
75
|
+
return Row(
|
|
76
|
+
children: [
|
|
77
|
+
const SizedBox(width: 250, child: Placeholder(color: Colors.blue)),
|
|
78
|
+
const VerticalDivider(width: 1),
|
|
79
|
+
Expanded(child: const Placeholder(color: Colors.green)),
|
|
80
|
+
],
|
|
81
|
+
);
|
|
82
|
+
} else {
|
|
83
|
+
return const Placeholder(color: Colors.green);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Constraining Width on Large Screens
|
|
92
|
+
|
|
93
|
+
```dart
|
|
94
|
+
class ConstrainedContent extends StatelessWidget {
|
|
95
|
+
const ConstrainedContent({super.key});
|
|
96
|
+
|
|
97
|
+
@override
|
|
98
|
+
Widget build(BuildContext context) {
|
|
99
|
+
return Scaffold(
|
|
100
|
+
body: Center(
|
|
101
|
+
child: ConstrainedBox(
|
|
102
|
+
constraints: const BoxConstraints(maxWidth: 800.0),
|
|
103
|
+
child: ListView.builder(
|
|
104
|
+
itemCount: 50,
|
|
105
|
+
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
|
|
106
|
+
),
|
|
107
|
+
),
|
|
108
|
+
),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Flutter Ultra Integration
|
|
115
|
+
|
|
116
|
+
After building the layout, verify responsiveness across breakpoints:
|
|
117
|
+
|
|
118
|
+
- `mcp__plugin_flutter_flutter-ultra-runtime__audit_responsive` — Automated responsive audit at multiple viewport sizes
|
|
119
|
+
- `mcp__plugin_flutter_flutter-ultra-runtime__screenshot` — Capture screenshots at each breakpoint
|
|
120
|
+
- `mcp__plugin_flutter_flutter-ultra-runtime__dump_render_tree` — Inspect render tree for constraint issues
|
|
121
|
+
- `mcp__plugin_flutter_flutter-ultra-runtime__get_runtime_errors` — Check for overflow errors at different sizes
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
> **Attribution:** This skill is vendored from [flutter/skills](https://github.com/flutter/skills) (BSD-3-Clause).
|
|
126
|
+
> Synced by `scripts/sync-upstream-skills.mjs`. Do not edit manually — changes will be overwritten on next sync.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: collect-coverage
|
|
3
|
+
description: Collect coverage using the coverage package and create an LCOV report
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Implementing Dart and Flutter Test Coverage
|
|
7
|
+
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Testing Fundamentals](#testing-fundamentals)
|
|
11
|
+
- [Coverage Directives](#coverage-directives)
|
|
12
|
+
- [Workflow: Configuring and Generating Coverage Reports](#workflow-configuring-and-generating-coverage-reports)
|
|
13
|
+
- [Workflow: Advanced Manual Coverage Collection](#workflow-advanced-manual-coverage-collection)
|
|
14
|
+
- [Examples](#examples)
|
|
15
|
+
|
|
16
|
+
## Testing Fundamentals
|
|
17
|
+
|
|
18
|
+
Structure your test suites using the standard Dart testing paradigms. Use `package:test` for Dart projects and `flutter_test` for Flutter projects.
|
|
19
|
+
|
|
20
|
+
- **Unit Tests:** Verify individual functions, methods, or classes.
|
|
21
|
+
- **Component/Widget Tests:** Verify component behavior, layout, and interaction using mock objects (`package:mockito`).
|
|
22
|
+
- **Integration Tests:** Verify entire app flows on simulated or real devices.
|
|
23
|
+
|
|
24
|
+
## Coverage Directives
|
|
25
|
+
|
|
26
|
+
Exclude specific lines, blocks, or entire files from coverage metrics using inline comments. Pass the `--check-ignore` flag during formatting to enforce these directives.
|
|
27
|
+
|
|
28
|
+
- Ignore a single line: `// coverage:ignore-line`
|
|
29
|
+
- Ignore a block of code: `// coverage:ignore-start` and `// coverage:ignore-end`
|
|
30
|
+
- Ignore an entire file: `// coverage:ignore-file`
|
|
31
|
+
|
|
32
|
+
## Workflow: Configuring and Generating Coverage Reports
|
|
33
|
+
|
|
34
|
+
Follow this sequential workflow to add the coverage package, execute tests, and generate an LCOV report.
|
|
35
|
+
|
|
36
|
+
**Task Progress Checklist:**
|
|
37
|
+
|
|
38
|
+
- [ ] 1. Add `coverage` as a `dev_dependency`.
|
|
39
|
+
- [ ] 2. Execute the automated coverage script.
|
|
40
|
+
- [ ] 3. Validate the LCOV output.
|
|
41
|
+
|
|
42
|
+
### 1. Add Dependencies
|
|
43
|
+
|
|
44
|
+
Add the `coverage` package as a `dev_dependency` to your project. Do not add it to standard dependencies.
|
|
45
|
+
|
|
46
|
+
If working in a standard Dart project:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
dart pub add dev:coverage
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If working in a Flutter project:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
flutter pub add dev:coverage
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Collect Coverage and Generate LCOV
|
|
59
|
+
|
|
60
|
+
Use the bundled `test_with_coverage` script. This script automatically runs all tests, collects the JSON coverage data from the Dart VM, and formats it into an LCOV report.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
dart run coverage:test_with_coverage
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. Feedback Loop: Validate Output
|
|
67
|
+
|
|
68
|
+
1. Verify that the `coverage/` directory was created in the project root.
|
|
69
|
+
2. Ensure `coverage/coverage.json` (raw data) and `coverage/lcov.info` (formatted report) exist.
|
|
70
|
+
3. If coverage is missing for specific files, ensure they are imported and executed by your test files, or add `// coverage:ignore-file` if they are intentionally excluded.
|
|
71
|
+
|
|
72
|
+
## Workflow: Advanced Manual Coverage Collection
|
|
73
|
+
|
|
74
|
+
If you require granular control over the VM service, isolate pausing, or need branch/function-level coverage, use the manual collection workflow.
|
|
75
|
+
|
|
76
|
+
**Task Progress Checklist:**
|
|
77
|
+
|
|
78
|
+
- [ ] 1. Run tests with VM service enabled.
|
|
79
|
+
- [ ] 2. Collect raw JSON coverage.
|
|
80
|
+
- [ ] 3. Format JSON to LCOV.
|
|
81
|
+
|
|
82
|
+
### 1. Run Tests with VM Service
|
|
83
|
+
|
|
84
|
+
Execute tests while pausing isolates on exit and exposing the VM service on a specific port (e.g., 8181).
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
dart run --pause-isolates-on-exit --disable-service-auth-codes --enable-vm-service=8181 test &
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 2. Collect Raw Coverage
|
|
91
|
+
|
|
92
|
+
Extract the coverage data from the running VM service and output it to a JSON file.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
dart run coverage:collect_coverage --wait-paused --uri=http://127.0.0.1:8181/ -o coverage/coverage.json --resume-isolates
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3. Format to LCOV
|
|
99
|
+
|
|
100
|
+
Convert the raw JSON data into the standard LCOV format.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
dart run coverage:format_coverage --packages=.dart_tool/package_config.json --lcov -i coverage/coverage.json -o coverage/lcov.info --check-ignore
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Examples
|
|
107
|
+
|
|
108
|
+
### Example: `pubspec.yaml` Configuration
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
name: my_dart_app
|
|
112
|
+
environment:
|
|
113
|
+
sdk: ^3.0.0
|
|
114
|
+
|
|
115
|
+
dependencies:
|
|
116
|
+
path: ^1.8.0
|
|
117
|
+
|
|
118
|
+
dev_dependencies:
|
|
119
|
+
test: ^1.24.0
|
|
120
|
+
coverage: ^1.15.0
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Example: Applying Ignore Directives
|
|
124
|
+
|
|
125
|
+
```dart
|
|
126
|
+
// coverage:ignore-file
|
|
127
|
+
import 'package:meta/meta.dart';
|
|
128
|
+
|
|
129
|
+
class SystemConfig {
|
|
130
|
+
final String env;
|
|
131
|
+
|
|
132
|
+
SystemConfig(this.env);
|
|
133
|
+
|
|
134
|
+
// coverage:ignore-start
|
|
135
|
+
void legacyInit() {
|
|
136
|
+
print('Deprecated initialization');
|
|
137
|
+
}
|
|
138
|
+
// coverage:ignore-end
|
|
139
|
+
|
|
140
|
+
bool isProduction() {
|
|
141
|
+
if (env == 'prod') return true;
|
|
142
|
+
return false; // coverage:ignore-line
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Flutter Ultra Integration
|
|
148
|
+
|
|
149
|
+
Collect coverage directly via the test runner:
|
|
150
|
+
|
|
151
|
+
- `mcp__plugin_flutter_flutter-ultra-build__start_run_unit_tests` — Run tests with `coverage: true` to collect LCOV data
|
|
152
|
+
- `mcp__plugin_flutter_flutter-ultra-build__get_run_unit_tests_result` — Get results including coverage report path
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
> **Attribution:** This skill is vendored from [dart-lang/skills](https://github.com/dart-lang/skills) (BSD-3-Clause).
|
|
157
|
+
> Synced by `scripts/sync-upstream-skills.mjs`. Do not edit manually — changes will be overwritten on next sync.
|