import 'package:flutter/material.dart'; import '../models/delivery.dart'; import '../theme/animation_system.dart'; import '../theme/color_system.dart'; class DeliveryListItem extends StatefulWidget { final Delivery delivery; final bool isSelected; final VoidCallback onTap; final VoidCallback? onCall; final int? animationIndex; const DeliveryListItem({ super.key, required this.delivery, required this.isSelected, required this.onTap, this.onCall, this.animationIndex, }); @override State createState() => _DeliveryListItemState(); } class _DeliveryListItemState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _slideAnimation; late Animation _fadeAnimation; late Animation _scaleAnimation; bool _isHovered = false; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(milliseconds: 400), vsync: this, ); final staggerDelay = Duration( milliseconds: (widget.animationIndex ?? 0) * AppAnimations.staggerDelayMs, ); Future.delayed(staggerDelay, () { if (mounted) { _controller.forward(); } }); _slideAnimation = Tween(begin: 20, end: 0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); _fadeAnimation = Tween(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); _scaleAnimation = Tween(begin: 0.95, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); } Color _getStatusColor(Delivery delivery) { if (delivery.isSkipped == true) return SvrntyColors.statusSkipped; if (delivery.delivered == true) return SvrntyColors.statusCompleted; return SvrntyColors.statusPending; } IconData _getStatusIcon(Delivery delivery) { if (delivery.isSkipped) return Icons.skip_next; if (delivery.delivered) return Icons.check_circle; return Icons.schedule; } String _getStatusLabel(Delivery delivery) { if (delivery.isSkipped) return 'Skipped'; if (delivery.delivered) return 'Delivered'; return 'Pending'; } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; final statusColor = _getStatusColor(widget.delivery); return ScaleTransition( scale: _scaleAnimation, child: FadeTransition( opacity: _fadeAnimation, child: Transform.translate( offset: Offset(_slideAnimation.value, 0), child: MouseRegion( onEnter: (_) => setState(() => _isHovered = true), onExit: (_) => setState(() => _isHovered = false), child: GestureDetector( onTap: widget.onTap, child: AnimatedContainer( duration: AppAnimations.durationFast, margin: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: _isHovered || widget.isSelected ? (isDark ? Colors.grey[800] : Colors.grey[100]) : Colors.transparent, boxShadow: _isHovered || widget.isSelected ? [ BoxShadow( color: Colors.black.withOpacity( isDark ? 0.3 : 0.08, ), blurRadius: 8, offset: const Offset(0, 4), ), ] : [], ), padding: const EdgeInsets.all(12), child: Column( children: [ // Main delivery info row Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Left accent bar Container( width: 4, height: 60, decoration: BoxDecoration( color: statusColor, borderRadius: BorderRadius.circular(2), ), ), const SizedBox(width: 12), // Delivery info Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Name Text( widget.delivery.name, style: Theme.of(context) .textTheme .titleSmall ?.copyWith( fontWeight: FontWeight.w600, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), // Address Text( widget.delivery.deliveryAddress ?.formattedAddress ?? 'No address', style: Theme.of(context) .textTheme .bodySmall ?.copyWith( color: isDark ? Colors.grey[400] : Colors.grey[600], ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), // Order count Text( '${widget.delivery.orders.length} order${widget.delivery.orders.length != 1 ? 's' : ''}', style: Theme.of(context) .textTheme .labelSmall ?.copyWith( fontSize: 10, color: isDark ? Colors.grey[500] : Colors.grey[500], ), ), ], ), ), const SizedBox(width: 8), // Status badge + Call button Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ // Status badge Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: statusColor, borderRadius: BorderRadius.circular(6), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( _getStatusIcon(widget.delivery), color: Colors.white, size: 12, ), const SizedBox(width: 4), Text( _getStatusLabel(widget.delivery), style: Theme.of(context) .textTheme .labelSmall ?.copyWith( color: Colors.white, fontWeight: FontWeight.w600, fontSize: 10, ), ), ], ), ), const SizedBox(height: 6), // Call button (if contact exists) if (widget.delivery.orders.isNotEmpty && widget.delivery.orders.first.contact != null) GestureDetector( onTap: widget.onCall, child: Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(6), ), child: Icon( Icons.phone, color: Colors.grey[700], size: 14, ), ), ), ], ), ], ), // Total amount (if present) if (widget.delivery.orders.isNotEmpty && widget.delivery.orders.first.totalAmount != null) Padding( padding: const EdgeInsets.only(top: 8, left: 16), child: Align( alignment: Alignment.centerLeft, child: Text( 'Total: \$${widget.delivery.orders.first.totalAmount!.toStringAsFixed(2)}', style: Theme.of(context) .textTheme .labelSmall ?.copyWith( color: isDark ? Colors.amber[300] : Colors.amber[700], fontWeight: FontWeight.w500, ), ), ), ), ], ), ), ), ), ), ), ); } }