import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:em2rp/utils/colors.dart'; import 'package:em2rp/models/container_model.dart'; import 'package:em2rp/models/equipment_model.dart'; import 'package:em2rp/providers/container_provider.dart'; import 'package:em2rp/views/equipment_detail_page.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:intl/intl.dart'; class ContainerDetailPage extends StatefulWidget { final ContainerModel container; const ContainerDetailPage({super.key, required this.container}); @override State createState() => _ContainerDetailPageState(); } class _ContainerDetailPageState extends State { late ContainerModel _container; List _equipmentList = []; bool _isLoadingEquipment = true; @override void initState() { super.initState(); _container = widget.container; _loadEquipment(); } Future _loadEquipment() async { setState(() { _isLoadingEquipment = true; }); try { final containerProvider = context.read(); final equipment = await containerProvider.getContainerEquipment(_container.id); setState(() { _equipmentList = equipment; _isLoadingEquipment = false; }); } catch (e) { setState(() { _isLoadingEquipment = false; }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Erreur lors du chargement: $e')), ); } } } Future _refreshContainer() async { final containerProvider = context.read(); final updated = await containerProvider.getContainerById(_container.id); if (updated != null) { setState(() { _container = updated; }); await _loadEquipment(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Détails du Container'), backgroundColor: AppColors.rouge, foregroundColor: Colors.white, actions: [ IconButton( icon: const Icon(Icons.edit), tooltip: 'Modifier', onPressed: _editContainer, ), IconButton( icon: const Icon(Icons.qr_code), tooltip: 'QR Code', onPressed: _showQRCode, ), PopupMenuButton( icon: const Icon(Icons.more_vert), onSelected: _handleMenuAction, itemBuilder: (context) => [ const PopupMenuItem( value: 'delete', child: Row( children: [ Icon(Icons.delete, color: Colors.red, size: 20), SizedBox(width: 8), Text('Supprimer', style: TextStyle(color: Colors.red)), ], ), ), ], ), ], ), body: RefreshIndicator( onRefresh: _refreshContainer, child: ListView( padding: const EdgeInsets.all(16), children: [ _buildHeaderCard(), const SizedBox(height: 16), _buildPhysicalCharacteristics(), const SizedBox(height: 16), _buildEquipmentSection(), const SizedBox(height: 16), if (_container.notes != null && _container.notes!.isNotEmpty) _buildNotesSection(), const SizedBox(height: 16), _buildHistorySection(), ], ), ), ); } Widget _buildHeaderCard() { 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( 'Type', _container.type.label, Icons.category, ), ), Expanded( child: _buildInfoItem( 'Statut', _getStatusLabel(_container.status), Icons.info, statusColor: _getStatusColor(_container.status), ), ), ], ), const SizedBox(height: 12), Row( children: [ Expanded( child: _buildInfoItem( 'Équipements', '${_container.itemCount}', Icons.inventory, ), ), Expanded( child: _buildInfoItem( 'Poids total', _calculateTotalWeight(), Icons.scale, ), ), ], ), ], ), ), ); } Widget _buildPhysicalCharacteristics() { final hasDimensions = _container.length != null || _container.width != null || _container.height != null; final hasWeight = _container.weight != null; final hasVolume = _container.volume != null; if (!hasDimensions && !hasWeight) { return const SizedBox.shrink(); } return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Caractéristiques physiques', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const Divider(height: 24), if (hasWeight) _buildCharacteristicRow( 'Poids à vide', '${_container.weight} kg', Icons.scale, ), if (hasDimensions) ...[ if (hasWeight) const SizedBox(height: 12), _buildCharacteristicRow( 'Dimensions (L×l×H)', '${_container.length ?? '?'} × ${_container.width ?? '?'} × ${_container.height ?? '?'} cm', Icons.straighten, ), ], if (hasVolume) ...[ const SizedBox(height: 12), _buildCharacteristicRow( 'Volume', '${_container.volume!.toStringAsFixed(3)} m³', Icons.view_in_ar, ), ], ], ), ), ); } Widget _buildEquipmentSection() { return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Contenu du container', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), ], ), const Divider(height: 24), if (_isLoadingEquipment) const Center( child: Padding( padding: EdgeInsets.all(16.0), child: CircularProgressIndicator(), ), ) else if (_equipmentList.isEmpty) Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( children: [ Icon( Icons.inventory_2_outlined, size: 60, color: Colors.grey.shade400, ), const SizedBox(height: 12), Text( 'Aucun équipement dans ce container', style: TextStyle( fontSize: 16, color: Colors.grey.shade600, ), ), ], ), ), ) else ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _equipmentList.length, separatorBuilder: (context, index) => const Divider(height: 1), itemBuilder: (context, index) { final equipment = _equipmentList[index]; return _buildEquipmentTile(equipment); }, ), ], ), ), ); } Widget _buildEquipmentTile(EquipmentModel equipment) { return ListTile( contentPadding: const EdgeInsets.symmetric(vertical: 8), leading: CircleAvatar( backgroundColor: AppColors.rouge.withOpacity(0.1), child: const Icon(Icons.inventory_2, color: AppColors.rouge), ), title: Text( equipment.id, style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (equipment.brand != null || equipment.model != null) Text('${equipment.brand ?? ''} ${equipment.model ?? ''}'), const SizedBox(height: 4), Row( children: [ _buildSmallBadge( _getCategoryLabel(equipment.category), Colors.blue, ), const SizedBox(width: 8), if (equipment.weight != null) _buildSmallBadge( '${equipment.weight} kg', Colors.grey, ), ], ), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.visibility, size: 20), tooltip: 'Voir détails', onPressed: () => _viewEquipment(equipment), ), IconButton( icon: const Icon(Icons.remove_circle, color: Colors.red, size: 20), tooltip: 'Retirer', onPressed: () => _removeEquipment(equipment), ), ], ), ); } Widget _buildNotesSection() { return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Notes', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const Divider(height: 24), Text( _container.notes!, style: const TextStyle(fontSize: 14), ), ], ), ), ); } Widget _buildHistorySection() { if (_container.history.isEmpty) { return const SizedBox.shrink(); } return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Historique', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const Divider(height: 24), ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _container.history.length > 10 ? 10 : _container.history.length, separatorBuilder: (context, index) => const Divider(height: 16), itemBuilder: (context, index) { final entry = _container.history[ _container.history.length - 1 - index]; // Plus récent en premier return _buildHistoryEntry(entry); }, ), ], ), ), ); } Widget _buildHistoryEntry(ContainerHistoryEntry entry) { IconData icon; Color color; String description; switch (entry.action) { case 'equipment_added': icon = Icons.add_circle; color = Colors.green; description = 'Équipement ajouté: ${entry.equipmentId ?? "?"}'; break; case 'equipment_removed': icon = Icons.remove_circle; color = Colors.red; description = 'Équipement retiré: ${entry.equipmentId ?? "?"}'; break; case 'status_change': icon = Icons.sync; color = Colors.blue; description = 'Statut changé: ${entry.previousValue} → ${entry.newValue}'; break; default: icon = Icons.info; color = Colors.grey; description = entry.action; } return Row( children: [ Icon(icon, color: color, size: 20), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( description, style: const TextStyle(fontSize: 14), ), const SizedBox(height: 2), Text( DateFormat('dd/MM/yyyy HH:mm').format(entry.timestamp), style: TextStyle( fontSize: 12, color: Colors.grey.shade600, ), ), ], ), ), ], ); } Widget _buildInfoItem(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, ), ), ], ); } Widget _buildCharacteristicRow(String label, String value, IconData icon) { return Row( children: [ Icon(icon, size: 20, color: AppColors.rouge), const SizedBox(width: 12), Expanded( child: Text( label, style: const TextStyle(fontSize: 14), ), ), Text( value, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, ), ), ], ); } Widget _buildSmallBadge(String label, Color color) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all(color: color.withOpacity(0.3)), ), child: Text( label, style: TextStyle( fontSize: 11, color: color, fontWeight: FontWeight.bold, ), ), ); } 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; } } 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 'Effets'; case EquipmentCategory.structure: return 'Structure'; case EquipmentCategory.consumable: return 'Consommable'; case EquipmentCategory.cable: return 'Câble'; case EquipmentCategory.other: return 'Autre'; } } void _handleMenuAction(String action) { if (action == 'delete') { _deleteContainer(); } } void _editContainer() { Navigator.pushNamed( context, '/container_form', arguments: _container, ).then((_) => _refreshContainer()); } void _showQRCode() { showDialog( context: context, builder: (context) => AlertDialog( title: Text('QR Code - ${_container.name}'), content: SizedBox( width: 250, child: Column( mainAxisSize: MainAxisSize.min, children: [ QrImageView( data: _container.id, version: QrVersions.auto, size: 200, ), const SizedBox(height: 16), Text( _container.id, style: const TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Fermer'), ), ], ), ); } void _viewEquipment(EquipmentModel equipment) { Navigator.push( context, MaterialPageRoute( builder: (context) => EquipmentDetailPage(equipment: equipment), ), ); } Future _removeEquipment(EquipmentModel equipment) async { final confirm = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Retirer l\'équipement'), content: Text( 'Êtes-vous sûr de vouloir retirer "${equipment.id}" de ce container ?', ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Annuler'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom(backgroundColor: Colors.red), child: const Text('Retirer'), ), ], ), ); if (confirm == true && mounted) { try { await context.read().removeEquipmentFromContainer( containerId: _container.id, equipmentId: equipment.id, ); await _refreshContainer(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Équipement retiré avec succès')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Erreur: $e')), ); } } } } Future _deleteContainer() async { final confirm = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Confirmer la suppression'), content: Text( 'Êtes-vous sûr de vouloir supprimer le container "${_container.name}" ?\n\n' 'Cette action est irréversible.', ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Annuler'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom(backgroundColor: Colors.red), child: const Text('Supprimer'), ), ], ), ); if (confirm == true && mounted) { try { await context.read().deleteContainer(_container.id); if (mounted) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Container supprimé avec succès')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Erreur: $e')), ); } } } } }