import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../models/delivery_route.dart'; import '../theme/spacing_system.dart'; import '../theme/size_system.dart'; import '../theme/animation_system.dart'; import '../theme/color_system.dart'; import '../utils/breakpoints.dart'; import '../providers/providers.dart'; import 'route_list_item.dart'; class CollapsibleRoutesSidebar extends ConsumerStatefulWidget { final List routes; final DeliveryRoute? selectedRoute; final ValueChanged onRouteSelected; const CollapsibleRoutesSidebar({ super.key, required this.routes, this.selectedRoute, required this.onRouteSelected, }); @override ConsumerState createState() => _CollapsibleRoutesSidebarState(); } class _CollapsibleRoutesSidebarState extends ConsumerState with SingleTickerProviderStateMixin { late AnimationController _animationController; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 300), vsync: this, ); // Set initial animation state based on provider value WidgetsBinding.instance.addPostFrameCallback((_) { final isExpanded = ref.read(collapseStateProvider); if (isExpanded) { _animationController.forward(); } else { _animationController.value = 0; } }); } @override void dispose() { _animationController.dispose(); super.dispose(); } void _toggleSidebar() { // Use shared provider state ref.read(collapseStateProvider.notifier).toggle(); final isExpanded = ref.read(collapseStateProvider); if (isExpanded) { _animationController.forward(); } else { _animationController.reverse(); } } @override Widget build(BuildContext context) { final isMobile = context.isMobile; final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isExpanded = ref.watch(collapseStateProvider); // On mobile, always show as collapsible if (isMobile) { return Container( color: isDarkMode ? SvrntyColors.almostBlack : Colors.white, child: Column( children: [ // Header with toggle button Container( padding: EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: isDarkMode ? SvrntyColors.darkSlate : SvrntyColors.slateGray.withValues(alpha: 0.2), width: 1, ), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (isExpanded) Text( 'Routes', style: Theme.of(context).textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w700, ), ), IconButton( icon: Icon(isExpanded ? Icons.menu_open : Icons.menu), onPressed: _toggleSidebar, iconSize: AppSizes.iconMd, ), ], ), ), // Collapsible content if (isExpanded) Expanded( child: _buildRoutesList(context, isExpanded), ), ], ), ); } // On tablet/desktop, show full sidebar with toggle (expanded: 300px, collapsed: 80px for badge) return AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, width: isExpanded ? 300 : 80, color: isDarkMode ? SvrntyColors.almostBlack : Colors.white, child: Column( children: [ // Header with toggle button Container( height: kToolbarHeight, padding: EdgeInsets.symmetric(horizontal: AppSpacing.xs), decoration: BoxDecoration( border: Border( left: BorderSide( color: isDarkMode ? SvrntyColors.darkSlate : SvrntyColors.slateGray.withValues(alpha: 0.2), width: 1, ), ), ), child: Row( mainAxisAlignment: isExpanded ? MainAxisAlignment.spaceBetween : MainAxisAlignment.center, children: [ if (isExpanded) Expanded( child: Padding( padding: EdgeInsets.only(left: AppSpacing.md), child: Text( 'Routes', style: Theme.of(context).textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w700, ), overflow: TextOverflow.ellipsis, ), ), ), SizedBox( width: AppSizes.buttonHeightMd, height: AppSizes.buttonHeightMd, child: IconButton( icon: Icon(isExpanded ? Icons.menu_open : Icons.menu), onPressed: _toggleSidebar, iconSize: AppSizes.iconMd, ), ), ], ), ), // Routes list Flexible( child: _buildRoutesList(context, isExpanded), ), ], ), ); } Widget _buildRoutesList(BuildContext context, bool isExpanded) { return ListView.builder( padding: const EdgeInsets.only(top: 4, bottom: 8), physics: const AlwaysScrollableScrollPhysics(), itemCount: widget.routes.length, itemBuilder: (context, index) { final route = widget.routes[index]; final isSelected = widget.selectedRoute?.id == route.id; return RouteListItem( route: route, isSelected: isSelected, onTap: () => widget.onRouteSelected(route), animationIndex: index, isCollapsed: !isExpanded, ); }, ); } }