import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:provider/provider.dart'; import 'package:em2rp/models/equipment_model.dart'; import 'package:em2rp/models/maintenance_model.dart'; import 'package:em2rp/providers/equipment_provider.dart'; 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/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'; import 'package:em2rp/views/widgets/equipment/equipment_referencing_containers.dart'; import 'package:em2rp/views/widgets/equipment/equipment_header_section.dart'; import 'package:em2rp/views/widgets/equipment/equipment_main_info_section.dart'; import 'package:em2rp/views/widgets/equipment/equipment_notes_section.dart'; import 'package:em2rp/views/widgets/equipment/equipment_associated_events_section.dart'; import 'package:em2rp/views/widgets/equipment/equipment_price_section.dart'; import 'package:em2rp/views/widgets/equipment/equipment_maintenance_history_section.dart'; import 'package:em2rp/views/widgets/equipment/equipment_dates_section.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:printing/printing.dart'; class EquipmentDetailPage extends StatefulWidget { final EquipmentModel equipment; const EquipmentDetailPage({super.key, required this.equipment}); @override State createState() => _EquipmentDetailPageState(); } class _EquipmentDetailPageState extends State { final EquipmentService _equipmentService = EquipmentService(); List _maintenances = []; bool _isLoadingMaintenances = true; @override void initState() { super.initState(); _loadMaintenances(); } Future _loadMaintenances() async { try { final maintenances = await _equipmentService.getMaintenancesForEquipment(widget.equipment.id); setState(() { _maintenances = maintenances; _isLoadingMaintenances = false; }); } catch (e) { setState(() { _isLoadingMaintenances = false; }); } } @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; final isDesktop = screenWidth >= 1200; final userProvider = Provider.of(context); final hasManagePermission = userProvider.hasPermission('manage_equipment'); return Scaffold( appBar: CustomAppBar( title: widget.equipment.id, actions: [ IconButton( icon: const Icon(Icons.qr_code), tooltip: 'Générer QR Code', onPressed: _showQRCode, ), if (hasManagePermission) IconButton( icon: const Icon(Icons.edit), tooltip: 'Modifier', onPressed: _editEquipment, ), if (hasManagePermission) IconButton( icon: const Icon(Icons.delete, color: Colors.red), tooltip: 'Supprimer', onPressed: _deleteEquipment, ), ], ), body: SingleChildScrollView( padding: EdgeInsets.all(screenWidth < 800 ? 16 : 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 1. Titre de la machine EquipmentHeaderSection(equipment: widget.equipment), const SizedBox(height: 24), // 2. Info principale EquipmentMainInfoSection(equipment: widget.equipment), const SizedBox(height: 24), // 3. Notes if (widget.equipment.notes != null && widget.equipment.notes!.isNotEmpty) ...[ EquipmentNotesSection(notes: widget.equipment.notes!), const SizedBox(height: 24), ], // 4. Événements associés const EquipmentAssociatedEventsSection(), const SizedBox(height: 24), // 5-7. Prix, Historique des maintenances, Dates en layout responsive if (isDesktop) _buildDesktopTwoColumnLayout(hasManagePermission) else _buildMobileLayout(hasManagePermission), const SizedBox(height: 24), // Containers parents (si applicable) if (widget.equipment.parentBoxIds.isNotEmpty) ...[ EquipmentParentContainers( parentBoxIds: widget.equipment.parentBoxIds, ), const SizedBox(height: 24), ], // Containers associés EquipmentReferencingContainers( equipmentId: widget.equipment.id, ), ], ), ), ); } /// Layout 2 colonnes pour desktop Widget _buildDesktopTwoColumnLayout(bool hasManagePermission) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Colonne gauche Expanded( child: Column( children: [ // Prix EquipmentPriceSection(equipment: widget.equipment), const SizedBox(height: 24), // Historique des maintenances EquipmentMaintenanceHistorySection( maintenances: _maintenances, isLoading: _isLoadingMaintenances, hasManagePermission: hasManagePermission, ), ], ), ), const SizedBox(width: 24), // Colonne droite Expanded( child: EquipmentDatesSection(equipment: widget.equipment), ), ], ); } /// Layout simple colonne pour mobile/tablette Widget _buildMobileLayout(bool hasManagePermission) { return Column( children: [ EquipmentPriceSection(equipment: widget.equipment), const SizedBox(height: 24), EquipmentMaintenanceHistorySection( maintenances: _maintenances, isLoading: _isLoadingMaintenances, hasManagePermission: hasManagePermission, ), const SizedBox(height: 24), EquipmentDatesSection(equipment: widget.equipment), ], ); } void _showQRCode() { showDialog( context: context, builder: (context) => Dialog( child: Container( padding: const EdgeInsets.all(24), constraints: const BoxConstraints(maxWidth: 500), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( children: [ const Icon(Icons.qr_code, color: AppColors.rouge, size: 32), const SizedBox(width: 12), Expanded( child: Text( 'QR Code - ${widget.equipment.id}', style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), ), IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context), ), ], ), const SizedBox(height: 24), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey[300]!), ), child: QrImageView( data: widget.equipment.id, version: QrVersions.auto, size: 300, backgroundColor: Colors.white, ), ), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.equipment.id, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 4), Text( '${widget.equipment.brand ?? ''} ${widget.equipment.model ?? ''}'.trim(), style: TextStyle(color: Colors.grey[700]), ), ], ), ), const SizedBox(height: 24), Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: () => _exportQRCode(), icon: const Icon(Icons.download), label: const Text('Télécharger PNG'), style: OutlinedButton.styleFrom( minimumSize: const Size(0, 48), ), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton.icon( onPressed: () { Navigator.pop(context); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.rouge, minimumSize: const Size(0, 48), ), icon: const Icon(Icons.close, color: Colors.white), label: const Text( 'Fermer', style: TextStyle(color: Colors.white), ), ), ), ], ), ], ), ), ), ); } Future _exportQRCode() async { // Afficher le dialog de chargement showDialog( context: context, barrierDismissible: false, builder: (context) => Dialog( child: Container( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ const CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(AppColors.rouge), ), const SizedBox(height: 16), const Text( 'Génération du QR Code...', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ], ), ), ), ); try { // Exécuter la génération dans un isolate séparé pour éviter le freeze final qrImage = await compute( _generateQRCodeIsolate, widget.equipment.id, ); // Fermer le dialog de chargement if (mounted) { Navigator.pop(context); } // Partager le fichier if (mounted) { await Printing.sharePdf( bytes: qrImage, filename: 'QRCode_${widget.equipment.id}.png', ); } if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('QR Code exporté avec succès'), backgroundColor: Colors.green, ), ); } } catch (e) { // Fermer le dialog de chargement en cas d'erreur if (mounted) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Erreur lors de l\'export: $e'), backgroundColor: Colors.red, ), ); } } } /// Fonction statique pour exécuter la génération QR code dans un isolate static Future _generateQRCodeIsolate(String equipmentId) async { return await QRCodeService.generateQRCode( equipmentId, size: 1024, useCache: false, ); } void _editEquipment() { Navigator.push( context, MaterialPageRoute( builder: (context) => EquipmentFormPage(equipment: widget.equipment), ), ).then((_) { Navigator.pop(context); }); } void _deleteEquipment() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Confirmer la suppression'), content: Text( 'Voulez-vous vraiment supprimer "${widget.equipment.id}" ?\n\nCette action est irréversible.', ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Annuler'), ), TextButton( onPressed: () async { Navigator.pop(context); try { await context .read() .deleteEquipment(widget.equipment.id); if (mounted) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Équipement supprimé avec succès'), backgroundColor: Colors.green, ), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Erreur: $e')), ); } } }, style: TextButton.styleFrom(foregroundColor: Colors.red), child: const Text('Supprimer'), ), ], ), ); } }