diff --git a/lib/components/collapsible_routes_sidebar.dart b/lib/components/collapsible_routes_sidebar.dart index 85c6ae0..a59d46b 100644 --- a/lib/components/collapsible_routes_sidebar.dart +++ b/lib/components/collapsible_routes_sidebar.dart @@ -78,7 +78,7 @@ class _CollapsibleRoutesSidebarState extends ConsumerState { ), ), const SizedBox(width: 8), - // Photo button + // Photo button (disabled when no delivery selected or warehouse delivery) Expanded( child: _buildBottomActionButton( label: 'Photo', 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), - // Note button (only enabled if delivery has notes) + // Note button (only enabled if delivery has notes and not warehouse) Expanded( child: _buildBottomActionButton( label: 'Note', icon: Icons.note_add, - onPressed: _hasNotes() + onPressed: _hasNotes() && widget.selectedDelivery != null && !widget.selectedDelivery!.isWarehouseDelivery ? () => widget.onAction?.call('note') : null, ), ), const SizedBox(width: 8), - // Completed button + // Completed button (disabled for warehouse delivery) Expanded( child: _buildBottomActionButton( label: widget.selectedDelivery?.delivered == true ? 'Undo' : 'Completed', 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.selectedDelivery!.delivered ? 'uncomplete' : 'complete', ) : null, - isPrimary: widget.selectedDelivery != null && !widget.selectedDelivery!.delivered, + isPrimary: widget.selectedDelivery != null && !widget.selectedDelivery!.delivered && !widget.selectedDelivery!.isWarehouseDelivery, ), ), ], diff --git a/lib/components/delivery_list_item.dart b/lib/components/delivery_list_item.dart index 317f626..55f4d4b 100644 --- a/lib/components/delivery_list_item.dart +++ b/lib/components/delivery_list_item.dart @@ -145,14 +145,20 @@ class _DeliveryListItemState extends State : [], ), child: Center( - child: Text( - '${widget.delivery.deliveryIndex + 1}', - style: const TextStyle( - color: Colors.white, - fontSize: 26, - fontWeight: FontWeight.w700, - ), - ), + child: widget.delivery.isWarehouseDelivery + ? const Icon( + Icons.warehouse, + color: Colors.white, + size: 32, + ) + : Text( + '${widget.delivery.deliveryIndex + 1}', + style: const TextStyle( + color: Colors.white, + fontSize: 26, + fontWeight: FontWeight.w700, + ), + ), ), ), if (_hasNote()) @@ -254,14 +260,20 @@ class _DeliveryListItemState extends State borderRadius: BorderRadius.circular(8), ), child: Center( - child: Text( - '${widget.delivery.deliveryIndex + 1}', - style: const TextStyle( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.w700, - ), - ), + child: widget.delivery.isWarehouseDelivery + ? const Icon( + Icons.warehouse, + color: Colors.white, + size: 24, + ) + : Text( + '${widget.delivery.deliveryIndex + 1}', + style: const TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w700, + ), + ), ), ), const SizedBox(width: 8), diff --git a/lib/models/delivery.dart b/lib/models/delivery.dart index e115a36..f78d40e 100644 --- a/lib/models/delivery.dart +++ b/lib/models/delivery.dart @@ -36,6 +36,39 @@ class Delivery implements Serializable { 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 json) { return Delivery( id: json['id'] as int, diff --git a/lib/models/delivery_address.dart b/lib/models/delivery_address.dart index 371ed01..e8c01a0 100644 --- a/lib/models/delivery_address.dart +++ b/lib/models/delivery_address.dart @@ -2,41 +2,41 @@ import '../api/types.dart'; class DeliveryAddress implements Serializable { final int id; - final String line1; - final String line2; - final String postalCode; - final String city; - final String subdivision; - final String countryCode; + final String? line1; + final String? line2; + final String? postalCode; + final String? city; + final String? subdivision; + final String? countryCode; final double? latitude; final double? longitude; - final String formattedAddress; + final String? formattedAddress; const DeliveryAddress({ required this.id, - required this.line1, - required this.line2, - required this.postalCode, - required this.city, - required this.subdivision, - required this.countryCode, + this.line1, + this.line2, + this.postalCode, + this.city, + this.subdivision, + this.countryCode, this.latitude, this.longitude, - required this.formattedAddress, + this.formattedAddress, }); factory DeliveryAddress.fromJson(Map json) { return DeliveryAddress( id: json['id'] as int, - line1: json['line1'] as String, - line2: json['line2'] as String, - postalCode: json['postalCode'] as String, - city: json['city'] as String, - subdivision: json['subdivision'] as String, - countryCode: json['countryCode'] as String, + line1: json['line1'] as String?, + line2: json['line2'] as String?, + postalCode: json['postalCode'] as String?, + city: json['city'] as String?, + subdivision: json['subdivision'] as String?, + countryCode: json['countryCode'] as String?, latitude: json['latitude'] as double?, longitude: json['longitude'] as double?, - formattedAddress: json['formattedAddress'] as String, + formattedAddress: json['formattedAddress'] as String?, ); } diff --git a/lib/pages/deliveries_page.dart b/lib/pages/deliveries_page.dart index dcbb7a7..f8ae480 100644 --- a/lib/pages/deliveries_page.dart +++ b/lib/pages/deliveries_page.dart @@ -292,6 +292,11 @@ class _DeliveriesPageState extends ConsumerState { String action, String? token, ) async { + // Prevent any actions on warehouse delivery except map navigation + if (delivery.isWarehouseDelivery && action != 'map') { + return; + } + if (token == null) { final l10n = AppLocalizations.of(context)!; ToastHelper.showError(context, l10n.authenticationRequired); @@ -621,7 +626,7 @@ class DeliveryCard extends StatelessWidget { const SizedBox(height: 12), if (delivery.deliveryAddress != null) Text( - delivery.deliveryAddress!.formattedAddress, + delivery.deliveryAddress!.formattedAddress ?? '', style: Theme.of(context).textTheme.bodySmall, maxLines: 2, overflow: TextOverflow.ellipsis, diff --git a/lib/pages/routes_page.dart b/lib/pages/routes_page.dart index a24b65f..72e45eb 100644 --- a/lib/pages/routes_page.dart +++ b/lib/pages/routes_page.dart @@ -520,6 +520,7 @@ class _RoutesPageState extends ConsumerState { appBar: AppBar( title: Text(l10n.deliveryRoutes), elevation: 0, + scrolledUnderElevation: 0, actions: [ IconButton( icon: (routesData.isLoading || allDeliveriesData.isLoading) diff --git a/lib/providers/providers.dart b/lib/providers/providers.dart index bd90506..17cf033 100644 --- a/lib/providers/providers.dart +++ b/lib/providers/providers.dart @@ -98,7 +98,18 @@ final deliveriesProvider = FutureProvider.family, 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 diff --git a/lib/theme.dart b/lib/theme.dart index 3f2267b..f86485b 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -177,7 +177,7 @@ class MaterialTheme { return const ColorScheme( brightness: Brightness.dark, primary: Color(0xffDF2D45), // Svrnty Crimson Red - surfaceTint: Color(0xffFF6B7D), + surfaceTint: Color(0xff4ADE80), // Success Green tint onPrimary: Color(0xffffffff), primaryContainer: Color(0xff9C1A29), onPrimaryContainer: Color(0xffFFE0E5), @@ -185,15 +185,15 @@ class MaterialTheme { onSecondary: Color(0xffffffff), secondaryContainer: Color(0xff3A4958), onSecondaryContainer: Color(0xffD0DCE8), - tertiary: Color(0xff5A8FA8), // Svrnty Teal variant - onTertiary: Color(0xffffffff), - tertiaryContainer: Color(0xff1D2C39), - onTertiaryContainer: Color(0xffBFD5E3), + tertiary: Color(0xff4ADE80), // Svrnty Success Green - Light + onTertiary: Color(0xff14532D), // Dark green for contrast + tertiaryContainer: Color(0xff15803D), // Svrnty Forest Dark Green + onTertiaryContainer: Color(0xffDCFCE7), // Light green tint error: Color(0xffFF6B6B), onError: Color(0xff4C0707), errorContainer: Color(0xff93000A), onErrorContainer: Color(0xffFEE2E2), - surface: Color(0xff0A0C10), // Svrnty Dark Background + surface: Color(0xff0C1410), // Svrnty Dark Green Background onSurface: Color(0xffF0F0F2), onSurfaceVariant: Color(0xffBFC3C8), outline: Color(0xff9CA3AF), // Enhanced contrast for dark mode @@ -210,17 +210,17 @@ class MaterialTheme { onSecondaryFixed: Color(0xff06080C), secondaryFixedDim: Color(0xff506576), onSecondaryFixedVariant: Color(0xff3A4958), - tertiaryFixed: Color(0xffBFD5E3), - onTertiaryFixed: Color(0xff001219), - tertiaryFixedDim: Color(0xff5A8FA8), - onTertiaryFixedVariant: Color(0xff1D2C39), - surfaceDim: Color(0xff0A0C10), - surfaceBright: Color(0xff404244), - surfaceContainerLowest: Color(0xff040507), - surfaceContainerLow: Color(0xff0F1114), - surfaceContainer: Color(0xff14161A), - surfaceContainerHigh: Color(0xff1F2228), - surfaceContainerHighest: Color(0xff2A2D34), + tertiaryFixed: Color(0xffDCFCE7), // Light green container + onTertiaryFixed: Color(0xff14532D), // Dark green text + tertiaryFixedDim: Color(0xff4ADE80), // Success green + onTertiaryFixedVariant: Color(0xff15803D), // Forest green + surfaceDim: Color(0xff0A110E), // Darker forest green + surfaceBright: Color(0xff1F2D25), // Brighter green tint + surfaceContainerLowest: Color(0xff070D0A), // Deepest green + surfaceContainerLow: Color(0xff141B18), // Low green + surfaceContainer: Color(0xff18221D), // Mid forest green + surfaceContainerHigh: Color(0xff1D2822), // High green + surfaceContainerHighest: Color(0xff222F29), // Highest green tint ); } diff --git a/screenshot_forest_green_theme.png b/screenshot_forest_green_theme.png new file mode 100644 index 0000000..b14d689 Binary files /dev/null and b/screenshot_forest_green_theme.png differ