import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'dart:math' as math; // Pour la rotation du chevron import '../../widgets/hover_relief_widget.dart'; // Import du nouveau widget import 'package:image_picker/image_picker.dart'; // import 'package:image_cropper/image_cropper.dart'; // Supprimé import 'dart:io' show File, Platform; // Ajout de Platform import 'package:flutter/foundation.dart' show kIsWeb; // Import pour kIsWeb // TODO: Créer un modèle de données pour l'enfant // class ChildData { ... } class ParentRegisterStep3Screen extends StatefulWidget { const ParentRegisterStep3Screen({super.key}); @override State createState() => _ParentRegisterStep3ScreenState(); } class _ParentRegisterStep3ScreenState extends State { // TODO: Gérer une liste d'enfants et leurs contrôleurs respectifs // List _children = [ChildData()]; // Commencer avec un enfant final _formKey = GlobalKey(); // Une clé par enfant sera nécessaire si validation complexe // Contrôleurs pour le premier enfant (pour l'instant) final _firstNameController = TextEditingController(); final _lastNameController = TextEditingController(); final _dobController = TextEditingController(); bool _photoConsent = false; bool _multipleBirth = false; bool _isUnbornChild = false; // Nouvelle variable d'état // TODO: Ajouter variable pour stocker l'image sélectionnée (par enfant) // File? _childImage; // File? _childImage; // Déjà présent et commenté // Liste pour stocker les images des enfants (si gestion multi-enfants) List _childImages = [null]; // Initialiser avec null pour le premier enfant @override void dispose() { _firstNameController.dispose(); _lastNameController.dispose(); _dobController.dispose(); // TODO: Disposer les contrôleurs de tous les enfants super.dispose(); } // TODO: Pré-remplir le nom de famille avec celui du parent 1 @override void initState() { super.initState(); } Future _selectDate(BuildContext context) async { final DateTime now = DateTime.now(); DateTime initialDatePickerDate = now; DateTime firstDatePickerDate = DateTime(1980); DateTime lastDatePickerDate = now; if (_isUnbornChild) { firstDatePickerDate = now; // Ne peut pas être avant aujourd'hui si à naître lastDatePickerDate = now.add(const Duration(days: 300)); // Environ 10 mois dans le futur // Si une date de naissance avait été entrée, on la garde pour initialDate si elle est dans la nouvelle plage if (_dobController.text.isNotEmpty) { try { // Tenter de parser la date existante List parts = _dobController.text.split('/'); DateTime? parsedDate = DateTime.tryParse("${parts[2]}-${parts[1].padLeft(2, '0')}-${parts[0].padLeft(2, '0')}"); if (parsedDate != null && !parsedDate.isBefore(firstDatePickerDate) && !parsedDate.isAfter(lastDatePickerDate)) { initialDatePickerDate = parsedDate; } } catch (e) { /* Ignorer si le format est incorrect */ } } } else { // Si une date prévisionnelle avait été entrée, on la garde pour initialDate si elle est dans la nouvelle plage if (_dobController.text.isNotEmpty) { try { List parts = _dobController.text.split('/'); DateTime? parsedDate = DateTime.tryParse("${parts[2]}-${parts[1].padLeft(2, '0')}-${parts[0].padLeft(2, '0')}"); if (parsedDate != null && !parsedDate.isBefore(firstDatePickerDate) && !parsedDate.isAfter(lastDatePickerDate)) { initialDatePickerDate = parsedDate; } } catch (e) { /* Ignorer */ } } } final DateTime? picked = await showDatePicker( context: context, initialDate: initialDatePickerDate, firstDate: firstDatePickerDate, lastDate: lastDatePickerDate, locale: const Locale('fr', 'FR'), ); if (picked != null) { setState(() { _dobController.text = "${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}"; }); } } // Méthode pour sélectionner une image Future _pickImage(int childIndex) async { final ImagePicker picker = ImagePicker(); try { final XFile? pickedFile = await picker.pickImage( source: ImageSource.gallery, imageQuality: 70, maxWidth: 1024, maxHeight: 1024, ); if (pickedFile != null) { // On utilise directement le fichier sélectionné, sans recadrage setState(() { if (childIndex < _childImages.length) { _childImages[childIndex] = File(pickedFile.path); } else { print("Erreur: Index d'enfant hors limites pour l'image."); } }); } // Fin de if (pickedFile != null) } catch (e) { print("Erreur lors de la sélection de l'image: $e"); } } @override Widget build(BuildContext context) { final screenSize = MediaQuery.of(context).size; return Scaffold( body: Stack( children: [ // Fond papier Positioned.fill( child: Image.asset( 'assets/images/paper2.png', fit: BoxFit.cover, repeat: ImageRepeat.repeat, ), ), // Contenu centré et scrollable Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(vertical: 40.0), // Ajout de padding vertical child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Indicateur d'étape Text( 'Étape 3/X', // Mettre à jour le numéro d'étape total style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54), ), const SizedBox(height: 10), // Texte d'instruction Text( 'Merci de renseigner les informations de/vos enfant(s) :', style: GoogleFonts.merienda( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black87, ), textAlign: TextAlign.center, ), const SizedBox(height: 30), // Zone principale : Cartes enfants + Bouton Ajouter // Utilisation d'une Row pour placer côte à côte comme sur la maquette // Il faudra peut-être ajuster pour les petits écrans (Wrap?) Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, // CHANGED: pour centrer verticalement children: [ // TODO: Remplacer par une ListView ou Column dynamique basée sur _children // Pour l'instant, une seule carte _buildChildCard(context, 0), // Index 0 pour le premier enfant const SizedBox(width: 30), HoverReliefWidget( onPressed: () { print("Ajouter un enfant via HoverReliefWidget"); // setState(() { _children.add(ChildData()); }); }, borderRadius: BorderRadius.circular(15), child: Image.asset( 'assets/images/plus.png', height: 80, width: 80, ), ), ], ), ], ), ), ), // Chevrons de navigation (identiques aux étapes précédentes) // Chevron Gauche (Retour Step 2) Positioned( top: screenSize.height / 2 - 20, left: 40, child: IconButton( icon: Transform( alignment: Alignment.center, transform: Matrix4.rotationY(math.pi), child: Image.asset('assets/images/chevron_right.png', height: 40), ), onPressed: () => Navigator.pop(context), // Retour étape 2 tooltip: 'Retour', ), ), // Chevron Droit (Suivant Step 4) Positioned( top: screenSize.height / 2 - 20, right: 40, child: IconButton( icon: Image.asset('assets/images/chevron_right.png', height: 40), onPressed: () { // TODO: Valider les infos enfants et Naviguer vers l'étape 4 print('Passer à l\'étape 4 (Situation familiale)'); // Navigator.pushNamed(context, '/parent-register/step4'); }, tooltip: 'Suivant', ), ), ], ), ); } // Widget pour construire UNE carte enfant // L'index permettra de lier aux bons contrôleurs et données Widget _buildChildCard(BuildContext context, int index) { final File? currentChildImage = (index < _childImages.length) ? _childImages[index] : null; // TODO: Déterminer la couleur de base de card_lavander.png et ajuster ces couleurs d'ombre final Color baseLavandeColor = Colors.purple.shade200; // Placeholder pour la couleur de la carte lavande final Color initialPhotoShadow = baseLavandeColor.withAlpha(90); final Color hoverPhotoShadow = baseLavandeColor.withAlpha(130); return Container( width: 300, padding: const EdgeInsets.all(20), decoration: BoxDecoration( image: const DecorationImage( image: AssetImage('assets/images/card_lavander.png'), fit: BoxFit.cover, ), borderRadius: BorderRadius.circular(20), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ HoverReliefWidget( onPressed: () { _pickImage(index); }, borderRadius: BorderRadius.circular(10), initialShadowColor: initialPhotoShadow, // Ombre lavande hoverShadowColor: hoverPhotoShadow, // Ombre lavande au survol child: SizedBox( height: 100, width: 100, child: Center( child: Padding( padding: const EdgeInsets.all(5.0), child: currentChildImage != null ? ClipRRect( borderRadius: BorderRadius.circular(8), child: kIsWeb // Condition pour le Web ? Image.network( // Utiliser Image.network pour le Web currentChildImage.path, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { // Optionnel: Afficher un placeholder ou un message en cas d'erreur de chargement print("Erreur de chargement de l'image réseau: $error"); return const Icon(Icons.broken_image, size: 40); }, ) : Image.file( // Utiliser Image.file pour les autres plateformes currentChildImage, fit: BoxFit.cover, ), ) : Image.asset( 'assets/images/photo.png', fit: BoxFit.contain, ), ), ), ), ), const SizedBox(height: 10), // Espace après la photo // Nouveau Switch pour "Enfant à naître ?" Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, // Aligner le label à gauche, switch à droite children: [ Text( 'Enfant à naître ?', style: GoogleFonts.merienda(fontSize: 14, fontWeight: FontWeight.w600), ), Switch( value: _isUnbornChild, onChanged: (bool newValue) { setState(() { _isUnbornChild = newValue; // Optionnel: Réinitialiser la date si le type change // _dobController.clear(); }); }, activeColor: Theme.of(context).primaryColor, // Utiliser une couleur de thème ), ], ), const SizedBox(height: 15), // Espace après le switch _buildTextField( _firstNameController, 'Prénom', hintText: _isUnbornChild ? 'Prénom (optionnel)' : 'Prénom de l\'enfant', // HintText ajusté isRequired: !_isUnbornChild, ), const SizedBox(height: 10), _buildTextField(_lastNameController, 'Nom', hintText: 'Nom de l\'enfant', enabled: true), const SizedBox(height: 10), _buildTextField( _dobController, _isUnbornChild ? 'Date prévisionnelle de naissance' : 'Date de naissance', hintText: 'JJ/MM/AAAA', readOnly: true, onTap: () => _selectDate(context), suffixIcon: Icons.calendar_today, ), const SizedBox(height: 20), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildCustomCheckbox( label: 'Consentement photo', value: _photoConsent, onChanged: (newValue) { setState(() => _photoConsent = newValue); } ), const SizedBox(height: 10), _buildCustomCheckbox( label: 'Naissance multiple', value: _multipleBirth, onChanged: (newValue) { setState(() => _multipleBirth = newValue); } ), ], ), ], ), ); } // Widget pour construire une checkbox personnalisée Widget _buildCustomCheckbox({required String label, required bool value, required ValueChanged onChanged}) { const double checkboxSize = 20.0; const double checkmarkSizeFactor = 1.4; // Augmenté pour une coche plus grande return GestureDetector( onTap: () => onChanged(!value), child: Row( mainAxisSize: MainAxisSize.min, children: [ SizedBox( // Envelopper le Stack dans un SizedBox pour fixer sa taille width: checkboxSize, height: checkboxSize, child: Stack( alignment: Alignment.center, clipBehavior: Clip.none, children: [ Image.asset( 'assets/images/square.png', height: checkboxSize, // Taille fixe width: checkboxSize, // Taille fixe ), if (value) Image.asset( 'assets/images/coche.png', height: checkboxSize * checkmarkSizeFactor, width: checkboxSize * checkmarkSizeFactor, ), ], ), ), const SizedBox(width: 10), Text(label, style: GoogleFonts.merienda(fontSize: 14)), ], ), ); } // Widget pour construire les champs de texte (peut être externalisé) // Ajout de onTap et suffixIcon pour le DatePicker Widget _buildTextField( TextEditingController controller, String label, { TextInputType? keyboardType, bool obscureText = false, String? hintText, bool enabled = true, bool readOnly = false, VoidCallback? onTap, IconData? suffixIcon, bool isRequired = true, // Nouveau paramètre, par défaut à true }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: GoogleFonts.merienda(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.black87), ), const SizedBox(height: 4), Container( height: 45, // Hauteur fixe pour correspondre à l'image de fond decoration: const BoxDecoration( image: DecorationImage( // Rétablir input_field_bg.png image: AssetImage('assets/images/input_field_bg.png'), fit: BoxFit.fill, ), // Pas de borderRadius ici si l'image de fond les a déjà ), child: TextFormField( controller: controller, keyboardType: keyboardType, obscureText: obscureText, enabled: enabled, readOnly: readOnly, onTap: onTap, style: GoogleFonts.merienda(fontSize: 15, color: enabled ? Colors.black87 : Colors.grey), textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( border: InputBorder.none, contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 12), // Augmentation du padding vertical hintText: hintText, hintStyle: GoogleFonts.merienda(fontSize: 15, color: Colors.black38), suffixIcon: suffixIcon != null ? Padding( padding: const EdgeInsets.only(right: 8.0), // Espace pour l'icône child: Icon(suffixIcon, color: Colors.black54, size: 20), ) : null, isDense: true, // Aide à réduire la hauteur par défaut ), validator: (value) { if (!enabled) return null; if (readOnly) return null; if (isRequired && (value == null || value.isEmpty)) { // Validation conditionnée par isRequired return 'Ce champ est obligatoire'; } // TODO: Validations spécifiques (à garder si pertinent pour d'autres champs) return null; }, ), ), ], ); } }