Refactor: Centralisation des labels et icônes pour les enums
Centralise la gestion des libellés, couleurs et icônes pour `EquipmentStatus`, `EquipmentCategory`, et `ContainerType` en utilisant des extensions Dart. - Ajout de nouvelles icônes SVG pour `flight-case`, `truss` et `tape`. - Refactorisation des vues pour utiliser les nouvelles extensions, supprimant ainsi la logique d'affichage dupliquée. - Mise à jour des `ChoiceChip` et des listes de filtres pour afficher les icônes à côté des labels.
This commit is contained in:
		| @@ -1,4 +1,6 @@ | ||||
| import 'package:cloud_firestore/cloud_firestore.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_svg/flutter_svg.dart'; | ||||
| import 'package:em2rp/models/equipment_model.dart'; | ||||
|  | ||||
| /// Type de container | ||||
| @@ -57,6 +59,119 @@ String containerTypeLabel(ContainerType type) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Extensions pour centraliser les informations d'affichage | ||||
| extension ContainerTypeExtension on ContainerType { | ||||
|   /// Retourne le label français du type de container | ||||
|   String get label { | ||||
|     switch (this) { | ||||
|       case ContainerType.flightCase: | ||||
|         return 'Flight Case'; | ||||
|       case ContainerType.pelicase: | ||||
|         return 'Pelicase'; | ||||
|       case ContainerType.bag: | ||||
|         return 'Sac'; | ||||
|       case ContainerType.openCrate: | ||||
|         return 'Caisse Ouverte'; | ||||
|       case ContainerType.toolbox: | ||||
|         return 'Boîte à Outils'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Retourne l'icône Material du type de container | ||||
|   IconData get iconData { | ||||
|     switch (this) { | ||||
|       case ContainerType.flightCase: | ||||
|         return Icons.work; | ||||
|       case ContainerType.pelicase: | ||||
|         return Icons.inventory_2; | ||||
|       case ContainerType.bag: | ||||
|         return Icons.shopping_bag; | ||||
|       case ContainerType.openCrate: | ||||
|         return Icons.inventory; | ||||
|       case ContainerType.toolbox: | ||||
|         return Icons.build_circle; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Retourne le chemin de l'icône personnalisée (si disponible) | ||||
|   String? get customIconPath { | ||||
|     switch (this) { | ||||
|       case ContainerType.flightCase: | ||||
|         return 'assets/icons/flight-case.svg'; | ||||
|       default: | ||||
|         return null; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Vérifie si une icône personnalisée est disponible | ||||
|   bool get hasCustomIcon => customIconPath != null; | ||||
|  | ||||
|   /// Retourne l'icône Widget à afficher (unifié pour Material et personnalisé) | ||||
|   Widget getIcon({double size = 24, Color? color}) { | ||||
|     final customPath = customIconPath; | ||||
|     if (customPath != null) { | ||||
|       // Détection automatique du format (SVG ou PNG) | ||||
|       final isSvg = customPath.toLowerCase().endsWith('.svg'); | ||||
|  | ||||
|       if (isSvg) { | ||||
|         // SVG : on peut appliquer la couleur sans dégrader la qualité | ||||
|         return SvgPicture.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           colorFilter: color != null | ||||
|             ? ColorFilter.mode(color, BlendMode.srcIn) | ||||
|             : null, | ||||
|           placeholderBuilder: (context) => Icon(iconData, size: size, color: color), | ||||
|         ); | ||||
|       } else { | ||||
|         // PNG : on n'applique PAS le color filter pour préserver la qualité | ||||
|         return Image.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           filterQuality: FilterQuality.high, | ||||
|           errorBuilder: (context, error, stackTrace) { | ||||
|             return Icon(iconData, size: size, color: color); | ||||
|           }, | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|     return Icon(iconData, size: size, color: color); | ||||
|   } | ||||
|  | ||||
|   /// Version pour CircleAvatar et contextes similaires | ||||
|   Widget getIconForAvatar({double size = 24, Color? color}) { | ||||
|     final customPath = customIconPath; | ||||
|     if (customPath != null) { | ||||
|       final isSvg = customPath.toLowerCase().endsWith('.svg'); | ||||
|  | ||||
|       if (isSvg) { | ||||
|         return SvgPicture.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           colorFilter: color != null | ||||
|             ? ColorFilter.mode(color, BlendMode.srcIn) | ||||
|             : null, | ||||
|           placeholderBuilder: (context) => Icon(iconData, size: size, color: color), | ||||
|         ); | ||||
|       } else { | ||||
|         return Image.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           filterQuality: FilterQuality.high, | ||||
|           errorBuilder: (context, error, stackTrace) { | ||||
|             return Icon(iconData, size: size, color: color); | ||||
|           }, | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|     return Icon(iconData, size: size, color: color); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// Modèle de container/boîte pour le matériel | ||||
| class ContainerModel { | ||||
|   final String id;                          // Identifiant unique (généré comme pour équipement) | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| import 'package:cloud_firestore/cloud_firestore.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_svg/flutter_svg.dart'; | ||||
|  | ||||
| enum EquipmentStatus { | ||||
|   available,      // Disponible | ||||
| @@ -99,6 +101,171 @@ EquipmentCategory equipmentCategoryFromString(String? category) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Extensions pour centraliser les informations d'affichage | ||||
| extension EquipmentCategoryExtension on EquipmentCategory { | ||||
|   /// Retourne le label français de la catégorie | ||||
|   String get label { | ||||
|     switch (this) { | ||||
|       case EquipmentCategory.lighting: | ||||
|         return 'Lumière'; | ||||
|       case EquipmentCategory.sound: | ||||
|         return 'Son'; | ||||
|       case EquipmentCategory.video: | ||||
|         return 'Vidéo'; | ||||
|       case EquipmentCategory.effect: | ||||
|         return 'Effets'; | ||||
|       case EquipmentCategory.structure: | ||||
|         return 'Structure'; | ||||
|       case EquipmentCategory.consumable: | ||||
|         return 'Consommable'; | ||||
|       case EquipmentCategory.cable: | ||||
|         return 'Câble'; | ||||
|       case EquipmentCategory.other: | ||||
|         return 'Autre'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Retourne l'icône Material de la catégorie | ||||
|   IconData get iconData { | ||||
|     switch (this) { | ||||
|       case EquipmentCategory.lighting: | ||||
|         return Icons.light_mode; | ||||
|       case EquipmentCategory.sound: | ||||
|         return Icons.volume_up; | ||||
|       case EquipmentCategory.video: | ||||
|         return Icons.videocam; | ||||
|       case EquipmentCategory.effect: | ||||
|         return Icons.auto_awesome; | ||||
|       case EquipmentCategory.structure: | ||||
|         return Icons.construction; | ||||
|       case EquipmentCategory.consumable: | ||||
|         return Icons.inventory_2; | ||||
|       case EquipmentCategory.cable: | ||||
|         return Icons.cable; | ||||
|       case EquipmentCategory.other: | ||||
|         return Icons.more_horiz; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Retourne le chemin de l'icône personnalisée (si disponible) | ||||
|   String? get customIconPath { | ||||
|     switch (this) { | ||||
|       case EquipmentCategory.structure: | ||||
|         return 'assets/icons/truss.svg'; | ||||
|       case EquipmentCategory.consumable: | ||||
|         return 'assets/icons/tape.svg'; | ||||
|       default: | ||||
|         return null; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Vérifie si une icône personnalisée est disponible | ||||
|   bool get hasCustomIcon => customIconPath != null; | ||||
|  | ||||
|   /// Retourne l'icône Widget à afficher (unifié pour Material et personnalisé) | ||||
|   Widget getIcon({double size = 24, Color? color}) { | ||||
|     final customPath = customIconPath; | ||||
|     if (customPath != null) { | ||||
|       // Détection automatique du format (SVG ou PNG) | ||||
|       final isSvg = customPath.toLowerCase().endsWith('.svg'); | ||||
|  | ||||
|       if (isSvg) { | ||||
|         // SVG : on peut appliquer la couleur sans dégrader la qualité | ||||
|         return SvgPicture.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           colorFilter: color != null | ||||
|             ? ColorFilter.mode(color, BlendMode.srcIn) | ||||
|             : null, | ||||
|           placeholderBuilder: (context) => Icon(iconData, size: size, color: color), | ||||
|         ); | ||||
|       } else { | ||||
|         // PNG : on n'applique PAS le color filter pour préserver la qualité | ||||
|         return Image.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           filterQuality: FilterQuality.high, | ||||
|           errorBuilder: (context, error, stackTrace) { | ||||
|             return Icon(iconData, size: size, color: color); | ||||
|           }, | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|     return Icon(iconData, size: size, color: color); | ||||
|   } | ||||
|  | ||||
|   /// Version pour CircleAvatar et contextes similaires (sans ColorFilter si Material Icon) | ||||
|   Widget getIconForAvatar({double size = 24, Color? color}) { | ||||
|     final customPath = customIconPath; | ||||
|     if (customPath != null) { | ||||
|       final isSvg = customPath.toLowerCase().endsWith('.svg'); | ||||
|  | ||||
|       if (isSvg) { | ||||
|         return SvgPicture.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           colorFilter: color != null | ||||
|             ? ColorFilter.mode(color, BlendMode.srcIn) | ||||
|             : null, | ||||
|           placeholderBuilder: (context) => Icon(iconData, size: size, color: color), | ||||
|         ); | ||||
|       } else { | ||||
|         return Image.asset( | ||||
|           customPath, | ||||
|           width: size, | ||||
|           height: size, | ||||
|           filterQuality: FilterQuality.high, | ||||
|           errorBuilder: (context, error, stackTrace) { | ||||
|             return Icon(iconData, size: size, color: color); | ||||
|           }, | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|     return Icon(iconData, size: size, color: color); | ||||
|   } | ||||
| } | ||||
|  | ||||
| extension EquipmentStatusExtension on EquipmentStatus { | ||||
|   /// Retourne le label français du statut | ||||
|   String get label { | ||||
|     switch (this) { | ||||
|       case EquipmentStatus.available: | ||||
|         return 'Disponible'; | ||||
|       case EquipmentStatus.inUse: | ||||
|         return 'En prestation'; | ||||
|       case EquipmentStatus.rented: | ||||
|         return 'Loué'; | ||||
|       case EquipmentStatus.lost: | ||||
|         return 'Perdu'; | ||||
|       case EquipmentStatus.outOfService: | ||||
|         return 'HS'; | ||||
|       case EquipmentStatus.maintenance: | ||||
|         return 'Maintenance'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Retourne la couleur associée au statut | ||||
|   Color get color { | ||||
|     switch (this) { | ||||
|       case EquipmentStatus.available: | ||||
|         return Colors.green; | ||||
|       case EquipmentStatus.inUse: | ||||
|         return Colors.blue; | ||||
|       case EquipmentStatus.rented: | ||||
|         return Colors.orange; | ||||
|       case EquipmentStatus.lost: | ||||
|         return Colors.red; | ||||
|       case EquipmentStatus.outOfService: | ||||
|         return Colors.red.shade900; | ||||
|       case EquipmentStatus.maintenance: | ||||
|         return Colors.amber; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| class EquipmentModel { | ||||
|   final String id;                          // Identifiant unique (clé) | ||||
|   final String name;                        // Nom de l'équipement | ||||
|   | ||||
| @@ -167,7 +167,7 @@ class _ContainerDetailPageState extends State<ContainerDetailPage> { | ||||
|                 Expanded( | ||||
|                   child: _buildInfoItem( | ||||
|                     'Type', | ||||
|                     containerTypeLabel(_container.type), | ||||
|                     _container.type.label, | ||||
|                     Icons.category, | ||||
|                   ), | ||||
|                 ), | ||||
|   | ||||
| @@ -177,7 +177,7 @@ class _ContainerFormPageState extends State<ContainerFormPage> { | ||||
|               items: ContainerType.values.map((type) { | ||||
|                 return DropdownMenuItem( | ||||
|                   value: type, | ||||
|                   child: Text(containerTypeLabel(type)), | ||||
|                   child: Text(type.label), | ||||
|                 ); | ||||
|               }).toList(), | ||||
|               onChanged: (value) { | ||||
|   | ||||
| @@ -190,7 +190,7 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|             ...ContainerType.values.map((type) { | ||||
|               return Padding( | ||||
|                 padding: const EdgeInsets.only(right: 8), | ||||
|                 child: _buildTypeChip(type, containerTypeLabel(type)), | ||||
|                 child: _buildTypeChip(type, type.label), | ||||
|               ); | ||||
|             }), | ||||
|           ], | ||||
| @@ -201,8 +201,19 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|  | ||||
|   Widget _buildTypeChip(ContainerType? type, String label) { | ||||
|     final isSelected = _selectedType == type; | ||||
|     final color = isSelected ? Colors.white : AppColors.noir; | ||||
|  | ||||
|     return ChoiceChip( | ||||
|       label: Text(label), | ||||
|       label: Row( | ||||
|         mainAxisSize: MainAxisSize.min, | ||||
|         children: [ | ||||
|           if (type != null) ...[ | ||||
|             type.getIcon(size: 16, color: color), | ||||
|             const SizedBox(width: 8), | ||||
|           ], | ||||
|           Text(label), | ||||
|         ], | ||||
|       ), | ||||
|       selected: isSelected, | ||||
|       onSelected: (selected) { | ||||
|         setState(() { | ||||
| @@ -212,7 +223,7 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|       }, | ||||
|       selectedColor: AppColors.rouge, | ||||
|       labelStyle: TextStyle( | ||||
|         color: isSelected ? Colors.white : AppColors.noir, | ||||
|         color: color, | ||||
|         fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, | ||||
|       ), | ||||
|     ); | ||||
| @@ -244,7 +255,7 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|           const SizedBox(height: 8), | ||||
|           _buildFilterOption(null, 'Tous les types'), | ||||
|           ...ContainerType.values.map((type) { | ||||
|             return _buildFilterOption(type, containerTypeLabel(type)); | ||||
|             return _buildFilterOption(type, type.label); | ||||
|           }), | ||||
|  | ||||
|           const Divider(height: 32), | ||||
| @@ -403,8 +414,7 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|                 ), | ||||
|  | ||||
|               // Icône du type de container | ||||
|               Icon( | ||||
|                 _getTypeIcon(container.type), | ||||
|               container.type.getIcon( | ||||
|                 size: 40, | ||||
|                 color: AppColors.rouge, | ||||
|               ), | ||||
| @@ -434,7 +444,7 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|                     Row( | ||||
|                       children: [ | ||||
|                         _buildInfoChip( | ||||
|                           containerTypeLabel(container.type), | ||||
|                           container.type.label, | ||||
|                           Icons.category, | ||||
|                         ), | ||||
|                         const SizedBox(width: 8), | ||||
| @@ -534,42 +544,17 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|   } | ||||
|  | ||||
|   Widget _buildStatusBadge(EquipmentStatus status) { | ||||
|     Color color; | ||||
|     String label; | ||||
|  | ||||
|     switch (status) { | ||||
|       case EquipmentStatus.available: | ||||
|         color = Colors.green; | ||||
|         label = 'Disponible'; | ||||
|         break; | ||||
|       case EquipmentStatus.inUse: | ||||
|         color = Colors.orange; | ||||
|         label = 'En prestation'; | ||||
|         break; | ||||
|       case EquipmentStatus.maintenance: | ||||
|         color = Colors.blue; | ||||
|         label = 'Maintenance'; | ||||
|         break; | ||||
|       case EquipmentStatus.outOfService: | ||||
|         color = Colors.red; | ||||
|         label = 'Hors service'; | ||||
|         break; | ||||
|       default: | ||||
|         color = Colors.grey; | ||||
|         label = 'Autre'; | ||||
|     } | ||||
|  | ||||
|     return Container( | ||||
|       padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), | ||||
|       decoration: BoxDecoration( | ||||
|         color: color.withOpacity(0.1), | ||||
|         color: status.color.withOpacity(0.1), | ||||
|         borderRadius: BorderRadius.circular(16), | ||||
|         border: Border.all(color: color), | ||||
|         border: Border.all(color: status.color), | ||||
|       ), | ||||
|       child: Text( | ||||
|         label, | ||||
|         status.label, | ||||
|         style: TextStyle( | ||||
|           color: color, | ||||
|           color: status.color, | ||||
|           fontWeight: FontWeight.bold, | ||||
|           fontSize: 12, | ||||
|         ), | ||||
| @@ -577,21 +562,6 @@ class _ContainerManagementPageState extends State<ContainerManagementPage> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   IconData _getTypeIcon(ContainerType type) { | ||||
|     switch (type) { | ||||
|       case ContainerType.flightCase: | ||||
|         return Icons.work; | ||||
|       case ContainerType.pelicase: | ||||
|         return Icons.work_outline; | ||||
|       case ContainerType.bag: | ||||
|         return Icons.shopping_bag; | ||||
|       case ContainerType.openCrate: | ||||
|         return Icons.inventory_2; | ||||
|       case ContainerType.toolbox: | ||||
|         return Icons.handyman; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   void _handleMenuAction(String action, ContainerModel container) { | ||||
|     switch (action) { | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import 'package:em2rp/providers/local_user_provider.dart'; | ||||
| import 'package:em2rp/services/equipment_service.dart'; | ||||
| import 'package:em2rp/services/qr_code_service.dart'; | ||||
| import 'package:em2rp/utils/colors.dart'; | ||||
| import 'package:em2rp/utils/permission_gate.dart'; | ||||
| import 'package:em2rp/views/widgets/nav/custom_app_bar.dart'; | ||||
| import 'package:em2rp/views/equipment_form_page.dart'; | ||||
| import 'package:em2rp/views/widgets/equipment/equipment_parent_containers.dart'; | ||||
| @@ -144,10 +143,9 @@ class _EquipmentDetailPageState extends State<EquipmentDetailPage> { | ||||
|               CircleAvatar( | ||||
|                 backgroundColor: Colors.white, | ||||
|                 radius: 30, | ||||
|                 child: Icon( | ||||
|                   _getCategoryIcon(widget.equipment.category), | ||||
|                   color: AppColors.rouge, | ||||
|                 child: widget.equipment.category.getIcon( | ||||
|                   size: 32, | ||||
|                   color: AppColors.rouge, | ||||
|                 ), | ||||
|               ), | ||||
|               const SizedBox(width: 16), | ||||
| @@ -187,7 +185,7 @@ class _EquipmentDetailPageState extends State<EquipmentDetailPage> { | ||||
|   } | ||||
|  | ||||
|   Widget _buildStatusBadge() { | ||||
|     final statusInfo = _getStatusInfo(widget.equipment.status); | ||||
|     final status = widget.equipment.status; | ||||
|     return Container( | ||||
|       padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), | ||||
|       decoration: BoxDecoration( | ||||
| @@ -201,17 +199,17 @@ class _EquipmentDetailPageState extends State<EquipmentDetailPage> { | ||||
|             width: 8, | ||||
|             height: 8, | ||||
|             decoration: BoxDecoration( | ||||
|               color: statusInfo.$2, | ||||
|               color: status.color, | ||||
|               shape: BoxShape.circle, | ||||
|             ), | ||||
|           ), | ||||
|           const SizedBox(width: 8), | ||||
|           Text( | ||||
|             statusInfo.$1, | ||||
|             status.label, | ||||
|             style: TextStyle( | ||||
|               fontSize: 14, | ||||
|               fontWeight: FontWeight.bold, | ||||
|               color: statusInfo.$2, | ||||
|               color: status.color, | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
| @@ -240,14 +238,14 @@ class _EquipmentDetailPageState extends State<EquipmentDetailPage> { | ||||
|               ], | ||||
|             ), | ||||
|             const Divider(height: 24), | ||||
|             _buildInfoRow('Catégorie', _getCategoryName(widget.equipment.category)), | ||||
|             _buildInfoRow('Catégorie', widget.equipment.category.label), | ||||
|             if (widget.equipment.brand != null && widget.equipment.brand!.isNotEmpty) | ||||
|               _buildInfoRow('Marque', widget.equipment.brand!), | ||||
|             if (widget.equipment.model != null && widget.equipment.model!.isNotEmpty) | ||||
|               _buildInfoRow('Modèle', widget.equipment.model!), | ||||
|             if (widget.equipment.category != EquipmentCategory.consumable && | ||||
|                 widget.equipment.category != EquipmentCategory.cable) | ||||
|               _buildInfoRow('Statut', _getStatusInfo(widget.equipment.status).$1), | ||||
|               _buildInfoRow('Statut', widget.equipment.status.label), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
| @@ -808,65 +806,6 @@ class _EquipmentDetailPageState extends State<EquipmentDetailPage> { | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   IconData _getCategoryIcon(EquipmentCategory category) { | ||||
|     switch (category) { | ||||
|       case EquipmentCategory.lighting: | ||||
|         return Icons.light_mode; | ||||
|       case EquipmentCategory.sound: | ||||
|         return Icons.volume_up; | ||||
|       case EquipmentCategory.video: | ||||
|         return Icons.videocam; | ||||
|       case EquipmentCategory.effect: | ||||
|         return Icons.auto_awesome; | ||||
|       case EquipmentCategory.structure: | ||||
|         return Icons.construction; | ||||
|       case EquipmentCategory.consumable: | ||||
|         return Icons.inventory_2; | ||||
|       case EquipmentCategory.cable: | ||||
|         return Icons.cable; | ||||
|       case EquipmentCategory.other: | ||||
|         return Icons.more_horiz; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String _getCategoryName(EquipmentCategory category) { | ||||
|     switch (category) { | ||||
|       case EquipmentCategory.lighting: | ||||
|         return 'Lumière'; | ||||
|       case EquipmentCategory.sound: | ||||
|         return 'Son'; | ||||
|       case EquipmentCategory.video: | ||||
|         return 'Vidéo'; | ||||
|       case EquipmentCategory.effect: | ||||
|         return 'Effets'; | ||||
|       case EquipmentCategory.structure: | ||||
|         return 'Structure'; | ||||
|       case EquipmentCategory.consumable: | ||||
|         return 'Consommable'; | ||||
|       case EquipmentCategory.cable: | ||||
|         return 'Câble'; | ||||
|       case EquipmentCategory.other: | ||||
|         return 'Autre'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   (String, Color) _getStatusInfo(EquipmentStatus status) { | ||||
|     switch (status) { | ||||
|       case EquipmentStatus.available: | ||||
|         return ('Disponible', Colors.green); | ||||
|       case EquipmentStatus.inUse: | ||||
|         return ('En prestation', Colors.blue); | ||||
|       case EquipmentStatus.rented: | ||||
|         return ('Loué', Colors.orange); | ||||
|       case EquipmentStatus.lost: | ||||
|         return ('Perdu', Colors.red); | ||||
|       case EquipmentStatus.outOfService: | ||||
|         return ('HS', Colors.red[900]!); | ||||
|       case EquipmentStatus.maintenance: | ||||
|         return ('Maintenance', Colors.amber); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   (String, IconData) _getMaintenanceTypeInfo(MaintenanceType type) { | ||||
|     switch (type) { | ||||
|       case MaintenanceType.preventive: | ||||
|   | ||||
| @@ -275,7 +275,7 @@ class _EquipmentFormPageState extends State<EquipmentFormPage> { | ||||
|                             items: EquipmentCategory.values.map((category) { | ||||
|                               return DropdownMenuItem( | ||||
|                                 value: category, | ||||
|                                 child: Text(_getCategoryLabel(category)), | ||||
|                                 child: Text(category.label), | ||||
|                               ); | ||||
|                             }).toList(), | ||||
|                             onChanged: (value) { | ||||
| @@ -301,7 +301,7 @@ class _EquipmentFormPageState extends State<EquipmentFormPage> { | ||||
|                               items: EquipmentStatus.values.map((status) { | ||||
|                                 return DropdownMenuItem( | ||||
|                                   value: status, | ||||
|                                   child: Text(_getStatusLabel(status)), | ||||
|                                   child: Text(status.label), | ||||
|                                 ); | ||||
|                               }).toList(), | ||||
|                               onChanged: (value) { | ||||
| @@ -654,47 +654,4 @@ class _EquipmentFormPageState extends State<EquipmentFormPage> { | ||||
|       if (mounted) setState(() => _isLoading = false); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Correction des enums dans _getCategoryLabel | ||||
|   String _getCategoryLabel(EquipmentCategory category) { | ||||
|     switch (category) { | ||||
|       case EquipmentCategory.lighting: | ||||
|         return 'Lumière'; | ||||
|       case EquipmentCategory.sound: | ||||
|         return 'Son'; | ||||
|       case EquipmentCategory.video: | ||||
|         return 'Vidéo'; | ||||
|       case EquipmentCategory.effect: | ||||
|         return 'Effet'; | ||||
|       case EquipmentCategory.structure: | ||||
|         return 'Structure'; | ||||
|       case EquipmentCategory.consumable: | ||||
|         return 'Consommable'; | ||||
|       case EquipmentCategory.cable: | ||||
|         return 'Câble'; | ||||
|       case EquipmentCategory.other: | ||||
|       default: | ||||
|         return 'Autre'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Correction des enums dans _getStatusLabel | ||||
|   String _getStatusLabel(EquipmentStatus status) { | ||||
|     switch (status) { | ||||
|       case EquipmentStatus.available: | ||||
|         return 'Disponible'; | ||||
|       case EquipmentStatus.inUse: | ||||
|         return 'En prestation'; | ||||
|       case EquipmentStatus.rented: | ||||
|         return 'Loué'; | ||||
|       case EquipmentStatus.lost: | ||||
|         return 'Perdu'; | ||||
|       case EquipmentStatus.outOfService: | ||||
|         return 'HS'; | ||||
|       case EquipmentStatus.maintenance: | ||||
|         return 'Maintenance'; | ||||
|       default: | ||||
|         return 'Autre'; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -293,7 +293,6 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage> | ||||
|                   }, | ||||
|                 ), | ||||
|               ), | ||||
|               const Divider(), | ||||
|               // Filtres par catégorie | ||||
|               Padding( | ||||
|                 padding: | ||||
| @@ -353,44 +352,34 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage> | ||||
|   } | ||||
|  | ||||
|   List<Widget> _buildCategoryChips() { | ||||
|     final categories = [ | ||||
|       (EquipmentCategory.lighting, Icons.light_mode, 'Lumière'), | ||||
|       (EquipmentCategory.sound, Icons.volume_up, 'Son'), | ||||
|       (EquipmentCategory.video, Icons.videocam, 'Vidéo'), | ||||
|       (EquipmentCategory.effect, Icons.auto_awesome, 'Effets'), | ||||
|       (EquipmentCategory.structure, Icons.construction, 'Structure'), | ||||
|       (EquipmentCategory.consumable, Icons.inventory_2, 'Consommable'), | ||||
|       (EquipmentCategory.cable, Icons.cable, 'Câble'), | ||||
|       (EquipmentCategory.other, Icons.more_horiz, 'Autre'), | ||||
|     ]; | ||||
|     return EquipmentCategory.values.map((category) { | ||||
|       final isSelected = _selectedCategory == category; | ||||
|       final color = isSelected ? Colors.white : AppColors.rouge; | ||||
|  | ||||
|     return categories.map((cat) { | ||||
|       final isSelected = _selectedCategory == cat.$1; | ||||
|       return Padding( | ||||
|         padding: const EdgeInsets.symmetric(horizontal: 4.0), | ||||
|         child: ChoiceChip( | ||||
|           label: Row( | ||||
|             mainAxisSize: MainAxisSize.min, | ||||
|             children: [ | ||||
|               Icon( | ||||
|                 cat.$2, | ||||
|               category.getIcon( | ||||
|                 size: 16, | ||||
|                 color: isSelected ? Colors.white : AppColors.rouge, | ||||
|                 color: color, | ||||
|               ), | ||||
|               const SizedBox(width: 8), | ||||
|               Text(cat.$3), | ||||
|               Text(category.label), | ||||
|             ], | ||||
|           ), | ||||
|           selected: isSelected, | ||||
|           onSelected: (selected) { | ||||
|             if (selected) { | ||||
|               setState(() => _selectedCategory = cat.$1); | ||||
|               context.read<EquipmentProvider>().setSelectedCategory(cat.$1); | ||||
|               setState(() => _selectedCategory = category); | ||||
|               context.read<EquipmentProvider>().setSelectedCategory(category); | ||||
|             } | ||||
|           }, | ||||
|           selectedColor: AppColors.rouge, | ||||
|           labelStyle: TextStyle( | ||||
|             color: isSelected ? Colors.white : AppColors.rouge, | ||||
|             color: color, | ||||
|             fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, | ||||
|           ), | ||||
|         ), | ||||
| @@ -399,26 +388,17 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage> | ||||
|   } | ||||
|  | ||||
|   List<Widget> _buildCategoryListTiles() { | ||||
|     final categories = [ | ||||
|       (EquipmentCategory.lighting, Icons.light_mode, 'Lumière'), | ||||
|       (EquipmentCategory.sound, Icons.volume_up, 'Son'), | ||||
|       (EquipmentCategory.video, Icons.videocam, 'Vidéo'), | ||||
|       (EquipmentCategory.effect, Icons.auto_awesome, 'Effets'), | ||||
|       (EquipmentCategory.structure, Icons.construction, 'Structure'), | ||||
|       (EquipmentCategory.consumable, Icons.inventory_2, 'Consommable'), | ||||
|       (EquipmentCategory.cable, Icons.cable, 'Câble'), | ||||
|       (EquipmentCategory.other, Icons.more_horiz, 'Autre'), | ||||
|     ]; | ||||
|     return EquipmentCategory.values.map((category) { | ||||
|       final isSelected = _selectedCategory == category; | ||||
|       final color = isSelected ? AppColors.rouge : Colors.grey[600]!; | ||||
|  | ||||
|     return categories.map((cat) { | ||||
|       final isSelected = _selectedCategory == cat.$1; | ||||
|       return ListTile( | ||||
|         leading: Icon( | ||||
|           cat.$2, | ||||
|           color: isSelected ? AppColors.rouge : Colors.grey[600], | ||||
|         leading: category.getIcon( | ||||
|           size: 24, | ||||
|           color: color, | ||||
|         ), | ||||
|         title: Text( | ||||
|           cat.$3, | ||||
|           category.label, | ||||
|           style: TextStyle( | ||||
|             color: isSelected ? AppColors.rouge : Colors.black87, | ||||
|             fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, | ||||
| @@ -427,8 +407,8 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage> | ||||
|         selected: isSelected, | ||||
|         selectedTileColor: AppColors.rouge.withOpacity(0.1), | ||||
|         onTap: () { | ||||
|           setState(() => _selectedCategory = cat.$1); | ||||
|           context.read<EquipmentProvider>().setSelectedCategory(cat.$1); | ||||
|           setState(() => _selectedCategory = category); | ||||
|           context.read<EquipmentProvider>().setSelectedCategory(category); | ||||
|         }, | ||||
|       ); | ||||
|     }).toList(); | ||||
| @@ -506,10 +486,10 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage> | ||||
|               ) | ||||
|             : CircleAvatar( | ||||
|                 backgroundColor: | ||||
|                     _getStatusColor(equipment.status).withOpacity(0.2), | ||||
|                 child: Icon( | ||||
|                   _getCategoryIcon(equipment.category), | ||||
|                   color: _getStatusColor(equipment.status), | ||||
|                     equipment.status.color.withOpacity(0.2), | ||||
|                 child: equipment.category.getIcon( | ||||
|                   size: 20, | ||||
|                   color: Colors.black, | ||||
|                 ), | ||||
|               ), | ||||
|         title: Row( | ||||
| @@ -659,67 +639,24 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage> | ||||
|   } | ||||
|  | ||||
|   Widget _buildStatusBadge(EquipmentStatus status) { | ||||
|     final statusInfo = _getStatusInfo(status); | ||||
|     return Container( | ||||
|       padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), | ||||
|       decoration: BoxDecoration( | ||||
|         color: statusInfo.$2.withOpacity(0.2), | ||||
|         color: status.color.withOpacity(0.2), | ||||
|         borderRadius: BorderRadius.circular(12), | ||||
|         border: Border.all(color: statusInfo.$2), | ||||
|         border: Border.all(color: status.color), | ||||
|       ), | ||||
|       child: Text( | ||||
|         statusInfo.$1, | ||||
|         status.label, | ||||
|         style: TextStyle( | ||||
|           fontSize: 12, | ||||
|           fontWeight: FontWeight.bold, | ||||
|           color: statusInfo.$2, | ||||
|           color: status.color, | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   (String, Color) _getStatusInfo(EquipmentStatus status) { | ||||
|     switch (status) { | ||||
|       case EquipmentStatus.available: | ||||
|         return ('Disponible', Colors.green); | ||||
|       case EquipmentStatus.inUse: | ||||
|         return ('En prestation', Colors.blue); | ||||
|       case EquipmentStatus.rented: | ||||
|         return ('Loué', Colors.orange); | ||||
|       case EquipmentStatus.lost: | ||||
|         return ('Perdu', Colors.red); | ||||
|       case EquipmentStatus.outOfService: | ||||
|         return ('HS', Colors.red[900]!); | ||||
|       case EquipmentStatus.maintenance: | ||||
|         return ('Maintenance', Colors.amber); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Color _getStatusColor(EquipmentStatus status) { | ||||
|     return _getStatusInfo(status).$2; | ||||
|   } | ||||
|  | ||||
|   IconData _getCategoryIcon(EquipmentCategory category) { | ||||
|     switch (category) { | ||||
|       case EquipmentCategory.lighting: | ||||
|         return Icons.light_mode; | ||||
|       case EquipmentCategory.sound: | ||||
|         return Icons.volume_up; | ||||
|       case EquipmentCategory.video: | ||||
|         return Icons.videocam; | ||||
|       case EquipmentCategory.effect: | ||||
|         return Icons.auto_awesome; | ||||
|       case EquipmentCategory.structure: | ||||
|         return Icons.construction; | ||||
|       case EquipmentCategory.consumable: | ||||
|         return Icons.inventory_2; | ||||
|       case EquipmentCategory.cable: | ||||
|         return Icons.cable; | ||||
|       case EquipmentCategory.other: | ||||
|         return Icons.more_horiz; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Actions | ||||
|   void _createNewEquipment() { | ||||
|     Navigator.push( | ||||
|   | ||||
| @@ -25,8 +25,7 @@ class ContainerHeaderCard extends StatelessWidget { | ||||
|           children: [ | ||||
|             Row( | ||||
|               children: [ | ||||
|                 Icon( | ||||
|                   _getTypeIcon(container.type), | ||||
|                 container.type.getIcon( | ||||
|                   size: 60, | ||||
|                   color: AppColors.rouge, | ||||
|                 ), | ||||
| @@ -62,7 +61,7 @@ class ContainerHeaderCard extends StatelessWidget { | ||||
|                   child: _buildInfoItem( | ||||
|                     context, | ||||
|                     'Type', | ||||
|                     containerTypeLabel(container.type), | ||||
|                     container.type.label, | ||||
|                     Icons.category, | ||||
|                   ), | ||||
|                 ), | ||||
| @@ -70,9 +69,9 @@ class ContainerHeaderCard extends StatelessWidget { | ||||
|                   child: _buildInfoItem( | ||||
|                     context, | ||||
|                     'Statut', | ||||
|                     _getStatusLabel(container.status), | ||||
|                     container.status.label, | ||||
|                     Icons.info, | ||||
|                     statusColor: _getStatusColor(container.status), | ||||
|                     statusColor: container.status.color, | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
| @@ -148,50 +147,5 @@ class ContainerHeaderCard extends StatelessWidget { | ||||
|     final totalWeight = container.calculateTotalWeight(equipmentList); | ||||
|     return '${totalWeight.toStringAsFixed(1)} kg'; | ||||
|   } | ||||
|  | ||||
|   IconData _getTypeIcon(ContainerType type) { | ||||
|     switch (type) { | ||||
|       case ContainerType.flightCase: | ||||
|         return Icons.work; | ||||
|       case ContainerType.pelicase: | ||||
|         return Icons.work_outline; | ||||
|       case ContainerType.bag: | ||||
|         return Icons.shopping_bag; | ||||
|       case ContainerType.openCrate: | ||||
|         return Icons.inventory_2; | ||||
|       case ContainerType.toolbox: | ||||
|         return Icons.handyman; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String _getStatusLabel(EquipmentStatus status) { | ||||
|     switch (status) { | ||||
|       case EquipmentStatus.available: | ||||
|         return 'Disponible'; | ||||
|       case EquipmentStatus.inUse: | ||||
|         return 'En prestation'; | ||||
|       case EquipmentStatus.maintenance: | ||||
|         return 'Maintenance'; | ||||
|       case EquipmentStatus.outOfService: | ||||
|         return 'Hors service'; | ||||
|       default: | ||||
|         return 'Autre'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Color _getStatusColor(EquipmentStatus status) { | ||||
|     switch (status) { | ||||
|       case EquipmentStatus.available: | ||||
|         return Colors.green; | ||||
|       case EquipmentStatus.inUse: | ||||
|         return Colors.orange; | ||||
|       case EquipmentStatus.maintenance: | ||||
|         return Colors.blue; | ||||
|       case EquipmentStatus.outOfService: | ||||
|         return Colors.red; | ||||
|       default: | ||||
|         return Colors.grey; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ElPoyo
					ElPoyo