feat: Ajout du scan de QR Code pour retrouver équipements et conteneurs
Cette mise à jour introduit une fonctionnalité de scan de QR codes directement depuis l'application, permettant aux utilisateurs de retrouver et d'accéder rapidement à la page de détail d'un équipement ou d'un conteneur.
**Features :**
- **Scan de QR Code :**
- Un nouveau bouton "Scanner QR Code" est ajouté sur les pages de gestion des équipements et des conteneurs.
- L'appui sur ce bouton ouvre une nouvelle boîte de dialogue (`QRCodeScannerDialog`) utilisant la caméra de l'appareil pour scanner un QR code.
- Le scanner affiche un overlay visuel clair avec un cadre de détection et fournit un retour visuel (icône de validation) lorsqu'un code est détecté avec succès.
- **Recherche et Redirection Intelligente :**
- Une fois un QR code scanné, l'application recherche l'ID correspondant d'abord dans les équipements, puis dans les conteneurs.
- Si une correspondance est trouvée, l'utilisateur est automatiquement redirigé vers la page de détail de l'élément correspondant (`EquipmentDetailPage` ou `ContainerDetailPage`).
- Un message informe l'utilisateur si aucun élément ne correspond à l'ID scanné.
**Changements Techniques :**
- **Dépendance :** Ajout de la bibliothèque `mobile_scanner` pour gérer la fonctionnalité de scan.
- **Nouveau Widget :** Création du widget `QRCodeScannerDialog`, un dialogue réutilisable et stylisé pour le scan, incluant un overlay personnalisé (`_ScannerOverlayPainter`).
- **Intégration UI :**
- Le `ManagementSearchBar` accepte désormais une liste de `additionalActions` pour permettre l'ajout de boutons personnalisés comme celui du scanner.
- Ajout du bouton de scan sur les écrans `EquipmentManagementPage` et `ContainerManagementPage`, à la fois en version bureau (icône) et mobile (bouton plein).
- **Logique de Recherche :** Implémentation de la fonction `_scanQRCode` dans les deux pages de gestion pour orchestrer l'ouverture du scanner, la recherche dans les `EquipmentProvider` et `ContainerProvider`, et la navigation.
This commit is contained in:
@@ -5,14 +5,19 @@ import 'package:em2rp/utils/permission_gate.dart';
|
||||
import 'package:em2rp/views/widgets/nav/main_drawer.dart';
|
||||
import 'package:em2rp/views/widgets/nav/custom_app_bar.dart';
|
||||
import 'package:em2rp/providers/container_provider.dart';
|
||||
import 'package:em2rp/providers/equipment_provider.dart';
|
||||
import 'package:em2rp/providers/local_user_provider.dart';
|
||||
import 'package:em2rp/models/container_model.dart';
|
||||
import 'package:em2rp/models/equipment_model.dart';
|
||||
import 'package:em2rp/views/equipment_detail_page.dart';
|
||||
import 'package:em2rp/views/widgets/common/qr_code_dialog.dart';
|
||||
import 'package:em2rp/views/widgets/common/qr_code_scanner_dialog.dart';
|
||||
import 'package:em2rp/views/widgets/common/qr_code_format_selector_dialog.dart';
|
||||
import 'package:em2rp/mixins/selection_mode_mixin.dart';
|
||||
import 'package:em2rp/views/widgets/management/management_search_bar.dart';
|
||||
import 'package:em2rp/views/widgets/management/management_card.dart';
|
||||
import 'package:em2rp/views/widgets/management/management_list.dart';
|
||||
import 'package:em2rp/utils/debug_log.dart';
|
||||
|
||||
class ContainerManagementPage extends StatefulWidget {
|
||||
const ContainerManagementPage({super.key});
|
||||
@@ -177,6 +182,14 @@ class _ContainerManagementPageState extends State<ContainerManagementPage>
|
||||
},
|
||||
onSelectionModeToggle: isSelectionMode ? null : toggleSelectionMode,
|
||||
showSelectionModeButton: !isSelectionMode,
|
||||
additionalActions: [
|
||||
const SizedBox(width: 12),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.qr_code_scanner, color: AppColors.rouge),
|
||||
tooltip: 'Scanner un QR Code',
|
||||
onPressed: _scanQRCode,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -417,7 +430,7 @@ class _ContainerManagementPageState extends State<ContainerManagementPage>
|
||||
_editContainer(container);
|
||||
break;
|
||||
case 'qr':
|
||||
// Non utilisé - les QR codes multiples sont générés via _generateQRCodesForSelected
|
||||
_showQRCode(container);
|
||||
break;
|
||||
case 'delete':
|
||||
_deleteContainer(container);
|
||||
@@ -425,6 +438,14 @@ class _ContainerManagementPageState extends State<ContainerManagementPage>
|
||||
}
|
||||
}
|
||||
|
||||
/// Afficher le QR code d'un conteneur
|
||||
void _showQRCode(ContainerModel container) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => QRCodeDialog.forContainer(container),
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToForm(BuildContext context) async {
|
||||
final result = await Navigator.pushNamed(context, '/container_form');
|
||||
if (result == true) {
|
||||
@@ -583,5 +604,120 @@ class _ContainerManagementPageState extends State<ContainerManagementPage>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Scanner un QR Code et ouvrir la vue de détail correspondante
|
||||
Future<void> _scanQRCode() async {
|
||||
try {
|
||||
// Ouvrir le scanner
|
||||
final scannedCode = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (context) => const QRCodeScannerDialog(),
|
||||
);
|
||||
|
||||
if (scannedCode == null || scannedCode.isEmpty) {
|
||||
return; // L'utilisateur a annulé
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
// Afficher un indicateur de chargement
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => const Center(
|
||||
child: CircularProgressIndicator(color: AppColors.rouge),
|
||||
),
|
||||
);
|
||||
|
||||
// Rechercher d'abord dans les conteneurs
|
||||
final containerProvider = context.read<ContainerProvider>();
|
||||
if (containerProvider.containers.isEmpty) {
|
||||
await containerProvider.loadContainers();
|
||||
}
|
||||
|
||||
final container = containerProvider.containers.firstWhere(
|
||||
(c) => c.id == scannedCode,
|
||||
orElse: () => ContainerModel(
|
||||
id: '',
|
||||
name: '',
|
||||
type: ContainerType.flightCase,
|
||||
status: EquipmentStatus.available,
|
||||
equipmentIds: [],
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
),
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop(); // Fermer l'indicateur
|
||||
}
|
||||
|
||||
if (container.id.isNotEmpty) {
|
||||
// Conteneur trouvé
|
||||
if (mounted) {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
'/container_detail',
|
||||
arguments: container,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Si pas trouvé dans les conteneurs, chercher dans les équipements
|
||||
final equipmentProvider = context.read<EquipmentProvider>();
|
||||
await equipmentProvider.ensureLoaded();
|
||||
|
||||
final equipment = equipmentProvider.allEquipment.firstWhere(
|
||||
(eq) => eq.id == scannedCode,
|
||||
orElse: () => EquipmentModel(
|
||||
id: '',
|
||||
name: '',
|
||||
category: EquipmentCategory.other,
|
||||
status: EquipmentStatus.available,
|
||||
parentBoxIds: [],
|
||||
maintenanceIds: [],
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
),
|
||||
);
|
||||
|
||||
if (equipment.id.isNotEmpty) {
|
||||
// Équipement trouvé
|
||||
if (mounted) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => EquipmentDetailPage(equipment: equipment),
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Rien trouvé
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Aucun conteneur ou équipement trouvé avec l\'ID : $scannedCode'),
|
||||
backgroundColor: Colors.orange,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
DebugLog.error('[ContainerManagementPage] Error scanning QR code', e);
|
||||
if (mounted) {
|
||||
// Fermer l'indicateur si ouvert
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur lors du scan : ${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user