📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-10 16:04:20 +00:00
parent 2bb0dc8c1d
commit 92c0c3f687
594 changed files with 55224 additions and 19038 deletions
@@ -1,9 +1,14 @@
---
name: flutter-expert
description: Master Flutter development with Dart 3, advanced widgets, and multi-platform deployment.
risk: unknown
category: mobile
risk: safe
source: community
source_type: community
date_added: '2026-02-27'
author: Franklyn-R-Silva
tags: [flutter, dart, mobile, cross-platform, riverpod]
tools: [claude, cursor, gemini]
---
## Use this skill when
@@ -0,0 +1,214 @@
# Flutter Implementation Playbook
Concrete, copy-adaptable patterns for the `flutter-expert` skill. Every snippet
targets **Flutter 3.x + Dart 3.x** with null safety. Use these as starting
points, then adapt to the project's architecture and constraints.
---
## 1. Recommended Project Structure (feature-first + clean layers)
```
lib/
main.dart
core/ # cross-cutting: theme, router, errors, DI
errors/failure.dart
network/dio_client.dart
features/
products/
data/ # models, DTOs, repositories impl
domain/ # entities, repository contracts, use cases
presentation/ # widgets, screens, providers/controllers
```
**Rule of thumb:** `presentation` may import `domain`; `data` implements
`domain` contracts; `domain` imports nothing from Flutter. This keeps business
logic testable without a widget tree.
---
## 2. State Management with Riverpod 2.x (recommended default)
Riverpod gives compile-time safety and easy testing. Prefer code-generation
(`riverpod_generator`) for new projects.
```dart
// products_controller.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'products_controller.g.dart';
@riverpod
class ProductsController extends _$ProductsController {
@override
Future<List<Product>> build() async {
// The return value is exposed as AsyncValue<List<Product>>.
return ref.watch(productRepositoryProvider).fetchAll();
}
Future<void> refresh() async {
state = const AsyncLoading();
state = await AsyncValue.guard(
() => ref.read(productRepositoryProvider).fetchAll(),
);
}
}
```
Consume it with explicit loading/error/data states — never assume data is
ready:
```dart
class ProductsScreen extends ConsumerWidget {
const ProductsScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final productsAsync = ref.watch(productsControllerProvider);
return productsAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, _) => ErrorView(message: err.toString()),
data: (products) => ListView.builder(
itemCount: products.length,
itemBuilder: (_, i) => ProductTile(product: products[i]),
),
);
}
}
```
---
## 3. Repository + Dio with error mapping
Keep network failures out of the UI. Map them to a typed `Failure` in the data
layer.
```dart
sealed class Failure {
const Failure(this.message);
final String message;
// Override toString so UI code that renders err.toString() shows the
// mapped message instead of "Instance of 'NetworkFailure'".
@override
String toString() => message;
}
class NetworkFailure extends Failure {
const NetworkFailure(super.message);
}
class ProductRepository {
ProductRepository(this._dio);
final Dio _dio;
Future<List<Product>> fetchAll() async {
try {
final res = await _dio.get('/products');
return (res.data as List)
.map((json) => Product.fromJson(json as Map<String, dynamic>))
.toList();
} on DioException catch (e) {
throw NetworkFailure('Failed to load products: ${e.message}');
}
}
}
```
---
## 4. Performance: rebuilds, const, and keys
- Mark widgets `const` whenever their inputs are compile-time constants — this
lets Flutter skip rebuilds entirely.
- Split large `build` methods into smaller widgets so only the changing subtree
rebuilds.
- Use `ListView.builder` / slivers for long or infinite lists (never map a huge
list into a `Column`).
- Give list items stable `Key`s when their order can change.
```dart
// Good: const stops this subtree from rebuilding on parent changes.
const _Header(title: 'Products');
// Bad: rebuilding a giant Column holds every child in memory.
Column(children: products.map(ProductTile.new).toList());
```
Profile with **Flutter DevTools → Performance** and enable the "Rebuild
counts" overlay to find widgets rebuilding more than expected.
---
## 5. Widget & golden testing
```dart
void main() {
testWidgets('shows product name', (tester) async {
await tester.pumpWidget(
const MaterialApp(home: ProductTile(product: Product(name: 'Seeds'))),
);
expect(find.text('Seeds'), findsOneWidget);
});
testWidgets('golden matches baseline', (tester) async {
await tester.pumpWidget(
const MaterialApp(home: ProductTile(product: Product(name: 'Seeds'))),
);
await expectLater(
find.byType(ProductTile),
matchesGoldenFile('goldens/product_tile.png'),
);
});
}
```
Run `flutter test --update-goldens` once to create the baseline, then commit the
PNG so CI can catch visual regressions.
---
## 6. Async & isolates for CPU-bound work
Never block the UI isolate with heavy work (parsing large JSON, image
processing). Offload with `compute`:
```dart
Future<List<Product>> parseProducts(String rawJson) {
return compute(_decode, rawJson); // runs on a background isolate
}
List<Product> _decode(String rawJson) =>
(jsonDecode(rawJson) as List)
.map((e) => Product.fromJson(e as Map<String, dynamic>))
.toList();
```
---
## 7. Common pitfalls
- **Problem:** `setState` called after `dispose``mounted` exception.
**Solution:** guard with `if (!mounted) return;` after any `await`.
- **Problem:** Rebuilding the whole screen on every keystroke.
**Solution:** isolate the changing widget or use a `select` on the provider.
- **Problem:** Memory leaks from uncancelled `StreamSubscription` / controllers.
**Solution:** cancel/dispose in `dispose()`; with Riverpod use `ref.onDispose`.
- **Problem:** Blocking the UI thread with synchronous file/JSON work.
**Solution:** move it to an isolate via `compute` (section 6).
---
## 8. Pre-ship checklist
- [ ] `flutter analyze` is clean (no warnings)
- [ ] `flutter test` passes, including golden tests
- [ ] Widgets use `const` where possible; long lists use builders/slivers
- [ ] All loading/error/empty states are handled in the UI
- [ ] Controllers, streams, and subscriptions are disposed
- [ ] Tested on a real device for both iOS and Android
- [ ] Accessibility: semantic labels on interactive widgets, adequate contrast