diff --git a/lib/components/photo_capture_dialog.dart b/lib/components/photo_capture_dialog.dart new file mode 100644 index 0000000..a867820 --- /dev/null +++ b/lib/components/photo_capture_dialog.dart @@ -0,0 +1,133 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:planb_logistic/l10n/app_localizations.dart'; + +/// A dialog component for confirming and displaying captured photos before upload. +/// +/// This dialog shows a preview of the captured photo and prompts the user +/// to confirm the upload or cancel/retake. +/// +/// Example: +/// ```dart +/// final confirmed = await PhotoCaptureDialog.show( +/// context, +/// imageFile: File(pickedFile.path), +/// deliveryName: delivery.name, +/// ); +/// +/// if (confirmed == true) { +/// // Proceed with upload +/// } +/// ``` +class PhotoCaptureDialog extends StatelessWidget { + /// The captured image file to display. + final File imageFile; + + /// The name of the delivery for the confirmation message. + final String deliveryName; + + const PhotoCaptureDialog({ + super.key, + required this.imageFile, + required this.deliveryName, + }); + + /// Shows the photo capture confirmation dialog. + /// + /// Returns `true` if the user confirms the upload, `false` if cancelled. + /// Returns `null` if the dialog is dismissed without selection. + static Future show( + BuildContext context, { + required File imageFile, + required String deliveryName, + }) { + return showDialog( + context: context, + builder: (BuildContext dialogContext) { + return PhotoCaptureDialog( + imageFile: imageFile, + deliveryName: deliveryName, + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context); + final colorScheme = Theme.of(context).colorScheme; + final textTheme = Theme.of(context).textTheme; + final screenSize = MediaQuery.of(context).size; + + return AlertDialog( + title: Text( + l10n.confirmPhoto, + style: textTheme.headlineSmall?.copyWith( + color: colorScheme.onSurface, + ), + ), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: screenSize.height * 0.5, + maxWidth: screenSize.width * 0.8, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + imageFile, + fit: BoxFit.contain, + errorBuilder: (context, error, stackTrace) { + return Container( + height: 200, + width: double.infinity, + decoration: BoxDecoration( + color: colorScheme.errorContainer, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Icon( + Icons.broken_image, + size: 48, + color: colorScheme.error, + ), + ), + ); + }, + ), + ), + ), + const SizedBox(height: 16), + Text( + l10n.uploadPhotoConfirmation(deliveryName), + style: textTheme.bodyMedium?.copyWith( + color: colorScheme.onSurface, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text( + l10n.cancel, + style: TextStyle(color: colorScheme.error), + ), + ), + ElevatedButton( + onPressed: () => Navigator.of(context).pop(true), + style: ElevatedButton.styleFrom( + backgroundColor: colorScheme.primary, + foregroundColor: colorScheme.onPrimary, + ), + child: Text(l10n.upload), + ), + ], + ); + } +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 94bbd3b..b132f88 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -117,5 +117,34 @@ } }, "noNotesMessage": "No notes attached to this delivery", - "close": "Close" + "close": "Close", + "confirmPhoto": "Confirm Photo", + "uploadPhotoConfirmation": "Upload this photo for {name}?", + "@uploadPhotoConfirmation": { + "placeholders": { + "name": {"type": "String"} + } + }, + "uploadingPhoto": "Uploading photo...", + "photoUploadSuccess": "Photo uploaded successfully", + "photoUploadFailed": "Upload failed: {statusCode}", + "@photoUploadFailed": { + "placeholders": { + "statusCode": {"type": "int"} + } + }, + "cameraError": "Camera error: {message}", + "@cameraError": { + "placeholders": { + "message": {"type": "String"} + } + }, + "uploadError": "Upload error: {message}", + "@uploadError": { + "placeholders": { + "message": {"type": "String"} + } + }, + "serverError": "Server error - Please contact support", + "retake": "Retake" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index b6ea8c6..dbb44ca 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -117,5 +117,34 @@ } }, "noNotesMessage": "Aucune note associée à cette livraison", - "close": "Fermer" + "close": "Fermer", + "confirmPhoto": "Confirmer la photo", + "uploadPhotoConfirmation": "Telecharger cette photo pour {name}?", + "@uploadPhotoConfirmation": { + "placeholders": { + "name": {"type": "String"} + } + }, + "uploadingPhoto": "Telechargement de la photo...", + "photoUploadSuccess": "Photo telechargee avec succes", + "photoUploadFailed": "Echec du telechargement: {statusCode}", + "@photoUploadFailed": { + "placeholders": { + "statusCode": {"type": "int"} + } + }, + "cameraError": "Erreur de camera: {message}", + "@cameraError": { + "placeholders": { + "message": {"type": "String"} + } + }, + "uploadError": "Erreur de telechargement: {message}", + "@uploadError": { + "placeholders": { + "message": {"type": "String"} + } + }, + "serverError": "Erreur serveur - Veuillez contacter le support", + "retake": "Reprendre" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 1ffde8f..7479dbd 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -577,6 +577,60 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Close'** String get close; + + /// No description provided for @confirmPhoto. + /// + /// In en, this message translates to: + /// **'Confirm Photo'** + String get confirmPhoto; + + /// No description provided for @uploadPhotoConfirmation. + /// + /// In en, this message translates to: + /// **'Upload this photo for {name}?'** + String uploadPhotoConfirmation(String name); + + /// No description provided for @uploadingPhoto. + /// + /// In en, this message translates to: + /// **'Uploading photo...'** + String get uploadingPhoto; + + /// No description provided for @photoUploadSuccess. + /// + /// In en, this message translates to: + /// **'Photo uploaded successfully'** + String get photoUploadSuccess; + + /// No description provided for @photoUploadFailed. + /// + /// In en, this message translates to: + /// **'Upload failed: {statusCode}'** + String photoUploadFailed(int statusCode); + + /// No description provided for @cameraError. + /// + /// In en, this message translates to: + /// **'Camera error: {message}'** + String cameraError(String message); + + /// No description provided for @uploadError. + /// + /// In en, this message translates to: + /// **'Upload error: {message}'** + String uploadError(String message); + + /// No description provided for @serverError. + /// + /// In en, this message translates to: + /// **'Server error - Please contact support'** + String get serverError; + + /// No description provided for @retake. + /// + /// In en, this message translates to: + /// **'Retake'** + String get retake; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index a9d982b..e2a15f0 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -267,4 +267,39 @@ class AppLocalizationsEn extends AppLocalizations { @override String get close => 'Close'; + + @override + String get confirmPhoto => 'Confirm Photo'; + + @override + String uploadPhotoConfirmation(String name) { + return 'Upload this photo for $name?'; + } + + @override + String get uploadingPhoto => 'Uploading photo...'; + + @override + String get photoUploadSuccess => 'Photo uploaded successfully'; + + @override + String photoUploadFailed(int statusCode) { + return 'Upload failed: $statusCode'; + } + + @override + String cameraError(String message) { + return 'Camera error: $message'; + } + + @override + String uploadError(String message) { + return 'Upload error: $message'; + } + + @override + String get serverError => 'Server error - Please contact support'; + + @override + String get retake => 'Retake'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 854f1b3..6b12a3b 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -267,4 +267,39 @@ class AppLocalizationsFr extends AppLocalizations { @override String get close => 'Fermer'; + + @override + String get confirmPhoto => 'Confirmer la photo'; + + @override + String uploadPhotoConfirmation(String name) { + return 'Telecharger cette photo pour $name?'; + } + + @override + String get uploadingPhoto => 'Telechargement de la photo...'; + + @override + String get photoUploadSuccess => 'Photo telechargee avec succes'; + + @override + String photoUploadFailed(int statusCode) { + return 'Echec du telechargement: $statusCode'; + } + + @override + String cameraError(String message) { + return 'Erreur de camera: $message'; + } + + @override + String uploadError(String message) { + return 'Erreur de telechargement: $message'; + } + + @override + String get serverError => 'Erreur serveur - Veuillez contacter le support'; + + @override + String get retake => 'Reprendre'; }