Déclenchement proactif (lot F) — quatre branchements : la garde, le cycle de vie accroché à VoiceController, les points GPS peuplés depuis la configuration, et un réglage visiteur. ⚠️ La garde recommandée par le plan aurait coûté de l'argent. _trigger appelle le LLM d'abord et ne parle qu'ensuite via activeVoiceOrchestrator?.ttsEngine, dont le ?. avale le cas « aucun mode vocal actif ». Avec proactiveModeEnabled seul, un visiteur traversant une zone avec l'app en poche et le vocal éteint consommait des jetons Gemini facturés au client pour une phrase que personne n'entend. La garde interroge l'orchestrateur : la vraie condition n'est pas « quel matériel » mais « y a-t-il quelqu'un pour écouter ». Il n'y avait pas de troisième mode à inventer : VoiceMode.voiceOnly existe déjà et construit le même orchestrateur que le mode lunettes. Le proactif est donc un sous-réglage, pas une tuile. glassesEnabled est supprimé, ses trois usages étaient morts — dont une pastille « Lunettes / Déconnecté » jamais affichée. M3 — meterZoneGPS devient le rayon par section, la constante n'étant plus qu'un défaut. Deux pièges de format vérifiés : currentSections porte des maps JSON brutes, pas des DTO, et latitude/longitude y sont des chaînes. Voix du guide — le sélecteur Viva/Marco de manager-app écrivait dans le vide : Instance.GuideVoiceId n'était lu nulle part ici, l'app utilisant une constante de build dont le défaut était Algieba, une voix que personne n'a écoutée. Même forme que W1. Et aucun APK ne parlait avec la voix du produit : GeminiTtsEngine n'est choisi que si GEMINI_API_KEY est injectée, ce qui n'était fait nulle part, donc repli silencieux sur la voix système. Le repli reste le défaut — les tests ne coûtent alors ni jetons ni argent — mais il s'annonce dans les logs. Code mort supprimé : wake_word_service.dart, glasses_qr_scanner_service.dart et glasses_tts_service.dart, les ancêtres de Services/Glasses/. Ils portaient les 4 erreurs kElevenLabs* et l'APK se construisait quand même, personne ne les important. flutter analyze lib rend désormais zéro erreur. ⚠️ android/.../WakeWordService.kt est un homonyme bien vivant, non touché. impl/elevenlabs_tts_engine.dart est conservé comme option. flutter build apk --debug --flavor dev : vert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
README
This README would normally document whatever steps are necessary to get your application up and running.
What is this repository for?
- Quick summary
- Version
- Learn Markdown
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 backendAPI_BASE_URL— l'URL de l'API backendAPI_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échargergoogle-services.json→ le copier dansandroid/app/src/newclient/google-services.json(et mettre à jour les autres flavors aussi) - Ajouter app iOS (
be.unov.myinfomate.newclient) → téléchargerGoogleService-Info.plist→ sauvegarder dansios/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.newclientavec 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_outlinedpour le loader,Icons.museum_outlinedpour le splash. Mais l'image doit quand même exister dansassets/(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.plistmarqués PLACEHOLDER doivent être remplacés par les vrais fichiers téléchargés depuis Firebase Console avant de builder en production iOS.