Ajout de la gestion des containers (création, édition, suppression, affichage des détails).
Introduction d'un système de génération de QR codes unifié et d'un mode de sélection multiple.
**Features:**
- **Gestion des Containers :**
- Nouvelle page de gestion des containers (`container_management_page.dart`) avec recherche et filtres.
- Formulaire de création/édition de containers (`container_form_page.dart`) avec génération d'ID automatique.
- Page de détails d'un container (`container_detail_page.dart`) affichant son contenu et ses caractéristiques.
- Ajout des routes et du provider (`ContainerProvider`) nécessaires.
- **Modèle de Données :**
- Ajout du `ContainerModel` pour représenter les boîtes, flight cases, etc.
- Le modèle `EquipmentModel` a été enrichi avec des caractéristiques physiques (poids, dimensions).
- **QR Codes :**
- Nouveau service unifié (`UnifiedPDFGeneratorService`) pour générer des PDFs de QR codes pour n'importe quelle entité.
- Services `PDFGeneratorService` et `ContainerPDFGeneratorService` transformés en wrappers pour maintenir la compatibilité.
- Amélioration de la performance de la génération de QR codes en masse.
- **Interface Utilisateur (UI/UX) :**
- Nouvelle page de détails pour le matériel (`equipment_detail_page.dart`).
- Ajout d'un `SelectionModeMixin` pour gérer la sélection multiple dans les pages de gestion.
- Dialogues réutilisables pour l'affichage de QR codes (`QRCodeDialog`) et la sélection de format d'impression (`QRCodeFormatSelectorDialog`).
- Ajout d'un bouton "Gérer les boîtes" sur la page de gestion du matériel.
**Refactorisation :**
- L' `IdGenerator` a été déplacé dans le répertoire `utils` et étendu pour gérer les containers.
- Mise à jour de nombreuses dépendances `pubspec.yaml` vers des versions plus récentes.
- Séparation de la logique d'affichage des containers et du matériel dans des widgets dédiés (`ContainerHeaderCard`, `EquipmentParentContainers`, etc.).
198 lines
5.3 KiB
Dart
198 lines
5.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:em2rp/utils/colors.dart';
|
|
import 'package:em2rp/models/container_model.dart';
|
|
import 'package:em2rp/models/equipment_model.dart';
|
|
|
|
/// Widget pour afficher la carte d'en-tête d'un container
|
|
class ContainerHeaderCard extends StatelessWidget {
|
|
final ContainerModel container;
|
|
final List<EquipmentModel> equipmentList;
|
|
|
|
const ContainerHeaderCard({
|
|
super.key,
|
|
required this.container,
|
|
required this.equipmentList,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Card(
|
|
elevation: 2,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
_getTypeIcon(container.type),
|
|
size: 60,
|
|
color: AppColors.rouge,
|
|
),
|
|
const SizedBox(width: 20),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
container.id,
|
|
style: const TextStyle(
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
container.name,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
color: Colors.grey.shade700,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Divider(height: 32),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
context,
|
|
'Type',
|
|
containerTypeLabel(container.type),
|
|
Icons.category,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
context,
|
|
'Statut',
|
|
_getStatusLabel(container.status),
|
|
Icons.info,
|
|
statusColor: _getStatusColor(container.status),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
context,
|
|
'Équipements',
|
|
'${container.itemCount}',
|
|
Icons.inventory,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
context,
|
|
'Poids total',
|
|
_calculateTotalWeight(),
|
|
Icons.scale,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildInfoItem(
|
|
BuildContext context,
|
|
String label,
|
|
String value,
|
|
IconData icon, {
|
|
Color? statusColor,
|
|
}) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(icon, size: 16, color: Colors.grey.shade600),
|
|
const SizedBox(width: 6),
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey.shade600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
value,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: statusColor,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
String _calculateTotalWeight() {
|
|
if (equipmentList.isEmpty && container.weight == null) {
|
|
return '-';
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|