Thomas Fransolet 6709726208 Splash, loader et mode hors ligne : ce qui etait invisible le reste
Le fil rouge de ces corrections : des replis silencieux. Une exception
rattrapee, une image absente, un fichier local jamais rattache — rien ne
plantait, mais rien ne marchait non plus, et aucun message ne le disait.

Splash et loader
- assets/splash et assets/loader ne contenaient que des PNG 1x1
  transparents. errorBuilder ne se declenche pas : le fichier est valide,
  juste vide. Logo et loader etaient donc invisibles PARTOUT, splash comme
  ecrans de chargement. assets/loader est supprime, kLoaderAsset avec.
- Le splash natif etait blanc (launch_background en @android:color/white,
  theme Light) puis l'app basculait en sombre. Fond unifie sur #111111,
  cote natif comme Dart, avec values-v31 : Android 12+ ignore
  windowBackground et repart sur le theme sans ces attributs.
- Le loader et l'image principale viennent maintenant du manager
  (Applications -> Mobile). InstanceImages les garde sur le device : le
  splash s'affiche avant tout appel API, il ne peut lire qu'un cache.
  Alimente au boot depuis instanceGetDetail, qui porte deja les
  ApplicationInstances — aucun appel supplementaire.
- Ouvrir une section montrait une page blanche avec un loader au milieu.
  SlideFromRightRoute devient non opaque et SectionPage garde un fond
  transparent tant que la section n'est pas prete : le visiteur garde sous
  les yeux l'ecran d'ou il vient.

Hors ligne
- L'audio d'un article ne repartait jamais du MP3 local : audioFile
  n'etait jamais renseigne, le lecteur retombait toujours sur l'URL.
- L'image de titre d'un article passait par NetworkImage, donc une croix
  rouge des que le reseau manque, alors que le fichier est sur le device.
- L'accueil ne gardait en base que order/gridSpan : une visite jamais
  telechargee disparaissait de la grille hors ligne. La visite entiere est
  desormais mise en cache, et une visite injoignable reste affichee,
  ternie et non ouvrable, plutot qu'absente.
- L'etat reseau datait du premier chargement et n'etait jamais remesure.
  WidgetsBindingObserver etait declare mais jamais enregistre : aucun
  rappel n'arrivait. L'accueil se recharge au retour dans l'app et
  remesure avant de refuser l'ouverture d'une visite.

Divers
- Le futur de getSectionDetail etait construit dans future:, donc relance
  a chaque rebuild — chaque rotation d'ecran refaisait l'appel reseau.
- ImageCustomProvider listait le repertoire d'une visite non telechargee :
  exception a chaque construction de chaque image, pour finir de toute
  facon sur le reseau.
- Scanner un QR d'une autre visite empilait les ConfigurationPage.
  pushAndRemoveUntil : une visite est une destination de premier niveau.
- Le scanner arrive sur l'accueil, en pastille de verre comme les autres
  actions de cet ecran. ScannerBouton prend size et transparent, et garde
  son apparence d'origine ailleurs.
- Le titre d'un article n'etait pas centre : customStylesBuilder ne
  s'applique qu'aux elements, et un titre sans balise n'en a aucun.
- Le lecteur audio replie ne lancait pas la lecture au premier appui, il
  ouvrait le panneau. Il lit, puis ouvre. En lecture auto il reste replie.
- Le dialogue de telechargement faisait la hauteur de l'ecran : un Center
  prend toute la hauteur maximale que lui donne un AlertDialog.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 16:47:27 +02:00
2022-06-12 00:09:39 +02:00
2026-07-17 15:23:12 +02:00
2024-10-16 16:39:53 +02:00
2022-06-12 00:09:39 +02:00
2022-06-12 00:09:39 +02:00
2024-07-07 22:17:34 +02:00

README

This README would normally document whatever steps are necessary to get your application up and running.

What is this repository for?

