auto-claude/001-normalize-code-update-packages-widgetify-component #1

Merged
mathias merged 12 commits from auto-claude/001-normalize-code-update-packages-widgetify-component into main 2026-01-20 12:25:49 -05:00
6 changed files with 84 additions and 177 deletions
Showing only changes of commit 697b724f02 - Show all commits

View File

@ -146,5 +146,8 @@
}
},
"serverError": "Server error - Please contact support",
"retake": "Retake"
"retake": "Retake",
"completingDelivery": "Completing delivery...",
"markingAsUncompleted": "Marking as uncompleted...",
"deliveryMarkedUncompleted": "Delivery marked as uncompleted"
}

View File

@ -146,5 +146,8 @@
}
},
"serverError": "Erreur serveur - Veuillez contacter le support",
"retake": "Reprendre"
"retake": "Reprendre",
"completingDelivery": "Completion de la livraison...",
"markingAsUncompleted": "Marquage comme a livrer...",
"deliveryMarkedUncompleted": "Livraison marquee comme a livrer"
}

View File

@ -631,6 +631,24 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Retake'**
String get retake;
/// No description provided for @completingDelivery.
///
/// In en, this message translates to:
/// **'Completing delivery...'**
String get completingDelivery;
/// No description provided for @markingAsUncompleted.
///
/// In en, this message translates to:
/// **'Marking as uncompleted...'**
String get markingAsUncompleted;
/// No description provided for @deliveryMarkedUncompleted.
///
/// In en, this message translates to:
/// **'Delivery marked as uncompleted'**
String get deliveryMarkedUncompleted;
}
class _AppLocalizationsDelegate

View File

@ -302,4 +302,13 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get retake => 'Retake';
@override
String get completingDelivery => 'Completing delivery...';
@override
String get markingAsUncompleted => 'Marking as uncompleted...';
@override
String get deliveryMarkedUncompleted => 'Delivery marked as uncompleted';
}

View File

@ -302,4 +302,13 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get retake => 'Reprendre';
@override
String get completingDelivery => 'Completion de la livraison...';
@override
String get markingAsUncompleted => 'Marquage comme a livrer...';
@override
String get deliveryMarkedUncompleted => 'Livraison marquee comme a livrer';
}

View File

