This commit is contained in:
Phuoc Nguyen
2025-10-17 17:22:28 +07:00
parent 2125e85d40
commit 628c81ce13
86 changed files with 31339 additions and 1710 deletions

551
RIVERPOD_SUMMARY.md Normal file
View File

@@ -0,0 +1,551 @@
# Riverpod 3.0 Setup Summary - Worker Flutter App
## ✅ Setup Complete!
Riverpod 3.0 with code generation has been successfully configured for the Worker Flutter app.
## What Was Configured
### 1. Dependencies Updated (pubspec.yaml)
**Production:**
- `flutter_riverpod: ^3.0.0` - Core Riverpod package for Flutter
- `riverpod_annotation: ^3.0.0` - Annotations for code generation
**Development:**
- `build_runner: ^2.4.11` - Code generation engine
- `riverpod_generator: ^3.0.0` - Generates provider code
- `riverpod_lint: ^3.0.0` - Riverpod-specific linting
- `custom_lint: ^0.8.0` - Required for riverpod_lint
### 2. Build Configuration (build.yaml)
✅ Configured to auto-generate code for:
- `**_provider.dart` files
- `**/providers/*.dart` directories
- `**/notifiers/*.dart` directories
### 3. Linting (analysis_options.yaml)
✅ Enabled custom_lint with Riverpod rules:
- `provider_dependencies` - Proper dependency tracking
- `avoid_ref_read_inside_build` - Performance optimization
- `avoid_public_notifier_properties` - Encapsulation
- `functional_ref` - Proper ref usage
- `notifier_build` - Correct Notifier implementation
- And more...
### 4. App Initialization (main.dart)
✅ Wrapped with ProviderScope:
```dart
void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
```
### 5. Core Providers Created
#### **connectivity_provider.dart** - Network Monitoring
Four providers for connectivity management:
1. **connectivityProvider** - Connectivity instance
2. **connectivityStreamProvider** - Real-time connectivity stream
3. **currentConnectivityProvider** - One-time connectivity check
4. **isOnlineProvider** - Boolean online/offline stream
**Usage Example:**
```dart
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final connectivityState = ref.watch(connectivityStreamProvider);
return connectivityState.when(
data: (status) {
if (status == ConnectivityStatus.offline) {
return OfflineBanner();
}
return OnlineContent();
},
loading: () => CircularProgressIndicator(),
error: (error, _) => ErrorView(error),
);
}
}
```
#### **provider_examples.dart** - Comprehensive Examples
Complete examples of all Riverpod 3.0 patterns:
- ✅ Simple providers (immutable values)
- ✅ Async providers (FutureProvider pattern)
- ✅ Stream providers
- ✅ Notifier (mutable state with methods)
- ✅ AsyncNotifier (async mutable state)
- ✅ StreamNotifier (stream mutable state)
- ✅ Family (parameters as function arguments)
- ✅ Provider composition
- ✅ AutoDispose vs KeepAlive
- ✅ Lifecycle hooks
- ✅ Error handling with AsyncValue.guard()
- ✅ ref.mounted checks
- ✅ Invalidation and refresh
### 6. Documentation
**RIVERPOD_SETUP.md** - Complete setup guide with:
- Installation instructions
- Code generation commands
- Usage patterns and examples
- Testing strategies
- Migration guide from Riverpod 2.x
- Common issues and solutions
**lib/core/providers/README.md** - Provider architecture documentation
**scripts/setup_riverpod.sh** - Automated setup script
## Directory Structure
```
lib/core/providers/
├── connectivity_provider.dart # Network monitoring provider
├── connectivity_provider.g.dart # ✅ Generated code
├── provider_examples.dart # All Riverpod 3.0 patterns
├── provider_examples.g.dart # ✅ Generated code
└── README.md # Architecture docs
scripts/
└── setup_riverpod.sh # Automated setup script
Root files:
├── build.yaml # Build configuration
├── analysis_options.yaml # Linting configuration
├── RIVERPOD_SETUP.md # Complete guide
└── RIVERPOD_SUMMARY.md # This file
```
## ✅ Verification
All code generation completed successfully:
- ✅ connectivity_provider.g.dart generated
- ✅ provider_examples.g.dart generated
- ✅ No Riverpod-related errors in flutter analyze
- ✅ Dependencies installed
- ✅ ProviderScope configured
## Quick Commands
### Install Dependencies
```bash
flutter pub get
```
### Generate Provider Code
```bash
# One-time generation
dart run build_runner build --delete-conflicting-outputs
# Watch mode (recommended during development)
dart run build_runner watch -d
# Clean and rebuild
dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
```
### Run Linting
```bash
# Check for Riverpod issues
dart run custom_lint
# Auto-fix issues
dart run custom_lint --fix
```
### Analyze Code
```bash
flutter analyze
```
### Use Setup Script
```bash
./scripts/setup_riverpod.sh
```
## Riverpod 3.0 Key Features
### 1. @riverpod Annotation
```dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'my_provider.g.dart';
@riverpod
String myValue(MyValueRef ref) => 'Hello';
```
### 2. Family as Function Parameters
```dart
@riverpod
Future<User> user(UserRef ref, String userId) async {
return await fetchUser(userId);
}
// Usage
ref.watch(userProvider('user123'));
```
### 3. Notifier for Mutable State
```dart
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state++;
}
// Usage
ref.watch(counterProvider); // Get state
ref.read(counterProvider.notifier).increment(); // Call method
```
### 4. AsyncNotifier for Async Mutable State
```dart
@riverpod
class UserProfile extends _$UserProfile {
@override
Future<User> build() async => await fetchUser();
Future<void> update(String name) async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
return await updateUser(name);
});
}
}
```
### 5. Unified Ref Type
```dart
// All providers use the same Ref type
@riverpod
Future<String> example(ExampleRef ref) async {
ref.watch(provider1);
ref.read(provider2);
ref.listen(provider3, (prev, next) {});
}
```
### 6. ref.mounted Check
```dart
@riverpod
class Example extends _$Example {
@override
String build() => 'Initial';
Future<void> update() async {
await Future.delayed(Duration(seconds: 2));
// Check if still mounted
if (!ref.mounted) return;
state = 'Updated';
}
}
```
## Usage in Widgets
### ConsumerWidget
```dart
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final value = ref.watch(myProvider);
return Text(value);
}
}
```
### ConsumerStatefulWidget
```dart
class MyWidget extends ConsumerStatefulWidget {
@override
ConsumerState<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends ConsumerState<MyWidget> {
@override
Widget build(BuildContext context) {
final value = ref.watch(myProvider);
return Text(value);
}
}
```
### Consumer (for optimization)
```dart
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
return Text('$count');
},
)
```
## Best Practices
### ✅ DO
1. **Use .select() for optimization**
```dart
final name = ref.watch(userProvider.select((user) => user.name));
```
2. **Use AsyncValue.guard() for error handling**
```dart
state = await AsyncValue.guard(() async {
return await api.call();
});
```
3. **Check ref.mounted after async operations**
```dart
await Future.delayed(Duration(seconds: 1));
if (!ref.mounted) return;
state = newValue;
```
4. **Use autoDispose by default**
```dart
@riverpod // autoDispose by default
String example(ExampleRef ref) => 'value';
```
5. **Keep providers in dedicated directories**
```
lib/features/auth/presentation/providers/
lib/features/products/presentation/providers/
```
### ❌ DON'T
1. **Don't use ref.read() in build methods**
```dart
// BAD
Widget build(BuildContext context, WidgetRef ref) {
final value = ref.read(myProvider); // ❌
return Text(value);
}
// GOOD
Widget build(BuildContext context, WidgetRef ref) {
final value = ref.watch(myProvider); // ✅
return Text(value);
}
```
2. **Don't use StateNotifierProvider** (deprecated in Riverpod 3.0)
```dart
// Use Notifier instead
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state++;
}
```
3. **Don't forget the part directive**
```dart
// Required!
part 'my_provider.g.dart';
```
## Next Steps
### 1. For Feature Development
Create providers in feature-specific directories:
```
lib/features/auth/presentation/providers/
├── auth_provider.dart
├── auth_provider.g.dart # Generated
├── login_form_provider.dart
└── login_form_provider.g.dart # Generated
```
### 2. Provider Template
```dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'my_provider.g.dart';
@riverpod
class MyFeature extends _$MyFeature {
@override
MyState build() {
// Initialize
return MyState.initial();
}
void updateState() {
// Modify state
state = state.copyWith(/* ... */);
}
}
```
### 3. Run Code Generation
After creating a provider:
```bash
dart run build_runner watch -d
```
### 4. Use in Widgets
```dart
class MyScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(myFeatureProvider);
return Column(
children: [
Text(state.value),
ElevatedButton(
onPressed: () {
ref.read(myFeatureProvider.notifier).updateState();
},
child: Text('Update'),
),
],
);
}
}
```
## Testing
### Unit Test Example
```dart
test('counter increments', () {
final container = ProviderContainer();
addTearDown(container.dispose);
expect(container.read(counterProvider), 0);
container.read(counterProvider.notifier).increment();
expect(container.read(counterProvider), 1);
});
```
### Widget Test Example
```dart
testWidgets('displays user name', (tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
userProvider.overrideWith((ref) => User(name: 'Test')),
],
child: MaterialApp(home: UserScreen()),
),
);
expect(find.text('Test'), findsOneWidget);
});
```
## Examples Reference
All Riverpod 3.0 patterns are documented with working examples in:
📄 **lib/core/providers/provider_examples.dart**
This file includes:
- ✅ 11 different provider patterns
- ✅ Real code examples (not pseudocode)
- ✅ Detailed comments explaining each pattern
- ✅ Usage examples in comments
- ✅ Migration notes from Riverpod 2.x
## Connectivity Provider
The connectivity provider is a real-world example showing:
- ✅ Simple provider (Connectivity instance)
- ✅ Stream provider (connectivity changes)
- ✅ Future provider (one-time check)
- ✅ Derived provider (isOnline boolean)
- ✅ Proper documentation
- ✅ Usage examples
Use it as a template for creating your own providers!
## Resources
- 📚 [Riverpod Documentation](https://riverpod.dev)
- 📚 [Code Generation Guide](https://riverpod.dev/docs/concepts/about_code_generation)
- 📚 [Migration Guide](https://riverpod.dev/docs/migration/from_state_notifier)
- 📄 [Provider Examples](./lib/core/providers/provider_examples.dart)
- 📄 [Connectivity Provider](./lib/core/providers/connectivity_provider.dart)
- 📄 [Complete Setup Guide](./RIVERPOD_SETUP.md)
## Support & Help
If you encounter issues:
1. **Check examples** in provider_examples.dart
2. **Review documentation** in RIVERPOD_SETUP.md
3. **Run linting** with `dart run custom_lint`
4. **Check generated files** (*.g.dart) exist
5. **Verify part directive** is present in provider files
6. **Ensure ProviderScope** wraps the app in main.dart
## Common Issues & Solutions
### Issue: "Target of URI doesn't exist"
**Solution:** Run code generation:
```bash
dart run build_runner build --delete-conflicting-outputs
```
### Issue: "Classes can only mix in mixins"
**Solution:** Make sure the part directive is correct:
```dart
part 'my_provider.g.dart'; // Must match filename
```
### Issue: Provider not updating
**Solution:** Use ref.watch() in build, ref.read() in callbacks
### Issue: Too many rebuilds
**Solution:** Use .select() to watch specific fields
## Conclusion
✅ Riverpod 3.0 with code generation is fully configured and ready to use!
**Key Benefits:**
- ✅ Type-safe state management
- ✅ Less boilerplate with code generation
- ✅ Automatic provider type selection
- ✅ Better hot-reload support
- ✅ Comprehensive linting
- ✅ Excellent documentation
**You can now:**
1. Create providers using @riverpod annotation
2. Use connectivity monitoring immediately
3. Reference provider_examples.dart for patterns
4. Start building feature-specific providers
5. Test providers with ProviderContainer
**Happy coding! 🚀**