54 lines
16 KiB
Markdown
54 lines
16 KiB
Markdown
---
|
||
title: Refonte visuelle des écrans Configuration & Section, et de leurs dialogues
|
||
area: manager
|
||
horizon: v1
|
||
tags: manager-app, UI, dialogues
|
||
flag: good | Maquette prête, code à faire
|
||
src: DOCS/claude design/refonte-configuration-sections.html
|
||
---
|
||
<p><strong>Lots 1 à 5 codés le 04/09</strong> (<code>flutter analyze</code> sans erreur, <code>flutter build web</code> passe ; <strong>rien de vérifié à l'écran</strong>). Pilote <code>select_resource_modal</code> : coquille standard, corps souple, plus de double défilement, <code>showValues</code> mort supprimé, largeur <code>0,85</code> conservée. Lot 1 : <code>text_field_container</code> sans <code>width: double.infinity</code> ni rayon 29, compteur discret dans <code>rounded_input_field</code>. Lot 2 : libellé au-dessus et plus d'auto-centrage dans <code>string_</code>/<code>multi_string_</code>/<code>resource_</code>/<code>check_input_container</code>. Lot 3 : grille responsive de sections, réordonnancement par <code>Draggable</code>/<code>DragTarget</code> (<code>ReorderableListView</code> ne fait pas de grille, et pas de dépendance nouvelle), tuile « Ajouter » à la place du bouton vert. Lot 4 : les deux écrans de détail en <code>EditorHeader</code> + <code>EditorColumns</code> + <code>Pane</code> (nouveau <code>Components/pane.dart</code>), <code>_buildFooter</code> supprimé, le QR devient le rail « Diffusion ». Lot 5 : grille de types dans <code>new_section_popup</code>, modal de traduction en rail de langues + <code>IndexedStack</code>, et <code>multi_input_modal</code> réduit à une redirection <code>isHTML: false</code>. 24 clés i18n ajoutées en FR/EN/NL.</p>
|
||
|
||
<p>🐛 <strong>Le bug des catégories est confirmé et corrigé</strong> : <code>showCreateOrUpdateCategories</code> recevait un <code>newValues</code> vide de l'appelant et le renvoyait tel quel — valider sans rien toucher <em>effaçait</em> les catégories. Le tampon part maintenant des catégories existantes, et les libellés en dur sont passés par <code>AppLocalizations</code>.</p>
|
||
|
||
<p><strong>Lot 6 entamé</strong> : <code>Components/collection_editor.dart</code> existe — liste ordonnée à gauche (réordonnancement par poignée), élément édité en place à droite, ligne « Ajouter » en fin de liste, suppression dans l'en-tête du détail. Trois types migrés : <strong>Slider</strong> et <strong>Article</strong> (via un <code>ContentFields</code> partagé, extrait de <code>showNewOrUpdateContentSlider</code>) et <strong>PDF</strong> (le bloc figé <code>70 × 440</code> disparaît). Les filtres d'envoi au backend sont conservés à l'identique (contenus sans ressource exclus, champs d'article recopiés).</p>
|
||
|
||
<p>⚠️ <strong>Trois fichiers sont devenus du code mort mais ne sont pas supprimés</strong> : <code>pdf_file_input_container.dart</code>, <code>pdf_list.dart</code>, <code>new_update_pdfFile.dart</code>. Ils portent des modifications non committées d'un autre lot — les effacer perdrait ce travail. À supprimer une fois l'arbre propre.</p>
|
||
|
||
<p><strong>Lot 6 terminé pour le gabarit B.</strong> Décision prise le 04/09 (artifact <code>4af75171</code>) : <code>CollectionEditor</code> reçoit un <strong>mode distant</strong> (<code>RemoteCollection</code> : <code>create</code> / <code>delete</code> / <code>reorder</code> asynchrones, voile de chargement, retour à l'état d'avant si l'appel échoue). <strong>Quiz</strong> l'utilise : la modale de question disparaît, les messages de score remontent en tête de carte, les réponses gardent <code>QuizzResponseList</code> tel quel. <strong>Menu</strong> garde la navigation vers <code>sub_section_edit_screen</code> — une sous-section est une section complète — et prend la grille de tuiles, extraite en <code>SectionGrid</code> et partagée avec les sections d'une configuration. <strong>Parcours</strong> : liste qui suit son contenu, les deux <code>SizedBox(height: 500)</code> de <code>event_config</code> et <code>section_parcours_config</code> retirés, éditeur à fenêtre unique inchangé.</p>
|
||
|
||
<p>🐛 <strong>Le rang en double est corrigé</strong> dans Quiz et Menu : ils n'écrivaient que l'<code>order</code> de l'élément déplacé, les autres gardaient le leur. La liste entière est renumérotée et envoyée en un <code>Future.wait</code>, comme le faisait déjà Parcours.</p>
|
||
|
||
<p><strong>Agenda n'a pas été migré, et c'est délibéré</strong> : ses événements sont groupés par langue (<code>_displayGroups</code>, pastilles de langue quand un groupe en compte plusieurs) et n'ont pas d'ordre — une liste ordonnée à édition en place perdrait le groupement. Il reçoit ce qui lui revient : hauteur pilotée par le contenu (le <code>height: 600</code> saute), lignes au système de tokens, modale conservée.</p>
|
||
|
||
<p><strong>Gabarit C — Jeu est fait, Map et Événement sont dégrossis.</strong> <code>game_config</code> devient champs à gauche + canevas à droite : le canevas montre le découpage réel de l'image en <code>rows × cols</code>, seule décision que le formulaire ne montrait pas. Au passage, son <code>TabBar</code> n'en était pas un — les deux onglets construisaient le même formulaire et ne servaient qu'à écrire <code>gameType</code> : c'est devenu un choix à deux valeurs, et le <code>SizedBox(height: 650)</code> a disparu. <code>geoloc_input_container</code> passe à la coquille standard et affiche les coordonnées retenues au lieu d'un bouton « Changer la localisation », la carte prenant la hauteur disponible. Côté <code>map_config</code> : en-tête en grille de tokens, <code>height: 700</code> et <code>height: 70</code> retirés. Côté <code>event_config</code> : <code>height: 600</code> retiré, la liste des blocs suit son contenu.</p>
|
||
|
||
<p><strong>Reste : le canevas de Map et d'Événement — et il est maintenant maquetté</strong> : <code>DOCS/claude design/refonte-gabarit-canevas.html</code> (diffusion : artifact <code>caf400b5</code>). Liste des points, fiche, carte côte à côte ; les points non sélectionnés restent visibles en gris ; <code>MapGeometryPicker</code> sort de son dialogue pour devenir le canevas (déplacement, pas écriture) ; les informations pratiques d'un point (5 champs sur 9) sont repliées derrière un compteur. Absorbe <code>showNewOrUpdateGeoPoint</code> (362 l.), <code>geometry_input_container</code> et <code>showNewOrUpdateMapAnnotation</code> (182 l.). <strong>Une question produit reste ouverte</strong> : que montre le canevas d'Événement quand <code>baseSectionMapId</code> est nul — carte vide, ou invitation à choisir un plan d'abord (ma proposition).</p>
|
||
|
||
<p><strong>Étape 1 du canevas faite le 04/09</strong> : <code>Components/map_canvas.dart</code> — le dessin est sorti du dialogue. Il reçoit une géométrie, la rend modifiable, rend la main <em>à chaque changement</em> (pas de bouton « Enregistrer » : c'est l'écran qui enregistre), et affiche les autres tracés en fond via <code>MapCanvasGhost</code>. Barre d'outils compacte sur la carte, pied qui donne les coordonnées et ce qu'on modifie, bouton « agrandir » optionnel. <code>MapGeometryPicker</code> n'est plus qu'une coquille autour de lui, donc <code>etape_fields</code> et <code>showNewOrUpdateEventAgenda</code> ne bougent pas. Au passage, ses libellés « Ligne » / « Polygone » en dur sont passés par <code>AppLocalizations</code>. <strong>Taille tranchée</strong> : 420 px par défaut + mode agrandi, pas une interface centrée carte — un point porte neuf champs traduits, la carte n'en porte qu'un.</p>
|
||
|
||
<p><strong>Étapes 2 à 4 faites : le gabarit C est en place dans Map.</strong> <code>Map/geo_point_editor.dart</code> — liste des points à gauche, fiche au centre, carte à droite ; les points non sélectionnés apparaissent en fond ; le mode agrandi replie la fiche et garde le rail. Les neuf champs traduits sont rangés par fréquence : titre, catégorie, description et image visibles, les cinq informations pratiques repliées derrière un compteur. <code>map_config</code> passe de 937 à ~510 lignes : la modale <code>showNewOrUpdateGeoPoint</code> n'est plus appelée, <code>getElement</code> et son <code>boxDecoration</code> sont supprimés, et recherche + catégories filtrent désormais la liste <em>et</em> la carte par un seul calcul. Les points sont créés, modifiés et supprimés directement par l'API (<code>sectionMapCreate</code> / <code>Update</code> / <code>Delete</code>), la suppression passant par la confirmation destructive.</p>
|
||
|
||
<p><strong>Étape 5 faite : le canevas d'Événement.</strong> Les annotations passent dans l'éditeur de collection en mode distant, avec le canevas dans le panneau d'édition. <strong>Plan par défaut</strong> retenu (décision Thomas) : le premier plan disponible est pris quand <code>baseSectionMapId</code> est nul, plutôt que de bloquer. 🐛 <strong>Trouvé en chemin</strong> : <code>MapAnnotationDTO</code> portait déjà un champ <code>geometry</code> que l'ancienne modale ne remplissait <em>jamais</em> — elle ne réglait que <code>geometryType</code>. Une annotation déclarait donc une forme sans jamais recevoir de coordonnées ; le canevas les lui donne. Enfin <code>showMultiStringInputAndResourceHTML</code> est passé à la coquille standard : plus aucun dialogue de ce chantier sur l'ancienne.</p>
|
||
|
||
<p><strong>Plan de test</strong> : <code>DOCS/test-plan-refonte-config-section.md</code>, 14 sections. Rien n'a été vérifié à l'écran — <code>flutter analyze</code> propre et <code>flutter build web</code> qui passe, c'est tout.</p>
|
||
|
||
<p><strong>Reste</strong> : supprimer le code mort une fois l'arbre git propre — <code>showNewOrUpdateGeoPoint</code>, <code>showNewOrUpdateMapAnnotation</code>, <code>pdf_file_input_container</code>, <code>pdf_list</code>, <code>new_update_pdfFile</code>, <code>listView_card_subSection</code>, <code>new_update_question_quizz</code> ; et <code>geometry_input_container</code> quand <code>etape_fields</code> et <code>showNewOrUpdateEventAgenda</code> auront leur canevas.</p> Restent aussi <code>showMultiStringInputAndResourceHTML</code> sur l'ancienne coquille, et le code mort à supprimer une fois l'arbre propre : <code>pdf_file_input_container</code>, <code>pdf_list</code>, <code>new_update_pdfFile</code>, <code>listView_card_subSection</code>, <code>new_update_question_quizz</code>.<br>⚠️ <strong>À vérifier manuellement en priorité</strong> : les deux chemins qui recréent les contrôleurs Quill (traduction IA, « appliquer à toutes les langues ») ; les hauteurs figées restées autour des champs devenus plus hauts (<code>height: 70</code>, <code>100</code>) dans les écrans non repris — <code>showNewOrUpdateGeoPoint</code>, <code>showNewOrUpdateEventAgenda</code>, <code>sub_section_edit_screen</code>, <code>new_configuration_popup</code>.</p>
|
||
|
||
<p><strong>Maquette prête et complète</strong> : <code>DOCS/claude design/refonte-configuration-sections.html</code> (diffusion : artifact <code>4d0c2ad6</code>). Elle contient le diagnostic, les deux écrans, les 3 gabarits qui couvrent les 13 types de section, la coquille de dialogue, et deux dialogues dessinés — traduction et choix du type. <strong>Rien à décider côté design : tout est tranché.</strong></p>
|
||
|
||
<p><strong>Le blanc ne vient pas des écrans mais de 4 composants partagés.</strong> <code>text_field_container.dart</code> impose <code>width: double.infinity</code> + rayon 29 ; <code>string_input_container.dart</code> met le label à gauche dans un <code>Row</code> ; <code>multi_string_input_container</code> et <code>resource_input_container</code> se centrent eux-mêmes ; <code>section_reorderList.dart</code> réserve <code>0,3 × hauteur</code> pour une liste horizontale de cartes 150×150. On les corrige une fois, les 13 types en héritent.</p>
|
||
|
||
<p>⚠️ <strong>Aucune direction visuelle à inventer</strong> : <code>constants.dart</code> porte déjà le système (<code>kSpace1..8</code>, <code>kRadiusInput</code> 5 / <code>Card</code> 8 / <code>Shell</code> 10 / <code>Pill</code>, <code>kTitleCard</code>, <code>kLabelField</code>, <code>kTextHint</code>) et <code>confirmation_dialog.dart</code> + <code>resource_picker.dart</code> l'appliquent déjà. Ces deux écrans sont simplement <em>antérieurs</em> au système.</p>
|
||
|
||
<p><strong>Premier pas conseillé : <code>select_resource_modal.dart</code>, pas les composants partagés.</strong> Un fichier, ~15 lignes, zéro ligne dans <code>ResourcesScreen</code>, et ça corrige un vrai bug — <code>AlertDialog</code> dispose de <code>hauteur − 48</code> mais le contenu en demande <code>0,85 × hauteur</code> plus titre plus actions, d'où un défilement dans un défilement. Ça sert de pilote avant de toucher aux composants qui irriguent 30 écrans. ⛔ <strong>Ne pas toucher à la largeur <code>0,85</code></strong> : la règle du rail de facettes de <code>v1-mediatheque-plan.md</code> §3.3 est écrite sur cette hypothèse et déjà codée.</p>
|
||
|
||
<p>⚠️ <strong>Deux pièges qui ne sont pas du visuel.</strong> D'abord, <code>manager-app</code> n'a que 3 tests, aucun sur ces composants : vérification manuelle, et il reste des conteneurs à hauteur figée (<code>height: 70</code>, <code>100</code>, <code>SizedBox(height: 250)</code>) autour — ce qui rentrait juste débordera. Ensuite un chemin d'écriture est câblé dans les composants : <code>section_detail_screen.dart:270</code> déclenche un <code>save(true, …)</code> depuis <code>MultiStringInputContainer.onGetResult</code>, et la ligne 381 un <code>save(false, …)</code> depuis la case iBeacon. À ne pas perdre ni dédoubler.</p>
|
||
|
||
<p>⚠️ <strong>Le piège Quill</strong> (remonté de mémoire par Thomas, confirmé dans le code). Ça marche aujourd'hui <em>parce que</em> l'empilement vertical monte toutes les langues : <code>_controllers</code> est bâtie une fois dans <code>initState</code> (<code>translation_input_container.dart:52</code>) et libérée seulement dans <code>dispose</code>. Le rail de langues de la maquette casse cette propriété s'il reconstruit l'éditeur à chaque bascule. <strong>Règle : map construite une fois pour toutes les langues, bascule par <code>IndexedStack</code>/<code>Offstage</code>, jamais de <code>TabBarView</code></strong> (construction paresseuse, enfants lâchés hors écran sans <code>AutomaticKeepAliveClientMixin</code>). Trace d'une tentative abandonnée : <code>translation_tab.dart</code> existe en <code>TabBar</code>, son appel est en commentaire dans <code>multi_input_modal.dart:46-51</code>. À retester en priorité : la traduction IA (ligne 142) et « appliquer à toutes les langues » (ligne 183), les deux chemins qui libèrent et recréent les contrôleurs.</p>
|
||
|
||
<p><strong>Deux fusions et un ménage</strong> décidés dans la maquette : <code>multi_input_modal.dart</code> est le jumeau sans HTML du modal de traduction (même travail, deux implémentations) → une coquille, deux corps, Quill si <code>isHTML</code> et champ simple sinon ; les 8 <code>showNewOrUpdate*</code> et les 2 sélecteurs géo disparaissent dans les gabarits B et C ; <code>showValues</code> est mort en double (<code>select_resource_modal.dart:64</code> et <code>multi_input_modal.dart:186</code>, appel commenté ligne 53).</p>
|
||
|
||
<p>⚠️ <strong>Conflit résolu avec l'audit</strong> — <code>security/audit-manager-app.md</code> recommandait d'extraire un <code>FormDialogScaffold</code> pour les 15 occurrences des <code>showNewOrUpdate*</code>. Or la refonte les <strong>supprime</strong> : les extraire d'abord, ce serait refactoriser du code à jeter. <strong>Ordre imposé : absorber d'abord (gabarits B et C), extraire ensuite sur ce qui survit</strong> — traduction, nouvelle section, nouvelle configuration, sélecteur de couleur, fichiers PDF, catégories. L'audit et <code>STATUS.md</code> ont été annotés en ce sens le 2026-09-04.</p>
|
||
|
||
<p>🐛 <strong>Trouvé en passant, à vérifier</strong> : <code>pdf_file_input_container.dart</code> et <code>category_input_container.dart</code> sont un copier-coller — mêmes dimensions, même structure — mais le second a ses libellés en dur (« Annuler », « Valider ») et son <code>onGetResult(result)</code> <strong>commenté</strong>. Une catégorie de carte modifiée ne remonte peut-être pas à la volée. Lecture de code, pas testé.</p>
|