@ -11,10 +11,12 @@ import '../providers/providers.dart';
import '../api/client.dart';
import '../utils/toast_helper.dart';
import '../api/openapi_config.dart';
import '../utils/breakpoints.dart';
import '../utils/http_client_factory.dart';
import '../components/collapsible_routes_sidebar.dart';
import '../components/dark_mode_map.dart';
import '../components/loading_dialog.dart';
import '../components/notes_dialog.dart';
import '../components/photo_capture_dialog.dart';
import '../services/location_permission_service.dart';
import 'deliveries_page.dart';
import 'settings_page.dart';
@ -81,13 +83,14 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
Delivery delivery,
int routeFragmentId,
) async {
// Capture l10n before async operations to avoid BuildContext across async gaps
final l10n = AppLocalizations.of(context);
final authService = ref.read(authServiceProvider);
// Ensure we have a valid token (automatically refreshes if needed)
final token = await authService.ensureValidToken();
if (token == null) {
if (mounted) {
final l10n = AppLocalizations.of(context)!;
ToastHelper.showError(context, l10n.authenticationRequired);
}
return;
@ -102,27 +105,7 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
switch (action) {
case 'complete':
if (mounted) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext dialogContext) {
return const Center(
child: Card(
child: Padding(
padding: EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Completing delivery...'),
],
),
),
),
);
},
);
LoadingDialog.show(context, message: l10n.completingDelivery);
}
final result = await authClient.executeCommand(
@ -134,7 +117,7 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
result.when(
success: (_) async {
if (mounted) {
Navigator.of(context).pop();
LoadingDialog.hide(context);
}
if (mounted) {
@ -176,23 +159,21 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
}
if (mounted) {
final l10n = AppLocalizations.of(context)!;
ToastHelper.showSuccess(context, l10n.deliverySuccessful);
}
}
},
onError: (error) {
if (mounted) {
Navigator.of(context).pop();
LoadingDialog.hide(context);
}
debugPrint('Complete delivery failed - Type: ${error.type}, Message: ${error.message}');
debugPrint('Error details: ${error.details}');
if (mounted) {
final l10n = AppLocalizations.of(context)!;
String errorMessage = l10n.error(error.message);
if (error.statusCode == 500) {
errorMessage = 'Server error - Please contact support';
errorMessage = l10n.serverError;
}
ToastHelper.showError(context, errorMessage);
}
@ -202,37 +183,17 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
case 'uncomplete':
if (mounted) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext dialogContext) {
return const Center(
child: Card(
child: Padding(
padding: EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Marking as uncompleted...'),
],
),
),
),
);
},
);
LoadingDialog.show(context, message: l10n.markingAsUncompleted);
}
final result = await authClient.executeCommand(
final uncompleteResult = await authClient.executeCommand(
endpoint: 'markDeliveryAsUncompleted',
command: MarkDeliveryAsUncompletedCommand(deliveryId: delivery.id),
);
result.when(
uncompleteResult.when(
success: (_) async {
if (mounted) {
Navigator.of(context).pop();
LoadingDialog.hide(context);
}
if (mounted) {
@ -257,18 +218,16 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
}
if (mounted) {
final l10n = AppLocalizations.of(context)!;
ToastHelper.showSuccess(context, 'Delivery marked as uncompleted');
ToastHelper.showSuccess(context, l10n.deliveryMarkedUncompleted);
}
}
},
onError: (error) {
if (mounted) {
Navigator.of(context).pop();
LoadingDialog.hide(context);
}
if (mounted) {
final l10n = AppLocalizations.of(context)!;
ToastHelper.showError(context, l10n.error(error.message));
}
},
@ -289,12 +248,12 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
Delivery delivery,
) async {
final authService = ref.read(authServiceProvider);
final l10n = AppLocalizations.of(context);
// Ensure we have a valid token (automatically refreshes if needed)
final token = await authService.ensureValidToken();
if (token == null) {
if (mounted) {
final l10n = AppLocalizations.of(context)!;
ToastHelper.showError(context, l10n.authenticationRequired);
}
return;
@ -309,7 +268,7 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
);
} catch (e) {
if (mounted) {
ToastHelper.showError(context, 'Camera error: $e');
ToastHelper.showError(context, l10n.cameraError(e.toString()));
}
return;
}
@ -320,45 +279,11 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
if (!mounted) return;
final bool? confirmed = await showDialog<bool>(
context: context,
builder: (BuildContext dialogContext) {
return AlertDialog(
title: const Text('Confirm Photo'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(dialogContext).size.height * 0.5,
maxWidth: MediaQuery.of(dialogContext).size.width * 0.8,
),
child: Image.file(
File(pickedFile!.path),
fit: BoxFit.contain,
),
),
const SizedBox(height: 16),
Text(
'Upload this photo for ${delivery.name}?',
textAlign: TextAlign.center,
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(false),
child: const Text('Cancel'),
),
ElevatedButton(
onPressed: () => Navigator.of(dialogContext).pop(true),
child: const Text('Upload'),
),
],
);
},
// Show photo confirmation dialog
final bool? confirmed = await PhotoCaptureDialog.show(
context,
imageFile: File(pickedFile.path),
deliveryName: delivery.name,
);
if (confirmed != true) {
@ -367,27 +292,8 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
if (!mounted) return;
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext dialogContext) {
return const Center(
child: Card(
child: Padding(
padding: EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Uploading photo...'),
],
),
),
),
);
},
);
// Show uploading dialog
LoadingDialog.show(context, message: l10n.uploadingPhoto);
try {
final Uri uploadUrl = Uri.parse(
@ -408,33 +314,31 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
client.close();
if (mounted) {
Navigator.of(context).pop();
LoadingDialog.hide(context);
}
if (response.statusCode >= 200 && response.statusCode < 300) {
if (mounted) {
ToastHelper.showSuccess(context, 'Photo uploaded successfully');
ToastHelper.showSuccess(context, l10n.photoUploadSuccess);
}
ref.refresh(allDeliveriesProvider);
ref.invalidate(allDeliveriesProvider);
} else {
debugPrint('Photo upload failed - Status: ${response.statusCode}');
debugPrint('Response body: ${response.body}');
if (mounted) {
String errorMessage = 'Upload failed';
String errorMessage = l10n.photoUploadFailed(response.statusCode);
if (response.statusCode == 500) {
errorMessage = 'Server error - Please contact support';
errorMessage = l10n.serverError;
} else if (response.statusCode == 401) {
errorMessage = 'Authentication required - Please log in again';
} else {
errorMessage = 'Upload failed: ${response.statusCode}';
errorMessage = l10n.authenticationRequired;
}
ToastHelper.showError(context, errorMessage);
}
}
} catch (e) {
if (mounted) {
Navigator.of(context).pop();
ToastHelper.showError(context, 'Upload error: $e');
LoadingDialog.hide(context);
ToastHelper.showError(context, l10n.uploadError(e.toString()));
}
}
}
@ -462,53 +366,14 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
}
Future<void> _showNotesDialog(Delivery delivery) async {
final notes = delivery.orders
.where((order) => order.note != null && order.note!.isNotEmpty)
.map((order) => order.note!)
.toList();
if (!mounted) return;
if (notes.isEmpty) {
ToastHelper.showInfo(context, 'No notes attached to this delivery');
return;
}
final l10n = AppLocalizations.of(context);
final hasNotes = await NotesDialog.show(context, delivery);
await showDialog(
context: context,
builder: (BuildContext dialogContext) {
return AlertDialog(
title: Text('Notes for ${delivery.name}'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: notes.map((note) => Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: Text(
note,
style: Theme.of(dialogContext).textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
)).toList(),
),
),
actionsAlignment: MainAxisAlignment.center,
actionsPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
actions: [
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () => Navigator.of(dialogContext).pop(),
child: const Text('Close'),
),
),
],
);
},
);
if (!hasNotes && mounted) {
ToastHelper.showInfo(context, l10n.noNotesMessage);
}
}
@override
@ -516,7 +381,7 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
final routesData = ref.watch(deliveryRoutesProvider);
final allDeliveriesData = ref.watch(allDeliveriesProvider);
final userProfile = ref.watch(userProfileProvider);
final l10n = AppLocalizations.of(context)!;
final l10n = AppLocalizations.of(context);
return Scaffold(
appBar: AppBar(
@ -535,8 +400,8 @@ class _RoutesPageState extends ConsumerState<RoutesPage> {
onPressed: (routesData.isLoading || allDeliveriesData.isLoading)
? null
: () {
ref.refresh(deliveryRoutesProvider);
ref.refresh(allDeliveriesProvider);
ref.invalidate(deliveryRoutesProvider);
ref.invalidate(allDeliveriesProvider);
},
tooltip: 'Refresh',
),