import 'package:flutter/material.dart'; import 'package:geosector_app/core/data/models/sector_model.dart'; import 'package:geosector_app/core/data/models/membre_model.dart'; import 'package:geosector_app/core/data/models/user_sector_model.dart'; import 'package:geosector_app/core/repositories/membre_repository.dart'; import 'package:geosector_app/core/services/current_amicale_service.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:geosector_app/core/constants/app_keys.dart'; class SectorDialog extends StatefulWidget { final SectorModel? existingSector; final List> coordinates; final Future Function(String name, String color, List memberIds) onSave; const SectorDialog({ super.key, this.existingSector, required this.coordinates, required this.onSave, }); @override State createState() => _SectorDialogState(); } class _SectorDialogState extends State { final _formKey = GlobalKey(); final _nameController = TextEditingController(); final _nameFocusNode = FocusNode(); Color _selectedColor = Colors.blue; final List _selectedMemberIds = []; bool _isLoading = false; bool _membersLoaded = false; @override void initState() { super.initState(); if (widget.existingSector != null) { _nameController.text = widget.existingSector!.libelle; _selectedColor = _hexToColor(widget.existingSector!.color); // Charger les membres affectés au secteur _loadSectorMembers(); } // Donner le focus au champ nom après que le dialog soit construit WidgetsBinding.instance.addPostFrameCallback((_) { _nameFocusNode.requestFocus(); }); } // Charger les membres actuellement affectés au secteur void _loadSectorMembers() { if (widget.existingSector == null) return; debugPrint('=== Début chargement membres pour secteur ${widget.existingSector!.id} - ${widget.existingSector!.libelle} ==='); try { // Vérifier si la box UserSector est ouverte if (!Hive.isBoxOpen(AppKeys.userSectorBoxName)) { debugPrint('Box UserSector non ouverte'); return; } final userSectorBox = Hive.box(AppKeys.userSectorBoxName); debugPrint('Box UserSector contient ${userSectorBox.length} entrées au total'); // Afficher toutes les entrées pour debug for (var i = 0; i < userSectorBox.length; i++) { final us = userSectorBox.getAt(i); if (us != null) { debugPrint(' - UserSector[$i]: membreId=${us.id}, fkSector=${us.fkSector}, name="${us.firstName} ${us.name}"'); } } // Récupérer tous les UserSectorModel pour ce secteur final userSectors = userSectorBox.values .where((us) => us.fkSector == widget.existingSector!.id) .toList(); debugPrint('Trouvé ${userSectors.length} UserSectorModel pour le secteur ${widget.existingSector!.id}'); // Pré-sélectionner les IDs des membres affectés setState(() { _selectedMemberIds.clear(); for (final userSector in userSectors) { // userSector.id est l'ID du membre (pas de l'utilisateur) _selectedMemberIds.add(userSector.id); debugPrint('Membre présélectionné: ${userSector.firstName} ${userSector.name} (membreId: ${userSector.id}, fkSector: ${userSector.fkSector})'); } }); debugPrint('=== Fin chargement: ${_selectedMemberIds.length} membres présélectionnés ==='); debugPrint('IDs présélectionnés: $_selectedMemberIds'); // Marquer le chargement comme terminé setState(() { _membersLoaded = true; }); } catch (e) { debugPrint('Erreur lors du chargement des membres du secteur: $e'); setState(() { _membersLoaded = true; // Même en cas d'erreur }); } } @override void dispose() { _nameController.dispose(); _nameFocusNode.dispose(); super.dispose(); } Color _hexToColor(String hexColor) { final String colorStr = hexColor.startsWith('#') ? hexColor.substring(1) : hexColor; final String fullColorStr = colorStr.length == 6 ? 'FF$colorStr' : colorStr; return Color(int.parse(fullColorStr, radix: 16)); } String _colorToHex(Color color) { return '#${color.value.toRadixString(16).substring(2).toUpperCase()}'; } void _handleSave() async { if (_formKey.currentState!.validate()) { // Vérifier qu'au moins un membre est sélectionné if (_selectedMemberIds.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Veuillez sélectionner au moins un membre'), backgroundColor: Colors.orange, duration: Duration(seconds: 3), ), ); return; } // Indiquer que nous sommes en train de sauvegarder setState(() => _isLoading = true); try { // Appeler le callback onSave et attendre sa résolution await widget.onSave( _nameController.text.trim(), _colorToHex(_selectedColor), _selectedMemberIds, ); // Si tout s'est bien passé, fermer le dialog if (mounted) { Navigator.of(context).pop(); } } catch (e) { // En cas d'erreur, réactiver le bouton if (mounted) { setState(() => _isLoading = false); } // L'erreur sera gérée par le callback onSave rethrow; } } } void _showColorPicker() { // Liste de couleurs prédéfinies final List colors = [ Colors.red, Colors.pink, Colors.purple, Colors.deepPurple, Colors.indigo, Colors.blue, Colors.lightBlue, Colors.cyan, Colors.teal, Colors.green, Colors.lightGreen, Colors.lime, Colors.yellow, Colors.amber, Colors.orange, Colors.deepOrange, Colors.brown, Colors.grey, Colors.blueGrey, const Color(0xFF1E88E5), // Bleu personnalisé const Color(0xFF43A047), // Vert personnalisé const Color(0xFFE53935), // Rouge personnalisé const Color(0xFFFFB300), // Ambre personnalisé const Color(0xFF8E24AA), // Violet personnalisé ]; showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Choisir une couleur'), content: Container( width: double.maxFinite, child: GridView.builder( shrinkWrap: true, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, mainAxisSpacing: 8, crossAxisSpacing: 8, ), itemCount: colors.length, itemBuilder: (context, index) { final color = colors[index]; return InkWell( onTap: () { setState(() { _selectedColor = color; }); Navigator.of(context).pop(); }, child: Container( decoration: BoxDecoration( color: color, border: Border.all( color: _selectedColor == color ? Colors.black : Colors.grey, width: _selectedColor == color ? 3 : 1, ), borderRadius: BorderRadius.circular(8), ), ), ); }, ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ], ), ); } @override Widget build(BuildContext context) { final currentAmicale = CurrentAmicaleService.instance.currentAmicale; return AlertDialog( title: Text(widget.existingSector == null ? 'Nouveau secteur' : 'Modifier le secteur'), content: SingleChildScrollView( child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Nom du secteur TextFormField( controller: _nameController, focusNode: _nameFocusNode, decoration: InputDecoration( labelText: 'Nom du secteur', labelStyle: TextStyle(color: Colors.black), label: Row( mainAxisSize: MainAxisSize.min, children: [ Text('Nom du secteur'), Text( ' *', style: TextStyle(color: Colors.red), ), ], ), hintText: 'Ex: Centre-ville', prefixIcon: Icon(Icons.location_on), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Veuillez entrer un nom'; } return null; }, ), const SizedBox(height: 20), // Couleur du secteur const Text( 'Couleur du secteur', style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 10), InkWell( onTap: () { _showColorPicker(); }, child: Container( height: 50, decoration: BoxDecoration( color: _selectedColor, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey), ), child: Center( child: Text( 'Toucher pour changer', style: TextStyle( color: _selectedColor.computeLuminance() > 0.5 ? Colors.black : Colors.white, fontWeight: FontWeight.bold, ), ), ), ), ), const SizedBox(height: 20), // Sélection des membres Row( children: [ const Text( 'Membres affectés', style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(width: 4), Text( '*', style: TextStyle( color: Colors.red, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 10), if (_selectedMemberIds.isEmpty) Padding( padding: const EdgeInsets.only(bottom: 8.0), child: Text( 'Sélectionnez au moins un membre', style: TextStyle( fontSize: 12, color: Colors.grey[600], fontStyle: FontStyle.italic, ), ), ), if (currentAmicale != null) ValueListenableBuilder>( valueListenable: Hive.box(AppKeys.membresBoxName).listenable(), builder: (context, box, _) { debugPrint('=== Build liste membres - IDs présélectionnés: $_selectedMemberIds ==='); final membres = box.values .where((m) => m.fkEntite == currentAmicale.id) .toList(); if (membres.isEmpty) { return const Center( child: Text('Aucun membre disponible'), ); } return Container( constraints: const BoxConstraints(maxHeight: 200), decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: BorderRadius.circular(8), ), child: ListView.builder( shrinkWrap: true, itemCount: membres.length, itemBuilder: (context, index) { final membre = membres[index]; final isSelected = _selectedMemberIds.contains(membre.id); // Log pour debug if (index < 3) { // Limiter les logs aux 3 premiers membres debugPrint('Membre ${index}: ${membre.firstName} ${membre.name} (ID: ${membre.id}) - isSelected: $isSelected'); } return CheckboxListTile( dense: true, contentPadding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 0.0), title: Text( '${membre.firstName} ${membre.name}${membre.sectName != null && membre.sectName!.isNotEmpty ? ' (${membre.sectName})' : ''}', style: const TextStyle(fontSize: 14), ), value: isSelected, onChanged: (bool? value) { setState(() { if (value == true) { _selectedMemberIds.add(membre.id); } else { _selectedMemberIds.remove(membre.id); } }); }, ); }, ), ); }, ), ], ), ), ), actions: [ TextButton( onPressed: _isLoading ? null : () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ElevatedButton( onPressed: _isLoading ? null : _handleSave, child: _isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : Text(widget.existingSector == null ? 'Créer' : 'Modifier'), ), ], ); } }