brand theme, allot of features, allot of bug fixes

This commit is contained in:
Mathias Beaulieu-Duncan 2025-11-26 18:39:45 -05:00
parent 2ecd1c5b4e
commit 8e6aa6ea8c
10 changed files with 129 additions and 65 deletions

View File

@ -78,7 +78,7 @@ class _CollapsibleRoutesSidebarState extends ConsumerState<CollapsibleRoutesSide
// On mobile, always show as collapsible // On mobile, always show as collapsible
if (isMobile) { if (isMobile) {
return Container( return Container(
color: isDarkMode ? SvrntyColors.almostBlack : Colors.white, color: Theme.of(context).colorScheme.surface,
child: Column( child: Column(
children: [ children: [
// Header with toggle button // Header with toggle button
@ -125,7 +125,7 @@ class _CollapsibleRoutesSidebarState extends ConsumerState<CollapsibleRoutesSide
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut, curve: Curves.easeInOut,
width: isExpanded ? 300 : 80, width: isExpanded ? 300 : 80,
color: isDarkMode ? SvrntyColors.almostBlack : Colors.white, color: Theme.of(context).colorScheme.surface,
child: Column( child: Column(
children: [ children: [
// Header with toggle button // Header with toggle button

View File

@ -578,37 +578,39 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
// Photo button // Photo button (disabled when no delivery selected or warehouse delivery)
Expanded( Expanded(
child: _buildBottomActionButton( child: _buildBottomActionButton(
label: 'Photo', label: 'Photo',
icon: Icons.camera_alt, icon: Icons.camera_alt,
onPressed: () => widget.onAction?.call('photo'), onPressed: widget.selectedDelivery != null && !widget.selectedDelivery!.isWarehouseDelivery
? () => widget.onAction?.call('photo')
: null,
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
// Note button (only enabled if delivery has notes) // Note button (only enabled if delivery has notes and not warehouse)
Expanded( Expanded(
child: _buildBottomActionButton( child: _buildBottomActionButton(
label: 'Note', label: 'Note',
icon: Icons.note_add, icon: Icons.note_add,
onPressed: _hasNotes() onPressed: _hasNotes() && widget.selectedDelivery != null && !widget.selectedDelivery!.isWarehouseDelivery
? () => widget.onAction?.call('note') ? () => widget.onAction?.call('note')
: null, : null,
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
// Completed button // Completed button (disabled for warehouse delivery)
Expanded( Expanded(
child: _buildBottomActionButton( child: _buildBottomActionButton(
label: widget.selectedDelivery?.delivered == true ? 'Undo' : 'Completed', label: widget.selectedDelivery?.delivered == true ? 'Undo' : 'Completed',
icon: widget.selectedDelivery?.delivered == true ? Icons.undo : Icons.check_circle, icon: widget.selectedDelivery?.delivered == true ? Icons.undo : Icons.check_circle,
onPressed: widget.selectedDelivery != null onPressed: widget.selectedDelivery != null && !widget.selectedDelivery!.isWarehouseDelivery
? () => widget.onAction?.call( ? () => widget.onAction?.call(
widget.selectedDelivery!.delivered ? 'uncomplete' : 'complete', widget.selectedDelivery!.delivered ? 'uncomplete' : 'complete',
) )
: null, : null,
isPrimary: widget.selectedDelivery != null && !widget.selectedDelivery!.delivered, isPrimary: widget.selectedDelivery != null && !widget.selectedDelivery!.delivered && !widget.selectedDelivery!.isWarehouseDelivery,
), ),
), ),
], ],

View File

@ -145,7 +145,13 @@ class _DeliveryListItemState extends State<DeliveryListItem>
: [], : [],
), ),
child: Center( child: Center(
child: Text( child: widget.delivery.isWarehouseDelivery
? const Icon(
Icons.warehouse,
color: Colors.white,
size: 32,
)
: Text(
'${widget.delivery.deliveryIndex + 1}', '${widget.delivery.deliveryIndex + 1}',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
@ -254,7 +260,13 @@ class _DeliveryListItemState extends State<DeliveryListItem>
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Center( child: Center(
child: Text( child: widget.delivery.isWarehouseDelivery
? const Icon(
Icons.warehouse,
color: Colors.white,
size: 24,
)
: Text(
'${widget.delivery.deliveryIndex + 1}', '${widget.delivery.deliveryIndex + 1}',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,

View File

@ -36,6 +36,39 @@ class Delivery implements Serializable {
required this.name, required this.name,
}); });
// Special warehouse ID constant
static const int warehouseDeliveryId = -1;
// Check if this is the warehouse delivery
bool get isWarehouseDelivery => id == warehouseDeliveryId;
// Create a static warehouse delivery item
static Delivery createWarehouseDelivery() {
return Delivery(
id: warehouseDeliveryId,
routeFragmentId: -1,
deliveryIndex: 999,
orders: const [],
deliveryAddress: const DeliveryAddress(
id: -1,
line1: '3550 Rue de Cherbourg Suite 108',
line2: '',
postalCode: 'G8Y 6S6',
city: 'Trois-Rivières',
subdivision: 'QC',
countryCode: 'CA',
latitude: 46.3384605,
longitude: -72.6080797,
formattedAddress: '3550 Rue de Cherbourg Suite 108, Trois-Rivières, QC G8Y 6S6',
),
createdAt: DateTime.now().toIso8601String(),
delivered: false,
hasBeenSkipped: false,
isSkipped: false,
name: 'Return to Warehouse',
);
}
factory Delivery.fromJson(Map<String, dynamic> json) { factory Delivery.fromJson(Map<String, dynamic> json) {
return Delivery( return Delivery(
id: json['id'] as int, id: json['id'] as int,

View File

@ -2,41 +2,41 @@ import '../api/types.dart';
class DeliveryAddress implements Serializable { class DeliveryAddress implements Serializable {
final int id; final int id;
final String line1; final String? line1;
final String line2; final String? line2;
final String postalCode; final String? postalCode;
final String city; final String? city;
final String subdivision; final String? subdivision;
final String countryCode; final String? countryCode;
final double? latitude; final double? latitude;
final double? longitude; final double? longitude;
final String formattedAddress; final String? formattedAddress;
const DeliveryAddress({ const DeliveryAddress({
required this.id, required this.id,
required this.line1, this.line1,
required this.line2, this.line2,
required this.postalCode, this.postalCode,
required this.city, this.city,
required this.subdivision, this.subdivision,
required this.countryCode, this.countryCode,
this.latitude, this.latitude,
this.longitude, this.longitude,
required this.formattedAddress, this.formattedAddress,
}); });
factory DeliveryAddress.fromJson(Map<String, dynamic> json) { factory DeliveryAddress.fromJson(Map<String, dynamic> json) {
return DeliveryAddress( return DeliveryAddress(
id: json['id'] as int, id: json['id'] as int,
line1: json['line1'] as String, line1: json['line1'] as String?,
line2: json['line2'] as String, line2: json['line2'] as String?,
postalCode: json['postalCode'] as String, postalCode: json['postalCode'] as String?,
city: json['city'] as String, city: json['city'] as String?,
subdivision: json['subdivision'] as String, subdivision: json['subdivision'] as String?,
countryCode: json['countryCode'] as String, countryCode: json['countryCode'] as String?,
latitude: json['latitude'] as double?, latitude: json['latitude'] as double?,
longitude: json['longitude'] as double?, longitude: json['longitude'] as double?,
formattedAddress: json['formattedAddress'] as String, formattedAddress: json['formattedAddress'] as String?,
); );
} }

View File

@ -292,6 +292,11 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
String action, String action,
String? token, String? token,
) async { ) async {
// Prevent any actions on warehouse delivery except map navigation
if (delivery.isWarehouseDelivery && action != 'map') {
return;
}
if (token == null) { if (token == null) {
final l10n = AppLocalizations.of(context)!; final l10n = AppLocalizations.of(context)!;
ToastHelper.showError(context, l10n.authenticationRequired); ToastHelper.showError(context, l10n.authenticationRequired);
@ -621,7 +626,7 @@ class DeliveryCard extends StatelessWidget {
const SizedBox(height: 12), const SizedBox(height: 12),
if (delivery.deliveryAddress != null) if (delivery.deliveryAddress != null)
Text( Text(
delivery.deliveryAddress!.formattedAddress, delivery.deliveryAddress!.formattedAddress ?? '',
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,

View File

@ -520,6 +520,7 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
appBar: AppBar( appBar: AppBar(
title: Text(l10n.deliveryRoutes), title: Text(l10n.deliveryRoutes),
elevation: 0, elevation: 0,
scrolledUnderElevation: 0,
actions: [ actions: [
IconButton( IconButton(
icon: (routesData.isLoading || allDeliveriesData.isLoading) icon: (routesData.isLoading || allDeliveriesData.isLoading)

View File

@ -98,7 +98,18 @@ final deliveriesProvider = FutureProvider.family<List<Delivery>, int>((ref, rout
}, },
); );
return result.whenSuccess((deliveries) => deliveries) ?? []; // Log error if API call failed
result.whenError((error) {
print('ERROR fetching deliveries for route $routeFragmentId: ${error.message}');
if (error.originalException != null) {
print('Original exception: ${error.originalException}');
}
});
final deliveries = result.whenSuccess((deliveries) => deliveries) ?? [];
// Always append the warehouse delivery at the end
return [...deliveries, Delivery.createWarehouseDelivery()];
}); });
/// Provider to get all deliveries from all routes /// Provider to get all deliveries from all routes

View File

@ -177,7 +177,7 @@ class MaterialTheme {
return const ColorScheme( return const ColorScheme(
brightness: Brightness.dark, brightness: Brightness.dark,
primary: Color(0xffDF2D45), // Svrnty Crimson Red primary: Color(0xffDF2D45), // Svrnty Crimson Red
surfaceTint: Color(0xffFF6B7D), surfaceTint: Color(0xff4ADE80), // Success Green tint
onPrimary: Color(0xffffffff), onPrimary: Color(0xffffffff),
primaryContainer: Color(0xff9C1A29), primaryContainer: Color(0xff9C1A29),
onPrimaryContainer: Color(0xffFFE0E5), onPrimaryContainer: Color(0xffFFE0E5),
@ -185,15 +185,15 @@ class MaterialTheme {
onSecondary: Color(0xffffffff), onSecondary: Color(0xffffffff),
secondaryContainer: Color(0xff3A4958), secondaryContainer: Color(0xff3A4958),
onSecondaryContainer: Color(0xffD0DCE8), onSecondaryContainer: Color(0xffD0DCE8),
tertiary: Color(0xff5A8FA8), // Svrnty Teal variant tertiary: Color(0xff4ADE80), // Svrnty Success Green - Light
onTertiary: Color(0xffffffff), onTertiary: Color(0xff14532D), // Dark green for contrast
tertiaryContainer: Color(0xff1D2C39), tertiaryContainer: Color(0xff15803D), // Svrnty Forest Dark Green
onTertiaryContainer: Color(0xffBFD5E3), onTertiaryContainer: Color(0xffDCFCE7), // Light green tint
error: Color(0xffFF6B6B), error: Color(0xffFF6B6B),
onError: Color(0xff4C0707), onError: Color(0xff4C0707),
errorContainer: Color(0xff93000A), errorContainer: Color(0xff93000A),
onErrorContainer: Color(0xffFEE2E2), onErrorContainer: Color(0xffFEE2E2),
surface: Color(0xff0A0C10), // Svrnty Dark Background surface: Color(0xff0C1410), // Svrnty Dark Green Background
onSurface: Color(0xffF0F0F2), onSurface: Color(0xffF0F0F2),
onSurfaceVariant: Color(0xffBFC3C8), onSurfaceVariant: Color(0xffBFC3C8),
outline: Color(0xff9CA3AF), // Enhanced contrast for dark mode outline: Color(0xff9CA3AF), // Enhanced contrast for dark mode
@ -210,17 +210,17 @@ class MaterialTheme {
onSecondaryFixed: Color(0xff06080C), onSecondaryFixed: Color(0xff06080C),
secondaryFixedDim: Color(0xff506576), secondaryFixedDim: Color(0xff506576),
onSecondaryFixedVariant: Color(0xff3A4958), onSecondaryFixedVariant: Color(0xff3A4958),
tertiaryFixed: Color(0xffBFD5E3), tertiaryFixed: Color(0xffDCFCE7), // Light green container
onTertiaryFixed: Color(0xff001219), onTertiaryFixed: Color(0xff14532D), // Dark green text
tertiaryFixedDim: Color(0xff5A8FA8), tertiaryFixedDim: Color(0xff4ADE80), // Success green
onTertiaryFixedVariant: Color(0xff1D2C39), onTertiaryFixedVariant: Color(0xff15803D), // Forest green
surfaceDim: Color(0xff0A0C10), surfaceDim: Color(0xff0A110E), // Darker forest green
surfaceBright: Color(0xff404244), surfaceBright: Color(0xff1F2D25), // Brighter green tint
surfaceContainerLowest: Color(0xff040507), surfaceContainerLowest: Color(0xff070D0A), // Deepest green
surfaceContainerLow: Color(0xff0F1114), surfaceContainerLow: Color(0xff141B18), // Low green
surfaceContainer: Color(0xff14161A), surfaceContainer: Color(0xff18221D), // Mid forest green
surfaceContainerHigh: Color(0xff1F2228), surfaceContainerHigh: Color(0xff1D2822), // High green
surfaceContainerHighest: Color(0xff2A2D34), surfaceContainerHighest: Color(0xff222F29), // Highest green tint
); );
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB