feat: add custom emoji field to shopping list items, expand catalog with 200+ items across 12 categories, and implement icon picker in item detail sheet
- Add `customEmoji` field to `ShoppingListItemEntity` for user-selected icons - Increment database version to 4 - Reorganize catalog categories: add "Condiments & Épices", "Snacks & Bonbons", "Maison & Jardin" - Expand catalog from ~50 to 200+ items with comprehensive product coverage across all categories - Add detail tags (Urgent, Offre, Quand cela convient) and
This commit is contained in:
parent
a9eb582c93
commit
b68212b99c
@ -21,7 +21,7 @@ import com.safebite.app.data.local.database.entity.UserProfileEntity
|
||||
ShoppingListEntity::class,
|
||||
ShoppingListItemEntity::class
|
||||
],
|
||||
version = 3,
|
||||
version = 4,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
|
||||
@ -98,5 +98,6 @@ data class ShoppingListItemEntity(
|
||||
val safetyStatus: String? = null, // "SAFE", "WARNING", "DANGER"
|
||||
val allergenWarning: String? = null, // Allergène détecté pour alerte
|
||||
val note: String? = null, // Quantité / description libre (ex: "2 kg")
|
||||
val customEmoji: String? = null, // Emoji personnalisé choisi par l'utilisateur
|
||||
val addedAt: Long = System.currentTimeMillis()
|
||||
)
|
||||
|
||||
@ -36,12 +36,15 @@ class CatalogProvider @Inject constructor() {
|
||||
"Produits laitiers",
|
||||
"Boucherie",
|
||||
"Épicerie",
|
||||
"Boissons",
|
||||
"Condiments & Épices",
|
||||
"Surgelés",
|
||||
"Snacks & Bonbons",
|
||||
"Boissons",
|
||||
"Hygiène",
|
||||
"Entretien",
|
||||
"Bébé",
|
||||
"Animaux"
|
||||
"Animaux",
|
||||
"Maison & Jardin"
|
||||
)
|
||||
|
||||
/** Liste plate du catalogue. */
|
||||
@ -66,6 +69,41 @@ class CatalogProvider @Inject constructor() {
|
||||
add(CatalogItem("Pomme de terre", "Fruits & Légumes", "🥔", listOf("patate")))
|
||||
add(CatalogItem("Champignon", "Fruits & Légumes", "🍄"))
|
||||
add(CatalogItem("Épinard", "Fruits & Légumes", "🥬"))
|
||||
add(CatalogItem("Ananas", "Fruits & Légumes", "🍍"))
|
||||
add(CatalogItem("Pêche", "Fruits & Légumes", "🍑"))
|
||||
add(CatalogItem("Cerise", "Fruits & Légumes", "🍒"))
|
||||
add(CatalogItem("Kiwi", "Fruits & Légumes", "🥝"))
|
||||
add(CatalogItem("Mangue", "Fruits & Légumes", "🥭"))
|
||||
add(CatalogItem("Melon", "Fruits & Légumes", "🍈"))
|
||||
add(CatalogItem("Pastèque", "Fruits & Légumes", "🍉"))
|
||||
add(CatalogItem("Noix de coco", "Fruits & Légumes", "🥥"))
|
||||
add(CatalogItem("Aubergine", "Fruits & Légumes", "🍆"))
|
||||
add(CatalogItem("Maïs", "Fruits & Légumes", "🌽"))
|
||||
add(CatalogItem("Piment", "Fruits & Légumes", "🌶️"))
|
||||
add(CatalogItem("Courgette", "Fruits & Légumes", "🥒"))
|
||||
add(CatalogItem("Chou-fleur", "Fruits & Légumes", "🥦"))
|
||||
add(CatalogItem("Chou", "Fruits & Légumes", "🥬"))
|
||||
add(CatalogItem("Betterave", "Fruits & Légumes", "🫐"))
|
||||
add(CatalogItem("Radis", "Fruits & Légumes", "🥕"))
|
||||
add(CatalogItem("Navet", "Fruits & Légumes", "🥕"))
|
||||
add(CatalogItem("Poireau", "Fruits & Légumes", "🥬"))
|
||||
add(CatalogItem("Céleri", "Fruits & Légumes", "🥬"))
|
||||
add(CatalogItem("Haricots verts", "Fruits & Légumes", "🫛"))
|
||||
add(CatalogItem("Petits pois", "Fruits & Légumes", "🫛"))
|
||||
add(CatalogItem("Artichaut", "Fruits & Légumes", "🥬"))
|
||||
add(CatalogItem("Asperge", "Fruits & Légumes", "🥬"))
|
||||
add(CatalogItem("Basilic", "Fruits & Légumes", "🌿"))
|
||||
add(CatalogItem("Persil", "Fruits & Légumes", "🌿"))
|
||||
add(CatalogItem("Coriandre", "Fruits & Légumes", "🌿"))
|
||||
add(CatalogItem("Menthe", "Fruits & Légumes", "🌿"))
|
||||
add(CatalogItem("Myrtilles", "Fruits & Légumes", "🫐"))
|
||||
add(CatalogItem("Framboises", "Fruits & Légumes", "🍓"))
|
||||
add(CatalogItem("Mûres", "Fruits & Légumes", "🫐"))
|
||||
add(CatalogItem("Abricot", "Fruits & Légumes", "🍑"))
|
||||
add(CatalogItem("Prune", "Fruits & Légumes", "🍑"))
|
||||
add(CatalogItem("Figue", "Fruits & Légumes", "🍇"))
|
||||
add(CatalogItem("Datte", "Fruits & Légumes", "🍇"))
|
||||
add(CatalogItem("Grenade", "Fruits & Légumes", "🍎"))
|
||||
|
||||
// Boulangerie
|
||||
add(CatalogItem("Pain", "Boulangerie", "🍞", listOf("baguette")))
|
||||
@ -75,16 +113,44 @@ class CatalogProvider @Inject constructor() {
|
||||
add(CatalogItem("Pain de mie", "Boulangerie", "🍞"))
|
||||
add(CatalogItem("Biscotte", "Boulangerie", "🍞"))
|
||||
add(CatalogItem("Tortillas", "Boulangerie", "🌯"))
|
||||
add(CatalogItem("Pain complet", "Boulangerie", "🍞"))
|
||||
add(CatalogItem("Pain aux céréales", "Boulangerie", "🍞"))
|
||||
add(CatalogItem("Pain de seigle", "Boulangerie", "🍞"))
|
||||
add(CatalogItem("Bagel", "Boulangerie", "🥯"))
|
||||
add(CatalogItem("Muffin", "Boulangerie", "🧁"))
|
||||
add(CatalogItem("Donut", "Boulangerie", "🍩"))
|
||||
add(CatalogItem("Pain au chocolat", "Boulangerie", "🥐"))
|
||||
add(CatalogItem("Chausson aux pommes", "Boulangerie", "🥐"))
|
||||
add(CatalogItem("Éclair", "Boulangerie", "🍰"))
|
||||
add(CatalogItem("Tarte", "Boulangerie", "🥧"))
|
||||
add(CatalogItem("Gâteau", "Boulangerie", "🍰"))
|
||||
|
||||
// Produits laitiers
|
||||
add(CatalogItem("Lait", "Produits laitiers", "🥛", listOf("milk")))
|
||||
add(CatalogItem("Yaourt", "Produits laitiers", "🥣", listOf("yogurt")))
|
||||
add(CatalogItem("Beurre", "Produits laitiers", "🧈"))
|
||||
add(CatalogItem("Fromage", "Produits laitiers", "🧀", listOf("cheese")))
|
||||
add(CatalogItem("Crème", "Produits laitiers", "🥛"))
|
||||
add(CatalogItem("Crème fraîche", "Produits laitiers", "🥛"))
|
||||
add(CatalogItem("Œufs", "Produits laitiers", "🥚", listOf("oeufs", "eggs")))
|
||||
add(CatalogItem("Mozzarella", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Parmesan", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Cheddar", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Emmental", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Camembert", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Brie", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Chèvre", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Roquefort", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Gorgonzola", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Feta", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Ricotta", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Mascarpone", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Fromage blanc", "Produits laitiers", "🥛"))
|
||||
add(CatalogItem("Cottage cheese", "Produits laitiers", "🧀"))
|
||||
add(CatalogItem("Crème liquide", "Produits laitiers", "🥛"))
|
||||
add(CatalogItem("Lait concentré", "Produits laitiers", "🥛"))
|
||||
add(CatalogItem("Lait de soja", "Produits laitiers", "🥛"))
|
||||
add(CatalogItem("Lait d'amande", "Produits laitiers", "🥛"))
|
||||
add(CatalogItem("Margarine", "Produits laitiers", "🧈"))
|
||||
|
||||
// Boucherie
|
||||
add(CatalogItem("Poulet", "Boucherie", "🍗"))
|
||||
@ -96,6 +162,27 @@ class CatalogProvider @Inject constructor() {
|
||||
add(CatalogItem("Bacon", "Boucherie", "🥓"))
|
||||
add(CatalogItem("Saumon", "Boucherie", "🐟"))
|
||||
add(CatalogItem("Thon", "Boucherie", "🐟"))
|
||||
add(CatalogItem("Dinde", "Boucherie", "🦃"))
|
||||
add(CatalogItem("Canard", "Boucherie", "🦆"))
|
||||
add(CatalogItem("Agneau", "Boucherie", "🥩"))
|
||||
add(CatalogItem("Veau", "Boucherie", "🥩"))
|
||||
add(CatalogItem("Côtelette", "Boucherie", "🥩"))
|
||||
add(CatalogItem("Rôti", "Boucherie", "🥩"))
|
||||
add(CatalogItem("Merguez", "Boucherie", "🌭"))
|
||||
add(CatalogItem("Chorizo", "Boucherie", "🌭"))
|
||||
add(CatalogItem("Salami", "Boucherie", "🥓"))
|
||||
add(CatalogItem("Saucisson", "Boucherie", "🥓"))
|
||||
add(CatalogItem("Pâté", "Boucherie", "🥓"))
|
||||
add(CatalogItem("Truite", "Boucherie", "🐟"))
|
||||
add(CatalogItem("Cabillaud", "Boucherie", "🐟"))
|
||||
add(CatalogItem("Dorade", "Boucherie", "🐟"))
|
||||
add(CatalogItem("Bar", "Boucherie", "🐟"))
|
||||
add(CatalogItem("Crevettes", "Boucherie", "🦐"))
|
||||
add(CatalogItem("Moules", "Boucherie", "🦪"))
|
||||
add(CatalogItem("Huîtres", "Boucherie", "🦪"))
|
||||
add(CatalogItem("Calamar", "Boucherie", "🦑"))
|
||||
add(CatalogItem("Crabe", "Boucherie", "🦀"))
|
||||
add(CatalogItem("Homard", "Boucherie", "🦞"))
|
||||
|
||||
// Épicerie
|
||||
add(CatalogItem("Riz", "Épicerie", "🍚"))
|
||||
@ -104,11 +191,9 @@ class CatalogProvider @Inject constructor() {
|
||||
add(CatalogItem("Farine", "Épicerie", "🌾"))
|
||||
add(CatalogItem("Sucre", "Épicerie", "🍬"))
|
||||
add(CatalogItem("Sel", "Épicerie", "🧂"))
|
||||
add(CatalogItem("Huile", "Épicerie", "🫒"))
|
||||
add(CatalogItem("Huile d'olive", "Épicerie", "🫒"))
|
||||
add(CatalogItem("Vinaigre", "Épicerie", "🧴"))
|
||||
add(CatalogItem("Moutarde", "Épicerie", "🟡"))
|
||||
add(CatalogItem("Ketchup", "Épicerie", "🍅"))
|
||||
add(CatalogItem("Mayonnaise", "Épicerie", "🥚"))
|
||||
add(CatalogItem("Confiture", "Épicerie", "🍓"))
|
||||
add(CatalogItem("Miel", "Épicerie", "🍯"))
|
||||
add(CatalogItem("Chocolat", "Épicerie", "🍫"))
|
||||
@ -116,18 +201,56 @@ class CatalogProvider @Inject constructor() {
|
||||
add(CatalogItem("Céréales", "Épicerie", "🥣", listOf("muesli")))
|
||||
add(CatalogItem("Lentilles", "Épicerie", "🫘"))
|
||||
add(CatalogItem("Pois chiches", "Épicerie", "🫘"))
|
||||
add(CatalogItem("Haricots rouges", "Épicerie", "🫘"))
|
||||
add(CatalogItem("Haricots blancs", "Épicerie", "🫘"))
|
||||
add(CatalogItem("Conserves", "Épicerie", "🥫"))
|
||||
add(CatalogItem("Soupe", "Épicerie", "🍲"))
|
||||
add(CatalogItem("Riz basmati", "Épicerie", "🍚"))
|
||||
add(CatalogItem("Quinoa", "Épicerie", "🍚"))
|
||||
add(CatalogItem("Couscous", "Épicerie", "🍚"))
|
||||
add(CatalogItem("Boulgour", "Épicerie", "🍚"))
|
||||
add(CatalogItem("Polenta", "Épicerie", "🌽"))
|
||||
add(CatalogItem("Flocons d'avoine", "Épicerie", "🥣"))
|
||||
add(CatalogItem("Muesli", "Épicerie", "🥣"))
|
||||
add(CatalogItem("Granola", "Épicerie", "🥣"))
|
||||
add(CatalogItem("Pâte à tartiner", "Épicerie", "🍫"))
|
||||
add(CatalogItem("Beurre de cacahuète", "Épicerie", "🥜"))
|
||||
add(CatalogItem("Sirop d'érable", "Épicerie", "🍯"))
|
||||
add(CatalogItem("Levure", "Épicerie", "🧂"))
|
||||
add(CatalogItem("Bicarbonate", "Épicerie", "🧂"))
|
||||
add(CatalogItem("Sucre vanillé", "Épicerie", "🍬"))
|
||||
add(CatalogItem("Cacao", "Épicerie", "🍫"))
|
||||
add(CatalogItem("Thon en boîte", "Épicerie", "🥫"))
|
||||
add(CatalogItem("Sardines", "Épicerie", "🥫"))
|
||||
add(CatalogItem("Maquereau", "Épicerie", "🥫"))
|
||||
add(CatalogItem("Sauce tomate", "Épicerie", "🍅"))
|
||||
add(CatalogItem("Concentré de tomate", "Épicerie", "🍅"))
|
||||
add(CatalogItem("Tomates pelées", "Épicerie", "🥫"))
|
||||
|
||||
// Boissons
|
||||
add(CatalogItem("Eau", "Boissons", "💧"))
|
||||
add(CatalogItem("Jus d'orange", "Boissons", "🧃"))
|
||||
add(CatalogItem("Café", "Boissons", "☕"))
|
||||
add(CatalogItem("Thé", "Boissons", "🍵"))
|
||||
add(CatalogItem("Vin", "Boissons", "🍷"))
|
||||
add(CatalogItem("Bière", "Boissons", "🍺"))
|
||||
add(CatalogItem("Soda", "Boissons", "🥤"))
|
||||
add(CatalogItem("Limonade", "Boissons", "🍋"))
|
||||
// Condiments & Épices
|
||||
add(CatalogItem("Moutarde", "Condiments & Épices", "🟡"))
|
||||
add(CatalogItem("Ketchup", "Condiments & Épices", "🍅"))
|
||||
add(CatalogItem("Mayonnaise", "Condiments & Épices", "🥚"))
|
||||
add(CatalogItem("Poivre", "Condiments & Épices", "🧂"))
|
||||
add(CatalogItem("Paprika", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Curry", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Cumin", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Curcuma", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Gingembre", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Cannelle", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Muscade", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Thym", "Condiments & Épices", "🌿"))
|
||||
add(CatalogItem("Romarin", "Condiments & Épices", "🌿"))
|
||||
add(CatalogItem("Origan", "Condiments & Épices", "🌿"))
|
||||
add(CatalogItem("Laurier", "Condiments & Épices", "🌿"))
|
||||
add(CatalogItem("Herbes de Provence", "Condiments & Épices", "🌿"))
|
||||
add(CatalogItem("Sauce soja", "Condiments & Épices", "🧴"))
|
||||
add(CatalogItem("Vinaigre balsamique", "Condiments & Épices", "🧴"))
|
||||
add(CatalogItem("Tabasco", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Harissa", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Wasabi", "Condiments & Épices", "🌶️"))
|
||||
add(CatalogItem("Pesto", "Condiments & Épices", "🌿"))
|
||||
add(CatalogItem("Tapenade", "Condiments & Épices", "🫒"))
|
||||
|
||||
// Surgelés
|
||||
add(CatalogItem("Pizza surgelée", "Surgelés", "🍕"))
|
||||
@ -135,33 +258,142 @@ class CatalogProvider @Inject constructor() {
|
||||
add(CatalogItem("Glace", "Surgelés", "🍨"))
|
||||
add(CatalogItem("Légumes surgelés", "Surgelés", "🥦"))
|
||||
add(CatalogItem("Poisson surgelé", "Surgelés", "🐟"))
|
||||
add(CatalogItem("Crevettes surgelées", "Surgelés", "🦐"))
|
||||
add(CatalogItem("Fruits surgelés", "Surgelés", "🍓"))
|
||||
add(CatalogItem("Plat préparé", "Surgelés", "🍱"))
|
||||
add(CatalogItem("Lasagnes", "Surgelés", "🍝"))
|
||||
add(CatalogItem("Nuggets", "Surgelés", "🍗"))
|
||||
add(CatalogItem("Poisson pané", "Surgelés", "🐟"))
|
||||
add(CatalogItem("Sorbet", "Surgelés", "🍧"))
|
||||
add(CatalogItem("Gâteau glacé", "Surgelés", "🍰"))
|
||||
|
||||
// Snacks & Bonbons
|
||||
add(CatalogItem("Chips", "Snacks & Bonbons", "🥔"))
|
||||
add(CatalogItem("Cacahuètes", "Snacks & Bonbons", "🥜"))
|
||||
add(CatalogItem("Noix", "Snacks & Bonbons", "🌰"))
|
||||
add(CatalogItem("Amandes", "Snacks & Bonbons", "🌰"))
|
||||
add(CatalogItem("Noisettes", "Snacks & Bonbons", "🌰"))
|
||||
add(CatalogItem("Pistaches", "Snacks & Bonbons", "🥜"))
|
||||
add(CatalogItem("Noix de cajou", "Snacks & Bonbons", "🥜"))
|
||||
add(CatalogItem("Pop-corn", "Snacks & Bonbons", "🍿"))
|
||||
add(CatalogItem("Bonbons", "Snacks & Bonbons", "🍬"))
|
||||
add(CatalogItem("Chewing-gum", "Snacks & Bonbons", "🍬"))
|
||||
add(CatalogItem("Chocolat noir", "Snacks & Bonbons", "🍫"))
|
||||
add(CatalogItem("Chocolat au lait", "Snacks & Bonbons", "🍫"))
|
||||
add(CatalogItem("Barres chocolatées", "Snacks & Bonbons", "🍫"))
|
||||
add(CatalogItem("Barres de céréales", "Snacks & Bonbons", "🥣"))
|
||||
add(CatalogItem("Fruits secs", "Snacks & Bonbons", "🍇"))
|
||||
add(CatalogItem("Raisins secs", "Snacks & Bonbons", "🍇"))
|
||||
|
||||
// Boissons
|
||||
add(CatalogItem("Eau", "Boissons", "💧"))
|
||||
add(CatalogItem("Eau gazeuse", "Boissons", "💧"))
|
||||
add(CatalogItem("Jus d'orange", "Boissons", "🧃"))
|
||||
add(CatalogItem("Jus de pomme", "Boissons", "🧃"))
|
||||
add(CatalogItem("Jus de raisin", "Boissons", "🧃"))
|
||||
add(CatalogItem("Jus multivitaminé", "Boissons", "🧃"))
|
||||
add(CatalogItem("Café", "Boissons", "☕"))
|
||||
add(CatalogItem("Café moulu", "Boissons", "☕"))
|
||||
add(CatalogItem("Café en grains", "Boissons", "☕"))
|
||||
add(CatalogItem("Café soluble", "Boissons", "☕"))
|
||||
add(CatalogItem("Thé", "Boissons", "🍵"))
|
||||
add(CatalogItem("Thé vert", "Boissons", "🍵"))
|
||||
add(CatalogItem("Thé noir", "Boissons", "🍵"))
|
||||
add(CatalogItem("Infusion", "Boissons", "🍵"))
|
||||
add(CatalogItem("Chocolat chaud", "Boissons", "☕"))
|
||||
add(CatalogItem("Vin rouge", "Boissons", "🍷"))
|
||||
add(CatalogItem("Vin blanc", "Boissons", "🍷"))
|
||||
add(CatalogItem("Vin rosé", "Boissons", "🍷"))
|
||||
add(CatalogItem("Champagne", "Boissons", "🍾"))
|
||||
add(CatalogItem("Bière", "Boissons", "🍺"))
|
||||
add(CatalogItem("Bière blonde", "Boissons", "🍺"))
|
||||
add(CatalogItem("Bière brune", "Boissons", "🍺"))
|
||||
add(CatalogItem("Cidre", "Boissons", "🍺"))
|
||||
add(CatalogItem("Soda", "Boissons", "🥤"))
|
||||
add(CatalogItem("Cola", "Boissons", "🥤"))
|
||||
add(CatalogItem("Limonade", "Boissons", "🍋"))
|
||||
add(CatalogItem("Orangina", "Boissons", "🍊"))
|
||||
add(CatalogItem("Sirop", "Boissons", "🧃"))
|
||||
add(CatalogItem("Smoothie", "Boissons", "🥤"))
|
||||
add(CatalogItem("Boisson énergisante", "Boissons", "🥤"))
|
||||
|
||||
// Hygiène
|
||||
add(CatalogItem("Papier toilette", "Hygiène", "🧻", listOf("toilet paper")))
|
||||
add(CatalogItem("Mouchoirs", "Hygiène", "🤧"))
|
||||
add(CatalogItem("Dentifrice", "Hygiène", "🦷"))
|
||||
add(CatalogItem("Brosse à dents", "Hygiène", "🪥"))
|
||||
add(CatalogItem("Fil dentaire", "Hygiène", "🦷"))
|
||||
add(CatalogItem("Bain de bouche", "Hygiène", "🦷"))
|
||||
add(CatalogItem("Shampoing", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Après-shampoing", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Savon", "Hygiène", "🧼"))
|
||||
add(CatalogItem("Gel douche", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Déodorant", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Parfum", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Crème hydratante", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Crème solaire", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Rasoir", "Hygiène", "🪒"))
|
||||
add(CatalogItem("Mousse à raser", "Hygiène", "🧴"))
|
||||
add(CatalogItem("Coton-tige", "Hygiène", "🧻"))
|
||||
add(CatalogItem("Coton", "Hygiène", "🧻"))
|
||||
add(CatalogItem("Serviettes hygiéniques", "Hygiène", "🧻"))
|
||||
add(CatalogItem("Tampons", "Hygiène", "🧻"))
|
||||
|
||||
// Entretien
|
||||
add(CatalogItem("Lessive", "Entretien", "🧺"))
|
||||
add(CatalogItem("Adoucissant", "Entretien", "🧴"))
|
||||
add(CatalogItem("Liquide vaisselle", "Entretien", "🧴"))
|
||||
add(CatalogItem("Tablettes lave-vaisselle", "Entretien", "🧴"))
|
||||
add(CatalogItem("Éponge", "Entretien", "🧽"))
|
||||
add(CatalogItem("Javel", "Entretien", "🧴"))
|
||||
add(CatalogItem("Nettoyant multi-usage", "Entretien", "🧴"))
|
||||
add(CatalogItem("Nettoyant vitres", "Entretien", "🧴"))
|
||||
add(CatalogItem("Nettoyant sol", "Entretien", "🧴"))
|
||||
add(CatalogItem("Nettoyant WC", "Entretien", "🧴"))
|
||||
add(CatalogItem("Sacs poubelle", "Entretien", "🗑️"))
|
||||
add(CatalogItem("Essuie-tout", "Entretien", "🧻"))
|
||||
add(CatalogItem("Serpillière", "Entretien", "🧹"))
|
||||
add(CatalogItem("Balai", "Entretien", "🧹"))
|
||||
add(CatalogItem("Pelle", "Entretien", "🧹"))
|
||||
|
||||
// Bébé
|
||||
add(CatalogItem("Couches", "Bébé", "👶"))
|
||||
add(CatalogItem("Lait infantile", "Bébé", "🍼"))
|
||||
add(CatalogItem("Compote bébé", "Bébé", "🍎"))
|
||||
add(CatalogItem("Lingettes bébé", "Bébé", "🧻"))
|
||||
add(CatalogItem("Petits pots", "Bébé", "🍼"))
|
||||
add(CatalogItem("Céréales bébé", "Bébé", "🥣"))
|
||||
add(CatalogItem("Biscuits bébé", "Bébé", "🍪"))
|
||||
add(CatalogItem("Biberon", "Bébé", "🍼"))
|
||||
add(CatalogItem("Tétine", "Bébé", "🍼"))
|
||||
add(CatalogItem("Crème pour le change", "Bébé", "🧴"))
|
||||
add(CatalogItem("Savon bébé", "Bébé", "🧼"))
|
||||
add(CatalogItem("Shampoing bébé", "Bébé", "🧴"))
|
||||
|
||||
// Animaux
|
||||
add(CatalogItem("Croquettes chien", "Animaux", "🐶"))
|
||||
add(CatalogItem("Croquettes chat", "Animaux", "🐱"))
|
||||
add(CatalogItem("Pâtée chien", "Animaux", "🐶"))
|
||||
add(CatalogItem("Pâtée chat", "Animaux", "🐈"))
|
||||
add(CatalogItem("Friandises chien", "Animaux", "🦴"))
|
||||
add(CatalogItem("Friandises chat", "Animaux", "🐟"))
|
||||
add(CatalogItem("Litière", "Animaux", "🐈"))
|
||||
add(CatalogItem("Jouets pour animaux", "Animaux", "🎾"))
|
||||
add(CatalogItem("Shampoing animal", "Animaux", "🧴"))
|
||||
|
||||
// Maison & Jardin
|
||||
add(CatalogItem("Ampoules", "Maison & Jardin", "💡"))
|
||||
add(CatalogItem("Piles", "Maison & Jardin", "🔋"))
|
||||
add(CatalogItem("Allumettes", "Maison & Jardin", "🔥"))
|
||||
add(CatalogItem("Bougies", "Maison & Jardin", "🕯️"))
|
||||
add(CatalogItem("Papier aluminium", "Maison & Jardin", "📦"))
|
||||
add(CatalogItem("Film alimentaire", "Maison & Jardin", "📦"))
|
||||
add(CatalogItem("Papier cuisson", "Maison & Jardin", "📦"))
|
||||
add(CatalogItem("Sacs congélation", "Maison & Jardin", "📦"))
|
||||
add(CatalogItem("Terreau", "Maison & Jardin", "🌱"))
|
||||
add(CatalogItem("Engrais", "Maison & Jardin", "🌱"))
|
||||
add(CatalogItem("Graines", "Maison & Jardin", "🌱"))
|
||||
add(CatalogItem("Pots de fleurs", "Maison & Jardin", "🪴"))
|
||||
}
|
||||
|
||||
/** Items pour une catégorie donnée (ordre catalogue). */
|
||||
@ -211,12 +443,15 @@ class CatalogProvider @Inject constructor() {
|
||||
"Produits laitiers" -> "🥛"
|
||||
"Boucherie" -> "🥩"
|
||||
"Épicerie" -> "🛒"
|
||||
"Boissons" -> "🥤"
|
||||
"Condiments & Épices" -> "🌶️"
|
||||
"Surgelés" -> "🧊"
|
||||
"Snacks & Bonbons" -> "🍿"
|
||||
"Boissons" -> "🥤"
|
||||
"Hygiène" -> "🧴"
|
||||
"Entretien" -> "🧹"
|
||||
"Bébé" -> "👶"
|
||||
"Animaux" -> "🐾"
|
||||
"Maison & Jardin" -> "🏡"
|
||||
else -> "📦"
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,324 @@
|
||||
package com.safebite.app.presentation.screen.lists
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateMapOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.safebite.app.domain.engine.CatalogProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun IconPickerSheet(
|
||||
currentEmoji: String,
|
||||
categories: List<String>,
|
||||
onDismiss: () -> Unit,
|
||||
onSelectIcon: (String) -> Unit,
|
||||
catalogProvider: CatalogProvider = hiltViewModel<ListDetailViewModel>().catalog
|
||||
) {
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
val expandedCategories = remember { mutableStateMapOf<String, Boolean>() }
|
||||
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = sheetState
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.navigationBarsPadding()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
// Header
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
IconButton(onClick = onDismiss) {
|
||||
Icon(Icons.Filled.Close, contentDescription = "Fermer")
|
||||
}
|
||||
Text(
|
||||
text = "Choisir une icône",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
IconButton(onClick = { onSelectIcon("") }) {
|
||||
Icon(
|
||||
Icons.Filled.Delete,
|
||||
contentDescription = "Supprimer l'icône",
|
||||
tint = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Current icon display
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 12.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(120.dp)
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.primaryContainer),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = currentEmoji,
|
||||
style = MaterialTheme.typography.displayLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Search bar
|
||||
OutlinedTextField(
|
||||
value = searchQuery,
|
||||
onValueChange = { searchQuery = it },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 12.dp),
|
||||
placeholder = { Text("Chercher une icône") },
|
||||
leadingIcon = {
|
||||
Icon(Icons.Filled.Search, contentDescription = null)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (searchQuery.isNotEmpty()) {
|
||||
IconButton(onClick = { searchQuery = "" }) {
|
||||
Icon(Icons.Filled.Close, contentDescription = "Effacer")
|
||||
}
|
||||
}
|
||||
},
|
||||
singleLine = true,
|
||||
shape = RoundedCornerShape(28.dp)
|
||||
)
|
||||
|
||||
// Icon grid by category
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
categories.forEach { category ->
|
||||
val categoryItems = catalogProvider.itemsForCategory(category)
|
||||
val filteredItems = if (searchQuery.isNotBlank()) {
|
||||
categoryItems.filter {
|
||||
it.name.contains(searchQuery, ignoreCase = true)
|
||||
}
|
||||
} else {
|
||||
categoryItems
|
||||
}
|
||||
|
||||
if (filteredItems.isNotEmpty()) {
|
||||
val expanded = expandedCategories[category] ?: (searchQuery.isNotBlank())
|
||||
|
||||
item(key = "header-$category") {
|
||||
CategoryHeader(
|
||||
title = category,
|
||||
count = filteredItems.size,
|
||||
expanded = expanded,
|
||||
onToggle = {
|
||||
expandedCategories[category] = !expanded
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (expanded) {
|
||||
item(key = "grid-$category") {
|
||||
IconGrid(
|
||||
items = filteredItems,
|
||||
currentEmoji = currentEmoji,
|
||||
onSelectIcon = onSelectIcon
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CategoryHeader(
|
||||
title: String,
|
||||
count: Int,
|
||||
expanded: Boolean,
|
||||
onToggle: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.clickable(onClick = onToggle)
|
||||
.padding(vertical = 12.dp, horizontal = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.KeyboardArrowRight,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.rotate(if (expanded) 90f else 0f),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Filled.KeyboardArrowDown,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IconGrid(
|
||||
items: List<CatalogProvider.CatalogItem>,
|
||||
currentEmoji: String,
|
||||
onSelectIcon: (String) -> Unit
|
||||
) {
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(3),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(((items.size + 2) / 3 * 100).dp.coerceAtMost(400.dp)),
|
||||
contentPadding = PaddingValues(4.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
items(items) { item ->
|
||||
IconCard(
|
||||
emoji = item.emoji,
|
||||
label = item.name,
|
||||
isSelected = item.emoji == currentEmoji,
|
||||
onClick = { onSelectIcon(item.emoji) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IconCard(
|
||||
emoji: String,
|
||||
label: String,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val backgroundColor = if (isSelected) {
|
||||
MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surfaceVariant
|
||||
}
|
||||
val contentColor = if (isSelected) {
|
||||
MaterialTheme.colorScheme.onPrimaryContainer
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onSurfaceVariant
|
||||
}
|
||||
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.clickable(onClick = onClick),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = backgroundColor)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.padding(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = emoji,
|
||||
style = MaterialTheme.typography.headlineMedium
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = contentColor,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 2,
|
||||
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal
|
||||
)
|
||||
}
|
||||
if (isSelected) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Check,
|
||||
contentDescription = "Sélectionné",
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(4.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,6 +260,7 @@ fun ListDetailScreen(
|
||||
onDismiss = viewModel::closeItemDetails,
|
||||
onUpdateNote = { note -> viewModel.updateItemNote(selected.id, note) },
|
||||
onUpdateCategory = { cat -> viewModel.updateItemCategory(selected.id, cat) },
|
||||
onUpdateEmoji = { emoji -> viewModel.updateItemEmoji(selected.id, emoji) },
|
||||
onMoveTo = { targetListId -> viewModel.moveItemToList(selected.id, targetListId) },
|
||||
onDelete = { viewModel.deleteItem(selected.id) },
|
||||
onOpenProduct = selected.barcode?.let { bc -> { onOpenProduct(bc) } }
|
||||
@ -774,6 +775,7 @@ private fun ItemDetailSheet(
|
||||
onDismiss: () -> Unit,
|
||||
onUpdateNote: (String) -> Unit,
|
||||
onUpdateCategory: (String) -> Unit,
|
||||
onUpdateEmoji: (String?) -> Unit,
|
||||
onMoveTo: (Long) -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
onOpenProduct: (() -> Unit)?
|
||||
@ -781,6 +783,7 @@ private fun ItemDetailSheet(
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
var note by remember(item.id) { mutableStateOf(item.note.orEmpty()) }
|
||||
var showCategoryPicker by remember { mutableStateOf(false) }
|
||||
var showIconPicker by remember { mutableStateOf(false) }
|
||||
var showMovePicker by remember { mutableStateOf(false) }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
@ -835,21 +838,85 @@ private fun ItemDetailSheet(
|
||||
maxLines = 3
|
||||
)
|
||||
|
||||
// Catégorie
|
||||
ActionRow(
|
||||
title = "Section",
|
||||
value = item.category ?: "Autre",
|
||||
onClick = { showCategoryPicker = true }
|
||||
// Détails de l'article
|
||||
Text(
|
||||
text = "Détails de l'article pour ${item.productName}",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
|
||||
// Déplacer
|
||||
if (otherLists.isNotEmpty()) {
|
||||
ActionRow(
|
||||
title = "Déplacer vers une autre liste",
|
||||
value = null,
|
||||
onClick = { showMovePicker = true },
|
||||
leadingIcon = Icons.Filled.SwapHoriz
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
DetailTagButton(
|
||||
icon = Icons.Filled.AutoAwesome,
|
||||
label = "Urgent",
|
||||
selected = false,
|
||||
onClick = { /* TODO */ },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
DetailTagButton(
|
||||
icon = Icons.Filled.Done,
|
||||
label = "Offre",
|
||||
selected = false,
|
||||
onClick = { /* TODO */ },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
DetailTagButton(
|
||||
icon = Icons.Filled.History,
|
||||
label = "Quand cela convient",
|
||||
selected = false,
|
||||
onClick = { /* TODO */ },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
|
||||
// Paramètres
|
||||
Text(
|
||||
text = "Paramètres",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
ParameterButton(
|
||||
icon = Icons.Filled.Done,
|
||||
label = "Changer une icône",
|
||||
onClick = { showIconPicker = true },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
ParameterButton(
|
||||
icon = Icons.Filled.Camera,
|
||||
label = "Ajouter une photo",
|
||||
onClick = { /* TODO: Photo picker */ },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
ParameterButton(
|
||||
icon = Icons.Filled.KeyboardArrowDown,
|
||||
label = "Changer une section",
|
||||
onClick = { showCategoryPicker = true },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
if (otherLists.isNotEmpty()) {
|
||||
ParameterButton(
|
||||
icon = Icons.Filled.SwapHoriz,
|
||||
label = "Déplacer l'article",
|
||||
onClick = { showMovePicker = true },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Ouvrir fiche produit
|
||||
@ -997,6 +1064,19 @@ private fun ItemDetailSheet(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sélecteur d'icône
|
||||
if (showIconPicker) {
|
||||
IconPickerSheet(
|
||||
currentEmoji = item.emoji,
|
||||
categories = categories,
|
||||
onDismiss = { showIconPicker = false },
|
||||
onSelectIcon = { emoji ->
|
||||
onUpdateEmoji(emoji.ifEmpty { null })
|
||||
showIconPicker = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -1044,3 +1124,97 @@ private fun ActionRow(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DetailTagButton(
|
||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
||||
label: String,
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val backgroundColor = if (selected) {
|
||||
MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.6f)
|
||||
}
|
||||
val contentColor = if (selected) {
|
||||
MaterialTheme.colorScheme.onPrimaryContainer
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onSurfaceVariant
|
||||
}
|
||||
|
||||
Card(
|
||||
modifier = modifier
|
||||
.heightIn(min = 56.dp)
|
||||
.clickable(onClick = onClick),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = backgroundColor)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = contentColor,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = contentColor,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ParameterButton(
|
||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
||||
label: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier
|
||||
.heightIn(min = 80.dp)
|
||||
.clickable(onClick = onClick),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.6f)
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(28.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,6 +322,15 @@ class ListDetailViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/** Change l'emoji personnalisé d'un article. */
|
||||
fun updateItemEmoji(id: Long, emoji: String?) {
|
||||
viewModelScope.launch {
|
||||
val listId = _listIdFlow.value
|
||||
val item = manageListUseCase.getItems(listId).firstOrNull { it.id == id } ?: return@launch
|
||||
manageListUseCase.updateItem(item.copy(customEmoji = emoji))
|
||||
}
|
||||
}
|
||||
|
||||
/** Déplace un article vers une autre liste. */
|
||||
fun moveItemToList(id: Long, targetListId: Long) {
|
||||
viewModelScope.launch {
|
||||
@ -393,7 +402,7 @@ class ListDetailViewModel @Inject constructor(
|
||||
safetyStatus = safetyStatus,
|
||||
allergenWarning = allergenWarning,
|
||||
note = note,
|
||||
emoji = catalog.emojiFor(productName, category)
|
||||
emoji = customEmoji ?: catalog.emojiFor(productName, category)
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user