How do I get set up?

  • Summary of set up
  • Configuration
  • Dependencies
  • Database configuration
  • How to run tests
  • Deployment instructions

Contribution guidelines

  • Writing tests
  • Code review
  • Other guidelines

Who do I talk to?

  • Repo owner or admin
  • Other community or team contact

OPENAPI Generation cmd

flutter clean

flutter pub get

flutter pub run build_runner build --delete-conflicting-outputs

Le fichier est dans le projet.

Assets

Les svg de drapeaux viennent de là https://flagicons.lipis.dev/

Publication sur le Google PlayStore

Les paramètres de signing sont les mêmes que pour l'application tablet (donc la même android key).

Puis :

flutter build appbundle

Faut pas oublier d'aller changer la version avant chaque upload de version (Puis mettre l'app bundle dans le dossier du PC, peut-être mettre sur le repos aussi ?)

Clients existants

Flavor Package Android Bundle iOS Instance ID Nom app
mdlf be.unov.mymuseum.mdlf be.unov.mymuseum.mdlf 65ccc67265373befd15be511 MDLF
fortsaintheribert be.unov.mymuseum.fortsaintheribert be.unov.mymuseum.fortsaintheribert 633ee379d9405f32f166f047 Fort Saint-Héribert
dev be.unov.myinfomate.test be.unov.myinfomate.test 63514fd67ed8c735aaa4b8f2 MyMuseum Dev

Builder pour un client

Les paramètres à passer à chaque build :

  • FLAVOR — nom du flavor (dev, mdlf, fortsaintheribert, ...)
  • INSTANCE_ID — le GUID de l'instance dans le backend
  • API_BASE_URL — l'URL de l'API backend
  • API_KEY — la clé API de l'instance (générée via le Manager, endpoint /api/apikey)

La clé API est embarquée dans le binaire au moment du build. Elle est récupérable dans le Manager.

Android (App Bundle pour Play Store)

flutter build appbundle --flavor mdlf --release -t lib/main.dart \
  --dart-define=FLAVOR=mdlf \
  --dart-define=INSTANCE_ID=65ccc67265373befd15be511 \
  --dart-define=API_BASE_URL=https://api.mymuseum.be \
  --dart-define=API_KEY=CLE_API_MDLF

flutter build appbundle --flavor fortsaintheribert --release -t lib/main.dart \
  --dart-define=FLAVOR=fortsaintheribert \
  --dart-define=INSTANCE_ID=633ee379d9405f32f166f047 \
  --dart-define=API_BASE_URL=https://api.mymuseum.be \
  --dart-define=API_KEY=CLE_API_FORTSAINTHERIBERT

iOS (fichier .ipa pour App Store)

IPA = format de fichier d'une app iOS, équivalent de l'App Bundle Android. C'est ce qu'on upload sur l'App Store Connect.

flutter build ipa --flavor mdlf --release -t lib/main.dart \
  --dart-define=FLAVOR=mdlf \
  --dart-define=INSTANCE_ID=65ccc67265373befd15be511 \
  --dart-define=API_BASE_URL=https://api.mymuseum.be \
  --dart-define=API_KEY=CLE_API_MDLF

flutter build ipa --flavor fortsaintheribert --release -t lib/main.dart \
  --dart-define=FLAVOR=fortsaintheribert \
  --dart-define=INSTANCE_ID=633ee379d9405f32f166f047 \
  --dart-define=API_BASE_URL=https://api.mymuseum.be \
  --dart-define=API_KEY=CLE_API_FORTSAINTHERIBERT

Dev local (flavor dev)

flutter run --flavor dev -t lib/main.dart \
  --dart-define=FLAVOR=dev \
  --dart-define=INSTANCE_ID=63514fd67ed8c735aaa4b8f2 \
  --dart-define=API_BASE_URL=http://192.168.x.x:5000 \
  --dart-define=API_KEY=CLE_API_DEV

