- 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.
557 lines
30 KiB
Markdown
557 lines
30 KiB
Markdown
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
|
||
-------------------------
|