auto-claude: subtask-2-3 - Create PhotoCaptureDialog component for photo confirmation
Add PhotoCaptureDialog widget component that: - Shows captured photo preview with proper constraints - Displays confirmation message using delivery name - Provides Cancel and Upload action buttons - Uses theme-aware styling with colorScheme - Handles image loading errors gracefully - Includes proper i18n support (EN/FR) Added localization keys: - confirmPhoto - uploadPhotoConfirmation (with name placeholder) - uploadingPhoto - photoUploadSuccess - photoUploadFailed - cameraError - uploadError - serverError - retake Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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<bool?> show(
|
||||
BuildContext context, {
|
||||
required File imageFile,
|
||||
required String deliveryName,
|
||||
}) {
|
||||
return showDialog<bool>(
|
||||
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),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user