import 'package:flutter/material.dart'; import '../models/delivery.dart'; import '../theme/animation_system.dart'; import '../theme/color_system.dart'; import '../l10n/app_localizations.dart'; class DeliveryListItem extends StatefulWidget { final Delivery delivery; final bool isSelected; final VoidCallback onTap; final VoidCallback? onCall; final Function(String)? onAction; final int? animationIndex; final bool isCollapsed; const DeliveryListItem({ super.key, required this.delivery, required this.isSelected, required this.onTap, this.onCall, this.onAction, this.animationIndex, this.isCollapsed = false, }); @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: 0, 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 delivered, always show green (even if selected) if (delivery.delivered == true) return SvrntyColors.success; // If selected and not delivered, show yellow/warning color if (widget.isSelected) return SvrntyColors.warning; // If skipped, show grey if (delivery.isSkipped == true) return SvrntyColors.statusCancelled; // Default: in-transit or pending deliveries return SvrntyColors.statusInTransit; } bool _hasNote() { return widget.delivery.orders.any((order) => order.note != null && order.note!.isNotEmpty ); } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; final statusColor = _getStatusColor(widget.delivery); final l10n = AppLocalizations.of(context)!; // Collapsed view: Show only the badge if (widget.isCollapsed) { return ScaleTransition( scale: _scaleAnimation, child: FadeTransition( opacity: _fadeAnimation, child: MouseRegion( onEnter: (_) => setState(() => _isHovered = true), onExit: (_) => setState(() => _isHovered = false), child: GestureDetector( onTap: widget.onTap, child: Container( margin: const EdgeInsets.symmetric( horizontal: 10, vertical: 10, ), child: Center( child: Stack( clipBehavior: Clip.none, children: [ Container( width: 60, height: 60, decoration: BoxDecoration( color: statusColor, borderRadius: BorderRadius.circular(10), border: widget.isSelected ? Border.all( color: Colors.white, width: 3, ) : null, boxShadow: (_isHovered || widget.isSelected) ? [ BoxShadow( color: widget.isSelected ? statusColor.withValues(alpha: 0.5) : Colors.black.withValues( alpha: isDark ? 0.3 : 0.15, ), blurRadius: widget.isSelected ? 12 : 8, offset: const Offset(0, 4), spreadRadius: widget.isSelected ? 2 : 0, ), ] : [], ), child: Center( child: Text( '${widget.delivery.deliveryIndex + 1}', style: const TextStyle( color: Colors.white, fontSize: 26, fontWeight: FontWeight.w700, ), ), ), ), if (_hasNote()) Positioned( top: -4, right: -4, child: Container( width: 20, height: 20, decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary, shape: BoxShape.circle, border: Border.all( color: Theme.of(context).colorScheme.surface, width: 2, ), ), child: Transform.rotate( angle: 4.71239, // 270 degrees in radians (3*pi/2) child: const Icon( Icons.note, size: 12, color: Colors.white, ), ), ), ), ], ), ), ), ), ), ), ); } // Expanded view: Show full layout 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: 2, vertical: 4, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: widget.delivery.delivered ? Colors.green.withValues(alpha: 0.15) : widget.isSelected ? statusColor.withValues(alpha: 0.15) : Theme.of(context).colorScheme.surfaceContainer, border: widget.isSelected ? Border.all( color: widget.delivery.delivered ? SvrntyColors.success : statusColor, width: 2, ) : null, boxShadow: (_isHovered || widget.isSelected) && !widget.delivery.delivered ? [ BoxShadow( color: Colors.black.withValues( alpha: isDark ? 0.3 : 0.08, ), blurRadius: 8, offset: const Offset(0, 4), ), ] : [], ), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 12), child: Stack( clipBehavior: Clip.none, children: [ Column( children: [ // Main delivery info row Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ // Order number badge (left of status bar) Container( width: 40, height: 40, decoration: BoxDecoration( color: statusColor, borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( '${widget.delivery.deliveryIndex + 1}', style: const TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.w700, ), ), ), ), const SizedBox(width: 8), // Left accent bar (vertical status bar) Container( width: 4, height: 50, decoration: BoxDecoration( color: statusColor, borderRadius: BorderRadius.circular(2), ), ), const SizedBox(width: 10), // Delivery info Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Customer Name Text( widget.delivery.name, style: Theme.of(context) .textTheme .titleMedium ?.copyWith( fontWeight: FontWeight.w600, fontSize: 16, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), // Address Text( widget.delivery.deliveryAddress ?.formattedAddress ?? l10n.noAddress, style: Theme.of(context) .textTheme .bodyMedium ?.copyWith( fontSize: 13, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ], ), if (_hasNote()) Positioned( top: -8, right: -4, child: Container( width: 24, height: 24, decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary, shape: BoxShape.circle, border: Border.all( color: Theme.of(context).colorScheme.surface, width: 2, ), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.2), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Transform.rotate( angle: 4.71239, // 270 degrees in radians (3*pi/2) child: const Icon( Icons.note, size: 14, color: Colors.white, ), ), ), ), ], ), ), ), ), ), ), ); } }