# 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(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 build() async => await fetchUser(); Future 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 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 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 createState() => _MyWidgetState(); } class _MyWidgetState extends ConsumerState { @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! 🚀**