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

View File

@ -578,37 +578,39 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
),
),
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,
),
),
],

View File

@ -145,14 +145,20 @@ class _DeliveryListItemState extends State<DeliveryListItem>
: [],
),
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<DeliveryListItem>
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),

View File

@ -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<String, dynamic> json) {
return Delivery(
id: json['id'] as int,

View File

@ -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<String, dynamic> 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?,
);
}

View File

@ -292,6 +292,11 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
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,

View File

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

View File

@ -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
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB