Tous les changements ci-dessous ont été appliqués :
dart format+dart analyzesur toutlib/: propre, aucune régression (les 28 alertes existantes sont toutes préexistantes, ailleurs dans le code)flutter run -d macos: l'app compile et se lance sans crash (process actif, logs normaux). Le socket du Dart VM Service n'a pas pu s'ouvrir dans cet environnement sandboxé (sans rapport avec le code applicatif) et la capture d'écran n'a pas été possible faute d'accès à l'affichage — la vérification visuelle interactive (naviguer vers "Messe (nouveau)", activer le flag, tester les dates/modes tab-scroll) n'a pas pu être automatisée ici et reste à faire manuellement.
Les phases 1-3 (dans offline-liturgy, branche masses) ont livré un pipeline Mass complet et exporté (massDetection, massExport, classes Mass/Masses). Il reste à construire la vue Flutter qui l'exploite, sur le modèle de morning_view — dernière étape du plan initial.
aelf-flutter suit une architecture à 4 couches déjà bien établie et documentée (docs/office_display.md) : BaseOfficeViewState<W,T> (chargement, sélection célébration/commun) → XxxOfficeDisplay (tabs/scroll) → widgets communs (ScriptureWidget, AntiphonWidget, CelebrationChipsSelector, buildOrationWidgets, etc.). Morning/Vespers/Readings suivent tous exactement ce patron ; Mass doit faire pareil.
Deux blocages trouvés en explorant, à lever avant que la vue soit utilisable :
pubspec.yamlépingleoffline_liturgysur un commit antérieur à tout le travail Mass (975d9b3c...), 10+ commits de retard surmain. Le pipeline Mass n'existe que sur la branchemasses(actuellementcef6fef8, poussée sur GitHub).- Aucune section "Messe offline" n'existe dans la navigation (
app_sections.dart,liturgy_screen.dart,LiturgyState) — seule l'ancienne messe basée sur l'API web AELF (mass_parser.dart, section"messes") existe.
Décisions validées avec l'utilisateur :
pubspec.yamlépinglé sur le commit actuel demasses(cef6fef82d1464528c4fdd08be948057aa63c0ad), pas sur le nom de branche.- La nouvelle vue coexiste avec l'ancienne "Messe" (API AELF) — ne la remplace pas. Cohérent avec
AGENTS.md: "Do not brake the existing liturgy (compline, mass, vesper, etc.) that uses external API [...] until the offline liturgy feature and branch get stable and merged." - Structure de la Liturgie de la Parole : un onglet par lecture (nommé par position), avec les deux modes tab et scroll comme les autres offices (pas de mode simplifié).
Particularité de Mass à noter : massDetection peut produire plusieurs entrées pour un même jour (ex: Rameaux → procession + messe de la Passion ; Pâques → vigile + messe du jour), chacune avec un massName distinct mais le même isCelebrable. Plutôt que construire un sélecteur dédié, on réutilise CelebrationChipsSelector tel quel : il traite naturellement ces variantes comme des "célébrations" alternatives sélectionnables par chips — cela fonctionne mécaniquement sans code neuf, au prix d'un libellé générique ("Choisir la célébration" plutôt que "Choisir la messe"). Précédent : l'ancienne messe (mass_parser.dart) résolvait déjà ce même problème via un menu de choix.
Changer le ref: de la dépendance git offline_liturgy de 975d9b3c27a333f97994bf29468b8bbb1d33a9de à cef6fef82d1464528c4fdd08be948057aa63c0ad. Lancer flutter pub get ensuite (régénère pubspec.lock).
Sur le modèle exact de offline_liturgy_morning_view.dart :
-
MassView(StatefulWidget, paramsmassList: Map<String, CelebrationContext>,date,calendar) →_MassViewState extends BaseOfficeViewState<MassView, Mass>aveccelebrationList => widget.massList,debugOfficeName => 'Mass',hasInputChanged(date + massList),exportOffice: (ctx) => massExport(ctx),buildOfficeDisplay(...) => MassOfficeDisplay(...). -
MassOfficeDisplay— dual mode tab/scroll piloté parcontext.watch<LiturgyState>().useScrollMode, exactement commeMorningOfficeDisplay. Contrairement à Morning (qui a un état local pour le choix du psaume d'invitatoire), Mass n'a besoin d'aucun état interne mutable —StatelessWidgetsuffit.Sections/onglets, dans l'ordre, chacune conditionnelle si les données sont vides (comme les autres offices) :
- Office (si
_hasMultipleCelebrationsou commun nécessaire) —_OfficeTab: copie quasi verbatim du_OfficeTabdemorning_view(logique 100% générique, déjà dupliquée à l'identique dans Vespers/Readings — même convention, pas de nouvelle abstraction partagée). - Introduction —
OfficeHeaderDisplay(identique aux autres offices) +AntiphonWidgetsurentranceAntiphon(jusqu'à 3MassAntiphon.content) +buildOrationWidgets(collect). - Une section par
MassReadingPartdereadingParts, labellisée par position (fonction_readingPartLabel) :READING/EPISTLE→ScriptureWidget(déjà quasi identique :title/reference: biblicalRef/content) ; options multiples au sein d'une même part (ex: choix Col 3 / 1 Co 5 à Pâques) séparées par "ou" (même idiome quebuildOrationWidgets).PSALM/CANTICLE→ nouveau petit widget (_MassPsalmContent, privé au fichier) : titre (refAbbr/biblicalRef) + refrain (chorus: List<MassChorusEntry>, rendu simple façon antienne) + texte (YamlTextFromString, même pipeline de marquage que le reste des contenus Mass).GOSPEL→ nouveau petit widget (_MassGospelContent) : titre/référence + antiennes d'acclamation (beforeAcclamationAntiphon/acclamationAntiphon/afterAcclamationAntiphon) + texte justifié (styleScriptureWidget).- Labellisation (
_readingPartLabel) : compte le nombre total de parts de chaque famille (lecture vs psaume) ; 1 seule → "Lecture"/"Psaume" ; 2 → "1ère lecture"/"2ème lecture" ; plus (vigile pascale) → "Lecture 1", "Lecture 2"… Gospel toujours "Évangile" (unique).
- Offrandes —
buildOrationWidgets(offeringPrayer);prefaceListaffiché en simple texte de référence s'il est présent (pas de bibliothèque de textes de préfaces existante — hors scope). - Communion —
AntiphonWidgetsurcommunionAntiphon+buildOrationWidgets(prayerAfterCommunion). - Bénédiction —
buildOrationWidgets(solemnBlessingList)si présent.
Les libellés de section spécifiques à la Messe (Lecture, Psaume, Évangile, Offrandes, Communion, Bénédiction…) sont codés en dur en français dans le widget plutôt qu'ajoutés à
liturgyLabelsdu packageoffline_liturgy— cohérent avec le précédent déjà présent dansmorning_view(Tab(text: 'Benedictus')en dur), et garde ce changement scopé àaelf-flutteruniquement. - Office (si
lib/data/app_sections.dart: ajouterAppSectionItem(title: "Messe (nouveau)", name: "offline_mass", ...), sur le modèle de"Laudes (nouveau)"→offline_morning. L'entrée "Messe" existante reste inchangée (coexistence).lib/states/liturgyState.dart: ajouterMap<String, CelebrationContext> offlineMass = {}, une méthodegetOfflineMass(dateTime, region)(calque degetOfflineMorning, utilisantFlutterDataLoader+massDetection), et uncase 'offline_mass':dans le switch deupdateLiturgy().lib/app_screens/liturgy_screen.dart: ajoutercase "offline_mass":retournantMassView(massList: liturgyState.offlineMass, date: ..., calendar: ...)avec le même garde "spinner tant que vide" que les autres cas.lib/widgets/left_menu.dart: aucun changement —offline_massest automatiquement filtré par la règle existante (name.startsWith('offline_') && !offlineEnabled → false), et'messes'n'étant pas ajouté à_aelfReplacedOffices, les deux entrées coexistent quand le flag est actif, comme décidé.lib/app_screens/aelf_home_page.dart: aucun changement — leFIXMEpréexistant sur le nombre de pages codé en dur (List.generate(10, ...)vs ~19appSections) n'est pas dans le scope de cette phase ; une entrée de plus ne fait qu'accentuer un écart déjà toléré (les sauts de page sont déjà clampés)._computeCurrentOffice()/offlineMapn'est pas non plus modifié : la détection automatique du dimanche continue de pointer vers la messe historique, cohérent avec la coexistence.
flutter pub getaprès le bump depubspec.yaml, vérifier quemassDetection/massExport/Masssont bien résolus (dart analyzene doit rapporter aucune erreur d'import).dart format libpuisdart analyze/flutter analyzesur toutlib/(convention du projet, cf.AGENTS.md).- Lancer l'app (
flutter run), activer le flagfeature_offline_liturgydans les réglages, vérifier que "Messe (nouveau)" apparaît dans le menu à côté de "Messe", et que l'ancienne messe fonctionne toujours à l'identique (non-régression explicitement demandée parAGENTS.md). - Tester la nouvelle vue sur plusieurs jours représentatifs (mêmes dates que la vérification du pipeline en phase 3) : un dimanche ordinaire, un jour de semaine, un dimanche des Rameaux (2 messes sélectionnables), Pâques (vigile + jour) — en mode onglets et en mode scroll (bascule via le réglage global).
- Vérifier l'alignement des colonnes (règle
AGENTS.mdsurLiturgyRow/hideVerseIdPlaceholder) sur les nouveaux widgets_MassPsalmContent/_MassGospelContent.
Aucune — phase 4 est la dernière étape du plan initial (schéma YAML → classe → pipeline → widget Flutter).