runable
This commit is contained in:
729
docs/PROVIDERS_DOCUMENTATION.md
Normal file
729
docs/PROVIDERS_DOCUMENTATION.md
Normal file
@@ -0,0 +1,729 @@
|
||||
# Riverpod 3.0 State Management - Complete Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This document provides comprehensive documentation for all Riverpod 3.0 providers in the Retail POS application. All providers use code generation with the `@riverpod` annotation.
|
||||
|
||||
---
|
||||
|
||||
## 1. Cart Management Providers
|
||||
|
||||
### Location: `/lib/features/home/presentation/providers/`
|
||||
|
||||
### 1.1 CartProvider (`cart_provider.dart`)
|
||||
|
||||
**Purpose**: Manages shopping cart state with full CRUD operations.
|
||||
|
||||
**Type**: `Notifier<List<CartItem>>`
|
||||
|
||||
**State**: `List<CartItem>`
|
||||
|
||||
**Methods**:
|
||||
- `addItem(Product product, int quantity)` - Add product to cart or update quantity
|
||||
- `removeItem(String productId)` - Remove item from cart
|
||||
- `updateQuantity(String productId, int newQuantity)` - Update item quantity
|
||||
- `incrementQuantity(String productId)` - Increase quantity by 1
|
||||
- `decrementQuantity(String productId)` - Decrease quantity by 1
|
||||
- `clearCart()` - Clear all items
|
||||
- `containsProduct(String productId)` - Check if product exists
|
||||
- `getProductQuantity(String productId)` - Get current quantity
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch cart state
|
||||
final cartItems = ref.watch(cartProvider);
|
||||
|
||||
// Add to cart
|
||||
ref.read(cartProvider.notifier).addItem(product, 1);
|
||||
|
||||
// Update quantity
|
||||
ref.read(cartProvider.notifier).updateQuantity('product-1', 3);
|
||||
|
||||
// Clear cart
|
||||
ref.read(cartProvider.notifier).clearCart();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.2 CartTotalProvider (`cart_total_provider.dart`)
|
||||
|
||||
**Purpose**: Calculates cart totals including subtotal, tax, and total.
|
||||
|
||||
**Type**: `Notifier<CartTotalData>`
|
||||
|
||||
**State**: `CartTotalData` (subtotal, tax, taxRate, total, itemCount)
|
||||
|
||||
**Dependencies**:
|
||||
- `cartProvider` - For cart items
|
||||
- `settingsProvider` - For tax rate
|
||||
|
||||
**Methods**:
|
||||
- `applyDiscount(double discountAmount)` - Calculate total with flat discount
|
||||
- `applyDiscountPercentage(double discountPercent)` - Calculate total with percentage discount
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch cart totals
|
||||
final totals = ref.watch(cartTotalProvider);
|
||||
|
||||
// Access values
|
||||
print('Subtotal: ${totals.subtotal}');
|
||||
print('Tax: ${totals.tax}');
|
||||
print('Total: ${totals.total}');
|
||||
print('Items: ${totals.itemCount}');
|
||||
|
||||
// Apply discount
|
||||
final discounted = ref.read(cartTotalProvider.notifier).applyDiscount(10.0);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.3 CartItemCountProvider (`cart_item_count_provider.dart`)
|
||||
|
||||
**Purpose**: Provides optimized cart item counts.
|
||||
|
||||
**Type**: Function provider (computed value)
|
||||
|
||||
**Providers**:
|
||||
- `cartItemCount` - Total quantity of all items
|
||||
- `cartUniqueItemCount` - Number of unique products
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Total items quantity
|
||||
final totalItems = ref.watch(cartItemCountProvider);
|
||||
|
||||
// Unique items count
|
||||
final uniqueItems = ref.watch(cartUniqueItemCountProvider);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Products Management Providers
|
||||
|
||||
### Location: `/lib/features/products/presentation/providers/`
|
||||
|
||||
### 2.1 ProductLocalDataSourceProvider (`product_datasource_provider.dart`)
|
||||
|
||||
**Purpose**: Dependency injection for product data source.
|
||||
|
||||
**Type**: `Provider<ProductLocalDataSource>` (keepAlive)
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
final dataSource = ref.read(productLocalDataSourceProvider);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.2 ProductsProvider (`products_provider.dart`)
|
||||
|
||||
**Purpose**: Fetches and manages all products from Hive.
|
||||
|
||||
**Type**: `AsyncNotifier<List<Product>>`
|
||||
|
||||
**State**: `AsyncValue<List<Product>>`
|
||||
|
||||
**Methods**:
|
||||
- `refresh()` - Refresh products from data source
|
||||
- `syncProducts()` - Sync with remote API
|
||||
- `getProductById(String id)` - Get specific product
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch products
|
||||
final productsAsync = ref.watch(productsProvider);
|
||||
|
||||
productsAsync.when(
|
||||
data: (products) => ProductGrid(products: products),
|
||||
loading: () => CircularProgressIndicator(),
|
||||
error: (error, stack) => ErrorWidget(error),
|
||||
);
|
||||
|
||||
// Refresh products
|
||||
await ref.read(productsProvider.notifier).refresh();
|
||||
|
||||
// Sync products
|
||||
await ref.read(productsProvider.notifier).syncProducts();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.3 SearchQueryProvider (`search_query_provider.dart`)
|
||||
|
||||
**Purpose**: Manages product search query state.
|
||||
|
||||
**Type**: `Notifier<String>`
|
||||
|
||||
**State**: `String` (search query)
|
||||
|
||||
**Methods**:
|
||||
- `setQuery(String query)` - Update search query
|
||||
- `clear()` - Clear search
|
||||
- `isSearching` - Check if search is active
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch search query
|
||||
final query = ref.watch(searchQueryProvider);
|
||||
|
||||
// Update search
|
||||
ref.read(searchQueryProvider.notifier).setQuery('laptop');
|
||||
|
||||
// Clear search
|
||||
ref.read(searchQueryProvider.notifier).clear();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.4 SelectedCategoryProvider (`selected_category_provider.dart`)
|
||||
|
||||
**Purpose**: Manages selected category filter.
|
||||
|
||||
**Type**: `Notifier<String?>`
|
||||
|
||||
**State**: `String?` (category ID or null for all)
|
||||
|
||||
**Methods**:
|
||||
- `selectCategory(String? categoryId)` - Select category
|
||||
- `clearSelection()` - Clear filter (show all)
|
||||
- `hasSelection` - Check if category selected
|
||||
- `isSelected(String categoryId)` - Check specific category
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch selected category
|
||||
final categoryId = ref.watch(selectedCategoryProvider);
|
||||
|
||||
// Select category
|
||||
ref.read(selectedCategoryProvider.notifier).selectCategory('electronics');
|
||||
|
||||
// Clear filter
|
||||
ref.read(selectedCategoryProvider.notifier).clearSelection();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.5 FilteredProductsProvider (`filtered_products_provider.dart`)
|
||||
|
||||
**Purpose**: Combines search and category filtering.
|
||||
|
||||
**Type**: `Notifier<List<Product>>`
|
||||
|
||||
**State**: `List<Product>` (filtered results)
|
||||
|
||||
**Dependencies**:
|
||||
- `productsProvider` - All products
|
||||
- `searchQueryProvider` - Search query
|
||||
- `selectedCategoryProvider` - Category filter
|
||||
|
||||
**Getters**:
|
||||
- `availableCount` - Count of available products
|
||||
- `outOfStockCount` - Count of out-of-stock products
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch filtered products (automatically updates when filters change)
|
||||
final filtered = ref.watch(filteredProductsProvider);
|
||||
|
||||
// Get counts
|
||||
final available = ref.read(filteredProductsProvider.notifier).availableCount;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.6 SortedProductsProvider (`filtered_products_provider.dart`)
|
||||
|
||||
**Purpose**: Sorts filtered products by various options.
|
||||
|
||||
**Type**: `Notifier<List<Product>>` with family parameter
|
||||
|
||||
**Parameters**: `ProductSortOption` enum
|
||||
|
||||
**Sort Options**:
|
||||
- `nameAsc` - Name A-Z
|
||||
- `nameDesc` - Name Z-A
|
||||
- `priceAsc` - Price low to high
|
||||
- `priceDesc` - Price high to low
|
||||
- `newest` - Newest first
|
||||
- `oldest` - Oldest first
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch sorted products
|
||||
final sorted = ref.watch(sortedProductsProvider(ProductSortOption.priceAsc));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Categories Management Providers
|
||||
|
||||
### Location: `/lib/features/categories/presentation/providers/`
|
||||
|
||||
### 3.1 CategoryLocalDataSourceProvider (`category_datasource_provider.dart`)
|
||||
|
||||
**Purpose**: Dependency injection for category data source.
|
||||
|
||||
**Type**: `Provider<CategoryLocalDataSource>` (keepAlive)
|
||||
|
||||
---
|
||||
|
||||
### 3.2 CategoriesProvider (`categories_provider.dart`)
|
||||
|
||||
**Purpose**: Fetches and manages all categories.
|
||||
|
||||
**Type**: `AsyncNotifier<List<Category>>`
|
||||
|
||||
**State**: `AsyncValue<List<Category>>`
|
||||
|
||||
**Methods**:
|
||||
- `refresh()` - Refresh categories
|
||||
- `syncCategories()` - Sync with remote API
|
||||
- `getCategoryById(String id)` - Get category
|
||||
- `getCategoryName(String id)` - Get category name
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch categories
|
||||
final categoriesAsync = ref.watch(categoriesProvider);
|
||||
|
||||
categoriesAsync.when(
|
||||
data: (categories) => CategoryGrid(categories: categories),
|
||||
loading: () => CircularProgressIndicator(),
|
||||
error: (error, stack) => ErrorWidget(error),
|
||||
);
|
||||
|
||||
// Get category name
|
||||
final name = ref.read(categoriesProvider.notifier).getCategoryName('electronics');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 CategoryProductCountProvider (`category_product_count_provider.dart`)
|
||||
|
||||
**Purpose**: Calculates product count per category.
|
||||
|
||||
**Type**: Function provider with family parameter
|
||||
|
||||
**Providers**:
|
||||
- `categoryProductCount(String categoryId)` - Count for specific category
|
||||
- `allCategoryProductCounts` - Map of all counts
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch count for specific category
|
||||
final count = ref.watch(categoryProductCountProvider('electronics'));
|
||||
|
||||
// Watch all counts
|
||||
final allCounts = ref.watch(allCategoryProductCountsProvider);
|
||||
print('Electronics: ${allCounts['electronics']}');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Settings Management Providers
|
||||
|
||||
### Location: `/lib/features/settings/presentation/providers/`
|
||||
|
||||
### 4.1 SettingsLocalDataSourceProvider (`settings_datasource_provider.dart`)
|
||||
|
||||
**Purpose**: Dependency injection for settings data source.
|
||||
|
||||
**Type**: `Provider<SettingsLocalDataSource>` (keepAlive)
|
||||
|
||||
---
|
||||
|
||||
### 4.2 SettingsProvider (`settings_provider.dart`)
|
||||
|
||||
**Purpose**: Manages all app settings.
|
||||
|
||||
**Type**: `AsyncNotifier<AppSettings>` (keepAlive)
|
||||
|
||||
**State**: `AsyncValue<AppSettings>`
|
||||
|
||||
**Methods**:
|
||||
- `updateThemeMode(ThemeMode mode)` - Update theme
|
||||
- `updateLanguage(String language)` - Update language
|
||||
- `updateTaxRate(double taxRate)` - Update tax rate
|
||||
- `updateStoreName(String storeName)` - Update store name
|
||||
- `updateCurrency(String currency)` - Update currency
|
||||
- `toggleSync()` - Toggle sync on/off
|
||||
- `updateLastSyncTime()` - Update sync timestamp
|
||||
- `resetToDefaults()` - Reset all settings
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch settings
|
||||
final settingsAsync = ref.watch(settingsProvider);
|
||||
|
||||
// Update theme
|
||||
await ref.read(settingsProvider.notifier).updateThemeMode(ThemeMode.dark);
|
||||
|
||||
// Update tax rate
|
||||
await ref.read(settingsProvider.notifier).updateTaxRate(0.08);
|
||||
|
||||
// Reset settings
|
||||
await ref.read(settingsProvider.notifier).resetToDefaults();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3 ThemeProvider (`theme_provider.dart`)
|
||||
|
||||
**Purpose**: Extracts theme-related data from settings.
|
||||
|
||||
**Type**: Function providers (computed values)
|
||||
|
||||
**Providers**:
|
||||
- `themeModeProvider` - Current theme mode
|
||||
- `isDarkModeProvider` - Check if dark mode
|
||||
- `isLightModeProvider` - Check if light mode
|
||||
- `isSystemThemeProvider` - Check if system theme
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch theme mode
|
||||
final theme = ref.watch(themeModeProvider);
|
||||
|
||||
// Check dark mode
|
||||
final isDark = ref.watch(isDarkModeProvider);
|
||||
|
||||
// Use in MaterialApp
|
||||
MaterialApp(
|
||||
themeMode: ref.watch(themeModeProvider),
|
||||
// ...
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.4 LanguageProvider (`language_provider.dart`)
|
||||
|
||||
**Purpose**: Manages language/locale settings.
|
||||
|
||||
**Type**: Function providers
|
||||
|
||||
**Providers**:
|
||||
- `appLanguageProvider` - Current language code
|
||||
- `supportedLanguagesProvider` - List of available languages
|
||||
|
||||
**Model**: `LanguageOption` (code, name, nativeName)
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch current language
|
||||
final language = ref.watch(appLanguageProvider);
|
||||
|
||||
// Get supported languages
|
||||
final languages = ref.watch(supportedLanguagesProvider);
|
||||
|
||||
// Display language selector
|
||||
DropdownButton(
|
||||
value: language,
|
||||
items: languages.map((lang) => DropdownMenuItem(
|
||||
value: lang.code,
|
||||
child: Text(lang.nativeName),
|
||||
)).toList(),
|
||||
onChanged: (code) => ref.read(settingsProvider.notifier).updateLanguage(code!),
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Core Providers
|
||||
|
||||
### Location: `/lib/core/providers/`
|
||||
|
||||
### 5.1 NetworkInfoProvider (`network_info_provider.dart`)
|
||||
|
||||
**Purpose**: Network connectivity management.
|
||||
|
||||
**Type**: Multiple providers
|
||||
|
||||
**Providers**:
|
||||
- `connectivityProvider` - Connectivity instance (keepAlive)
|
||||
- `networkInfoProvider` - NetworkInfo implementation (keepAlive)
|
||||
- `isConnectedProvider` - Check if connected
|
||||
- `connectivityStreamProvider` - Stream of connectivity changes
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Check if connected
|
||||
final isConnected = await ref.read(isConnectedProvider.future);
|
||||
|
||||
// Watch connectivity changes
|
||||
ref.listen(connectivityStreamProvider, (previous, next) {
|
||||
next.when(
|
||||
data: (connected) {
|
||||
if (connected) {
|
||||
print('Connected to internet');
|
||||
} else {
|
||||
print('Offline');
|
||||
}
|
||||
},
|
||||
loading: () {},
|
||||
error: (e, s) {},
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.2 SyncStatusProvider (`sync_status_provider.dart`)
|
||||
|
||||
**Purpose**: Manages data synchronization state.
|
||||
|
||||
**Type**: `AsyncNotifier<SyncResult>`
|
||||
|
||||
**State**: `AsyncValue<SyncResult>`
|
||||
|
||||
**Models**:
|
||||
- `SyncResult` (status, lastSyncTime, message, error)
|
||||
- `SyncState` enum (idle, syncing, success, failed, offline)
|
||||
|
||||
**Methods**:
|
||||
- `syncAll()` - Sync all data (categories + products)
|
||||
- `syncProducts()` - Sync only products
|
||||
- `syncCategories()` - Sync only categories
|
||||
- `resetStatus()` - Reset to idle state
|
||||
|
||||
**Getters**:
|
||||
- `isSyncing` - Check if syncing
|
||||
- `isSuccess` - Check if successful
|
||||
- `isFailed` - Check if failed
|
||||
- `isOffline` - Check if offline
|
||||
- `isIdle` - Check if idle
|
||||
|
||||
**Additional Providers**:
|
||||
- `lastSyncTimeProvider` - Get last sync time from settings
|
||||
|
||||
**Usage**:
|
||||
```dart
|
||||
// Watch sync status
|
||||
final syncAsync = ref.watch(syncStatusProvider);
|
||||
|
||||
syncAsync.when(
|
||||
data: (result) {
|
||||
if (result.isSyncing) {
|
||||
return CircularProgressIndicator();
|
||||
} else if (result.isSuccess) {
|
||||
return Text('Synced: ${result.lastSyncTime}');
|
||||
} else if (result.isFailed) {
|
||||
return Text('Error: ${result.message}');
|
||||
}
|
||||
return SyncButton();
|
||||
},
|
||||
loading: () => CircularProgressIndicator(),
|
||||
error: (e, s) => ErrorWidget(e),
|
||||
);
|
||||
|
||||
// Trigger sync
|
||||
await ref.read(syncStatusProvider.notifier).syncAll();
|
||||
|
||||
// Sync only products
|
||||
await ref.read(syncStatusProvider.notifier).syncProducts();
|
||||
|
||||
// Get last sync time
|
||||
final lastSync = ref.watch(lastSyncTimeProvider);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Provider Dependencies Graph
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ CORE PROVIDERS │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ - networkInfoProvider (keepAlive) │
|
||||
│ - connectivityProvider (keepAlive) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ SYNC STATUS PROVIDER │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Depends on: networkInfo, products, categories, settings │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────┼──────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ PRODUCTS │ │ CATEGORIES │ │ SETTINGS │
|
||||
│ - products │ │ - categories │ │ - settings │
|
||||
│ (async) │ │ (async) │ │ (async) │
|
||||
└──────────────────┘ └──────────────┘ └──────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ FILTERED │ │ CATEGORY │ │ THEME │
|
||||
│ PRODUCTS │ │ COUNTS │ │ LANGUAGE │
|
||||
│ - search query │ │ - product │ │ - theme mode │
|
||||
│ - selected cat │ │ counts │ │ - language │
|
||||
│ - filtered list │ │ │ │ │
|
||||
└──────────────────┘ └──────────────┘ └──────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ CART │
|
||||
│ - cart items │
|
||||
│ - cart total │
|
||||
│ - item count │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Generation
|
||||
|
||||
### Running Code Generator
|
||||
|
||||
```bash
|
||||
# One-time build
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
# Watch mode (auto-rebuild on changes)
|
||||
dart run build_runner watch --delete-conflicting-outputs
|
||||
|
||||
# Clean and rebuild
|
||||
dart run build_runner clean
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
```
|
||||
|
||||
### Generated Files
|
||||
|
||||
Each provider file with `@riverpod` annotation generates a corresponding `.g.dart` file:
|
||||
|
||||
- `cart_provider.dart` → `cart_provider.g.dart`
|
||||
- `products_provider.dart` → `products_provider.g.dart`
|
||||
- `categories_provider.dart` → `categories_provider.g.dart`
|
||||
- etc.
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Use .select() for Performance**
|
||||
```dart
|
||||
// Bad - rebuilds on any cart change
|
||||
final cart = ref.watch(cartProvider);
|
||||
|
||||
// Good - rebuilds only when length changes
|
||||
final itemCount = ref.watch(cartProvider.select((items) => items.length));
|
||||
```
|
||||
|
||||
### 2. **Use AsyncValue Properly**
|
||||
```dart
|
||||
// Use .when() for simple cases
|
||||
productsAsync.when(
|
||||
data: (data) => Text('$data'),
|
||||
loading: () => Loading(),
|
||||
error: (e, s) => Error(e),
|
||||
);
|
||||
|
||||
// Use pattern matching for complex cases
|
||||
switch (productsAsync) {
|
||||
case AsyncData(:final value):
|
||||
return ProductList(value);
|
||||
case AsyncError(:final error):
|
||||
return ErrorWidget(error);
|
||||
case AsyncLoading():
|
||||
return LoadingWidget();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **Check ref.mounted in Async Operations**
|
||||
```dart
|
||||
Future<void> updateData() async {
|
||||
state = const AsyncValue.loading();
|
||||
|
||||
await someAsyncOperation();
|
||||
|
||||
// Always check if still mounted
|
||||
if (!ref.mounted) return;
|
||||
|
||||
state = AsyncValue.data(result);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. **Use keepAlive for Dependencies**
|
||||
```dart
|
||||
// Dependency injection providers should be keepAlive
|
||||
@Riverpod(keepAlive: true)
|
||||
ProductDataSource productDataSource(Ref ref) {
|
||||
return ProductDataSourceImpl();
|
||||
}
|
||||
```
|
||||
|
||||
### 5. **Invalidate vs Refresh**
|
||||
```dart
|
||||
// Invalidate - reset provider to initial state
|
||||
ref.invalidate(productsProvider);
|
||||
|
||||
// Refresh - invalidate and immediately read
|
||||
final products = ref.refresh(productsProvider);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Providers
|
||||
|
||||
### Unit Testing Example
|
||||
|
||||
```dart
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
void main() {
|
||||
test('Cart adds items correctly', () {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
// Initial state
|
||||
expect(container.read(cartProvider), isEmpty);
|
||||
|
||||
// Add item
|
||||
container.read(cartProvider.notifier).addItem(mockProduct, 1);
|
||||
|
||||
// Verify
|
||||
expect(container.read(cartProvider).length, 1);
|
||||
expect(container.read(cartItemCountProvider), 1);
|
||||
});
|
||||
|
||||
test('Filtered products work correctly', () async {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
// Wait for products to load
|
||||
await container.read(productsProvider.future);
|
||||
|
||||
// Set search query
|
||||
container.read(searchQueryProvider.notifier).setQuery('laptop');
|
||||
|
||||
// Check filtered results
|
||||
final filtered = container.read(filteredProductsProvider);
|
||||
expect(filtered.every((p) => p.name.toLowerCase().contains('laptop')), true);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**Total Providers Created**: 25+
|
||||
|
||||
### By Feature:
|
||||
- **Cart**: 3 providers
|
||||
- **Products**: 5 providers
|
||||
- **Categories**: 3 providers
|
||||
- **Settings**: 4 providers
|
||||
- **Core/Sync**: 5+ providers
|
||||
|
||||
### By Type:
|
||||
- **AsyncNotifier**: 4 (products, categories, settings, sync)
|
||||
- **Notifier**: 4 (cart, searchQuery, selectedCategory, filteredProducts)
|
||||
- **Function Providers**: 10+ (counts, theme, language, etc.)
|
||||
- **Dependency Injection**: 4 (data sources, network info)
|
||||
|
||||
All providers follow Riverpod 3.0 best practices with code generation!
|
||||
Reference in New Issue
Block a user