import 'package:flutter/material.dart'; import 'services/cart_service.dart'; import 'models/cart_item_model.dart'; import 'widgets/empty_state_widget.dart'; class CartPage extends StatefulWidget { const CartPage({super.key}); @override State createState() => _CartPageState(); } class _CartPageState extends State { final CartService _cartService = CartService(); @override void initState() { super.initState(); _cartService.addListener(_onCartChanged); } @override void dispose() { _cartService.removeListener(_onCartChanged); super.dispose(); } void _onCartChanged() { if (mounted) { setState(() {}); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); final cartItems = _cartService.items; return Scaffold( appBar: AppBar( title: const Text('Your Cart'), centerTitle: true, actions: [ if (cartItems.isNotEmpty) IconButton( icon: const Icon(Icons.delete_sweep_outlined), tooltip: 'Clear Cart', onPressed: () { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Clear Cart?'), content: const Text('Are you sure you want to remove all items from your cart?'), actions: [ TextButton( child: const Text('Cancel'), onPressed: () => Navigator.of(ctx).pop(), ), TextButton( child: Text('Clear', style: TextStyle(color: theme.colorScheme.error)), onPressed: () { _cartService.clearCart(); Navigator.of(ctx).pop(); }, ), ], ), ); }, ), ], ), body: cartItems.isEmpty ? EmptyStateWidget( icon: Icons.shopping_cart_outlined, message: 'Your cart is empty.', actionButtonText: 'Start Shopping', onActionButtonPressed: () { // Navigate to home, clear stack if needed Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false); }, ) : Column( children: [ Expanded( child: ListView.builder( padding: const EdgeInsets.all(8.0), itemCount: cartItems.length, itemBuilder: (context, index) { final item = cartItems[index]; return _buildCartItemTile(context, item); }, ), ), _buildCartSummary(context, theme), ], ), ); } Widget _buildCartItemTile(BuildContext context, CartItem item) { final theme = Theme.of(context); return Card( margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8.0), child: Padding( padding: const EdgeInsets.all(12.0), child: Row( children: [ SizedBox( width: 80, height: 80, child: ClipRRect( borderRadius: BorderRadius.circular(8.0), child: Image.network( item.product.imageUrl, fit: BoxFit.cover, errorBuilder: (ctx, err, st) => Icon(Icons.image_not_supported, size: 40, color: theme.colorScheme.outline), ), ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(item.product.name, style: theme.textTheme.titleMedium, maxLines: 1, overflow: TextOverflow.ellipsis), const SizedBox(height: 4), Text('\$${item.product.price.toStringAsFixed(2)}', style: theme.textTheme.bodyMedium?.copyWith(color: theme.colorScheme.primary)), const SizedBox(height: 8), _buildQuantityControls(context, item), ], ), ), const SizedBox(width: 16), Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '\$${item.subtotal.toStringAsFixed(2)}', style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 10), IconButton( icon: Icon(Icons.delete_outline, color: theme.colorScheme.error), tooltip: 'Remove All Units', onPressed: () => _cartService.removeAllOfProduct(item.product.id), padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), ], ), ], ), ), ); } Widget _buildQuantityControls(BuildContext context, CartItem item) { final theme = Theme.of(context); return Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.remove_circle_outline, color: theme.colorScheme.primary), onPressed: () => _cartService.removeItem(item.product.id), iconSize: 22, padding: const EdgeInsets.symmetric(horizontal: 4), constraints: const BoxConstraints(), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text('${item.quantity}', style: theme.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)), ), IconButton( icon: Icon(Icons.add_circle_outline, color: theme.colorScheme.primary), onPressed: () => _cartService.addItem(item.product), iconSize: 22, padding: const EdgeInsets.symmetric(horizontal: 4), constraints: const BoxConstraints(), ), ], ); } Widget _buildCartSummary(BuildContext context, ThemeData theme) { if (_cartService.items.isEmpty) return const SizedBox.shrink(); return Container( padding: const EdgeInsets.all(16.0).copyWith(bottom: MediaQuery.of(context).padding.bottom + 16.0), // Safe area for bottom decoration: BoxDecoration( color: theme.cardColor, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), spreadRadius: 0, blurRadius: 10, offset: const Offset(0, -5), ), ], borderRadius: const BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ) ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Subtotal (${_cartService.itemCount} items):', style: theme.textTheme.titleMedium), Text('\$${_cartService.totalPrice.toStringAsFixed(2)}', style: theme.textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold)), ], ), const SizedBox(height: 8), // Mock Tax and Shipping Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Est. Tax:', style: theme.textTheme.bodyMedium), Text('\$${(_cartService.totalPrice * 0.07).toStringAsFixed(2)}', style: theme.textTheme.bodyMedium), // Mock 7% tax ], ), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Shipping:', style: theme.textTheme.bodyMedium), Text(_cartService.totalPrice > 50 ? 'FREE' : '\$5.00', style: theme.textTheme.bodyMedium?.copyWith(color: _cartService.totalPrice > 50 ? theme.colorScheme.primary : null)), // Mock free shipping over $50 ], ), const Divider(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Total:', style: theme.textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold)), Text( '\$${(_cartService.totalPrice + (_cartService.totalPrice * 0.07) + (_cartService.totalPrice > 50 ? 0 : 5.00)).toStringAsFixed(2)}', style: theme.textTheme.headlineSmall?.copyWith(color: theme.colorScheme.primary, fontWeight: FontWeight.bold) ), ], ), const SizedBox(height: 20), ElevatedButton( onPressed: () { Navigator.pushNamed(context, '/checkout'); }, child: const Text('Proceed to Checkout'), ), const SizedBox(height: 8), TextButton( onPressed: () { Navigator.pop(context); // Go back }, child: const Text('Continue Shopping'), ), ], ), ); } }