Compare commits

..

No commits in common. "44500835d751da2726b858274f3b1392200cfa93" and "65f0f4451b41d6190b15ab616105fd9c4e611f86" have entirely different histories.

2 changed files with 59 additions and 79 deletions

View File

@ -24,13 +24,10 @@ android {
applicationId = "com.goutezplanb.planb_logistic" applicationId = "com.goutezplanb.planb_logistic"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion // Required for Google Navigation Flutter minSdk = 23 // Required for Google Navigation Flutter
targetSdk = flutter.targetSdkVersion targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName
// OAuth redirect scheme for flutter_appauth
manifestPlaceholders["appAuthRedirectScheme"] = "com.goutezplanb.delivery"
} }
packagingOptions { packagingOptions {

View File

@ -312,7 +312,7 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
// Calculate dynamic padding for bottom button bar // Calculate dynamic padding for bottom button bar
final topPadding = 0.0; final topPadding = 0.0;
final bottomPadding = 110.0; final bottomPadding = widget.selectedDelivery != null ? 110.0 : 0.0;
return Stack( return Stack(
children: [ children: [
@ -327,34 +327,10 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
_navigationController = controller; _navigationController = controller;
// Apply dark mode style with a small delay to ensure map is ready // Apply dark mode style with a small delay to ensure map is ready
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 500));
// Safety check: ensure widget is still mounted before proceeding
if (!mounted) return;
await _applyDarkModeStyle(); await _applyDarkModeStyle();
controller.animateCamera(
// Wrap camera animation in try-catch to handle "No valid view found" errors CameraUpdate.newLatLngZoom(initialPosition, 12),
// This can happen on Android when the view isn't fully ready );
try {
if (mounted && _navigationController != null) {
await controller.animateCamera(
CameraUpdate.newLatLngZoom(initialPosition, 12),
);
}
} catch (e) {
debugPrint('Camera animation error (view may not be ready): $e');
// Retry once after a longer delay
await Future.delayed(const Duration(milliseconds: 1000));
if (mounted && _navigationController != null) {
try {
await controller.animateCamera(
CameraUpdate.newLatLngZoom(initialPosition, 12),
);
} catch (e2) {
debugPrint('Camera animation retry failed: $e2');
}
}
}
}, },
initialCameraPosition: CameraPosition( initialCameraPosition: CameraPosition(
target: initialPosition, target: initialPosition,
@ -362,8 +338,9 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
), ),
), ),
), ),
// Bottom action button bar - 4 equal-width buttons (always visible) // Bottom action button bar
Positioned( if (widget.selectedDelivery != null)
Positioned(
bottom: 0, bottom: 0,
left: 0, left: 0,
right: 0, right: 0,
@ -384,49 +361,55 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
), ),
child: Row( child: Row(
children: [ children: [
// Start button // Recenter button
Expanded( Expanded(
child: _buildBottomActionButton( child: _buildBottomActionButton(
label: _isNavigating ? 'Stop' : 'Start', label: 'Recenter',
icon: _isNavigating ? Icons.stop : Icons.navigation, icon: Icons.location_on,
onPressed: _isStartingNavigation || _isInitializing || (widget.selectedDelivery == null && !_isNavigating) onPressed: _recenterMap,
? null
: (_isNavigating ? _stopNavigation : _startNavigation),
isDanger: _isNavigating,
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 12),
// Photo button // Mark Complete button (if not already delivered)
Expanded( if (!widget.selectedDelivery!.delivered)
child: _buildBottomActionButton( Expanded(
label: 'Photo', child: _buildBottomActionButton(
icon: Icons.camera_alt, label: 'Mark Complete',
onPressed: () => widget.onAction?.call('photo'), icon: Icons.check_circle,
onPressed: () => widget.onAction?.call('complete'),
isPrimary: true,
),
), ),
), if (widget.selectedDelivery!.delivered)
const SizedBox(width: 8), Expanded(
// Note button child: _buildBottomActionButton(
Expanded( label: _isInitializing ? 'Initializing...' : 'Start Navigation',
child: _buildBottomActionButton( icon: Icons.directions,
label: 'Note', onPressed: _isInitializing ? null : _startNavigation,
icon: Icons.note_add, isPrimary: true,
onPressed: () => widget.onAction?.call('note'), ),
), ),
), if (!_isNavigating && !widget.selectedDelivery!.delivered)
const SizedBox(width: 8), const SizedBox(width: 12),
// Completed button if (!_isNavigating && !widget.selectedDelivery!.delivered)
Expanded( Expanded(
child: _buildBottomActionButton( child: _buildBottomActionButton(
label: widget.selectedDelivery?.delivered == true ? 'Undo' : 'Completed', label: _isStartingNavigation || _isInitializing ? 'Loading...' : 'Navigate',
icon: widget.selectedDelivery?.delivered == true ? Icons.undo : Icons.check_circle, icon: Icons.directions,
onPressed: widget.selectedDelivery != null onPressed: _isStartingNavigation || _isInitializing ? null : _startNavigation,
? () => widget.onAction?.call( ),
widget.selectedDelivery!.delivered ? 'uncomplete' : 'complete', ),
) if (_isNavigating)
: null, const SizedBox(width: 12),
isPrimary: widget.selectedDelivery != null && !widget.selectedDelivery!.delivered, if (_isNavigating)
Expanded(
child: _buildBottomActionButton(
label: 'Stop',
icon: Icons.stop,
onPressed: _stopNavigation,
isDanger: true,
),
), ),
),
], ],
), ),
), ),
@ -503,12 +486,12 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
Color textColor = Colors.white; Color textColor = Colors.white;
if (isDanger) { if (isDanger) {
backgroundColor = SvrntyColors.crimsonRed; backgroundColor = Colors.red.shade600;
} else if (isPrimary) { } else if (isPrimary) {
backgroundColor = SvrntyColors.crimsonRed; backgroundColor = SvrntyColors.crimsonRed;
} else { } else {
// Use the same slateGray as delivery list badges backgroundColor = Theme.of(context).colorScheme.surfaceContainerHighest;
backgroundColor = SvrntyColors.slateGray; textColor = Theme.of(context).colorScheme.onSurface;
} }
// Reduce opacity when disabled // Reduce opacity when disabled
@ -524,8 +507,8 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 14, horizontal: 12,
vertical: 14, vertical: 12,
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -534,15 +517,15 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
Icon( Icon(
icon, icon,
color: textColor, color: textColor,
size: 24, size: 18,
), ),
const SizedBox(width: 8), const SizedBox(width: 6),
Text( Text(
label, label,
style: TextStyle( style: TextStyle(
color: textColor, color: textColor,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w500,
fontSize: 18, fontSize: 14,
), ),
), ),
], ],