Compare commits
No commits in common. "5714fd84433845fd8730d18d6b200399afc52135" and "3f0310d856adb105ef6a14f9e0b1c1d30c3899dc" have entirely different histories.
5714fd8443
...
3f0310d856
@ -1,200 +0,0 @@
|
|||||||
import 'package:flutter/material.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 'glassmorphic_route_card.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class CollapsibleRoutesSidebar extends StatefulWidget {
|
|
||||||
final List<DeliveryRoute> routes;
|
|
||||||
final DeliveryRoute? selectedRoute;
|
|
||||||
final ValueChanged<DeliveryRoute> onRouteSelected;
|
|
||||||
|
|
||||||
const CollapsibleRoutesSidebar({
|
|
||||||
super.key,
|
|
||||||
required this.routes,
|
|
||||||
this.selectedRoute,
|
|
||||||
required this.onRouteSelected,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CollapsibleRoutesSidebar> createState() =>
|
|
||||||
_CollapsibleRoutesSidebarState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CollapsibleRoutesSidebarState extends State<CollapsibleRoutesSidebar>
|
|
||||||
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 = context.isMobile;
|
|
||||||
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
// 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.titleMedium,
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: AnimatedRotation(
|
|
||||||
turns: _isExpanded ? 0 : -0.25,
|
|
||||||
duration: Duration(
|
|
||||||
milliseconds: AppAnimations.durationFast.inMilliseconds,
|
|
||||||
),
|
|
||||||
child: const Icon(Icons.chevron_right),
|
|
||||||
),
|
|
||||||
onPressed: _toggleSidebar,
|
|
||||||
iconSize: AppSizes.iconMd,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Collapsible content
|
|
||||||
if (_isExpanded)
|
|
||||||
Expanded(
|
|
||||||
child: _buildRoutesList(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// On tablet/desktop, show full sidebar with toggle
|
|
||||||
return Container(
|
|
||||||
width: _isExpanded ? 280 : 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(
|
|
||||||
'Routes',
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Routes list
|
|
||||||
Expanded(
|
|
||||||
child: _buildRoutesList(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildRoutesList(BuildContext context) {
|
|
||||||
return ListView.builder(
|
|
||||||
padding: EdgeInsets.all(AppSpacing.sm),
|
|
||||||
itemCount: widget.routes.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final route = widget.routes[index];
|
|
||||||
final isSelected = widget.selectedRoute?.id == route.id;
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.only(bottom: AppSpacing.sm),
|
|
||||||
child: _buildRouteButton(context, route, isSelected),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildRouteButton(
|
|
||||||
BuildContext context,
|
|
||||||
DeliveryRoute route,
|
|
||||||
bool isSelected,
|
|
||||||
) {
|
|
||||||
return GlassmorphicRouteCard(
|
|
||||||
route: route,
|
|
||||||
isSelected: isSelected,
|
|
||||||
isCollapsed: !_isExpanded,
|
|
||||||
onTap: () => widget.onRouteSelected(route),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -302,7 +302,7 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
|
|||||||
label: 'Stop',
|
label: 'Stop',
|
||||||
icon: Icons.stop,
|
icon: Icons.stop,
|
||||||
onPressed: _stopNavigation,
|
onPressed: _stopNavigation,
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
color: Colors.grey[600]!,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -315,7 +315,9 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
|
|||||||
right: 0,
|
right: 0,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? const Color(0xFF14161A)
|
||||||
|
: Colors.white,
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.2),
|
color: Colors.black.withOpacity(0.2),
|
||||||
@ -351,7 +353,13 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
|
|||||||
'No address',
|
'No address',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall,
|
.bodySmall
|
||||||
|
?.copyWith(
|
||||||
|
color: Theme.of(context).brightness ==
|
||||||
|
Brightness.dark
|
||||||
|
? Colors.grey[400]
|
||||||
|
: Colors.grey[600],
|
||||||
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -70,10 +70,9 @@ class _DeliveryListItemState extends State<DeliveryListItem>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Color _getStatusColor(Delivery delivery) {
|
Color _getStatusColor(Delivery delivery) {
|
||||||
if (delivery.isSkipped == true) return SvrntyColors.statusCancelled;
|
if (delivery.isSkipped == true) return SvrntyColors.statusSkipped;
|
||||||
if (delivery.delivered == true) return SvrntyColors.statusCompleted;
|
if (delivery.delivered == true) return SvrntyColors.statusCompleted;
|
||||||
// Default: in-transit or pending deliveries
|
return SvrntyColors.statusPending;
|
||||||
return SvrntyColors.statusInTransit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IconData _getStatusIcon(Delivery delivery) {
|
IconData _getStatusIcon(Delivery delivery) {
|
||||||
@ -113,7 +112,9 @@ class _DeliveryListItemState extends State<DeliveryListItem>
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
color: _isHovered || widget.isSelected
|
color: _isHovered || widget.isSelected
|
||||||
? Theme.of(context).colorScheme.surfaceContainer
|
? (isDark
|
||||||
|
? Colors.grey[800]
|
||||||
|
: Colors.grey[100])
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
boxShadow: _isHovered || widget.isSelected
|
boxShadow: _isHovered || widget.isSelected
|
||||||
? [
|
? [
|
||||||
@ -169,7 +170,12 @@ class _DeliveryListItemState extends State<DeliveryListItem>
|
|||||||
'No address',
|
'No address',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall,
|
.bodySmall
|
||||||
|
?.copyWith(
|
||||||
|
color: isDark
|
||||||
|
? Colors.grey[400]
|
||||||
|
: Colors.grey[600],
|
||||||
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@ -182,6 +188,9 @@ class _DeliveryListItemState extends State<DeliveryListItem>
|
|||||||
.labelSmall
|
.labelSmall
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
|
color: isDark
|
||||||
|
? Colors.grey[500]
|
||||||
|
: Colors.grey[500],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -237,12 +246,12 @@ class _DeliveryListItemState extends State<DeliveryListItem>
|
|||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
color: Colors.grey[300],
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.phone,
|
Icons.phone,
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
color: Colors.grey[700],
|
||||||
size: 14,
|
size: 14,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -264,7 +273,9 @@ class _DeliveryListItemState extends State<DeliveryListItem>
|
|||||||
.textTheme
|
.textTheme
|
||||||
.labelSmall
|
.labelSmall
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
color: SvrntyColors.warning,
|
color: isDark
|
||||||
|
? Colors.amber[300]
|
||||||
|
: Colors.amber[700],
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,330 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'dart:ui' as ui;
|
|
||||||
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';
|
|
||||||
|
|
||||||
/// Modern glassmorphic route card with status-based gradient and animated progress
|
|
||||||
class GlassmorphicRouteCard extends StatefulWidget {
|
|
||||||
final DeliveryRoute route;
|
|
||||||
final bool isSelected;
|
|
||||||
final VoidCallback onTap;
|
|
||||||
final bool isCollapsed;
|
|
||||||
|
|
||||||
const GlassmorphicRouteCard({
|
|
||||||
super.key,
|
|
||||||
required this.route,
|
|
||||||
required this.isSelected,
|
|
||||||
required this.onTap,
|
|
||||||
this.isCollapsed = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<GlassmorphicRouteCard> createState() => _GlassmorphicRouteCardState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GlassmorphicRouteCardState extends State<GlassmorphicRouteCard>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late AnimationController _hoverController;
|
|
||||||
bool _isHovered = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_hoverController = AnimationController(
|
|
||||||
duration: Duration(milliseconds: AppAnimations.durationFast.inMilliseconds),
|
|
||||||
vsync: this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_hoverController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate color based on completion percentage
|
|
||||||
Color _getProgressColor(double progress) {
|
|
||||||
if (progress < 0.3) {
|
|
||||||
// Red to orange (0-30%)
|
|
||||||
return Color.lerp(
|
|
||||||
SvrntyColors.crimsonRed,
|
|
||||||
const Color(0xFFFF9800),
|
|
||||||
(progress / 0.3),
|
|
||||||
)!;
|
|
||||||
} else if (progress < 0.7) {
|
|
||||||
// Orange to yellow (30-70%)
|
|
||||||
return Color.lerp(
|
|
||||||
const Color(0xFFFF9800),
|
|
||||||
const Color(0xFFFFC107),
|
|
||||||
((progress - 0.3) / 0.4),
|
|
||||||
)!;
|
|
||||||
} else {
|
|
||||||
// Yellow to green (70-100%)
|
|
||||||
return Color.lerp(
|
|
||||||
const Color(0xFFFFC107),
|
|
||||||
const Color(0xFF4CAF50),
|
|
||||||
((progress - 0.7) / 0.3),
|
|
||||||
)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _setHovered(bool hovered) {
|
|
||||||
setState(() {
|
|
||||||
_isHovered = hovered;
|
|
||||||
});
|
|
||||||
if (hovered) {
|
|
||||||
_hoverController.forward();
|
|
||||||
} else {
|
|
||||||
_hoverController.reverse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
final progress = widget.route.deliveredCount / widget.route.deliveriesCount;
|
|
||||||
final progressColor = _getProgressColor(progress);
|
|
||||||
|
|
||||||
if (widget.isCollapsed) {
|
|
||||||
return _buildCollapsedCard(context, isDarkMode, progress, progressColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buildExpandedCard(context, isDarkMode, progress, progressColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCollapsedCard(BuildContext context, bool isDarkMode,
|
|
||||||
double progress, Color progressColor) {
|
|
||||||
return MouseRegion(
|
|
||||||
onEnter: (_) => _setHovered(true),
|
|
||||||
onExit: (_) => _setHovered(false),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: widget.onTap,
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: Duration(
|
|
||||||
milliseconds: AppAnimations.durationFast.inMilliseconds,
|
|
||||||
),
|
|
||||||
height: AppSizes.buttonHeightMd,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(AppSpacing.md),
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: [
|
|
||||||
// Glassmorphic background
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(AppSpacing.md),
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ui.ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: (isDarkMode
|
|
||||||
? SvrntyColors.darkSlate
|
|
||||||
: Colors.white)
|
|
||||||
.withValues(alpha: 0.7),
|
|
||||||
border: Border.all(
|
|
||||||
color: (isDarkMode ? Colors.white : Colors.white)
|
|
||||||
.withValues(alpha: 0.2),
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Progress indicator at bottom
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(AppSpacing.md - AppSpacing.xs),
|
|
||||||
bottomRight: Radius.circular(AppSpacing.md - AppSpacing.xs),
|
|
||||||
),
|
|
||||||
child: LinearProgressIndicator(
|
|
||||||
value: progress,
|
|
||||||
minHeight: 3,
|
|
||||||
backgroundColor: progressColor.withValues(alpha: 0.2),
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(progressColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Content
|
|
||||||
Center(
|
|
||||||
child: Text(
|
|
||||||
widget.route.name.substring(0, 1).toUpperCase(),
|
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 16,
|
|
||||||
color: widget.isSelected ? progressColor : null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildExpandedCard(BuildContext context, bool isDarkMode,
|
|
||||||
double progress, Color progressColor) {
|
|
||||||
return MouseRegion(
|
|
||||||
onEnter: (_) => _setHovered(true),
|
|
||||||
onExit: (_) => _setHovered(false),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: widget.onTap,
|
|
||||||
child: AnimatedBuilder(
|
|
||||||
animation: _hoverController,
|
|
||||||
builder: (context, child) {
|
|
||||||
final hoverValue = _hoverController.value;
|
|
||||||
final blurSigma = 8 + (hoverValue * 3);
|
|
||||||
final bgOpacity = 0.7 + (hoverValue * 0.1);
|
|
||||||
|
|
||||||
return AnimatedContainer(
|
|
||||||
duration: Duration(
|
|
||||||
milliseconds: AppAnimations.durationFast.inMilliseconds,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(AppSpacing.lg),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: progressColor.withValues(alpha: 0.1 + (hoverValue * 0.2)),
|
|
||||||
blurRadius: 12 + (hoverValue * 8),
|
|
||||||
offset: Offset(0, 2 + (hoverValue * 2)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
// Glassmorphic background
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(AppSpacing.lg),
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ui.ImageFilter.blur(sigmaX: blurSigma, sigmaY: blurSigma),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: (isDarkMode
|
|
||||||
? SvrntyColors.darkSlate
|
|
||||||
: Colors.white)
|
|
||||||
.withValues(alpha: bgOpacity),
|
|
||||||
border: Border.all(
|
|
||||||
color: (isDarkMode ? Colors.white : Colors.white)
|
|
||||||
.withValues(alpha: 0.2 + (hoverValue * 0.15)),
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(AppSpacing.lg),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Content
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(AppSpacing.md),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
// Route name
|
|
||||||
Text(
|
|
||||||
widget.route.name,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.labelLarge
|
|
||||||
?.copyWith(
|
|
||||||
color: widget.isSelected ? progressColor : null,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
SizedBox(height: AppSpacing.xs),
|
|
||||||
// Delivery count
|
|
||||||
RichText(
|
|
||||||
text: TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: '${widget.route.deliveredCount}',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodySmall
|
|
||||||
?.copyWith(
|
|
||||||
color: progressColor,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: 11,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: '/${widget.route.deliveriesCount}',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodySmall
|
|
||||||
?.copyWith(
|
|
||||||
fontSize: 11,
|
|
||||||
color: (Theme.of(context).brightness == Brightness.dark
|
|
||||||
? Colors.white
|
|
||||||
: Colors.black)
|
|
||||||
.withValues(alpha: 0.6),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: AppSpacing.sm),
|
|
||||||
// Animated gradient progress bar
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(3),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
// Background
|
|
||||||
Container(
|
|
||||||
height: 6,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: progressColor
|
|
||||||
.withValues(alpha: 0.15),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Progress fill with gradient
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(3),
|
|
||||||
child: Container(
|
|
||||||
height: 6,
|
|
||||||
width: 100 * progress,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.centerLeft,
|
|
||||||
end: Alignment.centerRight,
|
|
||||||
colors: [
|
|
||||||
SvrntyColors.crimsonRed,
|
|
||||||
progressColor,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(3),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: progressColor
|
|
||||||
.withValues(alpha: 0.4),
|
|
||||||
blurRadius: 4,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -93,7 +93,7 @@ class _PremiumRouteCardState extends State<PremiumRouteCard>
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: isDark ? const Color(0xFF14161A) : const Color(0xFFFAFAFC),
|
||||||
border: Border(
|
border: Border(
|
||||||
left: BorderSide(color: accentColor, width: 4),
|
left: BorderSide(color: accentColor, width: 4),
|
||||||
),
|
),
|
||||||
@ -134,7 +134,7 @@ class _PremiumRouteCardState extends State<PremiumRouteCard>
|
|||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' completed',
|
text: ' completed',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -167,6 +167,7 @@ class _PremiumRouteCardState extends State<PremiumRouteCard>
|
|||||||
Text(
|
Text(
|
||||||
'$progressPercentage% progress',
|
'$progressPercentage% progress',
|
||||||
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||||
|
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
letterSpacing: 0.3,
|
letterSpacing: 0.3,
|
||||||
),
|
),
|
||||||
@ -178,7 +179,7 @@ class _PremiumRouteCardState extends State<PremiumRouteCard>
|
|||||||
height: 6,
|
height: 6,
|
||||||
child: LinearProgressIndicator(
|
child: LinearProgressIndicator(
|
||||||
value: widget.route.progress,
|
value: widget.route.progress,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
backgroundColor: isDark ? Colors.grey[800] : Colors.grey[200],
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(accentColor),
|
valueColor: AlwaysStoppedAnimation<Color>(accentColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -2,17 +2,15 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import '../models/delivery.dart';
|
import '../models/delivery.dart';
|
||||||
import '../models/delivery_route.dart';
|
|
||||||
import '../providers/providers.dart';
|
import '../providers/providers.dart';
|
||||||
import '../api/client.dart';
|
import '../api/client.dart';
|
||||||
import '../api/openapi_config.dart';
|
import '../api/openapi_config.dart';
|
||||||
import '../models/delivery_commands.dart';
|
import '../models/delivery_commands.dart';
|
||||||
import '../utils/breakpoints.dart';
|
import '../utils/breakpoints.dart';
|
||||||
|
import '../utils/responsive.dart';
|
||||||
import '../components/map_sidebar_layout.dart';
|
import '../components/map_sidebar_layout.dart';
|
||||||
import '../components/dark_mode_map.dart';
|
import '../components/dark_mode_map.dart';
|
||||||
import '../components/delivery_list_item.dart';
|
import '../components/delivery_list_item.dart';
|
||||||
import '../components/collapsible_routes_sidebar.dart'
|
|
||||||
show CollapsibleRoutesSidebar;
|
|
||||||
|
|
||||||
class DeliveriesPage extends ConsumerStatefulWidget {
|
class DeliveriesPage extends ConsumerStatefulWidget {
|
||||||
final int routeFragmentId;
|
final int routeFragmentId;
|
||||||
@ -48,7 +46,6 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final deliveriesData = ref.watch(deliveriesProvider(widget.routeFragmentId));
|
final deliveriesData = ref.watch(deliveriesProvider(widget.routeFragmentId));
|
||||||
final routesData = ref.watch(deliveryRoutesProvider);
|
|
||||||
final token = ref.watch(authTokenProvider).valueOrNull;
|
final token = ref.watch(authTokenProvider).valueOrNull;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -65,38 +62,7 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
.where((d) => d.delivered)
|
.where((d) => d.delivered)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return routesData.when(
|
return MapSidebarLayout(
|
||||||
data: (routes) {
|
|
||||||
DeliveryRoute? currentRoute;
|
|
||||||
try {
|
|
||||||
currentRoute = routes.firstWhere(
|
|
||||||
(r) => r.id == widget.routeFragmentId,
|
|
||||||
);
|
|
||||||
} catch (_) {
|
|
||||||
currentRoute = routes.isNotEmpty ? routes.first : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
if (context.isDesktop && routes.isNotEmpty)
|
|
||||||
CollapsibleRoutesSidebar(
|
|
||||||
routes: routes,
|
|
||||||
selectedRoute: currentRoute,
|
|
||||||
onRouteSelected: (route) {
|
|
||||||
if (route.id != widget.routeFragmentId) {
|
|
||||||
Navigator.of(context).pushReplacement(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => DeliveriesPage(
|
|
||||||
routeFragmentId: route.id,
|
|
||||||
routeName: route.name,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: MapSidebarLayout(
|
|
||||||
mapWidget: DarkModeMapComponent(
|
mapWidget: DarkModeMapComponent(
|
||||||
deliveries: deliveries,
|
deliveries: deliveries,
|
||||||
selectedDelivery: _selectedDelivery,
|
selectedDelivery: _selectedDelivery,
|
||||||
@ -170,89 +136,6 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
loading: () => const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
error: (error, stackTrace) => MapSidebarLayout(
|
|
||||||
mapWidget: DarkModeMapComponent(
|
|
||||||
deliveries: deliveries,
|
|
||||||
selectedDelivery: _selectedDelivery,
|
|
||||||
onDeliverySelected: (delivery) {
|
|
||||||
setState(() {
|
|
||||||
_selectedDelivery = delivery;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
sidebarWidget: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: SegmentedButton<int>(
|
|
||||||
segments: const [
|
|
||||||
ButtonSegment(
|
|
||||||
value: 0,
|
|
||||||
label: Text('To Do'),
|
|
||||||
),
|
|
||||||
ButtonSegment(
|
|
||||||
value: 1,
|
|
||||||
label: Text('Delivered'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
selected: <int>{_currentSegment},
|
|
||||||
onSelectionChanged: (Set<int> newSelection) {
|
|
||||||
setState(() {
|
|
||||||
_currentSegment = newSelection.first;
|
|
||||||
_pageController.animateToPage(
|
|
||||||
_currentSegment,
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: PageView(
|
|
||||||
controller: _pageController,
|
|
||||||
onPageChanged: (index) {
|
|
||||||
setState(() {
|
|
||||||
_currentSegment = index;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
DeliveryListView(
|
|
||||||
deliveries: todoDeliveries,
|
|
||||||
selectedDelivery: _selectedDelivery,
|
|
||||||
onDeliverySelected: (delivery) {
|
|
||||||
setState(() {
|
|
||||||
_selectedDelivery = delivery;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onAction: (delivery, action) =>
|
|
||||||
_handleDeliveryAction(context, delivery, action, token),
|
|
||||||
),
|
|
||||||
DeliveryListView(
|
|
||||||
deliveries: completedDeliveries,
|
|
||||||
selectedDelivery: _selectedDelivery,
|
|
||||||
onDeliverySelected: (delivery) {
|
|
||||||
setState(() {
|
|
||||||
_selectedDelivery = delivery;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onAction: (delivery, action) =>
|
|
||||||
_handleDeliveryAction(context, delivery, action, token),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
loading: () => const Center(
|
loading: () => const Center(
|
||||||
@ -457,7 +340,7 @@ class DeliveryCard extends StatelessWidget {
|
|||||||
else if (order?.isNewCustomer ?? false)
|
else if (order?.isNewCustomer ?? false)
|
||||||
Chip(
|
Chip(
|
||||||
label: const Text('New Customer'),
|
label: const Text('New Customer'),
|
||||||
backgroundColor: const Color(0xFFFFFBEB),
|
backgroundColor: Colors.orange.shade100,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -152,14 +152,12 @@ class _LoginPageState extends ConsumerState<LoginPage> {
|
|||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
child: _isLoading
|
child: _isLoading
|
||||||
? SizedBox(
|
? const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
width: 20,
|
width: 20,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||||
Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const Text('Login'),
|
: const Text('Login'),
|
||||||
|
|||||||
@ -3,29 +3,17 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import '../models/delivery_route.dart';
|
import '../models/delivery_route.dart';
|
||||||
import '../providers/providers.dart';
|
import '../providers/providers.dart';
|
||||||
import '../utils/breakpoints.dart';
|
import '../utils/breakpoints.dart';
|
||||||
import '../components/collapsible_routes_sidebar.dart';
|
import '../utils/responsive.dart';
|
||||||
import '../components/dark_mode_map.dart';
|
import '../components/premium_route_card.dart';
|
||||||
import 'deliveries_page.dart';
|
import 'deliveries_page.dart';
|
||||||
import 'settings_page.dart';
|
import 'settings_page.dart';
|
||||||
|
|
||||||
class RoutesPage extends ConsumerWidget {
|
class RoutesPage extends ConsumerWidget {
|
||||||
const RoutesPage({super.key});
|
const RoutesPage({super.key});
|
||||||
|
|
||||||
void _navigateToDeliveries(BuildContext context, DeliveryRoute route) {
|
|
||||||
Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => DeliveriesPage(
|
|
||||||
routeFragmentId: route.id,
|
|
||||||
routeName: route.name,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final routesData = ref.watch(deliveryRoutesProvider);
|
final routesData = ref.watch(deliveryRoutesProvider);
|
||||||
final allDeliveriesData = ref.watch(allDeliveriesProvider);
|
|
||||||
final userProfile = ref.watch(userProfileProvider);
|
final userProfile = ref.watch(userProfileProvider);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -85,70 +73,14 @@ class RoutesPage extends ConsumerWidget {
|
|||||||
child: Text('No routes available'),
|
child: Text('No routes available'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return allDeliveriesData.when(
|
|
||||||
data: (allDeliveries) {
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
// ignore: unused_result
|
// ignore: unused_result
|
||||||
ref.refresh(deliveryRoutesProvider);
|
ref.refresh(deliveryRoutesProvider);
|
||||||
// ignore: unused_result
|
|
||||||
ref.refresh(allDeliveriesProvider);
|
|
||||||
},
|
},
|
||||||
child: context.isDesktop
|
child: context.isDesktop
|
||||||
? Row(
|
? _buildDesktopGrid(context, routes)
|
||||||
children: [
|
: _buildMobileList(context, routes),
|
||||||
Expanded(
|
|
||||||
child: DarkModeMapComponent(
|
|
||||||
deliveries: allDeliveries,
|
|
||||||
selectedDelivery: null,
|
|
||||||
onDeliverySelected: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CollapsibleRoutesSidebar(
|
|
||||||
routes: routes,
|
|
||||||
selectedRoute: null,
|
|
||||||
onRouteSelected: (route) {
|
|
||||||
_navigateToDeliveries(context, route);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: DarkModeMapComponent(
|
|
||||||
deliveries: allDeliveries,
|
|
||||||
selectedDelivery: null,
|
|
||||||
onDeliverySelected: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CollapsibleRoutesSidebar(
|
|
||||||
routes: routes,
|
|
||||||
selectedRoute: null,
|
|
||||||
onRouteSelected: (route) {
|
|
||||||
_navigateToDeliveries(context, route);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
loading: () => const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
error: (error, stackTrace) => Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text('Error loading deliveries: $error'),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => ref.refresh(allDeliveriesProvider),
|
|
||||||
child: const Text('Retry'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
loading: () => const Center(
|
loading: () => const Center(
|
||||||
@ -171,4 +103,53 @@ class RoutesPage extends ConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildMobileList(BuildContext context, List<DeliveryRoute> routes) {
|
||||||
|
final spacing = ResponsiveSpacing.md(context);
|
||||||
|
return ListView.builder(
|
||||||
|
padding: EdgeInsets.all(ResponsiveSpacing.md(context)),
|
||||||
|
itemCount: routes.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final route = routes[index];
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: spacing),
|
||||||
|
child: _buildRouteCard(context, route),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDesktopGrid(BuildContext context, List<DeliveryRoute> routes) {
|
||||||
|
final spacing = ResponsiveSpacing.lg(context);
|
||||||
|
final columns = context.isTablet ? 2 : 3;
|
||||||
|
return GridView.builder(
|
||||||
|
padding: EdgeInsets.all(spacing),
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: columns,
|
||||||
|
crossAxisSpacing: spacing,
|
||||||
|
mainAxisSpacing: spacing,
|
||||||
|
childAspectRatio: 1.2,
|
||||||
|
),
|
||||||
|
itemCount: routes.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final route = routes[index];
|
||||||
|
return _buildRouteCard(context, route);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRouteCard(BuildContext context, DeliveryRoute route) {
|
||||||
|
return PremiumRouteCard(
|
||||||
|
route: route,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => DeliveriesPage(
|
||||||
|
routeFragmentId: route.id,
|
||||||
|
routeName: route.name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,32 +100,6 @@ final deliveriesProvider = FutureProvider.family<List<Delivery>, int>((ref, rout
|
|||||||
return result.whenSuccess((deliveries) => deliveries) ?? [];
|
return result.whenSuccess((deliveries) => deliveries) ?? [];
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Provider to get all deliveries from all routes
|
|
||||||
final allDeliveriesProvider = FutureProvider<List<Delivery>>((ref) async {
|
|
||||||
final routes = ref.watch(deliveryRoutesProvider).valueOrNull ?? [];
|
|
||||||
|
|
||||||
if (routes.isEmpty) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch deliveries for all routes
|
|
||||||
final deliveriesFutures = routes.map((route) {
|
|
||||||
return ref.watch(deliveriesProvider(route.id)).when(
|
|
||||||
data: (deliveries) => deliveries,
|
|
||||||
loading: () => <Delivery>[],
|
|
||||||
error: (_, __) => <Delivery>[],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Combine all deliveries
|
|
||||||
final allDeliveries = <Delivery>[];
|
|
||||||
for (final deliveries in deliveriesFutures) {
|
|
||||||
allDeliveries.addAll(deliveries);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allDeliveries;
|
|
||||||
});
|
|
||||||
|
|
||||||
final languageProvider = StateProvider<String>((ref) {
|
final languageProvider = StateProvider<String>((ref) {
|
||||||
return 'fr';
|
return 'fr';
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,174 +11,149 @@ class SvrntyColors {
|
|||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
/// Crimson Red - Primary accent and brand signature
|
/// Crimson Red - Primary accent and brand signature
|
||||||
static const Color crimsonRed = Color(0xFFDF2D45);
|
static const Color crimsonRed = Color(0xDF2D45);
|
||||||
|
|
||||||
/// Almost Black - Primary dark background
|
/// Almost Black - Primary dark background
|
||||||
static const Color almostBlack = Color(0xFF06080C);
|
static const Color almostBlack = Color(0x06080C);
|
||||||
|
|
||||||
/// Dark Slate - Secondary dark tone
|
/// Dark Slate - Secondary dark tone
|
||||||
static const Color darkSlate = Color(0xFF3A4958);
|
static const Color darkSlate = Color(0x3A4958);
|
||||||
|
|
||||||
/// Slate Gray - Mid-tone gray
|
/// Slate Gray - Mid-tone gray
|
||||||
static const Color slateGray = Color(0xFF506576);
|
static const Color slateGray = Color(0x506576);
|
||||||
|
|
||||||
/// Teal - Tertiary accent
|
/// Teal - Tertiary accent
|
||||||
static const Color teal = Color(0xFF1D2C39);
|
static const Color teal = Color(0x1D2C39);
|
||||||
|
|
||||||
/// Light Gray - Neutral light
|
/// Light Gray - Neutral light
|
||||||
static const Color lightGray = Color(0xFFAEB8BE);
|
static const Color lightGray = Color(0xAEB8BE);
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// SEMANTIC COLORS
|
// SEMANTIC COLORS
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
/// Success - Green for positive actions and completed states
|
/// Success - Green for positive actions and completed states
|
||||||
static const Color success = Color(0xFF22C55E);
|
static const Color success = Color(0x22C55E);
|
||||||
|
|
||||||
/// Warning - Amber for warnings and attention-needed states
|
/// Warning - Amber for warnings and attention-needed states
|
||||||
static const Color warning = Color(0xFFF59E0B);
|
static const Color warning = Color(0xF59E0B);
|
||||||
|
|
||||||
/// Info - Blue for informational and in-progress states
|
/// Info - Blue for informational and in-progress states
|
||||||
static const Color info = Color(0xFF3B82F6);
|
static const Color info = Color(0x3B82F6);
|
||||||
|
|
||||||
/// Error - Red for errors, failures, and destructive actions
|
/// Error - Red for errors, failures, and destructive actions
|
||||||
static const Color error = Color(0xFFEF4444);
|
static const Color error = Color(0xEF4444);
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// DELIVERY STATUS COLORS (OPTIMIZED SVRNTY MAPPING)
|
// DELIVERY STATUS COLORS
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
/// Status Pending - Awaiting action (Amber - attention needed)
|
/// Status Pending - Awaiting action (Slate Gray)
|
||||||
static const Color statusPending = warning; // #F59E0B
|
static const Color statusPending = slateGray;
|
||||||
|
|
||||||
/// Status In Transit - Currently being delivered (Teal Blue - active process)
|
/// Status In Progress - Currently being delivered (Blue)
|
||||||
static const Color statusInTransit = slateGray; // #506576
|
static const Color statusInProgress = info;
|
||||||
|
|
||||||
/// Status Completed - Successfully delivered (Green - success)
|
/// Status Completed - Successfully delivered (Green)
|
||||||
static const Color statusCompleted = success; // #22C55E
|
static const Color statusCompleted = success;
|
||||||
|
|
||||||
/// Status Failed - Failed delivery (Error Red - problem)
|
/// Status Skipped - Skipped/passed delivery (Amber)
|
||||||
static const Color statusFailed = error; // #EF4444
|
static const Color statusSkipped = warning;
|
||||||
|
|
||||||
/// Status Cancelled - Cancelled delivery (Cool Gray - inactive)
|
/// Status Failed - Failed delivery (Red)
|
||||||
static const Color statusCancelled = lightGray; // #AEB8BE
|
static const Color statusFailed = error;
|
||||||
|
|
||||||
/// Status On Hold - Paused/waiting (Slate Blue - informational)
|
|
||||||
static const Color statusOnHold = darkSlate; // #3A4958
|
|
||||||
|
|
||||||
// ============================================
|
|
||||||
// STATUS COLOR LIGHT BACKGROUNDS
|
|
||||||
// ============================================
|
|
||||||
|
|
||||||
/// Pending background (light amber)
|
|
||||||
static const Color statusPendingBg = Color(0xFFFEF3C7);
|
|
||||||
|
|
||||||
/// In Transit background (light teal)
|
|
||||||
static const Color statusInTransitBg = Color(0xFFE0E7ED);
|
|
||||||
|
|
||||||
/// Completed background (light green)
|
|
||||||
static const Color statusCompletedBg = Color(0xFFD1FAE5);
|
|
||||||
|
|
||||||
/// Failed background (light red)
|
|
||||||
static const Color statusFailedBg = Color(0xFFFEE2E2);
|
|
||||||
|
|
||||||
/// Cancelled background (light gray)
|
|
||||||
static const Color statusCancelledBg = Color(0xFFF3F4F6);
|
|
||||||
|
|
||||||
/// On Hold background (light slate)
|
|
||||||
static const Color statusOnHoldBg = Color(0xFFE2E8F0);
|
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// SURFACE VARIANTS
|
// SURFACE VARIANTS
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
/// Surface Elevated - Light elevated surface
|
/// Surface Elevated - Light elevated surface
|
||||||
static const Color surfaceElevated = Color(0xFFF5F7FA);
|
static const Color surfaceElevated = Color(0xF5F7FA);
|
||||||
|
|
||||||
/// Surface Subdued - Subdued light surface
|
/// Surface Subdued - Subdued light surface
|
||||||
static const Color surfaceSubdued = Color(0xFFE8EAEE);
|
static const Color surfaceSubdued = Color(0xE8EAEE);
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// EXTENDED COLOR FAMILIES - SUCCESS (GREEN)
|
// EXTENDED COLOR FAMILIES - SUCCESS (GREEN)
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
/// Success color light theme
|
/// Success color light theme
|
||||||
static const Color successLight = Color(0xFF22C55E);
|
static const Color successLight = Color(0x22C55E);
|
||||||
|
|
||||||
/// Success on color light theme
|
/// Success on color light theme
|
||||||
static const Color onSuccessLight = Color(0xFFFFFFFF);
|
static const Color onSuccessLight = Color(0xFFFFFF);
|
||||||
|
|
||||||
/// Success container light theme
|
/// Success container light theme
|
||||||
static const Color successContainerLight = Color(0xFFDCFCE7);
|
static const Color successContainerLight = Color(0xDCFCE7);
|
||||||
|
|
||||||
/// Success on container light theme
|
/// Success on container light theme
|
||||||
static const Color onSuccessContainerLight = Color(0xFF14532D);
|
static const Color onSuccessContainerLight = Color(0x14532D);
|
||||||
|
|
||||||
/// Success color dark theme
|
/// Success color dark theme
|
||||||
static const Color successDark = Color(0xFF4ADE80);
|
static const Color successDark = Color(0x4ADE80);
|
||||||
|
|
||||||
/// Success on color dark theme
|
/// Success on color dark theme
|
||||||
static const Color onSuccessDark = Color(0xFF14532D);
|
static const Color onSuccessDark = Color(0x14532D);
|
||||||
|
|
||||||
/// Success container dark theme
|
/// Success container dark theme
|
||||||
static const Color successContainerDark = Color(0xFF15803D);
|
static const Color successContainerDark = Color(0x15803D);
|
||||||
|
|
||||||
/// Success on container dark theme
|
/// Success on container dark theme
|
||||||
static const Color onSuccessContainerDark = Color(0xFFDCFCE7);
|
static const Color onSuccessContainerDark = Color(0xDCFCE7);
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// EXTENDED COLOR FAMILIES - WARNING (AMBER)
|
// EXTENDED COLOR FAMILIES - WARNING (AMBER)
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
/// Warning color light theme
|
/// Warning color light theme
|
||||||
static const Color warningLight = Color(0xFFF59E0B);
|
static const Color warningLight = Color(0xF59E0B);
|
||||||
|
|
||||||
/// Warning on color light theme
|
/// Warning on color light theme
|
||||||
static const Color onWarningLight = Color(0xFFFFFFFF);
|
static const Color onWarningLight = Color(0xFFFFFF);
|
||||||
|
|
||||||
/// Warning container light theme
|
/// Warning container light theme
|
||||||
static const Color warningContainerLight = Color(0xFFFEF3C7);
|
static const Color warningContainerLight = Color(0xFEF3C7);
|
||||||
|
|
||||||
/// Warning on container light theme
|
/// Warning on container light theme
|
||||||
static const Color onWarningContainerLight = Color(0xFF78350F);
|
static const Color onWarningContainerLight = Color(0x78350F);
|
||||||
|
|
||||||
/// Warning color dark theme
|
/// Warning color dark theme
|
||||||
static const Color warningDark = Color(0xFFFBBF24);
|
static const Color warningDark = Color(0xFBBF24);
|
||||||
|
|
||||||
/// Warning on color dark theme
|
/// Warning on color dark theme
|
||||||
static const Color onWarningDark = Color(0xFF78350F);
|
static const Color onWarningDark = Color(0x78350F);
|
||||||
|
|
||||||
/// Warning container dark theme
|
/// Warning container dark theme
|
||||||
static const Color warningContainerDark = Color(0xFFD97706);
|
static const Color warningContainerDark = Color(0xD97706);
|
||||||
|
|
||||||
/// Warning on container dark theme
|
/// Warning on container dark theme
|
||||||
static const Color onWarningContainerDark = Color(0xFFFEF3C7);
|
static const Color onWarningContainerDark = Color(0xFEF3C7);
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// EXTENDED COLOR FAMILIES - INFO (BLUE)
|
// EXTENDED COLOR FAMILIES - INFO (BLUE)
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
/// Info color light theme
|
/// Info color light theme
|
||||||
static const Color infoLight = Color(0xFF3B82F6);
|
static const Color infoLight = Color(0x3B82F6);
|
||||||
|
|
||||||
/// Info on color light theme
|
/// Info on color light theme
|
||||||
static const Color onInfoLight = Color(0xFFFFFFFF);
|
static const Color onInfoLight = Color(0xFFFFFF);
|
||||||
|
|
||||||
/// Info container light theme
|
/// Info container light theme
|
||||||
static const Color infoContainerLight = Color(0xFFDEEEFF);
|
static const Color infoContainerLight = Color(0xDEEEFF);
|
||||||
|
|
||||||
/// Info on container light theme
|
/// Info on container light theme
|
||||||
static const Color onInfoContainerLight = Color(0xFF003DA1);
|
static const Color onInfoContainerLight = Color(0x003DA1);
|
||||||
|
|
||||||
/// Info color dark theme
|
/// Info color dark theme
|
||||||
static const Color infoDark = Color(0xFF90CAF9);
|
static const Color infoDark = Color(0x90CAF9);
|
||||||
|
|
||||||
/// Info on color dark theme
|
/// Info on color dark theme
|
||||||
static const Color onInfoDark = Color(0xFF003DA1);
|
static const Color onInfoDark = Color(0x003DA1);
|
||||||
|
|
||||||
/// Info container dark theme
|
/// Info container dark theme
|
||||||
static const Color infoContainerDark = Color(0xFF0D47A1);
|
static const Color infoContainerDark = Color(0x0D47A1);
|
||||||
|
|
||||||
/// Info on container dark theme
|
/// Info on container dark theme
|
||||||
static const Color onInfoContainerDark = Color(0xFFDEEEFF);
|
static const Color onInfoContainerDark = Color(0xDEEEFF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,17 +17,17 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.statusPending,
|
SvrntyColors.statusPending,
|
||||||
Color(0xFF506576), // Slightly different shade for gradient effect
|
Color(0x506576), // Slightly different shade for gradient effect
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
/// In Transit status gradient (Teal Blue)
|
/// In Progress status gradient (Blue/Info)
|
||||||
static const LinearGradient gradientStatusInTransit = LinearGradient(
|
static const LinearGradient gradientStatusInProgress = LinearGradient(
|
||||||
begin: Alignment.centerLeft,
|
begin: Alignment.centerLeft,
|
||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.statusInTransit,
|
SvrntyColors.statusInProgress,
|
||||||
Color(0xFF647A91), // Lighter teal for gradient
|
Color(0x5B9BFF), // Lighter blue for gradient
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -37,17 +37,17 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.statusCompleted,
|
SvrntyColors.statusCompleted,
|
||||||
Color(0xFF4ADE80), // Lighter green for gradient
|
Color(0x4ADE80), // Lighter green for gradient
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Cancelled status gradient (Light Gray)
|
/// Skipped status gradient (Amber/Warning)
|
||||||
static const LinearGradient gradientStatusCancelled = LinearGradient(
|
static const LinearGradient gradientStatusSkipped = LinearGradient(
|
||||||
begin: Alignment.centerLeft,
|
begin: Alignment.centerLeft,
|
||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.statusCancelled,
|
SvrntyColors.statusSkipped,
|
||||||
Color(0xFFC5CBD2), // Darker gray for gradient
|
Color(0xFBBF24), // Lighter amber for gradient
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.statusFailed,
|
SvrntyColors.statusFailed,
|
||||||
Color(0xFFFF7D7D), // Lighter red for gradient
|
Color(0xFF7D7D), // Lighter red for gradient
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.success,
|
SvrntyColors.success,
|
||||||
Color(0xFF4ADE80), // Lighter green
|
Color(0x4ADE80), // Lighter green
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.warning,
|
SvrntyColors.warning,
|
||||||
Color(0xFFFBBF24), // Lighter amber
|
Color(0xFBBF24), // Lighter amber
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.error,
|
SvrntyColors.error,
|
||||||
Color(0xFFFF7D7D), // Lighter red
|
Color(0xFF7D7D), // Lighter red
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.info,
|
SvrntyColors.info,
|
||||||
Color(0xFF5B9BFF), // Lighter blue
|
Color(0x5B9BFF), // Lighter blue
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ class AppGradients {
|
|||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
colors: [
|
colors: [
|
||||||
SvrntyColors.crimsonRed,
|
SvrntyColors.crimsonRed,
|
||||||
Color(0xFFC44D58), // Slightly darker shade
|
Color(0xC44D58), // Slightly darker shade
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -163,8 +163,8 @@ class AppGradients {
|
|||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
colors: [
|
colors: [
|
||||||
Color(0xFFFAFAFC),
|
Color(0xFAFAFC),
|
||||||
Color(0xFFF5F7FA),
|
Color(0xF5F7FA),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -173,8 +173,8 @@ class AppGradients {
|
|||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
colors: [
|
colors: [
|
||||||
Color(0xFF1A1C1E),
|
Color(0x1A1C1E),
|
||||||
Color(0xFF2A2D34),
|
Color(0x2A2D34),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -183,8 +183,8 @@ class AppGradients {
|
|||||||
begin: Alignment.topCenter,
|
begin: Alignment.topCenter,
|
||||||
end: Alignment.bottomCenter,
|
end: Alignment.bottomCenter,
|
||||||
colors: [
|
colors: [
|
||||||
Color(0xFFFFFFFF),
|
Color(0xFFFFFF),
|
||||||
Color(0xFFF5F7FA),
|
Color(0xF5F7FA),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -193,8 +193,8 @@ class AppGradients {
|
|||||||
begin: Alignment.topCenter,
|
begin: Alignment.topCenter,
|
||||||
end: Alignment.bottomCenter,
|
end: Alignment.bottomCenter,
|
||||||
colors: [
|
colors: [
|
||||||
Color(0xFF2A2D34),
|
Color(0x2A2D34),
|
||||||
Color(0xFF1F2123),
|
Color(0x1F2123),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -254,7 +254,7 @@ class AppGradients {
|
|||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
Color(0xFF2A2D34),
|
Color(0xFF2A2D34),
|
||||||
Color(0xFF383940),
|
Color(0x80383940),
|
||||||
Color(0xFF2A2D34),
|
Color(0xFF2A2D34),
|
||||||
],
|
],
|
||||||
stops: [0.1, 0.5, 0.9],
|
stops: [0.1, 0.5, 0.9],
|
||||||
@ -269,16 +269,14 @@ class AppGradients {
|
|||||||
switch (status.toLowerCase()) {
|
switch (status.toLowerCase()) {
|
||||||
case 'pending':
|
case 'pending':
|
||||||
return gradientStatusPending;
|
return gradientStatusPending;
|
||||||
case 'in_transit':
|
|
||||||
case 'in_progress':
|
case 'in_progress':
|
||||||
case 'inprogress':
|
case 'inprogress':
|
||||||
return gradientStatusInTransit;
|
return gradientStatusInProgress;
|
||||||
case 'completed':
|
case 'completed':
|
||||||
case 'done':
|
case 'done':
|
||||||
return gradientStatusCompleted;
|
return gradientStatusCompleted;
|
||||||
case 'cancelled':
|
|
||||||
case 'skipped':
|
case 'skipped':
|
||||||
return gradientStatusCancelled;
|
return gradientStatusSkipped;
|
||||||
case 'failed':
|
case 'failed':
|
||||||
return gradientStatusFailed;
|
return gradientStatusFailed;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -1,262 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'color_system.dart';
|
|
||||||
|
|
||||||
/// SVRNTY Status Color Utility
|
|
||||||
/// Provides consistent color access for delivery status indicators across the app
|
|
||||||
class StatusColorScheme {
|
|
||||||
// Pending: Amber - Attention needed
|
|
||||||
static const Color pending = SvrntyColors.statusPending; // #F59E0B
|
|
||||||
static const Color pendingBackground = SvrntyColors.statusPendingBg; // #FEF3C7
|
|
||||||
static const Color pendingText = Color(0xFF92400E);
|
|
||||||
|
|
||||||
// In Transit: Teal Blue - Active process
|
|
||||||
static const Color inTransit = SvrntyColors.statusInTransit; // #506576
|
|
||||||
static const Color inTransitBackground = SvrntyColors.statusInTransitBg; // #E0E7ED
|
|
||||||
static const Color inTransitText = Color(0xFF1D2C39);
|
|
||||||
|
|
||||||
// Completed: Green - Success
|
|
||||||
static const Color completed = SvrntyColors.statusCompleted; // #22C55E
|
|
||||||
static const Color completedBackground = SvrntyColors.statusCompletedBg; // #D1FAE5
|
|
||||||
static const Color completedText = Color(0xFF065F46);
|
|
||||||
|
|
||||||
// Failed: Red - Problem
|
|
||||||
static const Color failed = SvrntyColors.statusFailed; // #EF4444
|
|
||||||
static const Color failedBackground = SvrntyColors.statusFailedBg; // #FEE2E2
|
|
||||||
static const Color failedText = Color(0xFF991B1B);
|
|
||||||
|
|
||||||
// Cancelled: Gray - Inactive
|
|
||||||
static const Color cancelled = SvrntyColors.statusCancelled; // #AEB8BE
|
|
||||||
static const Color cancelledBackground = SvrntyColors.statusCancelledBg; // #F3F4F6
|
|
||||||
static const Color cancelledText = Color(0xFF374151);
|
|
||||||
|
|
||||||
// On Hold: Slate Blue - Paused/Informational
|
|
||||||
static const Color onHold = SvrntyColors.statusOnHold; // #3A4958
|
|
||||||
static const Color onHoldBackground = SvrntyColors.statusOnHoldBg; // #E2E8F0
|
|
||||||
static const Color onHoldText = Color(0xFF1E293B);
|
|
||||||
|
|
||||||
/// Get status color by status type
|
|
||||||
static Color getStatusColor(String status) {
|
|
||||||
switch (status.toLowerCase()) {
|
|
||||||
case 'pending':
|
|
||||||
return pending;
|
|
||||||
case 'in_transit':
|
|
||||||
case 'in_progress':
|
|
||||||
case 'processing':
|
|
||||||
return inTransit;
|
|
||||||
case 'completed':
|
|
||||||
case 'delivered':
|
|
||||||
case 'done':
|
|
||||||
return completed;
|
|
||||||
case 'failed':
|
|
||||||
case 'error':
|
|
||||||
return failed;
|
|
||||||
case 'cancelled':
|
|
||||||
case 'skipped':
|
|
||||||
case 'rejected':
|
|
||||||
return cancelled;
|
|
||||||
case 'on_hold':
|
|
||||||
case 'paused':
|
|
||||||
case 'waiting':
|
|
||||||
return onHold;
|
|
||||||
default:
|
|
||||||
return inTransit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get status background color by status type
|
|
||||||
static Color getStatusBackground(String status) {
|
|
||||||
switch (status.toLowerCase()) {
|
|
||||||
case 'pending':
|
|
||||||
return pendingBackground;
|
|
||||||
case 'in_transit':
|
|
||||||
case 'in_progress':
|
|
||||||
case 'processing':
|
|
||||||
return inTransitBackground;
|
|
||||||
case 'completed':
|
|
||||||
case 'delivered':
|
|
||||||
case 'done':
|
|
||||||
return completedBackground;
|
|
||||||
case 'failed':
|
|
||||||
case 'error':
|
|
||||||
return failedBackground;
|
|
||||||
case 'cancelled':
|
|
||||||
case 'skipped':
|
|
||||||
case 'rejected':
|
|
||||||
return cancelledBackground;
|
|
||||||
case 'on_hold':
|
|
||||||
case 'paused':
|
|
||||||
case 'waiting':
|
|
||||||
return onHoldBackground;
|
|
||||||
default:
|
|
||||||
return inTransitBackground;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get status text color by status type
|
|
||||||
static Color getStatusText(String status) {
|
|
||||||
switch (status.toLowerCase()) {
|
|
||||||
case 'pending':
|
|
||||||
return pendingText;
|
|
||||||
case 'in_transit':
|
|
||||||
case 'in_progress':
|
|
||||||
case 'processing':
|
|
||||||
return inTransitText;
|
|
||||||
case 'completed':
|
|
||||||
case 'delivered':
|
|
||||||
case 'done':
|
|
||||||
return completedText;
|
|
||||||
case 'failed':
|
|
||||||
case 'error':
|
|
||||||
return failedText;
|
|
||||||
case 'cancelled':
|
|
||||||
case 'skipped':
|
|
||||||
case 'rejected':
|
|
||||||
return cancelledText;
|
|
||||||
case 'on_hold':
|
|
||||||
case 'paused':
|
|
||||||
case 'waiting':
|
|
||||||
return onHoldText;
|
|
||||||
default:
|
|
||||||
return inTransitText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get status icon by status type
|
|
||||||
static IconData getStatusIcon(String status) {
|
|
||||||
switch (status.toLowerCase()) {
|
|
||||||
case 'pending':
|
|
||||||
return Icons.schedule;
|
|
||||||
case 'in_transit':
|
|
||||||
case 'in_progress':
|
|
||||||
case 'processing':
|
|
||||||
return Icons.local_shipping;
|
|
||||||
case 'completed':
|
|
||||||
case 'delivered':
|
|
||||||
case 'done':
|
|
||||||
return Icons.check_circle;
|
|
||||||
case 'failed':
|
|
||||||
case 'error':
|
|
||||||
return Icons.error;
|
|
||||||
case 'cancelled':
|
|
||||||
case 'skipped':
|
|
||||||
case 'rejected':
|
|
||||||
return Icons.cancel;
|
|
||||||
case 'on_hold':
|
|
||||||
case 'paused':
|
|
||||||
case 'waiting':
|
|
||||||
return Icons.pause_circle;
|
|
||||||
default:
|
|
||||||
return Icons.info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get status label by status type
|
|
||||||
static String getStatusLabel(String status) {
|
|
||||||
switch (status.toLowerCase()) {
|
|
||||||
case 'pending':
|
|
||||||
return 'Pending';
|
|
||||||
case 'in_transit':
|
|
||||||
case 'in_progress':
|
|
||||||
return 'In Transit';
|
|
||||||
case 'processing':
|
|
||||||
return 'Processing';
|
|
||||||
case 'completed':
|
|
||||||
case 'delivered':
|
|
||||||
return 'Delivered';
|
|
||||||
case 'done':
|
|
||||||
return 'Completed';
|
|
||||||
case 'failed':
|
|
||||||
case 'error':
|
|
||||||
return 'Failed';
|
|
||||||
case 'cancelled':
|
|
||||||
return 'Cancelled';
|
|
||||||
case 'skipped':
|
|
||||||
return 'Skipped';
|
|
||||||
case 'rejected':
|
|
||||||
return 'Rejected';
|
|
||||||
case 'on_hold':
|
|
||||||
return 'On Hold';
|
|
||||||
case 'paused':
|
|
||||||
return 'Paused';
|
|
||||||
case 'waiting':
|
|
||||||
return 'Waiting';
|
|
||||||
default:
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Status Badge Widget
|
|
||||||
class StatusBadgeWidget extends StatelessWidget {
|
|
||||||
final String status;
|
|
||||||
final bool showIcon;
|
|
||||||
final bool showLabel;
|
|
||||||
final double fontSize;
|
|
||||||
|
|
||||||
const StatusBadgeWidget({
|
|
||||||
Key? key,
|
|
||||||
required this.status,
|
|
||||||
this.showIcon = true,
|
|
||||||
this.showLabel = true,
|
|
||||||
this.fontSize = 12,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: StatusColorScheme.getStatusBackground(status),
|
|
||||||
borderRadius: BorderRadius.circular(6),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (showIcon) ...[
|
|
||||||
Icon(
|
|
||||||
StatusColorScheme.getStatusIcon(status),
|
|
||||||
color: StatusColorScheme.getStatusColor(status),
|
|
||||||
size: fontSize + 2,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 4),
|
|
||||||
],
|
|
||||||
if (showLabel)
|
|
||||||
Text(
|
|
||||||
StatusColorScheme.getStatusLabel(status),
|
|
||||||
style: TextStyle(
|
|
||||||
color: StatusColorScheme.getStatusColor(status),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: fontSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Status Accent Bar Widget (for list items)
|
|
||||||
class StatusAccentBar extends StatelessWidget {
|
|
||||||
final String status;
|
|
||||||
final double width;
|
|
||||||
final double height;
|
|
||||||
|
|
||||||
const StatusAccentBar({
|
|
||||||
Key? key,
|
|
||||||
required this.status,
|
|
||||||
this.width = 4,
|
|
||||||
this.height = 60,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: StatusColorScheme.getStatusColor(status),
|
|
||||||
borderRadius: BorderRadius.circular(width / 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user