Icône de l'app

Pour mettre une icône spécifique par client, utilise https://easyappicon.com/ pour générer les assets, puis place-les dans android/app/src/{flavor}/res/mipmap-*/ic_launcher.png (ils remplaceront automatiquement l'icône par défaut au build).

Ajouter un nouveau client

Exemple avec un client nommé newclient → package be.unov.myinfomate.newclient

1. Firebase Console → projet mymuseum-3b97f

  • Ajouter app Android (be.unov.myinfomate.newclient) → re-télécharger google-services.json → le copier dans android/app/src/newclient/google-services.json (et mettre à jour les autres flavors aussi)
  • Ajouter app iOS (be.unov.myinfomate.newclient) → télécharger GoogleService-Info.plist → sauvegarder dans ios/config/newclient/GoogleService-Info.plist
  • Uploader l'APNs Auth Key dans Firebase pour la nouvelle app iOS (même clé que les autres apps)

2. Apple Developer Portal

  • Créer App ID be.unov.myinfomate.newclient avec Push Notifications activé

3. android/app/build.gradle : ajouter le flavor dans productFlavors

newclient {
    dimension "client"
    applicationId "be.unov.myinfomate.newclient"
    resValue "string", "app_name", "Nom de l'app"
}

4. Xcode : dupliquer les 3 configs (Debug, Release, Profile) pour le nouveau flavor, créer le scheme partagé

  • Build Settings → PRODUCT_BUNDLE_IDENTIFIER = be.unov.myinfomate.newclient
  • Build Settings → ajouter FLUTTER_FLAVOR = newclient

5. Mettre à jour le tableau "Clients existants" en haut de ce README avec le nouveau client

6. Ajouter les couleurs dans lib/constants.dart Ajouter un nouveau cas dans chaque ternaire (kMainColor0, kMainColor1, kMainColor2) :

_flavor == 'newclient' ? 0xFFxxxxxx :  // couleur principale du client

7. Ajouter les assets splash et loader

  • assets/splash/newclient.png — logo affiché au démarrage de l'app (fond transparent, ~400×400px)
  • assets/loader/newclient.png — icône du loader in-app, affiché en rotation pendant les chargements (fond transparent, ~200×200px)

Puis ajouter le nouveau flavor dans les deux constantes de lib/constants.dart :

const kSplashLogoAsset = _flavor == 'mdlf'
    ? 'assets/splash/mdlf.png'
    : _flavor == 'fortsaintheribert'
        ? 'assets/splash/fortsaintheribert.png'
        : _flavor == 'newclient'
            ? 'assets/splash/newclient.png'
            : 'assets/splash/dev.png';

const kLoaderAsset = _flavor == 'mdlf'
    ? 'assets/loader/mdlf.png'
    : _flavor == 'fortsaintheribert'
        ? 'assets/loader/fortsaintheribert.png'
        : _flavor == 'newclient'
            ? 'assets/loader/newclient.png'
            : 'assets/loader/dev.png';

Si tu ne fournis pas d'image, le fallback est automatique : Icons.museum_outlined pour le loader, Icons.museum_outlined pour le splash. Mais l'image doit quand même exister dans assets/ (même un placeholder 1×1px) car Flutter vérifie les assets déclarés au build.

8. Tester

flutter run --flavor newclient -t lib/main.dart \
  --dart-define=FLAVOR=newclient \
  --dart-define=INSTANCE_ID=GUID_DU_CLIENT \
  --dart-define=API_BASE_URL=https://api.mymuseum.be

⚠️ Les fichiers ios/config/*/GoogleService-Info.plist marqués PLACEHOLDER doivent être remplacés par les vrais fichiers téléchargés depuis Firebase Console avant de builder en production iOS.

Description
No description provided
Readme 402 MiB
Languages
Dart 97.6%
CMake 1%
C++ 0.6%
Ruby 0.4%
Shell 0.2%