# Infrastructure générique pour les formulaires ## 📋 Vue d'ensemble Cette infrastructure permet de créer des formulaires qui s'adaptent automatiquement : - **Mode éditable** (inscription) vs **lecture seule** (récapitulatif) - **Layout mobile** (vertical, < 600px) vs **desktop** (horizontal, ≥ 600px) - **Mobile reste toujours vertical**, même en rotation paysage ## 🏗️ Architecture ### 1. `display_config.dart` - Configuration centrale ```dart // Mode d'affichage enum DisplayMode { editable, // Formulaire éditable readonly, // Récapitulatif } // Type de layout enum LayoutType { mobile, // < 600px, toujours vertical desktop, // ≥ 600px, horizontal } // Configuration complète DisplayConfig config = DisplayConfig.fromContext( context, mode: DisplayMode.editable, ); ``` ### 2. `form_field_wrapper.dart` - Champs génériques #### FormFieldWrapper Widget pour afficher un champ unique qui s'adapte automatiquement. **Mode éditable :** ```dart FormFieldWrapper( config: config, label: 'Prénom', value: '', controller: firstNameController, onChanged: (value) => {}, hint: 'Entrez votre prénom', ) ``` **Mode readonly :** ```dart FormFieldWrapper( config: config, label: 'Prénom', value: 'Jean', ) ``` #### FormFieldRow Widget pour afficher plusieurs champs sur une ligne (desktop) ou en colonne (mobile). ```dart FormFieldRow( config: config, fields: [ FormFieldWrapper(...), FormFieldWrapper(...), ], ) ``` ### 3. `base_form_screen.dart` - Structure de page générique Encapsule toute la structure d'une page de formulaire : - En-tête (étape + titre) - Carte avec fond adapté (horizontal/vertical) - Boutons de navigation - Gestion automatique du layout ```dart BaseFormScreen( config: DisplayConfig.fromContext( context, mode: DisplayMode.editable, ), stepText: 'Étape 1/4', title: 'Informations personnelles', cardColor: CardColorHorizontal.blue, previousRoute: '/previous', onSubmit: () => _handleSubmit(), content: Column( children: [ FormFieldRow( config: config, fields: [ FormFieldWrapper(...), FormFieldWrapper(...), ], ), ], ), ) ``` ## 📱 Comportement responsive ### Breakpoint : 600px | Largeur écran | LayoutType | Orientation carte | Disposition champs | |--------------|------------|-------------------|-------------------| | < 600px | mobile | Verticale | Colonne | | ≥ 600px | desktop | Horizontale | Ligne | ### Règle importante **Sur mobile, le layout reste TOUJOURS vertical**, même si l'utilisateur tourne son téléphone en mode paysage. ## 🎨 Utilisation dans un widget de formulaire ### Exemple : PersonalInfoFormScreen ```dart class PersonalInfoFormScreen extends StatefulWidget { final DisplayMode mode; final PersonalInfoData? initialData; final Function(PersonalInfoData) onSubmit; // ... } class _PersonalInfoFormScreenState extends State { late TextEditingController _firstNameController; late TextEditingController _lastNameController; @override Widget build(BuildContext context) { final config = DisplayConfig.fromContext( context, mode: widget.mode, ); return BaseFormScreen( config: config, stepText: 'Étape 1/4', title: 'Informations personnelles', cardColor: CardColorHorizontal.blue, previousRoute: '/previous', onSubmit: _handleSubmit, content: Column( children: [ FormFieldRow( config: config, fields: [ FormFieldWrapper( config: config, label: 'Prénom', value: _firstNameController.text, controller: config.isEditable ? _firstNameController : null, onChanged: config.isEditable ? (v) => setState(() {}) : null, ), FormFieldWrapper( config: config, label: 'Nom', value: _lastNameController.text, controller: config.isEditable ? _lastNameController : null, onChanged: config.isEditable ? (v) => setState(() {}) : null, ), ], ), ], ), ); } void _handleSubmit() { final data = PersonalInfoData( firstName: _firstNameController.text, lastName: _lastNameController.text, ); widget.onSubmit(data); } } ``` ## ✅ Avantages 1. **Code unique** : Un seul widget pour éditable + readonly + mobile + desktop 2. **Cohérence** : Tous les formulaires se comportent de la même façon 3. **Maintenance** : Modification centralisée de l'UI 4. **Performance** : Pas de rebuild inutile, layout déterminé au build 5. **Simplicité** : API claire et prévisible ## 🔧 Utilitaires disponibles ```dart // Détecter le type de layout bool isMobile = LayoutHelper.isMobile(context); bool isDesktop = LayoutHelper.isDesktop(context); // Espacement adaptatif double spacing = LayoutHelper.getSpacing( context, mobileSpacing: 12.0, desktopSpacing: 20.0, ); // Largeur max adaptative double maxWidth = LayoutHelper.getMaxWidth(context); ``` ## 🚀 Migration des widgets existants Pour migrer un widget existant vers cette infrastructure : 1. Ajouter paramètre `DisplayMode mode` 2. Créer `DisplayConfig.fromContext(context, mode: widget.mode)` 3. Remplacer la structure Scaffold par `BaseFormScreen` 4. Remplacer les champs par `FormFieldWrapper` 5. Grouper les champs avec `FormFieldRow` 6. Tester en mode editable + readonly + mobile + desktop