diff --git a/lib/components/notes_dialog.dart b/lib/components/notes_dialog.dart new file mode 100644 index 0000000..f603293 --- /dev/null +++ b/lib/components/notes_dialog.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; +import 'package:planb_logistic/l10n/app_localizations.dart'; +import '../models/delivery.dart'; + +/// A dialog component for displaying delivery notes. +/// +/// This dialog extracts and displays all non-empty notes from the +/// orders associated with a delivery. +class NotesDialog extends StatelessWidget { + /// The delivery whose notes should be displayed. + final Delivery delivery; + + const NotesDialog({ + super.key, + required this.delivery, + }); + + /// Extracts non-empty notes from the delivery's orders. + List _extractNotes() { + return delivery.orders + .where((order) => order.note != null && order.note!.isNotEmpty) + .map((order) => order.note!) + .toList(); + } + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context); + final colorScheme = Theme.of(context).colorScheme; + final notes = _extractNotes(); + + return AlertDialog( + title: Text( + l10n.notesTitle(delivery.name), + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + color: colorScheme.onSurface, + ), + ), + 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(context).textTheme.bodyLarge?.copyWith( + color: colorScheme.onSurface, + 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(context).pop(), + child: Text( + l10n.close, + style: TextStyle(color: colorScheme.onPrimary), + ), + ), + ), + ], + ); + } + + /// Shows the notes dialog for a delivery. + /// + /// Returns `true` if the dialog was shown (i.e., the delivery has notes), + /// `false` otherwise. + /// + /// If the delivery has no notes, this method returns `false` without + /// showing the dialog. The caller is responsible for handling this case, + /// typically by showing an info message. + static Future show(BuildContext context, Delivery delivery) async { + final notes = delivery.orders + .where((order) => order.note != null && order.note!.isNotEmpty) + .map((order) => order.note!) + .toList(); + + if (notes.isEmpty) { + return false; + } + + await showDialog( + context: context, + builder: (BuildContext dialogContext) { + return NotesDialog(delivery: delivery); + }, + ); + + return true; + } +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index d63426d..94bbd3b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -109,5 +109,13 @@ "passwordRequired": "Password is required", "loginButton": "Login", "navigate": "Navigate", - "upload": "Upload" + "upload": "Upload", + "notesTitle": "Notes for {name}", + "@notesTitle": { + "placeholders": { + "name": {"type": "String"} + } + }, + "noNotesMessage": "No notes attached to this delivery", + "close": "Close" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 2bab17f..b6ea8c6 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -109,5 +109,13 @@ "passwordRequired": "Le mot de passe est requis", "loginButton": "Connexion", "navigate": "Naviguer", - "upload": "Téléverser" + "upload": "Téléverser", + "notesTitle": "Notes pour {name}", + "@notesTitle": { + "placeholders": { + "name": {"type": "String"} + } + }, + "noNotesMessage": "Aucune note associée à cette livraison", + "close": "Fermer" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 8c9de9c..1ffde8f 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -559,6 +559,24 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Upload'** String get upload; + + /// No description provided for @notesTitle. + /// + /// In en, this message translates to: + /// **'Notes for {name}'** + String notesTitle(String name); + + /// No description provided for @noNotesMessage. + /// + /// In en, this message translates to: + /// **'No notes attached to this delivery'** + String get noNotesMessage; + + /// No description provided for @close. + /// + /// In en, this message translates to: + /// **'Close'** + String get close; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 0399f33..a9d982b 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -256,4 +256,15 @@ class AppLocalizationsEn extends AppLocalizations { @override String get upload => 'Upload'; + + @override + String notesTitle(String name) { + return 'Notes for $name'; + } + + @override + String get noNotesMessage => 'No notes attached to this delivery'; + + @override + String get close => 'Close'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 6ebea89..854f1b3 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -256,4 +256,15 @@ class AppLocalizationsFr extends AppLocalizations { @override String get upload => 'Téléverser'; + + @override + String notesTitle(String name) { + return 'Notes pour $name'; + } + + @override + String get noNotesMessage => 'Aucune note associée à cette livraison'; + + @override + String get close => 'Fermer'; }