6.8 KiB
6.8 KiB
Cart Initialization & Keep Alive Implementation
Overview
The cart is now initialized when the app starts (on HomePage mount) and kept alive throughout the entire app session. This ensures:
- Cart data is loaded from API once on startup
- Cart state persists across all navigation
- No unnecessary re-fetching when navigating between pages
- Real-time cart badge updates across all screens
Implementation Details
1. Cart Provider with Keep Alive
File: lib/features/cart/presentation/providers/cart_provider.dart
@Riverpod(keepAlive: true) // ✅ Keep alive throughout app session
class Cart extends _$Cart {
@override
CartState build() {
return CartState.initial().copyWith(
memberTier: 'Diamond',
memberDiscountPercent: 15.0,
);
}
Future<void> initialize() async {
// Load cart from API with Hive fallback
// ...
}
}
// Dependent providers also need keepAlive
@Riverpod(keepAlive: true)
int cartItemCount(Ref ref) {
final cartState = ref.watch(cartProvider);
return cartState.items.length;
}
@Riverpod(keepAlive: true)
double cartTotal(Ref ref) {
final cartState = ref.watch(cartProvider);
return cartState.total;
}
1.1 Cart Data Providers with Keep Alive
File: lib/features/cart/data/providers/cart_data_providers.dart
CRITICAL: All cart data layer providers must also use keepAlive: true to prevent disposal errors:
@Riverpod(keepAlive: true)
CartLocalDataSource cartLocalDataSource(Ref ref) {
final hiveService = HiveService();
return CartLocalDataSourceImpl(hiveService);
}
@Riverpod(keepAlive: true)
Future<CartRemoteDataSource> cartRemoteDataSource(Ref ref) async {
final dioClient = await ref.watch(dioClientProvider.future);
return CartRemoteDataSourceImpl(dioClient);
}
@Riverpod(keepAlive: true)
Future<CartRepository> cartRepository(Ref ref) async {
final remoteDataSource = await ref.watch(cartRemoteDataSourceProvider.future);
final localDataSource = ref.watch(cartLocalDataSourceProvider);
return CartRepositoryImpl(
remoteDataSource: remoteDataSource,
localDataSource: localDataSource,
);
}
Why all providers need keepAlive:
- Cart provider depends on cartRepository
- If repository is disposed, cart operations fail with "Ref disposed" error
- All dependencies in the chain must persist together
- Ensures consistent lifecycle management
Benefits of keepAlive: true:
- Provider state is never disposed
- Cart data persists when navigating away and back
- No re-initialization needed on subsequent visits
- Consistent cart count across all app screens
- No "Ref disposed" errors during async operations
2. HomePage Initialization
File: lib/features/home/presentation/pages/home_page.dart
class HomePage extends ConsumerStatefulWidget {
const HomePage({super.key});
@override
ConsumerState<HomePage> createState() => _HomePageState();
}
class _HomePageState extends ConsumerState<HomePage> {
@override
void initState() {
super.initState();
// Initialize cart from API on app startup
WidgetsBinding.instance.addPostFrameCallback((_) {
ref.read(cartProvider.notifier).initialize();
});
}
@override
Widget build(BuildContext context) {
// Watch cart item count for badge
final cartItemCount = ref.watch(cartItemCountProvider);
// ...
}
}
Why in HomePage?
- HomePage is the first screen after login
- Ensures cart is loaded early in app lifecycle
- Provides immediate cart count for navigation badge
3. Cart Badge Integration
Location: All pages with cart icon/badge
// Any page can watch cart count - it's always available
final cartItemCount = ref.watch(cartItemCountProvider);
// Display badge
if (cartItemCount > 0)
Badge(
label: Text('$cartItemCount'),
child: Icon(Icons.shopping_cart),
)
Data Flow
App Start
↓
HomePage mounts
↓
initState() calls cart.initialize()
↓
Cart loads from API → Syncs to Hive
↓
Cart state updates with items
↓
cartItemCountProvider updates
↓
All badges across app update reactively
↓
[keepAlive ensures state persists during navigation]
API & Local Storage Integration
Initialize Flow
- API First: Fetch cart items from ERPNext API
- Product Details: For each cart item, fetch full product data
- Calculate Conversions: Apply business rules (boxes, m², etc.)
- Update State: Set cart items with full product info
- Local Sync: Automatically synced to Hive by repository
Offline Fallback
- If API fails, cart loads from Hive cache
- All mutations queue for sync when online
- See
cart_repository_impl.dartfor sync logic
Cart Operations
All cart operations work seamlessly after initialization:
// Add to cart (from any page)
await ref.read(cartProvider.notifier).addToCart(product, quantity: 2.0);
// Remove from cart
await ref.read(cartProvider.notifier).removeFromCart(productId);
// Update quantity
await ref.read(cartProvider.notifier).updateQuantity(productId, 5.0);
// Clear cart
await ref.read(cartProvider.notifier).clearCart();
All operations:
- Sync to API first
- Fallback to local on failure
- Queue for sync when offline
- Update UI reactively
Testing Keep Alive
To verify keepAlive works:
- Navigate to HomePage → Cart initializes
- Add items to cart → Badge shows count
- Navigate to Products page → Badge still shows count
- Navigate back to HomePage → Cart state preserved, no re-fetch
- Navigate to Cart page → Same items, no loading
- Hot restart app → Cart reloads from API
Performance Benefits
- One-time API call: Cart loads once on startup
- No re-fetching: Navigation doesn't trigger reloads
- Instant updates: All cart operations update state immediately
- Offline support: Hive cache provides instant fallback
- Memory efficient: Single provider instance for entire app
Error Handling
If cart initialization fails:
- Error stored in
cartState.errorMessage - Can retry via
ref.read(cartProvider.notifier).initialize() - Cart page shows error state with retry button
- Local Hive cache used if available
Related Files
- Cart Provider:
lib/features/cart/presentation/providers/cart_provider.dart - Cart State:
lib/features/cart/presentation/providers/cart_state.dart - Data Providers:
lib/features/cart/data/providers/cart_data_providers.dart - Repository:
lib/features/cart/data/repositories/cart_repository_impl.dart - HomePage:
lib/features/home/presentation/pages/home_page.dart
Future Enhancements
Potential improvements:
- Add periodic background sync (every 5 minutes)
- Implement optimistic updates for faster UI
- Add cart merge logic when switching accounts
- Implement cart expiry (clear after 30 days)
- Add analytics tracking for cart events