This commit is contained in:
2025-10-28 00:09:46 +07:00
parent 9ebe7c2919
commit de49f564b1
110 changed files with 15392 additions and 3996 deletions

View File

@@ -0,0 +1,508 @@
# Riverpod Providers Quick Reference
## Essential Providers at a Glance
### Authentication
```dart
// Check if user is logged in
final isAuth = ref.watch(isAuthenticatedProvider);
// Get current user
final user = ref.watch(currentUserProvider);
// Login
ref.read(authProvider.notifier).login(username, password);
// Logout
ref.read(authProvider.notifier).logout();
// Check auth on app start
ref.read(authProvider.notifier).checkAuthStatus();
// Listen to auth changes
ref.listen<AuthState>(authProvider, (previous, next) {
if (next.isAuthenticated) {
// Navigate to home
}
if (next.error != null) {
// Show error
}
});
```
### Warehouse
```dart
// Load warehouses
ref.read(warehouseProvider.notifier).loadWarehouses();
// Get warehouses list
final warehouses = ref.watch(warehousesListProvider);
// Get selected warehouse
final selected = ref.watch(selectedWarehouseProvider);
// Select a warehouse
ref.read(warehouseProvider.notifier).selectWarehouse(warehouse);
// Clear selection
ref.read(warehouseProvider.notifier).clearSelection();
// Check loading state
final isLoading = ref.watch(isWarehouseLoadingProvider);
// Get error
final error = ref.watch(warehouseErrorProvider);
```
### Products
```dart
// Load products
ref.read(productsProvider.notifier).loadProducts(
warehouseId,
warehouseName,
'import', // or 'export'
);
// Get products list
final products = ref.watch(productsListProvider);
// Refresh products
ref.read(productsProvider.notifier).refreshProducts();
// Clear products
ref.read(productsProvider.notifier).clearProducts();
// Check loading state
final isLoading = ref.watch(isProductsLoadingProvider);
// Get products count
final count = ref.watch(productsCountProvider);
// Get operation type
final type = ref.watch(operationTypeProvider);
// Get error
final error = ref.watch(productsErrorProvider);
```
## Widget Setup
### ConsumerWidget (Stateless)
```dart
class MyPage extends ConsumerWidget {
const MyPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final data = ref.watch(someProvider);
return Widget();
}
}
```
### ConsumerStatefulWidget (Stateful)
```dart
class MyPage extends ConsumerStatefulWidget {
const MyPage({Key? key}) : super(key: key);
@override
ConsumerState<MyPage> createState() => _MyPageState();
}
class _MyPageState extends ConsumerState<MyPage> {
@override
void initState() {
super.initState();
// Load data on init
Future.microtask(() {
ref.read(someProvider.notifier).loadData();
});
}
@override
Widget build(BuildContext context) {
final data = ref.watch(someProvider);
return Widget();
}
}
```
## Common Patterns
### Pattern 1: Display Loading State
```dart
final isLoading = ref.watch(isAuthLoadingProvider);
return isLoading
? CircularProgressIndicator()
: YourContent();
```
### Pattern 2: Handle Errors
```dart
final error = ref.watch(authErrorProvider);
return Column(
children: [
if (error != null)
Text(error, style: TextStyle(color: Colors.red)),
YourContent(),
],
);
```
### Pattern 3: Conditional Navigation
```dart
ref.listen<AuthState>(authProvider, (previous, next) {
if (next.isAuthenticated) {
Navigator.pushReplacementNamed(context, '/home');
}
});
```
### Pattern 4: Pull to Refresh
```dart
RefreshIndicator(
onRefresh: () async {
await ref.read(warehouseProvider.notifier).refresh();
},
child: ListView(...),
)
```
### Pattern 5: Load Data on Page Open
```dart
@override
void initState() {
super.initState();
Future.microtask(() {
ref.read(warehouseProvider.notifier).loadWarehouses();
});
}
```
## Key Methods by Feature
### Auth Methods
- `login(username, password)` - Authenticate user
- `logout()` - Sign out user
- `checkAuthStatus()` - Check if token exists
- `clearError()` - Clear error message
- `reset()` - Reset to initial state
### Warehouse Methods
- `loadWarehouses()` - Fetch all warehouses
- `selectWarehouse(warehouse)` - Select a warehouse
- `clearSelection()` - Clear selected warehouse
- `refresh()` - Reload warehouses
- `clearError()` - Clear error message
- `reset()` - Reset to initial state
### Products Methods
- `loadProducts(warehouseId, name, type)` - Fetch products
- `refreshProducts()` - Reload current products
- `clearProducts()` - Clear products list
## Provider Types Explained
### Provider (Read-only)
```dart
// For services, repositories, use cases
final myServiceProvider = Provider<MyService>((ref) {
return MyService();
});
// Usage
final service = ref.watch(myServiceProvider);
```
### StateNotifierProvider (Mutable State)
```dart
// For managing mutable state
final myStateProvider = StateNotifierProvider<MyNotifier, MyState>((ref) {
return MyNotifier();
});
// Usage - watch state
final state = ref.watch(myStateProvider);
// Usage - call methods
ref.read(myStateProvider.notifier).doSomething();
```
## Ref Methods
### ref.watch()
- Use in `build()` method
- Rebuilds widget when provider changes
- Reactive to state updates
```dart
final data = ref.watch(someProvider);
```
### ref.read()
- Use in event handlers, callbacks
- One-time read, no rebuild
- For calling methods
```dart
onPressed: () {
ref.read(authProvider.notifier).login(user, pass);
}
```
### ref.listen()
- Use for side effects
- Navigation, dialogs, snackbars
- Doesn't rebuild widget
```dart
ref.listen<AuthState>(authProvider, (previous, next) {
if (next.error != null) {
showDialog(...);
}
});
```
## App Initialization
```dart
void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends ConsumerStatefulWidget {
@override
ConsumerState<MyApp> createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> {
@override
void initState() {
super.initState();
// Check auth on app start
Future.microtask(() {
ref.read(authProvider.notifier).checkAuthStatus();
});
}
@override
Widget build(BuildContext context) {
final isAuthenticated = ref.watch(isAuthenticatedProvider);
return MaterialApp(
home: isAuthenticated
? WarehouseSelectionPage()
: LoginPage(),
);
}
}
```
## Complete Example Flow
### 1. Login Page
```dart
class LoginPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isLoading = ref.watch(isAuthLoadingProvider);
final error = ref.watch(authErrorProvider);
ref.listen<AuthState>(authProvider, (previous, next) {
if (next.isAuthenticated) {
Navigator.pushReplacementNamed(context, '/warehouses');
}
});
return Scaffold(
body: Column(
children: [
if (error != null)
Text(error, style: TextStyle(color: Colors.red)),
TextField(controller: usernameController),
TextField(controller: passwordController, obscureText: true),
ElevatedButton(
onPressed: isLoading ? null : () {
ref.read(authProvider.notifier).login(
usernameController.text,
passwordController.text,
);
},
child: isLoading
? CircularProgressIndicator()
: Text('Login'),
),
],
),
);
}
}
```
### 2. Warehouse Selection Page
```dart
class WarehouseSelectionPage extends ConsumerStatefulWidget {
@override
ConsumerState<WarehouseSelectionPage> createState() => _State();
}
class _State extends ConsumerState<WarehouseSelectionPage> {
@override
void initState() {
super.initState();
Future.microtask(() {
ref.read(warehouseProvider.notifier).loadWarehouses();
});
}
@override
Widget build(BuildContext context) {
final warehouses = ref.watch(warehousesListProvider);
final isLoading = ref.watch(isWarehouseLoadingProvider);
return Scaffold(
appBar: AppBar(
title: Text('Select Warehouse'),
actions: [
IconButton(
icon: Icon(Icons.logout),
onPressed: () {
ref.read(authProvider.notifier).logout();
},
),
],
),
body: isLoading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: warehouses.length,
itemBuilder: (context, index) {
final warehouse = warehouses[index];
return ListTile(
title: Text(warehouse.name),
subtitle: Text(warehouse.code),
onTap: () {
ref.read(warehouseProvider.notifier)
.selectWarehouse(warehouse);
Navigator.pushNamed(context, '/operations');
},
);
},
),
);
}
}
```
### 3. Products Page
```dart
class ProductsPage extends ConsumerStatefulWidget {
final int warehouseId;
final String warehouseName;
final String operationType;
const ProductsPage({
required this.warehouseId,
required this.warehouseName,
required this.operationType,
});
@override
ConsumerState<ProductsPage> createState() => _ProductsPageState();
}
class _ProductsPageState extends ConsumerState<ProductsPage> {
@override
void initState() {
super.initState();
Future.microtask(() {
ref.read(productsProvider.notifier).loadProducts(
widget.warehouseId,
widget.warehouseName,
widget.operationType,
);
});
}
@override
Widget build(BuildContext context) {
final products = ref.watch(productsListProvider);
final isLoading = ref.watch(isProductsLoadingProvider);
final error = ref.watch(productsErrorProvider);
return Scaffold(
appBar: AppBar(
title: Text('${widget.warehouseName} - ${widget.operationType}'),
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
ref.read(productsProvider.notifier).refreshProducts();
},
),
],
),
body: isLoading
? Center(child: CircularProgressIndicator())
: error != null
? Center(child: Text(error))
: RefreshIndicator(
onRefresh: () async {
await ref.read(productsProvider.notifier)
.refreshProducts();
},
child: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
title: Text(product.name),
subtitle: Text(product.code),
trailing: Text('${product.piecesInStock} pcs'),
);
},
),
),
);
}
}
```
## Troubleshooting
### Provider Not Found
- Ensure `ProviderScope` wraps your app in `main.dart`
- Check that you're using `ConsumerWidget` or `ConsumerStatefulWidget`
### State Not Updating
- Use `ref.watch()` not `ref.read()` in build method
- Verify the provider is actually updating its state
### Null Value
- Check if data is loaded before accessing
- Use null-safe operators `?.` and `??`
### Infinite Loop
- Don't call `ref.read(provider.notifier).method()` directly in build
- Use `Future.microtask()` in initState or callbacks
## Cheat Sheet
| Task | Code |
|------|------|
| Watch state | `ref.watch(provider)` |
| Read once | `ref.read(provider)` |
| Call method | `ref.read(provider.notifier).method()` |
| Listen for changes | `ref.listen(provider, callback)` |
| Get loading | `ref.watch(isXxxLoadingProvider)` |
| Get error | `ref.watch(xxxErrorProvider)` |
| Check auth | `ref.watch(isAuthenticatedProvider)` |
| Get user | `ref.watch(currentUserProvider)` |
| Get warehouses | `ref.watch(warehousesListProvider)` |
| Get products | `ref.watch(productsListProvider)` |