feat: add user testing plan for SafeBite app
- Created a comprehensive user testing plan document to validate the app's usability, reliability, accessibility, and resilience. - Included various test scenarios covering onboarding, product scanning, manual barcode entry, and accessibility features. chore: update dependencies for code quality tools - Added ktlint version 12.2.0 for Kotlin code style enforcement. - Added detekt version 1.23.7 for static code analysis. chore: increment version numbers - Updated MINOR version to 32 and CODE to 43 in version.properties to reflect recent changes.
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
# 💡 Propositions d'amélioration — SafeBite
|
||||
|
||||
**Document évolutif • 11 mai 2026**
|
||||
|
||||
Chaque proposition peut être cochée :
|
||||
- ✅ Acceptée — à planifier
|
||||
- ❌ Rejetée — pas pertinent
|
||||
- 💤 En attente — à réévaluer plus tard
|
||||
|
||||
Une section **Commentaires** en bas permet de modifier/affiner les propositions.
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UX / UI
|
||||
|
||||
- [ ] **1. Transition ContainerTransform FAB → Scanner**
|
||||
- Animation Material Design fluide entre le FAB central et l'écran scanner plein écran (actuellement navigation standard sans transition partagée).
|
||||
- Effort : 1j | Impact : ⭐⭐⭐⭐⭐
|
||||
|
||||
- [ ] **2. Widget Android « Scan rapide »**
|
||||
- Widget 1×1 sur l'écran d'accueil qui ouvre directement le scanner. 1 tap au lieu de 2.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- [ ] **3. Mode AMOLED Black**
|
||||
- Ajouter une 3ᵉ option de thème : fond noir pur (`#000000`) en plus du dark actuel, pour économie de batterie sur écrans OLED.
|
||||
- Effort : 0.5j | Impact : ⭐⭐⭐
|
||||
|
||||
- [ ] **4. Mode paysage pour le scanner**
|
||||
- Adapter l'overlay scanner et le layout pour la rotation paysage. Actuellement verrouillé en portrait.
|
||||
- Effort : 1j | Impact : ⭐⭐⭐
|
||||
|
||||
- [ ] **5. Skeleton screens sur tous les chargements**
|
||||
- Étendre le `ProductSkeleton` à : Dashboard (stats), Listes, Suivi, Profils. Cohérence visuelle.
|
||||
- Effort : 1j | Impact : ⭐⭐⭐
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Nouvelles fonctionnalités
|
||||
|
||||
- [ ] **6. Comparateur de produits**
|
||||
- Scanner 2 produits → écran côte à côte avec verdict, Nutri-Score, prix, allergènes. Aide à choisir en magasin.
|
||||
- Effort : 3j | Impact : ⭐⭐⭐⭐⭐
|
||||
|
||||
- [ ] **7. Mode « Repas complet »**
|
||||
- Scanner plusieurs produits d'un même repas → verdict global pour tous les membres de la famille. « Ce repas est-il safe pour tout le monde ? »
|
||||
- Effort : 3j | Impact : ⭐⭐⭐⭐⭐
|
||||
|
||||
- [ ] **8. Répertoire « Mes produits safe »**
|
||||
- Section favoris où l'utilisateur sauvegarde les produits qu'il achète régulièrement. Accès rapide sans re-scan.
|
||||
- Effort : 1.5j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- [ ] **9. Carte d'allergies digitale (QR code)**
|
||||
- Générer un QR code contenant les allergènes de la famille. Pour restaurateurs/scolaires : scan → liste des allergènes à éviter.
|
||||
- Effort : 1j | Impact : ⭐⭐⭐⭐⭐
|
||||
|
||||
- [ ] **10. Notifications push — alerte sécurité**
|
||||
- Firebase Cloud Messaging : notification quand un allergène critique est détecté lors d'un scan (ex: « ⚠️ ARACHIDES détecté dans Snickers — interdit pour Julie »).
|
||||
- Effort : 3j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- [ ] **11. Export des données (PDF/CSV)**
|
||||
- Exporter l'historique des scans en PDF ou CSV. Utile pour partager avec un médecin/allergologue.
|
||||
- Effort : 1.5j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- [ ] **12. Journal alimentaire (food diary)**
|
||||
- En plus de l'historique, permettre de noter les repas consommés + réactions éventuelles. Suivi médical.
|
||||
- Effort : 4j | Impact : ⭐⭐⭐
|
||||
|
||||
- ✅ **13. Scanner de liste de courses (multi-codes)**
|
||||
- Mode « course » : scanner tous les produits d'un ticket de caisse en rafale. Verdict pour l'ensemble du panier.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐
|
||||
|
||||
- ✅ **14. Partage/analyse URL ajout de produit**
|
||||
- Permettre de partager une URL de produit (ex: page Amazon) → extraire les infos, analyser et ajouter le produit à la base de données et dans une liste d'achat existante choisie par l'utilisateur ou une nouvelle liste créée par l'utilisateur. Dans la gestion des items, il faudrait ajouter une option url pour que l'utilisateur puisse ajouter un produit à partir d'une url (ex: page Amazon). L'app analyserait la page, extraire les infos du produit et l'ajouterait à la base de données et dans une liste d'achat existante choisie par l'utilisateur ou une nouvelle liste créée par l'utilisateur. l'URL peut provenir d'un partage ou être collée ou écrit manuellement dans l'app.
|
||||
- Effort : inconnu | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- ✅ **15. Ajouter section Recettes**
|
||||
- Entre la section « Listes » et « Suivi », ajouter une section « Recettes » où les utilisateurs peuvent trouver des idées de repas safe pour leur famille, basées sur les allergènes déclarés. Les recettes pourraient être filtrées par type de repas (petit-déjeuner, déjeuner, dîner) et par allergène (ex: recettes sans gluten). Unne fois une recette sélectionnée, afficher les ingrédients nécessaires et permettre d'ajouter les ingrédients à une liste d'épicerie. De plus, dans la section recette, obtenir des suggestions de recettes à partir des ingrédients disponible a la maison, tout en vérifiant la compatibilité avec les allergènes de la famille. Cela permettrait d'optimiser l'utilisation des produits déjà achetés et de réduire le gaspillage alimentaire.
|
||||
- Effort : inconnu | Impact : ⭐⭐⭐⭐⭐
|
||||
|
||||
- ✅ **16. Ajouter section Frigo**
|
||||
- Ajouter une section « Frigo » où les utilisateurs peuvent scanner les produits ou ajouter les produits manuellement qu'ils ont chez eux. Ce suivi permettrait de retirer un produit quand il est terminer et demandé de l'ajouter à une liste d'épicerie que l'utilisateur doit choisir. De plus, dans la section recette, obtenir des suggestions de recettes à partir de ces ingrédients disponible a la maison, tout en vérifiant la compatibilité avec les allergènes de la famille. Cela permettrait d'optimiser l'utilisation des produits déjà achetés et de réduire le gaspillage alimentaire.
|
||||
- Effort : inconnu | Impact : ⭐⭐⭐⭐⭐
|
||||
---
|
||||
|
||||
## ♿ Accessibilité & Inclusivité
|
||||
|
||||
- [ ] **30. Mode vocal**
|
||||
- Annonce vocale du verdict après scan via TTS (Text-to-Speech) Android. « Attention : ce produit contient des arachides. Interdit pour Julie. »
|
||||
- Effort : 1j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- [ ] **31. Personnalisation daltonienne**
|
||||
- Permettre à l'utilisateur de choisir son type de daltonisme (deutéranopie, protanopie, tritanopie) → adapter la palette de couleurs en conséquence.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐
|
||||
|
||||
- [ ] **32. Mode simplifié « Senior »**
|
||||
- UI épurée : texte plus grand, boutons plus gros, moins d'options. Un seul écran : Scanner → Verdict.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐
|
||||
|
||||
- [ ] **33. Contenu éducatif sur les allergènes**
|
||||
- Fiches info par allergène : qu'est-ce que c'est, où ça se cache, symptômes, alternatives. Depuis l'écran de profil ou le verdict.
|
||||
- Effort : 3j | Impact : ⭐⭐⭐
|
||||
|
||||
---
|
||||
|
||||
## ☁️ Cloud & Collaboration
|
||||
|
||||
- [ ] **40. Synchronisation cloud des profils (Firebase Auth + Firestore)**
|
||||
- Sauvegarder les profils famille + listes dans le cloud. Restaurer sur un nouveau téléphone. Optionnel, sans compte obligatoire.
|
||||
- Effort : 5j | Impact : ⭐⭐⭐⭐⭐
|
||||
|
||||
- [ ] **41. Listes de courses collaboratives (temps réel)**
|
||||
- Partager une liste avec le/la conjoint(e). Modifications synchronisées en temps réel via Firestore.
|
||||
- Effort : 5j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- [ ] **42. Contribution Open Food Facts**
|
||||
- Permettre d'envoyer une photo d'étiquette + code-barres directement à la base OFF quand un produit est inconnu. Simplifier le flow actuel.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Internationalisation
|
||||
|
||||
- [ ] **50. Traductions supplémentaires**
|
||||
- Ajouter EN (déjà partiel), ES, DE, IT, PT. Rendre tous les strings traduisibles.
|
||||
- Effort : 3j | Impact : ⭐⭐⭐⭐
|
||||
|
||||
- [ ] **51. Détection automatique de la langue des ingrédients**
|
||||
- Améliorer l'OCR : détecter automatiquement si l'étiquette est en FR, EN, ES, etc. et adapter le moteur d'analyse.
|
||||
- Effort : 3j | Impact : ⭐⭐⭐
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Technique / Qualité
|
||||
|
||||
- [ ] **60. Tests screenshot automatisés (Paparazzi)**
|
||||
- Capturer des screenshots de tous les écrans dans différents thèmes/locales → détecter les régressions visuelles.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐
|
||||
|
||||
- [ ] **61. CI/CD GitHub Actions**
|
||||
- Build + tests automatiques à chaque PR. Génération APK de preview. Déploiement sur Firebase App Distribution.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐
|
||||
|
||||
- [ ] **62. Benchmark de performance (Macrobenchmark)**
|
||||
- Mesurer le temps d'ouverture scanner, temps d'affichage verdict, fluidité scroll. Éviter les régressions.
|
||||
- Effort : 1.5j | Impact : ⭐⭐
|
||||
|
||||
- [ ] **63. Pré-chargement intelligent du cache**
|
||||
- Télécharger périodiquement les produits populaires / de saison en arrière-plan. Scanner instantané même hors-ligne.
|
||||
- Effort : 2j | Impact : ⭐⭐⭐
|
||||
|
||||
- [ ] **64. Mode démo / onboarding interactif**
|
||||
- Simuler un scan sans caméra pour démo en magasin ou salon. Code-barres virtuels avec résultats pré-enregistrés.
|
||||
- Effort : 1j | Impact : ⭐⭐
|
||||
|
||||
---
|
||||
|
||||
## 📝 Commentaires
|
||||
|
||||
*Utilisez cette section pour annoter/modifier les propositions ci-dessus.*
|
||||
|
||||
### Exemple :
|
||||
> **Proposition 6 (Comparateur)** → intéressant mais plutôt en V2. À coupler avec le mode « Repas complet ».
|
||||
>
|
||||
> **Proposition 9 (Carte allergie)** → prioritaire ! Parfait pour la rentrée scolaire.
|
||||
|
||||
---
|
||||
|
||||
*Vos notes :*
|
||||
|
||||
- [x] **IconPicker** : ajouter toutes les catégories d'émojis (pas seulement alimentation). → Fait le 11/05 — 7 catégories ajoutées : 🐾 Animaux, ⚽ Sports, 🚗 Transports, 🏠 Maison, 🎉 Fêtes, 💊 Santé, ⭐ Symboles (~100 émojis).
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Légende :** ✅ Acceptée | ❌ Rejetée | 💤 En attente
|
||||
@@ -0,0 +1,556 @@
|
||||
Prompt de Développement — SafeBite : Sections « Recettes » et « Frigo »
|
||||
|
||||
-------------------------
|
||||
|
||||
Contexte Général
|
||||
|
||||
Tu es un développeur Android expert travaillant sur SafeBite, une application de gestion des allergènes alimentaires pour les familles. L'application existante possède déjà les fonctionnalités suivantes :
|
||||
- Profils familiaux avec allergènes déclarés par membre
|
||||
- Scanner de produits (code-barres) avec vérification des allergènes via l'API OpenFoodFacts
|
||||
- Listes d'épicerie (création, ajout de produits, partage)
|
||||
- Section Suivi (historique des produits scannés, alertes)
|
||||
- Base de données locale (Room) et synchronisation Firebase
|
||||
Tu dois implémenter deux nouvelles sections : « Frigo » et « Recettes », insérées dans la navigation principale dans cet ordre : Accueil → Scanner → Listes → Frigo → Recettes → Suivi → Profil.
|
||||
-------------------------
|
||||
|
||||
Principes Directeurs (UX/UI)
|
||||
|
||||
- Minimum de manipulations : chaque action doit nécessiter le moins de taps possible (max 2-3 taps pour toute action courante).
|
||||
- Automatisation intelligente : pré-remplir, auto-suggérer, détecter automatiquement tout ce qui peut l'être.
|
||||
- Cohérence visuelle : respecter le design system existant de SafeBite (couleurs, typographie, composants Material 3, thème clair/sombre).
|
||||
- Intégration fluide : les nouvelles sections doivent communiquer naturellement avec les sections existantes (Listes, Scanner, Profils).
|
||||
- Allergènes toujours en arrière-plan : chaque recette, chaque produit, chaque suggestion doit être automatiquement filtré selon les allergènes de la famille sans que l'utilisateur ait à y penser.
|
||||
-------------------------
|
||||
|
||||
SECTION 1 : FRIGO (Mon Garde-Manger)
|
||||
|
||||
1.1 — Objectif
|
||||
|
||||
Permettre à l'utilisateur de maintenir un inventaire en temps réel des produits disponibles chez lui (frigo, congélateur, placard), avec un minimum d'effort, et créer un pont vers les Listes d'épicerie et les Recettes.
|
||||
1.2 — Structure de données
|
||||
|
||||
|
||||
@Entity(tableName = "fridge_items")
|
||||
data class FridgeItem(
|
||||
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||
val productName: String,
|
||||
val barcode: String? = null, // null si ajout manuel
|
||||
val category: FridgeCategory, // FRIGO, CONGELATEUR, PLACARD
|
||||
val quantity: Int = 1,
|
||||
val unit: String? = null, // "pièces", "litres", "kg", etc.
|
||||
val expirationDate: Long? = null, // timestamp, nullable
|
||||
val dateAdded: Long = System.currentTimeMillis(),
|
||||
val imageUrl: String? = null, // image du produit (OpenFoodFacts)
|
||||
val allergens: List<String> = emptyList(), // allergènes détectés
|
||||
val isAllergenSafe: Boolean = true, // safe pour toute la famille
|
||||
val familyId: String, // lié à la famille active
|
||||
val openFoodFactsData: String? = null // JSON brut pour référence
|
||||
)
|
||||
|
||||
enum class FridgeCategory {
|
||||
FRIGO, CONGELATEUR, PLACARD
|
||||
}
|
||||
|
||||
|
||||
1.3 — Écrans et Interactions
|
||||
|
||||
Écran principal « Mon Frigo »
|
||||
|
||||
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 🏠 Mon Garde-Manger [+ Ajouter]│
|
||||
│─────────────────────────────────────────│
|
||||
│ [Frigo 🧊] [Congélateur ❄️] [Placard 🗄️] │ ← Tabs/Chips filtres
|
||||
│─────────────────────────────────────────│
|
||||
│ 🔍 Rechercher un produit... │
|
||||
│─────────────────────────────────────────│
|
||||
│ ⚠️ Expire bientôt (2) │ ← Section prioritaire auto
|
||||
│ ┌─────────────────────────────────────┐│
|
||||
│ │ 🥛 Lait demi-écrémé x1 ││
|
||||
│ │ ⚠️ Expire dans 2 jours [−][+][✓] ││
|
||||
│ │ 🫧 Sans allergènes ││
|
||||
│ ├─────────────────────────────────────┤│
|
||||
│ │ 🧀 Fromage râpé x1 ││
|
||||
│ │ ⚠️ Expire demain [−][+][✓] ││
|
||||
│ │ 🔴 Contient : LAIT ││
|
||||
│ └─────────────────────────────────────┘│
|
||||
│ │
|
||||
│ Tous les produits (12) │
|
||||
│ ┌─────────────────────────────────────┐│
|
||||
│ │ 🍎 Pommes x4 ││
|
||||
│ │ Pas de date [−][+][✓] ││
|
||||
│ ├─────────────────────────────────────┤│
|
||||
│ │ 🍝 Pâtes fusilli x2 ││
|
||||
│ │ Exp: 15/03/2026 [−][+][✓] ││
|
||||
│ │ 🔴 Contient : GLUTEN ││
|
||||
│ └─────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ────────────────────────────────── │
|
||||
│ [📷 Scanner] [✏️ Manuel] [🍽️ Recettes] │ ← Actions rapides flottantes
|
||||
└─────────────────────────────────────────┘
|
||||
|
||||
|
||||
Ajout de produit — 3 méthodes (toujours en max 2 taps)
|
||||
|
||||
Méthode 1 — Scan (recommandée, 1 tap + scan) :
|
||||
- L'utilisateur appuie sur « Scanner » → la caméra s'ouvre (réutiliser le composant Scanner existant)
|
||||
- Le produit est reconnu via OpenFoodFacts → pré-remplissage automatique du nom, de la catégorie probable, de l'image, des allergènes
|
||||
- Un bottom sheet apparaît avec les infos pré-remplies :
|
||||
- Nom du produit (modifiable)
|
||||
- Catégorie : Frigo / Congélateur / Placard (pré-sélectionnée intelligemment selon la catégorie du produit — ex: produit laitier → Frigo)
|
||||
- Quantité : 1 (modifiable avec stepper +/-)
|
||||
- Date d'expiration : optionnel, avec un date picker rapide ou saisie manuelle
|
||||
- Badge allergènes affiché automatiquement (🔴 si contient un allergène familial, ✅ si safe)
|
||||
- Un seul tap sur « Ajouter » pour confirmer → le produit est dans le frigo
|
||||
Méthode 2 — Ajout manuel (2 taps) :
|
||||
- L'utilisateur appuie sur « Manuel » → un bottom sheet s'ouvre
|
||||
- Champ de saisie avec auto-complétion basée sur :
|
||||
- Les produits précédemment ajoutés
|
||||
- Les produits des listes d'épicerie
|
||||
- La base OpenFoodFacts (recherche par nom)
|
||||
- En sélectionnant une suggestion, les champs se pré-remplissent automatiquement
|
||||
- Même bottom sheet de confirmation que le scan
|
||||
Méthode 3 — Depuis les Listes d'épicerie (intégration, 1 tap) :
|
||||
- Quand l'utilisateur coche un produit comme « acheté » dans une liste d'épicerie, un snackbar propose : « Ajouter au frigo ? » avec bouton « Oui »
|
||||
- 1 seul tap → le produit est transféré dans le frigo avec toutes ses données
|
||||
Consommation / Retrait d'un produit
|
||||
|
||||
- Bouton ✓ (terminé) sur chaque produit dans le frigo
|
||||
- Au tap sur ✓, un dialogue léger apparaît :
|
||||
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🍝 Pâtes fusilli terminé ! │
|
||||
│ │
|
||||
│ Ajouter à une liste d'épicerie ? │
|
||||
│ │
|
||||
│ 📋 Liste de la semaine │ ← Dernière liste utilisée (pré-sélectionnée)
|
||||
│ 📋 Liste Costco │
|
||||
│ 📋 Créer nouvelle liste... │
|
||||
│ │
|
||||
│ [Non merci] [✅ Ajouter] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
|
||||
- La dernière liste utilisée est pré-sélectionnée pour minimiser les taps
|
||||
- Si « Ajouter » → le produit est retiré du frigo ET ajouté à la liste choisie en 1 tap
|
||||
- Si « Non merci » → le produit est simplement retiré du frigo
|
||||
- Le bouton [−] décrémente la quantité (si quantité > 1)
|
||||
- Le bouton [+] incrémente la quantité
|
||||
Notifications intelligentes
|
||||
|
||||
- Notification push 2 jours avant expiration : « Votre lait expire dans 2 jours ! Voir des recettes pour l'utiliser 🍳 »
|
||||
- Au tap sur la notification → ouvre directement la section Recettes avec filtre « ingrédients du frigo » pré-activé et ce produit mis en avant
|
||||
- Notification push le jour de l'expiration : « Votre fromage râpé expire aujourd'hui ! »
|
||||
- Fréquence paramétrable dans les Réglages (désactivable)
|
||||
1.4 — Intégrations avec les sections existantes
|
||||
|
||||
| Section existante | Intégration |
|
||||
|---|---|
|
||||
| **Scanner** | Après un scan depuis n'importe où, proposer « Ajouter au frigo ? » en plus des actions existantes |
|
||||
| **Listes** | Produit coché « acheté » → proposition d'ajout au frigo. Produit retiré du frigo → proposition d'ajout à une liste |
|
||||
| **Profils** | Chaque produit du frigo est automatiquement évalué contre les allergènes de TOUS les membres de la famille. Badge visuel clair (🔴/✅) |
|
||||
| **Suivi** | Les produits consommés depuis le frigo apparaissent dans l'historique du suivi |
|
||||
|
||||
|
||||
|
||||
-------------------------
|
||||
|
||||
SECTION 2 : RECETTES
|
||||
|
||||
2.1 — Objectif
|
||||
|
||||
Proposer des recettes garanties safe pour la famille, avec un système de suggestions intelligent basé sur les ingrédients du frigo, les allergènes familiaux et les préférences alimentaires, tout en permettant l'ajout direct des ingrédients manquants aux listes d'épicerie.
|
||||
2.2 — Source de données Recettes
|
||||
|
||||
Utiliser une approche hybride :
|
||||
- API de recettes : intégrer l'API Spoonacular (ou Edamam ou TheMealDB) pour obtenir un catalogue de recettes riche avec filtrage par allergènes et ingrédients
|
||||
- Cache local (Room) pour les recettes favorites et les résultats récents
|
||||
- IA générative (optionnel, phase 2) : utiliser l'API Gemini/OpenAI pour générer des recettes personnalisées quand aucune recette de la base ne correspond
|
||||
|
||||
@Entity(tableName = "recipes")
|
||||
data class Recipe(
|
||||
@PrimaryKey val id: String,
|
||||
val title: String,
|
||||
val imageUrl: String?,
|
||||
val mealType: MealType, // PETIT_DEJEUNER, DEJEUNER, DINER, COLLATION
|
||||
val preparationTime: Int, // en minutes
|
||||
val servings: Int,
|
||||
val difficulty: Difficulty, // FACILE, MOYEN, DIFFICILE
|
||||
val ingredients: List<RecipeIngredient>,
|
||||
val steps: List<String>,
|
||||
val allergens: List<String>, // allergènes présents dans la recette
|
||||
val isSafeForFamily: Boolean, // calculé dynamiquement
|
||||
val unsafeForMembers: List<String>, // noms des membres à risque
|
||||
val matchingFridgeIngredients: Int, // nombre d'ingrédients déjà dans le frigo
|
||||
val totalIngredients: Int,
|
||||
val isFavorite: Boolean = false,
|
||||
val source: RecipeSource // API, USER_CREATED, AI_GENERATED
|
||||
)
|
||||
|
||||
data class RecipeIngredient(
|
||||
val name: String,
|
||||
val quantity: Double,
|
||||
val unit: String,
|
||||
val isInFridge: Boolean, // calculé dynamiquement
|
||||
val containsAllergen: Boolean,
|
||||
val allergenDetails: List<String>
|
||||
)
|
||||
|
||||
enum class MealType {
|
||||
PETIT_DEJEUNER, DEJEUNER, DINER, COLLATION
|
||||
}
|
||||
|
||||
|
||||
2.3 — Écrans et Interactions
|
||||
|
||||
Écran principal « Recettes »
|
||||
|
||||
|
||||
┌──────────────────────────────────────────┐
|
||||
│ 🍽️ Recettes [🔍][⚙️]│
|
||||
│──────────────────────────────────────────│
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────┐│
|
||||
│ │ 🧊 Avec votre frigo (8 recettes) ││ ← Bandeau principal
|
||||
│ │ Utilisez vos 12 produits avant ││
|
||||
│ │ qu'ils n'expirent ! ││
|
||||
│ │ [Explorer →] ││
|
||||
│ └──────────────────────────────────────┘│
|
||||
│ │
|
||||
│ Filtres rapides : │
|
||||
│ [🌅 P.Déj] [🍽️ Déj] [🌙 Dîner] [🍪 Collation] │
|
||||
│ [✅ Safe famille] [🧊 Dans mon frigo] │
|
||||
│ [⏱️ < 30 min] [👶 Facile] │
|
||||
│ │
|
||||
│ ── Suggestions pour vous ───────────── │
|
||||
│ (basées sur votre frigo + allergènes) │
|
||||
│ │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ 📸 │ │ 📸 │ │ 📸 │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │Crêpes │ │Salade │ │Poulet │ │
|
||||
│ │sans │ │César │ │grillé │ │
|
||||
│ │gluten │ │maison │ │légumes │ │
|
||||
│ │✅ Safe │ │✅ Safe │ │✅ Safe │ │
|
||||
│ │🧊 4/6 │ │🧊 3/5 │ │🧊 5/8 │ │
|
||||
│ │⏱️ 20min │ │⏱️ 15min │ │⏱️ 45min │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ ← scroll horizontal → │
|
||||
│ │
|
||||
│ ── Populaires sans [Gluten] ────────── │ ← Basé sur allergènes famille
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ ... │ │ ... │ │ ... │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ │
|
||||
│ ── Populaires sans [Arachides] ─────── │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ ... │ │ ... │ │ ... │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ │
|
||||
│ ── Toutes les recettes safe ───────── │
|
||||
│ ┌──────────────────────────────────┐ │
|
||||
│ │ 📸 │ Omelette aux champignons │ │
|
||||
│ │ │ ✅ Safe │ 🧊 2/4 │ ⏱️ 10min │ │
|
||||
│ ├──────────────────────────────────┤ │
|
||||
│ │ 📸 │ Riz sauté aux légumes │ │
|
||||
│ │ │ ✅ Safe │ 🧊 3/6 │ ⏱️ 25min │ │
|
||||
│ └──────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────┘
|
||||
|
||||
|
||||
Note : Le filtre ✅ Safe famille est activé par défaut. L'utilisateur peut le désactiver pour voir toutes les recettes (les recettes non-safe affichent alors clairement les avertissements).
|
||||
Écran « Avec mon frigo » (suggestions basées sur les ingrédients)
|
||||
|
||||
|
||||
┌──────────────────────────────────────────┐
|
||||
│ ← 🧊 Avec mon frigo │
|
||||
│──────────────────────────────────────────│
|
||||
│ │
|
||||
│ Vos ingrédients disponibles : │
|
||||
│ [🥛Lait ×] [🥚Oeufs ×] [🍎Pommes ×] │ ← Chips supprimables
|
||||
│ [🧈Beurre ×] [🍝Pâtes ×] [🧅Oignon ×] │
|
||||
│ [+ Ajouter un ingrédient] │
|
||||
│ │
|
||||
│ ── ⚠️ À utiliser en priorité ────────── │
|
||||
│ 🥛 Lait expire dans 2 jours │
|
||||
│ 🧀 Fromage expire demain │
|
||||
│ │
|
||||
│ Résultats : 8 recettes trouvées │
|
||||
│ Triées par : [Meilleure correspondance ▼]│
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────┐│
|
||||
│ │ 📸 Gratin de pâtes ││
|
||||
│ │ ✅ Safe pour toute la famille ││
|
||||
│ │ 🧊 5/7 ingrédients disponibles ││
|
||||
│ │ 🛒 2 ingrédients manquants ││
|
||||
│ │ ⏱️ 35 min │ 👤 4 portions ││
|
||||
│ │ ⚠️ Utilise votre lait + fromage ││ ← Met en avant produits qui expirent
|
||||
│ ├──────────────────────────────────────┤│
|
||||
│ │ 📸 Pâtes carbonara (sans crème) ││
|
||||
│ │ ✅ Safe pour toute la famille ││
|
||||
│ │ 🧊 4/5 ingrédients disponibles ││
|
||||
│ │ 🛒 1 ingrédient manquant ││
|
||||
│ │ ⏱️ 20 min │ 👤 4 portions ││
|
||||
│ └──────────────────────────────────────┘│
|
||||
└──────────────────────────────────────────┘
|
||||
|
||||
|
||||
Écran « Détail d'une recette »
|
||||
|
||||
|
||||
┌──────────────────────────────────────────┐
|
||||
│ ← [❤️][📤] │
|
||||
│ ┌──────────────────────────────────────┐│
|
||||
│ │ ││
|
||||
│ │ 📸 Image recette ││
|
||||
│ │ ││
|
||||
│ └──────────────────────────────────────┘│
|
||||
│ │
|
||||
│ Gratin de pâtes maison │
|
||||
│ ✅ Safe pour toute la famille │
|
||||
│ ⏱️ 35 min │ 👤 4 portions │ ⭐ Facile │
|
||||
│ │
|
||||
│ ── Ingrédients (7) ─────────────────── │
|
||||
│ │
|
||||
│ ✅ 🧊 Pâtes fusilli — 250g [Dans frigo] │
|
||||
│ ✅ 🧊 Lait — 200ml [Dans frigo] │
|
||||
│ ✅ 🧊 Beurre — 30g [Dans frigo] │
|
||||
│ ✅ 🧊 Oignon — 1 [Dans frigo] │
|
||||
│ ✅ 🧊 Fromage râpé — 100g [Dans frigo] │
|
||||
│ ❌ Crème fraîche — 100ml [+ Liste] │ ← 1 tap pour ajouter
|
||||
│ ❌ Muscade — 1 pincée [+ Liste] │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────┐│
|
||||
│ │ 🛒 Ajouter les 2 manquants à : ││
|
||||
│ │ [📋 Liste de la semaine ▼] ││ ← Pré-sélectionne dernière liste
|
||||
│ │ [Ajouter tout →] ││ ← 1 TAP pour tout ajouter
|
||||
│ └──────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ── Étapes de préparation ───────────── │
|
||||
│ │
|
||||
│ 1. ☐ Faire bouillir l'eau et cuire les │
|
||||
│ pâtes selon les instructions... │
|
||||
│ 2. ☐ Dans une poêle, faire fondre le │
|
||||
│ beurre et faire revenir l'oignon..│
|
||||
│ 3. ☐ Ajouter le lait, la crème et la │
|
||||
│ muscade. Mélanger... │
|
||||
│ 4. ☐ Dans un plat à gratin, disposer │
|
||||
│ les pâtes et verser la sauce... │
|
||||
│ 5. ☐ Parsemer de fromage râpé et │
|
||||
│ enfourner 20 min à 200°C... │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────┐│
|
||||
│ │ 🍳 Commencer la recette ││ ← Mode cuisine pas-à-pas
|
||||
│ │ (mode écran allumé) ││
|
||||
│ └──────────────────────────────────────┘│
|
||||
└──────────────────────────────────────────┘
|
||||
|
||||
|
||||
2.4 — Logique de Suggestion Intelligente
|
||||
|
||||
|
||||
// Algorithme de scoring des recettes
|
||||
fun calculateRecipeScore(recipe: Recipe, fridgeItems: List<FridgeItem>, familyAllergens: List<String>): Double {
|
||||
var score = 0.0
|
||||
|
||||
// 1. SÉCURITÉ (filtrage obligatoire si filtre actif)
|
||||
if (recipe.allergens.any { it in familyAllergens }) {
|
||||
if (safeFilterEnabled) return -1.0 // Exclure
|
||||
score -= 1000 // Pénalité massive si filtre désactivé
|
||||
}
|
||||
|
||||
// 2. CORRESPONDANCE FRIGO (0-50 points)
|
||||
val fridgeMatchRatio = recipe.matchingFridgeIngredients.toDouble() / recipe.totalIngredients
|
||||
score += fridgeMatchRatio * 50
|
||||
|
||||
// 3. URGENCE EXPIRATION (0-30 points)
|
||||
// Bonus si la recette utilise des produits qui expirent bientôt
|
||||
val expiringIngredientsUsed = countExpiringIngredientsInRecipe(recipe, fridgeItems)
|
||||
score += expiringIngredientsUsed * 10
|
||||
|
||||
// 4. FACILITÉ (0-10 points)
|
||||
score += when(recipe.difficulty) {
|
||||
Difficulty.FACILE -> 10.0
|
||||
Difficulty.MOYEN -> 5.0
|
||||
Difficulty.DIFFICILE -> 0.0
|
||||
}
|
||||
|
||||
// 5. TEMPS (0-10 points)
|
||||
score += when {
|
||||
recipe.preparationTime <= 15 -> 10.0
|
||||
recipe.preparationTime <= 30 -> 7.0
|
||||
recipe.preparationTime <= 60 -> 4.0
|
||||
else -> 0.0
|
||||
}
|
||||
|
||||
return score
|
||||
}
|
||||
|
||||
|
||||
2.5 — Intégrations avec les sections existantes
|
||||
|
||||
| Section | Intégration |
|
||||
|---|---|
|
||||
| **Frigo** | Les ingrédients du frigo alimentent automatiquement les suggestions. Badge `🧊 X/Y` sur chaque recette. Produits expirant bientôt = priorité dans les suggestions |
|
||||
| **Listes** | Bouton « Ajouter les ingrédients manquants à une liste » en 1 tap. Pré-sélection de la dernière liste utilisée |
|
||||
| **Scanner** | Après scan d'un produit, suggestion « Voir des recettes avec ce produit » |
|
||||
| **Profils** | Filtrage automatique par allergènes de tous les membres. Si un membre est exclu temporairement (ex: invité), pouvoir l'inclure/exclure du filtre |
|
||||
| **Suivi** | Les recettes préparées peuvent être marquées et apparaître dans le suivi |
|
||||
|
||||
|
||||
|
||||
-------------------------
|
||||
|
||||
INTÉGRATIONS CROISÉES FRIGO ↔ RECETTES
|
||||
|
||||
Flux utilisateur complet (exemple)
|
||||
|
||||
|
||||
1. L'utilisateur scanne ses courses → produits ajoutés au frigo (auto)
|
||||
2. Notification : "Votre lait expire dans 2 jours"
|
||||
3. L'utilisateur ouvre Recettes → voit "Suggestions avec votre frigo"
|
||||
4. Il choisit "Gratin de pâtes" → voit 5/7 ingrédients dans son frigo
|
||||
5. Il tape "Ajouter les 2 manquants" → ajoutés à sa liste d'épicerie (1 tap)
|
||||
6. Il prépare la recette → les ingrédients utilisés sont décrémentés du frigo
|
||||
7. Le lait est terminé → dialogue "Ajouter à la liste ?" → 1 tap
|
||||
|
||||
|
||||
Décrémentation automatique après recette (optionnel mais recommandé)
|
||||
|
||||
Quand l'utilisateur marque une recette comme « préparée » :
|
||||
- Proposer un bottom sheet : « Retirer les ingrédients utilisés du frigo ? »
|
||||
- Liste pré-cochée de tous les ingrédients de la recette qui étaient dans le frigo
|
||||
- L'utilisateur peut décocher ceux qu'il n'a pas entièrement utilisés
|
||||
- 1 tap sur « Confirmer » → mise à jour du frigo
|
||||
-------------------------
|
||||
|
||||
ARCHITECTURE TECHNIQUE
|
||||
|
||||
Nouveaux modules / packages
|
||||
|
||||
|
||||
com.safebite.app/
|
||||
├── feature/
|
||||
│ ├── fridge/
|
||||
│ │ ├── data/
|
||||
│ │ │ ├── FridgeRepository.kt
|
||||
│ │ │ ├── FridgeDao.kt
|
||||
│ │ │ └── FridgeItemEntity.kt
|
||||
│ │ ├── domain/
|
||||
│ │ │ ├── AddToFridgeUseCase.kt
|
||||
│ │ │ ├── RemoveFromFridgeUseCase.kt
|
||||
│ │ │ ├── GetExpiringItemsUseCase.kt
|
||||
│ │ │ └── TransferToGroceryListUseCase.kt
|
||||
│ │ └── ui/
|
||||
│ │ ├── FridgeScreen.kt
|
||||
│ │ ├── FridgeViewModel.kt
|
||||
│ │ ├── AddFridgeItemBottomSheet.kt
|
||||
│ │ └── RemoveItemDialog.kt
|
||||
│ │
|
||||
│ ├── recipes/
|
||||
│ │ ├── data/
|
||||
│ │ │ ├── RecipeRepository.kt
|
||||
│ │ │ ├── RecipeDao.kt
|
||||
│ │ │ ├── RecipeApiService.kt // Spoonacular / Edamam
|
||||
│ │ │ └── RecipeEntity.kt
|
||||
│ │ ├── domain/
|
||||
│ │ │ ├── GetRecipesUseCase.kt
|
||||
│ │ │ ├── GetFridgeRecipesUseCase.kt
|
||||
│ │ │ ├── FilterRecipesByAllergenUseCase.kt
|
||||
│ │ │ ├── CalculateRecipeScoreUseCase.kt
|
||||
│ │ │ └── AddMissingIngredientsToListUseCase.kt
|
||||
│ │ └── ui/
|
||||
│ │ ├── RecipesScreen.kt
|
||||
│ │ ├── RecipesViewModel.kt
|
||||
│ │ ├── RecipeDetailScreen.kt
|
||||
│ │ ├── RecipeDetailViewModel.kt
|
||||
│ │ ├── FridgeRecipesScreen.kt
|
||||
│ │ └── components/
|
||||
│ │ ├── RecipeCard.kt
|
||||
│ │ ├── IngredientsList.kt
|
||||
│ │ ├── MealTypeFilter.kt
|
||||
│ │ └── StepByStepView.kt
|
||||
|
||||
|
||||
Navigation mise à jour
|
||||
|
||||
|
||||
// Ajouter dans la bottom navigation
|
||||
sealed class BottomNavItem(val route: String, val icon: ImageVector, val label: String) {
|
||||
object Home : BottomNavItem("home", Icons.Default.Home, "Accueil")
|
||||
object Scanner : BottomNavItem("scanner", Icons.Default.QrCodeScanner, "Scanner")
|
||||
object Lists : BottomNavItem("lists", Icons.Default.ShoppingCart, "Listes")
|
||||
object Fridge : BottomNavItem("fridge", Icons.Default.Kitchen, "Frigo") // NOUVEAU
|
||||
object Recipes : BottomNavItem("recipes", Icons.Default.Restaurant, "Recettes") // NOUVEAU
|
||||
object Tracking : BottomNavItem("tracking", Icons.Default.Timeline, "Suivi")
|
||||
object Profile : BottomNavItem("profile", Icons.Default.Person, "Profil")
|
||||
}
|
||||
|
||||
|
||||
> **Note sur la barre de navigation :** Avec 7 éléments, utiliser un **Bottom Navigation avec scroll horizontal** ou regrouper certains éléments (ex: accueil et profil en haut, garder 5 éléments en bas). Alternativement, utiliser un **Navigation Drawer** latéral pour les éléments secondaires.
|
||||
|
||||
Workers pour les notifications
|
||||
|
||||
|
||||
class ExpirationCheckWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||
override suspend fun doWork(): Result {
|
||||
val expiringItems = fridgeRepository.getItemsExpiringWithinDays(2)
|
||||
expiringItems.forEach { item ->
|
||||
notificationManager.showExpirationNotification(
|
||||
title = "${item.productName} expire bientôt !",
|
||||
body = "Expire dans ${item.daysUntilExpiration} jour(s). Voir des recettes pour l'utiliser 🍳",
|
||||
deepLink = "safebite://recipes?fridgeItemId=${item.id}"
|
||||
)
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-------------------------
|
||||
|
||||
CRITÈRES D'ACCEPTATION
|
||||
|
||||
Frigo
|
||||
|
||||
- L'utilisateur peut ajouter un produit par scan en 2 taps max (scan + confirmer)
|
||||
- L'utilisateur peut ajouter un produit manuellement avec auto-complétion
|
||||
- Un produit coché « acheté » dans une liste propose l'ajout au frigo (1 tap)
|
||||
- Chaque produit affiche son statut allergène (🔴/✅) automatiquement
|
||||
- Retirer un produit terminé propose l'ajout à une liste d'épicerie (1 tap)
|
||||
- Les produits expirant bientôt sont affichés en priorité
|
||||
- Les notifications d'expiration fonctionnent (2 jours avant et jour J)
|
||||
- Filtrage par catégorie (Frigo/Congélateur/Placard)
|
||||
- Synchronisation Firebase entre appareils de la famille
|
||||
Recettes
|
||||
|
||||
- Les recettes sont filtrées par défaut selon les allergènes de la famille
|
||||
- Les filtres par type de repas fonctionnent
|
||||
- Les suggestions « Avec mon frigo » montrent les recettes triées par score de correspondance
|
||||
- Les produits expirant bientôt sont prioritaires dans les suggestions
|
||||
- Le badge 🧊 X/Y indique les ingrédients disponibles sur chaque carte recette
|
||||
- L'écran détail distingue visuellement les ingrédients disponibles vs manquants
|
||||
- « Ajouter les ingrédients manquants » fonctionne en 1 tap avec pré-sélection de liste
|
||||
- Les recettes favorites sont sauvegardées localement
|
||||
- Le mode « pas-à-pas » garde l'écran allumé
|
||||
Intégrations
|
||||
|
||||
- Scanner → proposition « Ajouter au frigo »
|
||||
- Liste (produit acheté) → proposition « Ajouter au frigo »
|
||||
- Frigo (produit terminé) → proposition « Ajouter à une liste »
|
||||
- Frigo → alimente les suggestions Recettes automatiquement
|
||||
- Recette (ingrédients manquants) → ajout à une liste d'épicerie
|
||||
- Recette (préparée) → proposition de décrémentation du frigo
|
||||
- Notification expiration → deep link vers Recettes avec filtre
|
||||
- Tous les produits et recettes respectent le filtre allergènes familial
|
||||
-------------------------
|
||||
|
||||
PRIORITÉ D'IMPLÉMENTATION
|
||||
|
||||
- Sprint 1 : Frigo — modèle de données, écran principal, ajout par scan et manuel
|
||||
- Sprint 2 : Frigo — retrait de produit avec transfert vers liste, notifications expiration
|
||||
- Sprint 3 : Recettes — intégration API, écran principal, filtres par type/allergènes
|
||||
- Sprint 4 : Recettes — suggestions basées sur le frigo, scoring, écran détail
|
||||
- Sprint 5 : Intégrations croisées complètes, décrémentation post-recette, polish UX
|
||||
- Sprint 6 : Tests, optimisation performances, synchronisation Firebase
|
||||
-------------------------
|
||||
+320
-549
@@ -1,63 +1,60 @@
|
||||
# 🗺️ ROADMAP PROJET — SafeBite Android
|
||||
# 🗺️ ROADMAP — SafeBite Android
|
||||
|
||||
**Document de suivi de progression • Version 1.0 • 26 avril 2026**
|
||||
**Document de suivi de progression • v1.27.0 • 11 mai 2026**
|
||||
|
||||
---
|
||||
|
||||
## 📋 TABLE DES MATIÈRES
|
||||
|
||||
1. [Vue d'ensemble du projet](#1-vue-densemble-du-projet)
|
||||
1. [Vue d'ensemble](#1-vue-densemble)
|
||||
2. [État d'avancement global](#2-état-davancement-global)
|
||||
3. [Phase 0 — Fondation (COMPLÉTÉE)](#3-phase-0--fondation-complétée)
|
||||
4. [Phase 1 — Navigation, Scanner, Verdict, Dashboard](#4-phase-1--navigation-scanner-verdict-dashboard)
|
||||
5. [Phase 2 — Listes intelligentes](#5-phase-2--listes-intelligentes)
|
||||
6. [Phase 3 — Suivi & Statistiques](#6-phase-3--suivi--statistiques)
|
||||
7. [Phase 4 — Profils famille (améliorations)](#7-phase-4--profils-famille-améliorations)
|
||||
8. [Phase 5 — Fiche produit détaillée](#8-phase-5--fiche-produit-détaillée)
|
||||
9. [Phase 6 — Gestion des erreurs & cas limites](#9-phase-6--gestion-des-erreurs--cas-limites)
|
||||
10. [Phase 7 — Accessibilité & Qualité](#10-phase-7--accessibilité--qualité)
|
||||
11. [Phase 8 — Tests & Validation](#11-phase-8--tests--validation)
|
||||
12. [Phase 9 — Préparation Release](#12-phase-9--préparation-release)
|
||||
13. [Annexes](#13-annexes)
|
||||
3. [Phases complétées (0-9)](#3-phases-complétées-0-9)
|
||||
4. [Phase 10 — Polish UX (P0 Bloquant)](#4-phase-10--polish-ux-p0-bloquant)
|
||||
5. [Phase 11 — Qualité perçue & Performance (P1 Important)](#5-phase-11--qualité-perçue--performance-p1-important)
|
||||
6. [Phase 12 — Lancement Play Store (P2 Nécessaire)](#6-phase-12--lancement-play-store-p2-nécessaire)
|
||||
7. [Idées V2 (P3 Différenciateur)](#7-idées-v2-p3-différenciateur)
|
||||
8. [Annexes](#8-annexes)
|
||||
|
||||
---
|
||||
|
||||
## 1. VUE D'ENSEMBLE DU PROJET
|
||||
## 1. VUE D'ENSEMBLE
|
||||
|
||||
### 1.1 Description
|
||||
|
||||
**SafeBite** est une application Android (et potentiellement iOS) permettant de scanner des produits alimentaires et d'obtenir un verdict de sécurité immédiat basé sur les allergies des membres de la famille. L'application utilise le **feu tricolore** (🟢 Vert / 🟠 Orange / 🔴 Rouge) pour indiquer si un produit est sûr.
|
||||
**SafeBite** est une application Android native (Kotlin + Jetpack Compose) qui scanne des produits alimentaires et donne un verdict immédiat de sécurité basé sur les allergies des membres de la famille. Verdict visuel par **feu tricolore** (🟢 SAFE / 🟠 ATTENTION / 🔴 DANGER).
|
||||
|
||||
### 1.2 Architecture technique
|
||||
### 1.2 Version actuelle
|
||||
|
||||
| Couche | Technologie |
|
||||
|--------|-------------|
|
||||
| **UI** | Jetpack Compose (Material 3) |
|
||||
| **Navigation** | Compose Navigation |
|
||||
| **Architecture** | MVVM + Clean Architecture |
|
||||
| **DI** | Hilt |
|
||||
| **Base locale** | Room |
|
||||
| **API distante** | Retrofit (OpenFoodFacts) |
|
||||
| **Caméra** | CameraX + ML Kit Barcode Scanning |
|
||||
| **OCR** | ML Kit Text Recognition |
|
||||
| **Préférences** | DataStore |
|
||||
| Champ | Valeur |
|
||||
|---|---|
|
||||
| Version | **1.27.0** |
|
||||
| Code | 38 |
|
||||
| minSdk / targetSdk | 26 (Android 8.0) / 34 (Android 14) |
|
||||
| Tests | 58 tests (~55% couverture) |
|
||||
| APK Release | < 25 Mo (R8 + ProGuard actifs) |
|
||||
|
||||
### 1.3 Principes fondateurs (prioritaires)
|
||||
### 1.3 Architecture
|
||||
|
||||
```
|
||||
MVVM + Clean Architecture
|
||||
├── presentation/ → Jetpack Compose (Material 3)
|
||||
├── domain/ → UseCases + Engine (allergènes, santé)
|
||||
├── data/ → Room (cache) + Retrofit (OpenFoodFacts) + DataStore (préférences)
|
||||
├── di/ → Hilt
|
||||
└── navigation/ → Compose Navigation + Bottom Nav 4 onglets + FAB Scanner
|
||||
```
|
||||
|
||||
### 1.4 Principes fondateurs (rappel)
|
||||
|
||||
| # | Principe | Règle |
|
||||
|---|----------|-------|
|
||||
| P1 | **2 taps max** | Scanner accessible en ≤ 2 taps depuis n'importe quel écran |
|
||||
| P2 | **Verdict immédiat** | Verdict affiché en < 500ms perçues |
|
||||
| P3 | **Feu tricolore** | 3 couleurs sémantiques max — jamais de bleu pour les statuts |
|
||||
| P2 | **Verdict immédiat** | Verdict affiché en < 500ms perçues (skeleton screen) |
|
||||
| P3 | **Feu tricolore** | 3 couleurs sémantiques — jamais de bleu pour les statuts |
|
||||
| P4 | **Icônes + couleurs** | Aucune info critique basée uniquement sur la couleur |
|
||||
| P5 | **Guidage positif** | Pas d'erreurs brutes — toujours une action de repli |
|
||||
| P5 | **Guidage positif** | Toujours une action de repli (pas d'erreurs brutes) |
|
||||
| P6 | **Mobile-first** | Conception une main, pouce accessible |
|
||||
|
||||
### 1.4 Documents de référence
|
||||
|
||||
- [`docs/flux-UX.md`](flux-UX.md) — Spécification UX/UI détaillée
|
||||
- [`docs/architecture-ui-ux.md`](architecture-ui-ux.md) — Architecture UI-UX et plan de migration
|
||||
|
||||
---
|
||||
|
||||
## 2. ÉTAT D'AVANCEMENT GLOBAL
|
||||
@@ -68,574 +65,314 @@
|
||||
|-------|-------------|--------|-------------|
|
||||
| **Phase 0** | Fondation (Clean Architecture, Room, Retrofit, Hilt) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 1** | Navigation, Scanner, Verdict, Dashboard | ✅ COMPLÉTÉ | 95% |
|
||||
| **Phase 2** | Listes intelligentes | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 3** | Suivi & Statistiques | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 4** | Profils famille (améliorations) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 5** | Fiche produit détaillée | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 6** | Gestion des erreurs & cas limites | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 7** | Accessibilité & Qualité | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 8** | Tests & Validation | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 9** | Préparation Release | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 2** | Listes intelligentes (création, swipe, filtres, partage) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 3** | Suivi & Statistiques (graphiques, historique) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 4** | Profils famille (grille, 3 états allergie) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 5** | Fiche produit détaillée (4 tabs) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 6** | Gestion des erreurs & cas limites (offline, OCR, permissions) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 7** | Accessibilité WCAG 2.1 AA (TalkBack, daltonien) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 8** | Tests & Validation (58 tests unitaires + UI) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 9** | Préparation Release (R8, LeakCanary, signing) | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 10** | **Polish UX — P0 Bloquant** | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 11** | **Qualité perçue & Performance — P1 Important** | ✅ COMPLÉTÉ | 100% |
|
||||
| **Phase 12** | **Lancement Play Store — P2 Nécessaire** | 🟡 PARTIEL | 50% |
|
||||
|
||||
### 2.2 Fichiers existants vs requis
|
||||
> Reste : screenshots, fiche Play Store, politique confidentialité, tests utilisateurs.
|
||||
|
||||
| Catégorie | Fichiers existants | Fichiers requis | Écart |
|
||||
|-----------|-------------------|-----------------|-------|
|
||||
| **Screens** | 17 fichiers | ~20 fichiers | ~3 à créer |
|
||||
| **ViewModels** | 8 fichiers | ~10 fichiers | ~2 à créer |
|
||||
| **Composants** | 8 fichiers | ~10 fichiers | ~2 à créer/adaptater |
|
||||
| **Thème** | 6 fichiers | 6 fichiers | ✅ OK |
|
||||
| **Navigation** | 2 fichiers | 2 fichiers | 🟡 À adapter |
|
||||
| **Data/Domain** | ~15 fichiers | ~15 fichiers | ✅ OK |
|
||||
### 2.2 Inventaire des écrans
|
||||
|
||||
| Écran | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Splash | `splash/SplashScreen.kt` | ✅ |
|
||||
| Onboarding | `onboarding/OnboardingScreen.kt` | ✅ |
|
||||
| MainScreen (Bottom Nav + FAB) | `main/MainScreen.kt` | ✅ |
|
||||
| Dashboard | `dashboard/DashboardScreen.kt` | 🟡 Données hardcodées |
|
||||
| Scanner | `scanner/ScannerScreen.kt` | ✅ Fait |
|
||||
| Résultat (verdict) | `result/ResultScreen.kt` | 🟡 Manque bouton Alternatives |
|
||||
| Produit non trouvé | `result/ProductNotFoundScreen.kt` | ✅ |
|
||||
| Fiche produit détaillée | `product/ProductDetailScreen.kt` | ✅ |
|
||||
| Listes (liste des listes) | `lists/ListsScreen.kt` | ✅ |
|
||||
| Détail liste | `lists/ListDetailScreen.kt` | ✅ |
|
||||
| Création liste | `lists/create/CreateListScreen.kt` | ✅ |
|
||||
| Paramètres liste | `lists/settings/ListSettingsScreen.kt` | ✅ |
|
||||
| Tri / Région / Nom / Membres | `lists/settings/` (4 écrans) | ✅ |
|
||||
| Catalogue | `catalog/CatalogScreen.kt` | ✅ |
|
||||
| Domaines / Catégories / Recherche | `catalog/` (3 écrans) | ✅ |
|
||||
| Suivi & Statistiques | `tracking/TrackingScreen.kt` | ✅ |
|
||||
| Profils famille | `family/FamilyScreen.kt` | ✅ |
|
||||
| Édition profil | `profile/ProfileEditScreen.kt` | ✅ |
|
||||
| OCR Capture + Review | `ocr/OcrCaptureScreen.kt`, `ocr/OcrReviewScreen.kt` | ✅ |
|
||||
| Paramètres | `settings/SettingsScreen.kt` | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 3. PHASE 0 — FONDATION (COMPLÉTÉE)
|
||||
## 3. PHASES COMPLÉTÉES (0-9)
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ**
|
||||
Toutes les phases 0 à 9 sont terminées. Voir le [CHANGELOG](../CHANGELOG.md) pour l'historique détaillé.
|
||||
|
||||
### 3.1 Éléments implémentés
|
||||
### Résumé des acquis majeurs
|
||||
|
||||
- [x] Architecture Clean Architecture (presentation/domain/data)
|
||||
- [x] Injection de dépendances avec Hilt (`di/`)
|
||||
- [x] Base de données Room (`database/`)
|
||||
- [x] `SafeBiteDatabase.kt`
|
||||
- [x] DAOs : `ProductCacheDao`, `ScanHistoryDao`, `UserProfileDao`
|
||||
- [x] Entités : `Entities.kt`
|
||||
- [x] Converters : `Converters.kt`
|
||||
- [x] API Retrofit (`OpenFoodFactsApi.kt`)
|
||||
- [x] Repository pattern implémenté
|
||||
- [x] Domain layer avec UseCases (`UseCases.kt`)
|
||||
- [x] Moteur d'analyse allergènes (`AllergenAnalysisEngine.kt`)
|
||||
- [x] Classificateur santé (`HealthClassifier.kt`)
|
||||
- [x] Modèles domaine (`DomainModels.kt`, `AllergenType.kt`)
|
||||
- [x] Thème Material 3 (`theme/`)
|
||||
- [x] Composants UI de base (`components/`)
|
||||
- [x] Navigation de base (`NavGraph.kt`, `Screen.kt`)
|
||||
- [x] Onboarding (`OnboardingScreen.kt`, `OnboardingViewModel.kt`)
|
||||
- [x] Scanner code-barres (`ScannerScreen.kt`, `BarcodeAnalyzer.kt`)
|
||||
- [x] Écran résultat (`ResultScreen.kt`, `ResultViewModel.kt`)
|
||||
- [x] Suivi & Statistiques (`TrackingScreen.kt`, `TrackingViewModel.kt`)
|
||||
- [x] Profils famille (`FamilyScreen.kt`, `ProfileViewModel.kt`, etc.)
|
||||
- [x] Paramètres (`SettingsScreen.kt`, `SettingsViewModel.kt`)
|
||||
- [x] OCR capture (`OcrCaptureScreen.kt`, `OcrReviewScreen.kt`, `OcrViewModel.kt`)
|
||||
- [x] Dashboard (structure initiale : `DashboardScreen.kt`)
|
||||
- [x] Listes (structure initiale : `ListsScreen.kt`)
|
||||
- [x] Composants graphiques (`Charts.kt` : DonutChart, Sparkline, HorizontalBarChart)
|
||||
- [x] MainScreen avec navigation (`MainScreen.kt`)
|
||||
- [x] Connectivité (`ConnectivityObserver.kt`)
|
||||
|
||||
### 3.2 Prochaines étapes
|
||||
|
||||
→ Passer à la **Phase 1** pour la refonte UI/UX complète.
|
||||
- ✅ Clean Architecture MVVM + Hilt
|
||||
- ✅ Bottom Navigation 4 onglets + FAB Scanner central animé (scale/fade/slide, 200ms)
|
||||
- ✅ Scanner CameraX + ML Kit avec overlay réticulé laser vert
|
||||
- ✅ Haptique au scan (60ms)
|
||||
- ✅ `SafetyStatusBanner` 3 variantes avec noms de profils et allergènes
|
||||
- ✅ Système daltonien : formes géométriques (🔵 cercle / 🔺 triangle / 🔷 losange)
|
||||
- ✅ `ProductSkeleton` shimmer animé (1.5s loop)
|
||||
- ✅ TalkBack : `LiveRegionMode.Assertive` pour verdicts, `contentDescription` partout
|
||||
- ✅ Listes intelligentes : swipe, filtres, fusion, partage, catalogue
|
||||
- ✅ Suivi & Statistiques : donut chart, sparkline, barres horizontales
|
||||
- ✅ Profils famille : grille 3 états (NONE → TRACE ⚠️ → SEVERE ❌)
|
||||
- ✅ Fiche produit : 4 tabs (Résumé, Allergènes, Additifs, Alternatives)
|
||||
- ✅ Mode hors-ligne avec cache Room
|
||||
- ✅ OCR ingrédients intégralement sur appareil (ML Kit)
|
||||
- ✅ 58 tests unitaires + UI (~55% couverture)
|
||||
- ✅ R8/ProGuard + LeakCanary + signing configuré
|
||||
- ✅ Dark mode (couleurs vérifiées, `StatusColors` light/dark câblés)
|
||||
- ✅ Haptic feedback FAB (15ms) + scan (60ms)
|
||||
- ✅ Saisie manuelle code-barres avec validation format (8-13 chiffres)
|
||||
- ✅ Bouton "Alternatives" dans ResultScreen (si verdict != SAFE)
|
||||
- ✅ Dashboard données réelles : stats hebdo, scans récents, 3 modes contextuels
|
||||
- ✅ Animations stagger sur les actions (slide-up + fade, délais 0/50/100/150ms)
|
||||
- ✅ Transition slide-up sur ResultScreen (250ms)
|
||||
- ✅ Validation format code-barres (ML Kit + manuel)
|
||||
|
||||
---
|
||||
|
||||
## 4. PHASE 1 — NAVIGATION, SCANNER, VERDICT, DASHBOARD
|
||||
## 4. PHASE 10 — POLISH UX (P0 BLOQUANT)
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ**
|
||||
**Priorité :** 🔴 **HAUTE**
|
||||
**Référence :** [`architecture-ui-ux.md`](architecture-ui-ux.md) §7.1
|
||||
|
||||
### 4.1 Étape 1.1 — Bottom Navigation (4 onglets) ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Adapter `Screen.kt` avec nouvelles routes | `navigation/Screen.kt` | ✅ COMPLÉTÉ | Routes Dashboard, Lists, Tracking, Family implémentées |
|
||||
| Refondre `NavGraph.kt` avec bottom nav | `navigation/NavGraph.kt` | ✅ COMPLÉTÉ | Structure avec NavHost interne |
|
||||
| Créer/adapter `MainScreen.kt` avec Scaffold + FAB | `screen/main/MainScreen.kt` | ✅ COMPLÉTÉ | Scaffold + BottomNavigation + FAB |
|
||||
| Implémenter `BottomNavItem` avec badges | `navigation/Screen.kt` | ✅ COMPLÉTÉ | data class + liste bottomNavItems |
|
||||
| Configurer icônes filled/outline | `MainScreen.kt` | ✅ COMPLÉTÉ | Home, List, ShowChart, People |
|
||||
|
||||
### 4.2 Étape 1.2 — FAB Scanner ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer FAB central 56dp | `MainScreen.kt` | ✅ COMPLÉTÉ | `SafeBiteFab` composable |
|
||||
| Positionner FAB (chevauchement bottom bar) | `MainScreen.kt` | ✅ COMPLÉTÉ | `FabPosition.Center` |
|
||||
| Animation disappear/appear (200ms) | `MainScreen.kt` | ✅ COMPLÉTÉ | fadeIn/fadeOut + scaleIn/scaleOut + slideIn/slideOut |
|
||||
| Haptic feedback 15ms | `MainScreen.kt` | ⚠️ Partiel | À ajouter dans `onClick` du FAB |
|
||||
| Visibilité conditionnelle par onglet | `MainScreen.kt` | ✅ COMPLÉTÉ | `fabVisible` basé sur route |
|
||||
| ContentDescription TalkBack | `MainScreen.kt` | ✅ COMPLÉTÉ | `stringResource(R.string.fab_scan)` |
|
||||
|
||||
### 4.3 Étape 1.3 — Design System (couleurs spec) ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Ajouter `SemanticColors` (feu tricolore) | `theme/Color.kt` | ✅ COMPLÉTÉ | #2ECC71, #E67E22, #E74C3C + containers |
|
||||
| Ajouter `NeutralColors` | `theme/Color.kt` | ✅ COMPLÉTÉ | #F5F5F0, #FFFFFF, #2D3436, #636E72, #DFE6E9 |
|
||||
| Adapter `StatusColors.kt` aux nouvelles couleurs | `theme/StatusColors.kt` | ✅ COMPLÉTÉ | LightStatusColors + DarkStatusColors |
|
||||
| Créer `SafeBiteTypography` | `theme/Type.kt` | ✅ COMPLÉTÉ | 15 styles M3 complets |
|
||||
| Créer `ElevationTokens` | `theme/Dimens.kt` | ✅ COMPLÉTÉ | elevationSm à elevationXl + hauteurs |
|
||||
|
||||
### 4.4 Étape 1.4 — Refonte ScannerScreen ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Transition ContainerTransform depuis FAB | `scanner/ScannerScreen.kt` | ⚠️ Optionnel | Navigation standard existante |
|
||||
| Top bar transparente overlay | `scanner/ScannerScreen.kt` | ✅ COMPLÉTÉ | `SafeBiteTopAppBar` avec onBack |
|
||||
| Saisie manuelle code-barres | `scanner/ScannerScreen.kt` | 🔴 À faire (optionnel) | Dialog à ajouter |
|
||||
| Pré-initialisation caméra | `scanner/ScannerScreen.kt` | ⚠️ Partiel | CameraProvider dans factory |
|
||||
| Réticule animé (laser vert) | `scanner/ScannerScreen.kt` | ✅ COMPLÉTÉ | `ScanOverlay` avec ligne verte animée |
|
||||
| Bottom bar locale (saisie + flash) | `scanner/ScannerScreen.kt` | ✅ COMPLÉTÉ | Toggle torch implémenté |
|
||||
|
||||
### 4.5 Étape 1.5 — Skeleton Screen ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer `ProductSkeleton` composable | `common/components/Feedback.kt` | ✅ COMPLÉTÉ | `ProductSkeleton` avec ShimmerBox |
|
||||
| Créer `ShimmerBox` base | `common/components/Feedback.kt` | ✅ COMPLÉTÉ | Gradient animé 1.2s loop |
|
||||
| Intégrer skeleton dans ResultScreen | `result/ResultScreen.kt` | 🔴 À faire | Remplacer `LoadingIndicator` par `ProductSkeleton` |
|
||||
|
||||
### 4.6 Étape 1.6 — VerdictBanner (3 variantes) 🟡 À ADAPTER
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Adapter `SafetyStatusBanner` aux couleurs spec | `common/components/Components.kt` | 🟡 À adapter | Utilise déjà `statusColor()` |
|
||||
| Créer 3 variantes (OK/Warning/Danger) | `common/components/Components.kt` | 🟡 Partiel | Messages via stringResource |
|
||||
| Ajouter formes daltonien (cercle/triangle/losange) | `common/components/Components.kt` | 🔴 À faire | Emojis existants (✅⚠️⛔) |
|
||||
| Intégrer noms profils dans messages | `common/components/Components.kt` | 🔴 À faire | "Attention pour Julie" |
|
||||
| Animation stagger sur actions | `result/ResultScreen.kt` | 🔴 À faire | +50ms chaque bouton |
|
||||
|
||||
### 4.7 Étape 1.7 — DashboardScreen contextuel 🟡 À COMPLÉTER
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer `DashboardUiState` sealed class | `dashboard/DashboardViewModel.kt` | 🔴 À faire | Loading, StoreMode, HomeMode, FirstTime, Error |
|
||||
| Implémenter détection contexte (heure/lieu) | `dashboard/DashboardViewModel.kt` | 🔴 À faire | Géolocalisation + heure |
|
||||
| Créer layout mode magasin | `dashboard/DashboardScreen.kt` | 🟡 Partiel | Structure existante à enrichir |
|
||||
| Créer layout mode maison | `dashboard/DashboardScreen.kt` | 🟡 Partiel | Stats + derniers scans (placeholders) |
|
||||
| Créer layout premier lancement | `dashboard/DashboardScreen.kt` | 🟡 Partiel | CTA "Commencer" à ajouter |
|
||||
| Remplacer HomeScreen par Dashboard | `navigation/NavGraph.kt` | ✅ COMPLÉTÉ | Dashboard est startDestination |
|
||||
|
||||
### 4.8 Étape 1.8 — Adapter ResultScreen 🟡 À COMPLÉTER
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Bottom sheet transition | `result/ResultScreen.kt` | 🔴 À faire | Slide up 250ms |
|
||||
| Stagger actions animation | `result/ResultScreen.kt` | 🔴 À faire | 4 boutons décalés |
|
||||
| Bouton "Alternatives" | `result/ResultScreen.kt` | 🔴 À faire | Nouveau |
|
||||
| Bouton "Ajouter à la liste" | `result/ResultScreen.kt` | 🔴 À faire | Nouveau |
|
||||
| TalkBack announcement | `result/ResultScreen.kt` | 🔴 À faire | "Verdict : {status}..." |
|
||||
| Intégrer skeleton au lieu de spinner | `result/ResultScreen.kt` | 🔴 À faire | Ligne 109 : remplacer `LoadingIndicator()` |
|
||||
**Statut :** 🔴 À FAIRE
|
||||
**Priorité :** 🔴 **CRITIQUE** — Ces 5 items doivent être résolus avant tout lancement public.
|
||||
**Effort estimé :** ~3-4 jours
|
||||
|
||||
---
|
||||
|
||||
## 5. PHASE 2 — LISTES INTELLIGENTES
|
||||
### 4.1 Haptic feedback sur le FAB Scanner
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ** (90%)
|
||||
**Priorité :** 🟠 **MOYENNE**
|
||||
**Référence :** [`flux-UX.md`](flux-UX.md) FLOW 5
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Ajouter `triggerFabHaptic` au `onClick` du FAB | `main/MainScreen.kt` | ✅ Fait |
|
||||
| Durée : 15ms (léger, distinct du scan 60ms) | `main/MainScreen.kt` | ✅ Fait |
|
||||
| Respecter la préférence `hapticsEnabled` du DataStore | `main/MainScreen.kt` | 🟡 P3 (V2) |
|
||||
|
||||
### 5.1 Étape 2.1 — ListsScreen (liste des listes) ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer `ListsViewModel` | `lists/ListsViewModel.kt` | ✅ COMPLÉTÉ | State : listes + progression |
|
||||
| Créer écran liste des listes | `lists/ListsScreen.kt` | ✅ COMPLÉTÉ | Cards avec progression |
|
||||
| Affichage cartes listes (nom, count, progress) | `lists/ListsScreen.kt` | ✅ COMPLÉTÉ | LinearProgressIndicator |
|
||||
| Bouton "+ Nouvelle liste" | `lists/ListsScreen.kt` | ✅ COMPLÉTÉ | AlertDialog |
|
||||
| Empty state guidant | `lists/ListsScreen.kt` | ✅ COMPLÉTÉ | EmptyState composable |
|
||||
|
||||
### 5.2 Étape 2.2 — ListDetailScreen ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer `ListDetailViewModel` | `lists/ListDetailViewModel.kt` | ✅ COMPLÉTÉ | State : produits + filtres |
|
||||
| Créer écran détail liste | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | Voir spec FLOW 5 |
|
||||
| Chips filtres par rayon | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | FilterChip |
|
||||
| Affichage produits avec verdicts | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | ✅/⚠️/❌ sur chaque ligne |
|
||||
| Swipe right : cocher/décocher | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | SwipeToDismissBox |
|
||||
| Swipe left : supprimer | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | SwipeToDismissBox |
|
||||
| Boutons "Tout décocher" | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | TextButton |
|
||||
|
||||
### 5.3 Étape 2.3 — Domain/Data pour Listes ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Entité Room `ShoppingList` | `database/entity/Entities.kt` | ✅ COMPLÉTÉ | ShoppingListEntity |
|
||||
| Entité Room `ShoppingListItem` | `database/entity/Entities.kt` | ✅ COMPLÉTÉ | ShoppingListItemEntity |
|
||||
| DAO `ShoppingListDao` | `database/dao/ShoppingListDao.kt` | ✅ COMPLÉTÉ | CRUD complet + stats |
|
||||
| Repository `ShoppingListRepository` | `domain/repository/Repositories.kt` | ✅ COMPLÉTÉ | Interface + impl |
|
||||
| UseCases associés | `domain/usecase/UseCases.kt` | ✅ COMPLÉTÉ | GetShoppingListsUseCase, ManageShoppingListUseCase |
|
||||
|
||||
### 5.4 Étape 2.4 — Smart Features ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Auto-categorisation par rayon | `domain/engine/CategoryEngine.kt` | ✅ COMPLÉTÉ | Détection par mots-clés |
|
||||
| Alertes allergies dans listes | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | ⚠️/❌ visible |
|
||||
| Fusion de listes | `lists/ListsScreen.kt` | ✅ COMPLÉTÉ | Menu ⋮ → Fusionner |
|
||||
| Partage liste (SMS/email/PDF) | `lists/ListDetailScreen.kt` | ✅ COMPLÉTÉ | Intent ACTION_SEND |
|
||||
**Note :** Le retour haptique est fonctionnel (15ms). Le respect de la préférence `hapticsEnabled` est repoussé en V2 pour rester cohérent avec le scanner qui ignore aussi cette préférence.
|
||||
|
||||
---
|
||||
|
||||
## 6. PHASE 3 — SUIVI & STATISTIQUES
|
||||
### 4.2 Saisie manuelle du code-barres dans le Scanner
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ**
|
||||
**Priorité :** 🟡 **MOYENNE**
|
||||
**Référence :** [`flux-UX.md`](flux-UX.md) FLOW 6
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Créer un `AlertDialog` avec `OutlinedTextField` pour saisir un code-barres | `scanner/ScannerScreen.kt` | ✅ Fait |
|
||||
| Ajouter un bouton "Saisie manuelle" dans la bottom bar du scanner | `scanner/ScannerScreen.kt` | ✅ Fait |
|
||||
| Valider le format (8-13 chiffres) avant soumission | `scanner/ScannerScreen.kt` | ✅ Fait |
|
||||
| Fallback automatique si permission caméra refusée définitivement | `scanner/ScannerScreen.kt` | ✅ Fait |
|
||||
| Strings FR ajoutés (`scanner_manual_entry_*`) | `strings.xml` | ✅ Fait |
|
||||
|
||||
### 6.1 Étape 3.1 — TrackingScreen complet ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer `TrackingViewModel` | `tracking/TrackingViewModel.kt` | ✅ COMPLÉTÉ | State : stats + historique + filtres |
|
||||
| Cercle progression (donut chart) | `common/components/Charts.kt` | ✅ COMPLÉTÉ | `DonutChart` composable |
|
||||
| Graphique évolution (sparkline) | `common/components/Charts.kt` | ✅ COMPLÉTÉ | `Sparkline` composable |
|
||||
| Top allergènes détectés | `tracking/TrackingScreen.kt` | ✅ COMPLÉTÉ | `TopAllergensSection` |
|
||||
| Filtres temporels | `tracking/TrackingScreen.kt` | ✅ COMPLÉTÉ | `TimeFilterRow` (Semaine/Mois/Année/Tout) |
|
||||
| Historique récent avec verdicts | `tracking/TrackingScreen.kt` | ✅ COMPLÉTÉ | `HistoryItemCard` avec swipe delete |
|
||||
| Empty state | `tracking/TrackingScreen.kt` | ✅ COMPLÉTÉ | `EmptyState` composable |
|
||||
| Graphique barres (distribution) | `common/components/Charts.kt` | ✅ COMPLÉTÉ | `HorizontalBarChart` |
|
||||
| Cartes statistiques | `common/components/Charts.kt` | ✅ COMPLÉTÉ | `StatCard`, `StatCardMini` |
|
||||
| Skeleton loading | `tracking/TrackingScreen.kt` | ✅ COMPLÉTÉ | `TrackingLoadingSkeleton` |
|
||||
|
||||
### 6.2 Étape 3.2 — Migrer HistoryScreen → TrackingScreen ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Fusionner fonctionnalités | `tracking/TrackingScreen.kt` | ✅ COMPLÉTÉ | History + stats intégrés |
|
||||
| Supprimer `history/` obsolète | `screen/history/` | ✅ COMPLÉTÉ | Dossier supprimé |
|
||||
| Adapter route navigation | `navigation/NavGraph.kt` | ✅ COMPLÉTÉ | HistoryScreen → TrackingScreen |
|
||||
**Spécification :** Sous le réticule, un `TextButton` "Saisir un code-barres" ouvre un `AlertDialog` avec `OutlinedTextField` (clavier numérique, max 13 chiffres), validation 8-13 chiffres, boutons [Annuler] [Rechercher]. Affiché aussi quand la permission caméra est refusée.
|
||||
|
||||
---
|
||||
|
||||
## 7. PHASE 4 — PROFILS FAMILLE (AMÉLIORATIONS)
|
||||
### 4.3 Bouton "Alternatives" dans ResultScreen
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ**
|
||||
**Priorité :** 🟡 **MOYENNE**
|
||||
**Référence :** [`flux-UX.md`](flux-UX.md) FLOW 8
|
||||
|
||||
### 7.1 Étape 4.1 — Refonte FamilyScreen ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Grille profils avec cartes | `family/FamilyScreen.kt` | ✅ COMPLÉTÉ | LazyVerticalGrid 2 colonnes |
|
||||
| Affichage allergies par profil | `family/FamilyScreen.kt` | ✅ COMPLÉTÉ | `AllergenDisplayGrid` avec ⚠️/❌ |
|
||||
| Bouton "+ Ajouter un membre" | `family/FamilyScreen.kt` | ✅ COMPLÉTÉ | FAB avec icône Add |
|
||||
| Navigation vers détail profil | `family/FamilyScreen.kt` | ✅ COMPLÉTÉ | Tap sur carte → ProfileEditScreen |
|
||||
| Activation/désactivation profil | `family/FamilyScreen.kt` | ✅ COMPLÉTÉ | Icône étoile |
|
||||
| Suppression avec confirmation | `family/FamilyScreen.kt` | ✅ COMPLÉTÉ | AlertDialog |
|
||||
| Profil par défaut | `family/FamilyScreen.kt` | ✅ COMPLÉTÉ | Badge "Par défaut" |
|
||||
| ViewModel dédié | `family/FamilyViewModel.kt` | ✅ COMPLÉTÉ | State + active profiles |
|
||||
|
||||
### 7.2 Étape 4.2 — AllergenSelectionGrid ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer composant grille allergènes | `common/components/AllergenGrid.kt` | ✅ COMPLÉTÉ | LazyVerticalGrid 3 colonnes |
|
||||
| 3 états par tap (NONE → TRACE → SEVERE) | `common/components/AllergenGrid.kt` | ✅ COMPLÉTÉ | Cycle : Aucun → ⚠️ → ❌ |
|
||||
| Couleurs fond par état | `common/components/AllergenGrid.kt` | ✅ COMPLÉTÉ | #FEF5E7 (traces) / #FDEDEC (sévère) |
|
||||
| Icônes emoji (🥜🥛🍞🦐🥚🐟...) | `common/components/AllergenGrid.kt` | ✅ COMPLÉTÉ | Via `AllergenType.icon` |
|
||||
| Bordures colorées par état | `common/components/AllergenGrid.kt` | ✅ COMPLÉTÉ | Orange/Rouge |
|
||||
| AllergenDisplayGrid (lecture seule) | `common/components/AllergenGrid.kt` | ✅ COMPLÉTÉ | Pour FamilyScreen |
|
||||
| AllergenBadge individuel | `common/components/AllergenGrid.kt` | ✅ COMPLÉTÉ | Badge avec icône + nom |
|
||||
|
||||
### 7.3 Étape 4.3 — ProfileEditScreen (3 états allergie) ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Adapter écran édition profil | `profile/ProfileEditScreen.kt` | ✅ COMPLÉTÉ | Utilise AllergenSelectionGrid |
|
||||
| Intégrer AllergenSelectionGrid | `profile/ProfileEditScreen.kt` | ✅ COMPLÉTÉ | Remplace les 2 grilles séparées |
|
||||
| ViewModel 3 états | `profile/ProfileViewModel.kt` | ✅ COMPLÉTÉ | `allergenLevels: Map<AllergenType, AllergenLevel>` |
|
||||
| Compatibilité ancien système | `profile/ProfileViewModel.kt` | ✅ COMPLÉTÉ | `severe` et `moderate` calculés |
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Ajouter un bouton "Voir les alternatives" dans la section actions | `result/ResultScreen.kt` | ✅ Fait |
|
||||
| Navigation vers `ProductDetailScreen` (onglet Alternatives) | `result/ResultScreen.kt`, `NavGraph.kt` | ✅ Fait |
|
||||
| Afficher le bouton uniquement si verdict != SAFE | `result/ResultScreen.kt` | ✅ Fait |
|
||||
| String FR ajouté (`result_see_alternatives`) | `strings.xml` | ✅ Fait |
|
||||
|
||||
---
|
||||
|
||||
## 8. PHASE 5 — FICHE PRODUIT DÉTAILLÉE
|
||||
### 4.4 Dashboard avec données réelles
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ**
|
||||
**Priorité :** 🟠 **MOYENNE**
|
||||
**Référence :** [`architecture-ui-ux.md`](architecture-ui-ux.md) §5.4, [`flux-UX.md`](flux-UX.md) FLOW 3
|
||||
|
||||
### 8.1 Étape 5.1 — ProductDetailScreen ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Créer `ProductDetailViewModel` | `product/ProductDetailViewModel.kt` | ✅ COMPLÉTÉ | State sealed : Loading/Success/Error |
|
||||
| Créer écran fiche produit | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | ScrollableTabRow 4 tabs |
|
||||
| Navigation vers fiche produit | `navigation/Screen.kt` | ✅ COMPLÉTÉ | `Screen.ProductDetail` |
|
||||
| Intégration NavGraph | `navigation/NavGraph.kt` | ✅ COMPLÉTÉ | composable ProductDetail |
|
||||
|
||||
### 8.2 Étape 5.2 — Tab Résumé ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Verdict sécurité (répété) | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `VerdictBadge` composable |
|
||||
| Nutri-Score visuel (A-E) | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `NutriScoreCard` avec couleurs |
|
||||
| Calories / 100g | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `CaloriesCard` |
|
||||
| Jauges sucre/sel/gras | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `NutritionGauges` + `GaugeRow` |
|
||||
| Verdict santé | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `HealthVerdictCard` |
|
||||
|
||||
### 8.3 Étape 5.3 — Tab Allergènes ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Liste 14 allergènes réglementaires | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `AllergensTab` |
|
||||
| Statut : Présent ❌ / Traces ⚠️ / Absent ✅ | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `AllergenStatusRow` |
|
||||
| Highlight allergènes famille | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | Fond #FEF5E7 / #FDEDEC |
|
||||
|
||||
### 8.4 Étape 5.4 — Tab Additifs ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Affichage ingrédients | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `AdditivesTab` |
|
||||
| Description courte | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | Texte brut |
|
||||
|
||||
### 8.5 Étape 5.5 — Tab Alternatives ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Structure tab alternatives | `product/ProductDetailScreen.kt` | ✅ COMPLÉTÉ | `AlternativesTab` |
|
||||
| UseCase recherche alternatives | `domain/usecase/GetAlternativesUseCase.kt` | ✅ COMPLÉTÉ | Interface repository |
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Injecter `GetScanHistoryUseCase` dans `DashboardViewModel` | `dashboard/DashboardViewModel.kt` | ✅ Fait |
|
||||
| Calculer `WeeklyStats` (semaine en cours : % safe, warnings, dangers) | `dashboard/DashboardViewModel.kt` | ✅ Fait |
|
||||
| Afficher les 5 derniers scans réels avec verdict, marque, temps relatif | `dashboard/DashboardScreen.kt` | ✅ Fait |
|
||||
| Carte de stats hebdomadaires (✅ % / ⚠️ nb / ❌ nb) | `dashboard/DashboardScreen.kt` | ✅ Fait |
|
||||
| Gérer l'état vide (0 scan) avec message "Aucun scan récent" | `dashboard/DashboardScreen.kt` | ✅ Fait |
|
||||
| Strings FR ajoutés (`dashboard_stats_*`) | `strings.xml` | ✅ Fait |
|
||||
|
||||
---
|
||||
|
||||
## 9. PHASE 6 — GESTION DES ERREURS & CAS LIMITES
|
||||
### 4.5 Détection contextuelle magasin / maison
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ**
|
||||
**Priorité :** 🟠 **MOYENNE**
|
||||
**Référence :** [`flux-UX.md`](flux-UX.md) FLOW 7
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Ajouter `DashboardContextMode` (FIRST_TIME, STORE, HOME) | `dashboard/DashboardViewModel.kt` | ✅ Fait |
|
||||
| Détection : FIRST_TIME si 0 scan, STORE si 8h-20h semaine ou liste active, HOME sinon | `dashboard/DashboardViewModel.kt` | ✅ Fait |
|
||||
| Layout FIRST_TIME : CTA "Commencer" + illustration 🎉 | `dashboard/DashboardScreen.kt` | ✅ Fait |
|
||||
| Layout STORE : scan prominent + liste en cours 🛒 | `dashboard/DashboardScreen.kt` | ✅ Fait |
|
||||
| Layout HOME : résumé hebdo + derniers scans + listes | `dashboard/DashboardScreen.kt` | ✅ Fait |
|
||||
|
||||
### 9.1 Cas 1 : Produit non trouvé ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Écran "Produit non reconnu" | `result/ProductNotFoundScreen.kt` | ✅ COMPLÉTÉ | Message explicatif |
|
||||
| Photo étiquette (OCR) | `result/ProductNotFoundScreen.kt` | ✅ COMPLÉTÉ | Bouton → OcrCapture |
|
||||
| Saisie manuelle produit | `result/ProductNotFoundScreen.kt` | ✅ COMPLÉTÉ | Nom + code-barres |
|
||||
| Message confirmation | `result/ProductNotFoundScreen.kt` | ✅ COMPLÉTÉ | "Merci ! Analyse sous 24h" |
|
||||
|
||||
### 9.2 Cas 2 : Pas de connexion ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Mode dégradé transparent | `common/components/Feedback.kt` | ✅ COMPLÉTÉ | `OfflineIndicator` existant |
|
||||
| Bandeau "Mode hors-ligne" | `common/components/Feedback.kt` | ✅ COMPLÉTÉ | errorContainer + CloudOff |
|
||||
| Cache local pour produits | `repository/ProductRepositoryImpl.kt` | ✅ COMPLÉTÉ | `getCachedProduct` |
|
||||
| Gestion erreur offline | `result/ResultViewModel.kt` | ✅ COMPLÉTÉ | `ProductFetchResult.Error(offline=true)` |
|
||||
|
||||
### 9.3 Cas 3 : OCR illisible ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Gestion texte vide | `ocr/OcrReviewScreen.kt` | ✅ COMPLÉTÉ | Message "Aucun texte détecté" |
|
||||
| Réessayer | `ocr/OcrReviewScreen.kt` | ✅ COMPLÉTÉ | Bouton retour capture |
|
||||
| Saisie manuelle | `ocr/OcrReviewScreen.kt` | ✅ COMPLÉTÉ | TextField éditable |
|
||||
|
||||
### 9.4 Cas 4 : Permissions refusées ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| ErrorView caméra | `scanner/ScannerScreen.kt` | ✅ COMPLÉTÉ | Message + bouton réessayer |
|
||||
| Fallback saisie manuelle | `result/ResultScreen.kt` | ✅ COMPLÉTÉ | Bouton OCR toujours dispo |
|
||||
|
||||
### 9.5 Timeouts scan ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Loading skeleton | `result/ResultScreen.kt` | ✅ COMPLÉTÉ | `ProductSkeleton` immédiat |
|
||||
| ErrorView avec actions | `common/components/Feedback.kt` | ✅ COMPLÉTÉ | `ErrorView` + `OutlinedActionButton` |
|
||||
| Actions : Réessayer + OCR | `result/ResultScreen.kt` | ✅ COMPLÉTÉ | 2 boutons en erreur |
|
||||
**Note :** La géolocalisation est repoussée en V2 (P3). La détection utilise l'heure et le jour de la semaine.
|
||||
|
||||
---
|
||||
|
||||
## 10. PHASE 7 — ACCESSIBILITÉ & QUALITÉ
|
||||
## 5. PHASE 11 — QUALITÉ PERÇUE & PERFORMANCE (P1 IMPORTANT)
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ** (95%)
|
||||
**Priorité :** 🟡 **MOYENNE**
|
||||
**Référence :** [`flux-UX.md`](flux-UX.md) §6, [`architecture-ui-ux.md`](architecture-ui-ux.md) §8.2
|
||||
|
||||
### 10.1 Accessibilité WCAG 2.1 AA
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Contraste texte ≥ 4.5:1 | Tous les écrans | ✅ COMPLÉTÉ | Couleurs Material 3 conformes par défaut |
|
||||
| Contraste UI ≥ 3:1 | Tous les écrans | ✅ COMPLÉTÉ | Validation visuelle effectuée |
|
||||
| ContentDescription sur éléments interactifs | Tous les écrans | ✅ COMPLÉTÉ | Tous les écrans mis à jour |
|
||||
| Images décoratives : contentDescription = null | Tous les écrans | ✅ COMPLÉTÉ | Images produits ont contentDescription |
|
||||
| Annonces TalkBack (verdict, chargement, erreurs) | Tous les écrans | ✅ COMPLÉTÉ | LiveRegionMode.Assertive pour verdict |
|
||||
| Ordre focus logique (gauche→droite, haut→bas) | Tous les écrans | ✅ COMPLÉTÉ | Ordre naturel Compose |
|
||||
| Zones tactiles ≥ 48dp × 48dp | `Buttons.kt` | ✅ COMPLÉTÉ | `ButtonTokens.MinHeight = 48.dp` |
|
||||
| Espacement ≥ 8dp entre zones | Tous les écrans | ✅ COMPLÉTÉ | `dimens.spacingSm` minimum |
|
||||
| Texte dynamique jusqu'à 200% | Tous les écrans | ✅ COMPLÉTÉ | sp (pas dp) partout |
|
||||
| Focus indicators visibles (anneau #2ECC71, 2dp) | Tous les écrans | ✅ COMPLÉTÉ | Material 3 par défaut |
|
||||
|
||||
### 10.2 Système daltonien
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Formes distinctes (cercle/triangle/losange) | `common/components/Components.kt` | ✅ COMPLÉTÉ | `DaltonianShape` composable |
|
||||
| Jamais couleur seule | Tous les verdicts | ✅ COMPLÉTÉ | Forme + icône + couleur + texte |
|
||||
| Test utilisateur daltonien | Testing | ✅ COMPLÉTÉ | Validé par test manuel avec TalkBack |
|
||||
|
||||
### 10.3 Écrans améliorés pour l'accessibilité
|
||||
|
||||
| Écran | Fichier | ContentDescription | TalkBack | Notes |
|
||||
|-------|---------|-------------------|----------|-------|
|
||||
| Résultat | `ResultScreen.kt` | ✅ | ✅ | LiveRegion pour verdict |
|
||||
| Scanner | `ScannerScreen.kt` | ✅ | ✅ | Zone de scan + lampe |
|
||||
| Famille | `FamilyScreen.kt` | ✅ | ✅ | Profils actifs/inactifs |
|
||||
| Listes | `ListsScreen.kt` | ✅ | ✅ | Menu options + actions |
|
||||
| Suivi | `TrackingScreen.kt` | ✅ | ✅ | Filtres + historique |
|
||||
| Fiche produit | `ProductDetailScreen.kt` | ✅ | ✅ | Nutri-Score + allergènes |
|
||||
| Produit non trouvé | `ProductNotFoundScreen.kt` | ✅ | ✅ | OCR + saisie manuelle |
|
||||
|
||||
### 10.4 Strings d'accessibilité ajoutés
|
||||
|
||||
| Catégorie | Strings | Statut |
|
||||
|-----------|---------|--------|
|
||||
| Verdicts | `a11y_safe_status`, `a11y_warning_status`, `a11y_danger_status` | ✅ |
|
||||
| Verdicts (annonces) | `a11y_verdict_safe`, `a11y_verdict_warning`, `a11y_verdict_danger` | ✅ |
|
||||
| Navigation | `a11y_back`, `a11y_settings`, `a11y_close` | ✅ |
|
||||
| Actions | `a11y_add`, `a11y_delete`, `a11y_edit`, `a11y_search`, `a11y_filter` | ✅ |
|
||||
| États | `a11y_loading`, `a11y_error`, `a11y_offline` | ✅ |
|
||||
| Nutrition | `a11y_nutri_score`, `a11y_nova_group`, `a11y_eco_score` | ✅ |
|
||||
| Allergènes | `a11y_allergen_present`, `a11y_allergen_trace`, `a11y_allergen_absent` | ✅ |
|
||||
| Profils | `a11y_profile_active`, `a11y_profile_inactive` | ✅ |
|
||||
| UI | `a11y_expand`, `a11y_collapse`, `a11y_toggle`, `a11y_more_options` | ✅ |
|
||||
| Autres | `a11y_merge`, `a11y_clear_all`, `a11y_confirm`, `a11y_cancel` | ✅ |
|
||||
| Divers | `a11y_torch`, `a11y_scan_area`, `a11y_product_image`, `a11y_avatar` | ✅ |
|
||||
|
||||
### 10.5 Composants daltoniens
|
||||
|
||||
| Composant | Fichier | Forme | Statut |
|
||||
|-----------|---------|-------|--------|
|
||||
| `DaltonianShape` | `Components.kt` | Cercle/Triangle/Losange | ✅ |
|
||||
| `SafetyStatusBanner` | `Components.kt` | Intègre DaltonianShape | ✅ |
|
||||
| `VerdictBadge` | `ProductDetailScreen.kt` | Texte + couleur + emoji | ✅ |
|
||||
| `AllergenStatusRow` | `ProductDetailScreen.kt` | Emoji + texte | ✅ |
|
||||
|
||||
### 10.6 Performance perçue
|
||||
|
||||
| Métrique | Cible | Statut | Méthode |
|
||||
|----------|-------|--------|---------|
|
||||
| Ouverture scanner | < 300ms | ✅ COMPLÉTÉ | Pré-initialisation caméra existante |
|
||||
| Affichage verdict | < 500ms | ✅ COMPLÉTÉ | `ProductSkeleton` immédiat + async |
|
||||
| Transition écrans | 200-300ms | ✅ COMPLÉTÉ | ease-out, jamais > 400ms |
|
||||
| Scroll FPS | 60fps | ✅ COMPLÉTÉ | LazyColumn + pagination |
|
||||
| Taille APK | < 25 Mo | ✅ COMPLÉTÉ | R8/ProGuard activé + isShrinkResources = true
|
||||
**Statut :** ✅ COMPLÉTÉ
|
||||
**Priorité :** 🟠 **IMPORTANT** — Améliore significativement l'expérience utilisateur.
|
||||
**Effort :** ~2-3 jours (fait)
|
||||
|
||||
---
|
||||
|
||||
## 11. PHASE 8 — TESTS & VALIDATION
|
||||
### 5.1 Animations stagger sur les actions ResultScreen
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ** (100%)
|
||||
**Priorité :** 🟡 **MOYENNE**
|
||||
**Référence :** [`flux-UX.md`](flux-UX.md) §🧪
|
||||
|
||||
### 11.1 Tests unitaires
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Tests UseCases | `domain/usecase/` | 🟡 Faible priorité | Couverture minimale requise |
|
||||
| Tests ViewModels | `presentation/screen/*/` | 🟡 Faible priorité | Couverture minimale requise |
|
||||
| Tests Repository | `repository/` | 🟡 Faible priorité | Couverture minimale requise |
|
||||
| Tests AllergenAnalysisEngine | `domain/engine/` | ✅ COMPLÉTÉ | 25 tests existants |
|
||||
| Tests HealthClassifier | `domain/engine/` | ✅ COMPLÉTÉ | 14 tests créés |
|
||||
|
||||
### 11.2 Tests UI
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Tests Compose (navigation, interactions) | `app/src/androidTest/` | ✅ COMPLÉTÉ | `ExampleComposeTest.kt` créé |
|
||||
| Tests screenshot (paparazzi/roborazzi) | `app/src/test/` | 🟡 Future | Infrastructure optionnelle |
|
||||
| Tests accessibilité | Tous les écrans | ✅ COMPLÉTÉ | TalkBack + contrastes validés |
|
||||
|
||||
### 11.3 Tests UX (validation)
|
||||
|
||||
| Test | Objectif | Statut | Notes |
|
||||
|------|----------|--------|-------|
|
||||
| 5 utilisateurs, scenario "scanner produit dangereux" | < 2s pour identifier danger | 🟡 Manuel | Test utilisateur requis |
|
||||
| Test daltonien (1 utilisateur minimum) | Distinction verdicts | ✅ COMPLÉTÉ | Formes géométriques validées |
|
||||
| Scan rapide 10 produits d'affilée | Pas de crash, performance | 🟡 Manuel | Test manuel requis |
|
||||
| Rotation écran pendant scan | Pas de perte d'état | ✅ COMPLÉTÉ | ViewModel + collectAsStateWithLifecycle |
|
||||
| Appel téléphonique interrompt scan | Reprise correcte | ✅ COMPLÉTÉ | Lifecycle géré par CameraX |
|
||||
| Batterie faible | Mode dégradé | ✅ COMPLÉTÉ | ErrorView avec fallback |
|
||||
| Stockage presque plein | Gestion erreur | ✅ COMPLÉTÉ | Room gère les erreurs SQLite |
|
||||
|
||||
### 11.4 Couverture de tests
|
||||
|
||||
| Module | Tests | Couverture | Statut |
|
||||
|--------|-------|------------|--------|
|
||||
| AllergenAnalysisEngine | 25 tests | ~85% | ✅ |
|
||||
| HealthClassifier | 14 tests | ~90% | ✅ |
|
||||
| ViewModels | 6 tests | ~60% | ✅ `ResultViewModelTest` |
|
||||
| UseCases | 5 tests | ~70% | ✅ `GetAlternativesUseCaseTest` |
|
||||
| Repositories | 8 tests | ~65% | ✅ `ProductRepositoryImplTest` |
|
||||
| **Total** | **58 tests** | **~55%** | ✅ |
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Ajouter `StaggeredAction` avec délai progressif (0/50/100/150ms) | `result/ResultScreen.kt` | ✅ Fait |
|
||||
| Animation fadeIn + slideInVertically par bouton | `result/ResultScreen.kt` | ✅ Fait |
|
||||
| Ordre : Ouvrir OFF → Ajouter liste → Alternatives → Scanner/Lire | `result/ResultScreen.kt` | ✅ Fait |
|
||||
|
||||
---
|
||||
|
||||
## 12. PHASE 9 — PRÉPARATION RELEASE
|
||||
### 5.2 Pré-initialisation de la caméra
|
||||
|
||||
**Statut :** ✅ **COMPLÉTÉ** (100%)
|
||||
**Priorité :** 🟢 **BASSE** (après toutes les autres phases)
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| `ProcessCameraProvider.getInstance()` déjà asynchrone dans CameraView | `scanner/ScannerScreen.kt` | 🟡 Différé P3 |
|
||||
|
||||
### 12.1 Optimisation ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Statut | Notes |
|
||||
|-------|--------|-------|
|
||||
| R8/ProGuard configuration | ✅ COMPLÉTÉ | `isMinifyEnabled = true` + `isShrinkResources = true` dans build.gradle |
|
||||
| Optimisation ressources | ✅ COMPLÉTÉ | Vector drawables déjà utilisées, excludes META-INF |
|
||||
| Supprimer code mort | ✅ COMPLÉTÉ | Dossier `history/` supprimé, imports vérifiés |
|
||||
| Vérifier dépendances inutilisées | ✅ COMPLÉTÉ | `gradle libs.versions.toml` vérifié |
|
||||
|
||||
### 12.2 Qualité code ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Statut | Notes |
|
||||
|-------|--------|-------|
|
||||
| Ktlint / Detekt | 🟡 Configuré | Dépendances ajoutées, à exécuter manuellement |
|
||||
| Vérification fuites mémoire | ✅ COMPLÉTÉ | LeakCanary 2.14 intégré (debug) |
|
||||
| Revue architecture complète | ✅ COMPLÉTÉ | Clean Architecture respectée |
|
||||
| Documentation code (KDoc) | ✅ COMPLÉTÉ | KDoc ajoutés sur fichiers principaux |
|
||||
|
||||
### 12.3 Release ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Statut | Notes |
|
||||
|-------|--------|-------|
|
||||
| Versioning (`version.properties`) | ✅ COMPLÉTÉ | v1.2.0 (code 3) |
|
||||
| Signing APK/AAB | ✅ COMPLÉTÉ | SigningConfig configuré dans build.gradle |
|
||||
| Changelog | ✅ COMPLÉTÉ | [`CHANGELOG.md`](../CHANGELOG.md) créé |
|
||||
| Screenshots Play Store | 🟡 À faire | Manuel requis |
|
||||
| Description Play Store | 🟡 À faire | Manuel requis |
|
||||
| Test internal/closed testing | ✅ COMPLÉTÉ | Infrastructure prête |
|
||||
|
||||
### 12.4 Tests unitaires ✅ COMPLÉTÉ
|
||||
|
||||
| Tâche | Fichier | Statut | Notes |
|
||||
|-------|---------|--------|-------|
|
||||
| Tests UseCases | `GetAlternativesUseCaseTest.kt` | ✅ COMPLÉTÉ | 5 tests |
|
||||
| Tests ViewModels | `ResultViewModelTest.kt` | ✅ COMPLÉTÉ | 6 tests |
|
||||
| Tests Repositories | `ProductRepositoryImplTest.kt` | ✅ COMPLÉTÉ | 8 tests |
|
||||
| Tests UI Compose | `ExampleComposeTest.kt` | ✅ COMPLÉTÉ | Infrastructure validée |
|
||||
|
||||
### 12.5 Dépendances ajoutées
|
||||
|
||||
| Dépendance | Version | Usage |
|
||||
|------------|---------|-------|
|
||||
| LeakCanary | 2.14 | Détection fuites mémoire (debug) |
|
||||
| Compose UI Test JUnit4 | BOM | Tests UI instrumentés |
|
||||
| Compose UI Test Manifest | BOM | Manifest pour tests UI |
|
||||
| AndroidX Test Runner | 1.6.2 | Runner pour tests instrumentés |
|
||||
| AndroidX Test Rules | 1.6.1 | Rules pour tests instrumentés |
|
||||
**Note :** L'initialisation est déjà asynchrone. La pré-initialisation en arrière-plan (singleton) est repoussée en V2 car l'impact est mineur (~200ms gagnés).
|
||||
|
||||
---
|
||||
|
||||
## 13. ANNEXES
|
||||
### 5.3 Transition BottomSheet → Plein écran pour ResultScreen
|
||||
|
||||
### 13.1 Glossaire
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Animation slide-up (fadeIn + slideInVertically, 250ms) sur le contenu complet | `result/ResultScreen.kt` | ✅ Fait |
|
||||
| Effet visuel "Slide up from bottom" reproduit via `AnimatedVisibility` | `result/ResultScreen.kt` | ✅ Fait |
|
||||
|
||||
**Note :** Pas de `ModalBottomSheet` natif (conflit avec le Scaffold existant). L'animation slide-up sur le contenu produit le même effet perçu.
|
||||
|
||||
---
|
||||
|
||||
### 5.4 Vérification et correction du mode sombre
|
||||
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| Vérifier `StatusColors` light/dark (Safe #2ECC71, Warning #E67E22, Danger #E74C3C) | `theme/StatusColors.kt` | ✅ Validé |
|
||||
| Confirmer le wiring dans `Theme.kt` (`LocalStatusColors provides statusColors`) | `theme/Theme.kt` | ✅ Validé |
|
||||
| Contrastes Material 3 conformes par défaut | Tous les écrans | ✅ Validé |
|
||||
|
||||
**Note :** Le thème sombre est correctement câblé avec `DarkStatusColors`. Les couleurs sémantiques sont adaptées pour le mode sombre (containers assombris).
|
||||
|
||||
---
|
||||
|
||||
### 5.5 Validation du format code-barres
|
||||
|
||||
| Tâche | Fichier | Statut |
|
||||
|-------|---------|--------|
|
||||
| ML Kit déjà configuré pour EAN-13/8, UPC-A/E, QR uniquement | `scanner/BarcodeAnalyzer.kt` | ✅ Fait |
|
||||
| Validation format 8-13 chiffres pour la saisie manuelle | `scanner/ScannerScreen.kt` | ✅ Fait |
|
||||
| Message d'erreur "Format invalide" dans le dialog manuel | `scanner/ScannerScreen.kt` | ✅ Fait |
|
||||
|
||||
---
|
||||
|
||||
## 6. PHASE 12 — LANCEMENT PLAY STORE (P2 NÉCESSAIRE)
|
||||
|
||||
**Statut :** 🔴 À FAIRE
|
||||
**Priorité :** 🟡 **NÉCESSAIRE** — Incontournable pour publier sur Google Play.
|
||||
**Effort estimé :** ~1-2 jours
|
||||
|
||||
---
|
||||
|
||||
### 6.1 Assets Play Store
|
||||
|
||||
| Tâche | Statut |
|
||||
|-------|--------|
|
||||
| Captures d'écran format Play Store : 8+ screenshots (phone + tablette) | 🔴 À faire |
|
||||
| Icône adaptive icon (foreground/background) : vérifier et finaliser | 🔴 À faire |
|
||||
| Feature graphic (1024×500 px) pour la fiche Play Store | 🔴 À faire |
|
||||
| Vidéo de démonstration (optionnelle mais recommandée, 30s) | 🟡 Optionnel |
|
||||
|
||||
**Screenshots requis :**
|
||||
1. Dashboard (ou onboarding)
|
||||
2. Scanner en action
|
||||
3. Verdict SAFE
|
||||
4. Verdict DANGER
|
||||
5. Fiche produit détaillée
|
||||
6. Listes intelligentes
|
||||
7. Suivi & Statistiques
|
||||
8. Profils famille
|
||||
|
||||
---
|
||||
|
||||
### 6.2 Fiche Play Store
|
||||
|
||||
| Tâche | Statut |
|
||||
|-------|--------|
|
||||
| Description courte (80 caractères) FR + EN | 🔴 À faire |
|
||||
| Description longue (4000 caractères) FR + EN | 🔴 À faire |
|
||||
| Mots-clés ASO (recherche organique) | 🔴 À faire |
|
||||
| Catégorie "Santé & Bien-être" ou "Shopping" | 🔴 À décider |
|
||||
| Politique de confidentialité (obligatoire) | 🔴 À faire |
|
||||
| Déclaration de sécurité des données (Data Safety) | 🔴 À faire |
|
||||
|
||||
---
|
||||
|
||||
### 6.3 Qualité code & Documentation
|
||||
|
||||
| Tâche | Statut |
|
||||
|-------|--------|
|
||||
| Ajouter les plugins Ktlint (v12.2.0) + Detekt (v1.23.7) | ✅ Fait |
|
||||
| Configurer `.editorconfig` (Compose PascalCase, max-line-length off) | ✅ Fait |
|
||||
| Configurer `detekt.yml` (règles adaptées Android/Compose) | ✅ Fait |
|
||||
| **Exécuter** : `./gradlew ktlintCheck && ./gradlew ktlintFormat && ./gradlew detekt && ./gradlew detektBaseline` | ✅ Fait — BUILD SUCCESSFUL |
|
||||
| CHANGELOG à jour (v1.0.0 → v1.28.0) | ✅ Fait |
|
||||
|
||||
---
|
||||
|
||||
### 6.4 Tests utilisateurs
|
||||
|
||||
| Tâche | Statut |
|
||||
|-------|--------|
|
||||
| Créer le plan de tests (10 scénarios + accessibilité) | ✅ Fait |
|
||||
| Document dans [`docs/test-plan.md`](test-plan.md) | ✅ Fait |
|
||||
| Produits de test avec codes-barres suggérés | ✅ Fait |
|
||||
| Grille d'observation pour 5 testeurs | ✅ Fait |
|
||||
| **À exécuter manuellement** : recruter 5 testeurs et exécuter les scénarios | 🟡 Manuel |
|
||||
|
||||
---
|
||||
|
||||
## 7. IDÉES V2 (P3 DIFFÉRENCIATEUR)
|
||||
|
||||
**Statut :** 💤 EN ATTENTE
|
||||
**Priorité :** 🟢 **FUTUR** — Ces fonctionnalités différencient SafeBite sur le marché mais ne sont pas nécessaires pour un MVP professionnel.
|
||||
|
||||
---
|
||||
|
||||
| # | Fonctionnalité | Effort estimé |
|
||||
|---|---------------|---------------|
|
||||
| 1 | **Notifications push** — Alerte critique quand un allergène sévère est détecté (Firebase FCM) | 3-4 jours |
|
||||
| 2 | **Centre de notifications in-app** — Cloche dans la top bar + résumé hebdomadaire | 2-3 jours |
|
||||
| 3 | **Géolocalisation réelle** — Détection magasin via Geofence/Places API | 2-3 jours |
|
||||
| 4 | **Partage liste collaboratif** — Liste partagée en temps réel (Firestore/Cloud) | 5-7 jours |
|
||||
| 5 | **Scanner rayon** — Reconnaissance multiple de produits en une capture | 5-7 jours |
|
||||
| 6 | **Badge scoring personnalisé** — Score santé pondéré par le profil utilisateur | 3-4 jours |
|
||||
| 7 | **Intégration Drive/Click&Collect** — Ajout direct au panier en ligne | 5-7 jours |
|
||||
| 8 | **Tests screenshot automatisés** — Paparazzi / Roborazzi | 1-2 jours |
|
||||
| 9 | **Module catalogue hors-ligne complet** — Téléchargement périodique des produits | 3-4 jours |
|
||||
| 10 | **Widget Android** — Scan rapide depuis l'écran d'accueil | 2-3 jours |
|
||||
|
||||
---
|
||||
|
||||
## 8. ANNEXES
|
||||
|
||||
### 8.1 Glossaire
|
||||
|
||||
| Terme | Définition |
|
||||
|-------|------------|
|
||||
| **Verdict** | Résultat d'analyse : SAFE (🟢), WARNING (🟠), DANGER (🔴) |
|
||||
| **FAB** | Floating Action Button — bouton scanner central |
|
||||
| **FAB** | Floating Action Button — bouton scanner central 56dp |
|
||||
| **Skeleton Screen** | Écran de chargement avec shimmer (pas de spinner) |
|
||||
| **ContainerTransform** | Transition Material entre FAB et écran scanner |
|
||||
| **AllergenLevel** | NONE, TRACE (⚠️), SEVERE (❌) |
|
||||
| **ContextMode** | FirstTime, StoreMode, HomeMode — modes du dashboard |
|
||||
|
||||
### 13.2 Couleurs de référence
|
||||
### 8.2 Couleurs de référence
|
||||
|
||||
| Usage | Couleur | Hex |
|
||||
|-------|---------|-----|
|
||||
@@ -649,20 +386,54 @@
|
||||
| Séparateurs | Separator | `#DFE6E9` |
|
||||
| FAB | FAB | `#2D3436` |
|
||||
|
||||
### 13.3 Liens vers documents
|
||||
### 8.3 Liens
|
||||
|
||||
- **Spec UX/UI complète :** [`flux-UX.md`](flux-UX.md)
|
||||
- **Architecture UI-UX :** [`architecture-ui-ux.md`](architecture-ui-ux.md)
|
||||
- **README projet :** [`../README.md`](../README.md)
|
||||
- **CHANGELOG :** [`../CHANGELOG.md`](../CHANGELOG.md)
|
||||
|
||||
### 13.4 Légende des statuts
|
||||
### 8.4 Légende des statuts
|
||||
|
||||
| Symbole | Signification |
|
||||
|---------|---------------|
|
||||
| ✅ | COMPLÉTÉ |
|
||||
| 🟡 | EN COURS / PARTIEL |
|
||||
| 🔴 | À FAIRE |
|
||||
| 💤 | EN ATTENTE |
|
||||
|
||||
---
|
||||
|
||||
**Ce document est vivant et doit être mis à jour après chaque phase complétée. Dernière mise à jour : 26 avril 2026 — Phase 9 COMPLÉTÉE.**
|
||||
### 8.5 Plan de travail résumé (ordre d'exécution recommandé)
|
||||
|
||||
```
|
||||
Phase 10 (P0 Bloquant) ───── ✅ COMPLÉTÉ ─────
|
||||
1. Haptic feedback FAB ✅
|
||||
2. Saisie manuelle code-barres ✅
|
||||
3. Bouton Alternatives ResultScreen ✅
|
||||
4. Dashboard données réelles ✅
|
||||
5. Détection contextuelle magasin/maison ✅
|
||||
|
||||
Phase 11 (P1 Important) ──── ✅ COMPLÉTÉ ─────
|
||||
6. Stagger animations ResultScreen ✅
|
||||
7. Pré-initialisation caméra 🟡 Différé P3
|
||||
8. Transition slide-up ResultScreen ✅
|
||||
9. Vérification mode sombre ✅
|
||||
10. Validation format code-barres ✅
|
||||
|
||||
Phase 12 (P2 Play Store) ─── 🟡 PARTIEL ─────
|
||||
11. Screenshots + Feature graphic 🟡 Manuel
|
||||
12. Fiche Play Store FR/EN 🟡 Manuel (reporté)
|
||||
13. Ktlint/Detekt + CHANGELOG ✅
|
||||
14. Tests utilisateurs ✅ Plan prêt, 🟡 exécution
|
||||
15. Politique de confidentialité 🟡 À rédiger
|
||||
|
||||
─────────────────────────────────────────────
|
||||
RESTANT : 4 tâches manuelles uniquement
|
||||
→ APPLICATION PRÊTE POUR LANCEMENT PUBLIC
|
||||
─────────────────────────────────────────────
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Ce document est vivant. Dernière mise à jour : 11 mai 2026 — Toutes les phases code sont COMPLÉTÉES. Restent 4 tâches manuelles Play Store.**
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
# 🧪 Plan de tests utilisateurs — SafeBite
|
||||
|
||||
**Document de validation UX • 11 mai 2026**
|
||||
|
||||
---
|
||||
|
||||
## 1. Objectifs
|
||||
|
||||
Valider que SafeBite est :
|
||||
- **Compréhensible** : utilisateur identifie un verdict DANGER en < 2 secondes
|
||||
- **Fiable** : 10 scans d'affilée sans crash ni freeze
|
||||
- **Accessible** : utilisable par une personne daltonienne + TalkBack
|
||||
- **Résilient** : rotation écran, appel entrant, batterie faible
|
||||
|
||||
---
|
||||
|
||||
## 2. Profils testeurs requis
|
||||
|
||||
| # | Profil | Critère |
|
||||
|---|--------|---------|
|
||||
| 1 | Adulte sans allergie | Usage smartphone quotidien |
|
||||
| 2 | Adulte avec allergie(s) | Connaît ses allergènes |
|
||||
| 3 | Parent (enfant allergique) | Gère un profil famille |
|
||||
| 4 | Senior (50+) | Usage smartphone basique |
|
||||
| 5 | Daltonien (deutéranopie ou protanopie) | Distinction rouge/vert altérée |
|
||||
|
||||
---
|
||||
|
||||
## 3. Scénarios de test
|
||||
|
||||
### S1 — Premier lancement (Onboarding)
|
||||
```
|
||||
Prérequis : App fresh install
|
||||
1. Ouvrir l'application
|
||||
2. Suivre l'onboarding (prénom, allergies, objectif)
|
||||
3. Arriver sur le dashboard FIRST_TIME
|
||||
|
||||
✅ Succès si : onboarding complété en < 60 secondes
|
||||
❌ Échec si : confusion sur les étapes, blocage
|
||||
```
|
||||
|
||||
### S2 — Scan d'un produit dangereux (test principal)
|
||||
```
|
||||
Prérequis : Profil configuré avec allergie "Arachides"
|
||||
Produit : Snickers (contient arachides) — code 5000159461153
|
||||
|
||||
1. Depuis le dashboard, tap sur FAB Scanner
|
||||
2. Scanner le code-barres Snickers
|
||||
3. Observer le verdict
|
||||
|
||||
✅ Succès si : verdict ROUGE identifié en < 2s
|
||||
❌ Échec si : confusion sur le verdict (ne sait pas si c'est safe ou pas)
|
||||
```
|
||||
|
||||
### S3 — Scan d'un produit safe
|
||||
```
|
||||
Produit : Bouteille d'eau — code 3274080005007
|
||||
|
||||
1. Scanner le code-barres
|
||||
2. Observer le verdict VERT
|
||||
|
||||
✅ Succès si : verdict SAFE clairement identifié
|
||||
❌ Échec si : confusion avec warning
|
||||
```
|
||||
|
||||
### S4 — Saisie manuelle code-barres
|
||||
```
|
||||
Prérequis : Produit non reconnu par le scanner
|
||||
|
||||
1. Ouvrir le scanner
|
||||
2. Tap "Saisir un code-barres"
|
||||
3. Entrer 3017620422003 (Nutella)
|
||||
4. Valider
|
||||
|
||||
✅ Succès si : résultat affiché (verdict + fiche produit)
|
||||
❌ Échec si : erreur de format, blocage
|
||||
```
|
||||
|
||||
### S5 — Scan OCR (produit non trouvé)
|
||||
```
|
||||
Prérequis : Code-barres inconnu (ex: 1234567890123)
|
||||
|
||||
1. Scanner le code inconnu
|
||||
2. Tap "Lire les ingrédients"
|
||||
3. Prendre une photo d'étiquette
|
||||
4. Vérifier le texte OCR extrait
|
||||
|
||||
✅ Succès si : OCR capture ouverte, photo possible
|
||||
❌ Échec si : app crash, freeze
|
||||
```
|
||||
|
||||
### S6 — Gestion de liste
|
||||
```
|
||||
Prérequis : Au moins 1 produit scanné
|
||||
|
||||
1. Aller dans l'onglet Listes
|
||||
2. Créer une liste "Test courses"
|
||||
3. Ajouter un produit depuis le verdict
|
||||
4. Swiper pour cocher/décocher
|
||||
5. Supprimer un produit (swipe left)
|
||||
|
||||
✅ Succès si : toutes les actions fonctionnent
|
||||
❌ Échec si : swipe bloqué, produit non ajouté
|
||||
```
|
||||
|
||||
### S7 — 10 scans rapides d'affilée
|
||||
```
|
||||
Prérequis : App ouverte
|
||||
|
||||
1. Scanner 10 produits différents aussi vite que possible
|
||||
2. Observer le comportement
|
||||
|
||||
✅ Succès si : 0 crash, 0 freeze > 5s
|
||||
❌ Échec si : crash, ANR, perte de données
|
||||
```
|
||||
|
||||
### S8 — Rotation écran pendant scan
|
||||
```
|
||||
1. Ouvrir le scanner
|
||||
2. Pivoter le téléphone (paysage → portrait)
|
||||
3. Scanner un produit
|
||||
4. Pivoter pendant l'affichage du verdict
|
||||
|
||||
✅ Succès si : pas de perte d'état, scan fonctionne après rotation
|
||||
❌ Échec si : caméra freeze, UI cassée
|
||||
```
|
||||
|
||||
### S9 — Appel entrant pendant le scan
|
||||
```
|
||||
1. Ouvrir le scanner
|
||||
2. Recevoir un appel (ou simuler avec un second téléphone)
|
||||
3. Revenir dans l'app après l'appel
|
||||
|
||||
✅ Succès si : le scanner se réinitialise et fonctionne
|
||||
❌ Échec si : caméra bloquée, crash
|
||||
```
|
||||
|
||||
### S10 — Mode sombre
|
||||
```
|
||||
1. Activer le mode sombre (paramètres)
|
||||
2. Visiter les 4 onglets (Dashboard, Listes, Suivi, Famille)
|
||||
3. Scanner un produit et vérifier le verdict
|
||||
|
||||
✅ Succès si : tout est lisible, contraste OK
|
||||
❌ Échec si : texte illisible, icônes invisibles
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Test Accessibilité
|
||||
|
||||
### A1 — TalkBack
|
||||
```
|
||||
1. Activer TalkBack dans Paramètres Android
|
||||
2. Naviguer dans tous les onglets
|
||||
3. Scanner un produit et écouter l'annonce du verdict
|
||||
|
||||
✅ Succès si : tous les boutons annoncés, verdict annoncé correctement
|
||||
❌ Échec si : éléments sans contentDescription, verdict silencieux
|
||||
```
|
||||
|
||||
### A2 — Taille de texte maximale
|
||||
```
|
||||
1. Paramètres → Affichage → Taille police → Maximum
|
||||
2. Naviguer dans tous les écrans
|
||||
|
||||
✅ Succès si : pas de texte coupé, pas de chevauchement
|
||||
❌ Échec si : boutons hors écran, texte tronqué
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Grille d'observation
|
||||
|
||||
| Testeur | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | A1 | A2 | Notes |
|
||||
|---------|----|----|----|----|----|----|----|----|----|-----|----|----|-------|
|
||||
| #1 | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | |
|
||||
| #2 | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | |
|
||||
| #3 | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | |
|
||||
| #4 | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | |
|
||||
| #5 | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | |
|
||||
|
||||
Légende : ✅ OK | ⚠️ Mineur | ❌ Bloquant
|
||||
|
||||
---
|
||||
|
||||
## 6. Produits de test recommandés
|
||||
|
||||
| Produit | Code-barres | Allergène connu |
|
||||
|---------|-------------|-----------------|
|
||||
| Snickers | 5000159461153 | Arachides, Lait |
|
||||
| Nutella | 3017620422003 | Noisettes, Lait |
|
||||
| Bouteille d'eau Cristaline | 3274080005007 | Aucun |
|
||||
| Barre Kinder | 8000500310427 | Lait, Gluten |
|
||||
| Sauce Soja Kikkoman | 8715035111108 | Soja, Gluten |
|
||||
|
||||
---
|
||||
|
||||
## 7. Rapport final
|
||||
|
||||
Une fois les tests complétés, remplir :
|
||||
|
||||
| Métrique | Cible | Résultat |
|
||||
|----------|-------|----------|
|
||||
| Temps identification verdict danger | < 2s | ___ |
|
||||
| Crashs sur 10 scans | 0 | ___ |
|
||||
| Score accessibilité TalkBack | 100% | ___ |
|
||||
| Bugs bloquants découverts | 0 | ___ |
|
||||
| Satisfaction globale (1-5) | ≥ 4 | ___ |
|
||||
Reference in New Issue
Block a user