ionic-planb-logistic-app-fl.../lib/components/map_sidebar_layout.dart
Jean-Philippe Brule 98ce195bbb Add delivery order badges and optimize list performance
Enhance delivery list UI with sequential order badges and improve scrolling
performance with faster animations for better user experience.

Delivery Order Badge:
- Add 60x60px status-colored square badge showing delivery sequence number
- Position badge to the left of vertical status bar for clear visual hierarchy
- White text (26px, bold) centered in badge
- Automatically displays deliveryIndex + 1 (first delivery = 1, second = 2, etc.)
- Status color matches delivery state (green for completed, gray for pending, etc.)
- 10px border radius for modern appearance

Layout Enhancements:
- Sidebar expanded from 360px to 420px to accommodate order badges
- Vertical centering of row elements for better visual balance
- Maintains optimized spacing: badge (60px) + gap (12px) + bar (6px) + gap (16px) + content
- Full list scrolling restored (removed 4-item limit)

Animation Performance:
- Stagger animation delay reduced by 90% (50ms to 5ms)
- Fast stagger: 30ms to 3ms for ultra-responsive scrolling
- Delivery items appear almost instantly when scrolling
- Total animation time for 20 items: 500ms to 100ms
- Maintains subtle stagger effect while feeling immediate

User Experience Improvements:
- Clear visual indication of delivery order in route
- Faster perceived loading when scrolling through deliveries
- Better readability with larger, prominent order numbers
- Consistent status color coding across badge and accent bar

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 10:29:17 -05:00

138 lines
4.2 KiB
Dart

import 'package:flutter/material.dart';
import '../utils/breakpoints.dart';
import '../theme/spacing_system.dart';
import '../theme/size_system.dart';
import '../theme/animation_system.dart';
import '../theme/color_system.dart';
class MapSidebarLayout extends StatefulWidget {
final Widget mapWidget;
final Widget sidebarWidget;
final double mapRatio;
const MapSidebarLayout({
super.key,
required this.mapWidget,
required this.sidebarWidget,
this.mapRatio = 0.60, // Reduced from 2/3 to give 15% more space to sidebar
});
@override
State<MapSidebarLayout> createState() => _MapSidebarLayoutState();
}
class _MapSidebarLayoutState extends State<MapSidebarLayout>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
bool _isExpanded = true;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
if (_isExpanded) {
_animationController.forward();
}
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _toggleSidebar() {
setState(() {
_isExpanded = !_isExpanded;
});
if (_isExpanded) {
_animationController.forward();
} else {
_animationController.reverse();
}
}
@override
Widget build(BuildContext context) {
final isMobile = MediaQuery.of(context).size.width < Breakpoints.tablet;
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
if (isMobile) {
return widget.sidebarWidget;
}
// Desktop: Show map with collapsible sidebar
return Row(
children: [
Expanded(
flex: (widget.mapRatio * 100).toInt(),
child: widget.mapWidget,
),
// Collapsible sidebar with toggle button (expanded to 420px for badge + content)
AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: _isExpanded ? 420 : 64,
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: Text(
'Deliveries',
style: Theme.of(context).textTheme.titleMedium,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(
width: AppSizes.buttonHeightMd,
height: AppSizes.buttonHeightMd,
child: IconButton(
icon: AnimatedRotation(
turns: _isExpanded ? 0 : -0.5,
duration: Duration(
milliseconds:
AppAnimations.durationFast.inMilliseconds,
),
child: const Icon(Icons.chevron_right),
),
onPressed: _toggleSidebar,
iconSize: AppSizes.iconMd,
),
),
],
),
),
// Sidebar content
Expanded(
child: _isExpanded ? widget.sidebarWidget : const SizedBox.shrink(),
),
],
),
),
],
);
}
}