From 83b92c942dac86838c9cdeace4bba2d7ba984743 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Sat, 25 Apr 2026 10:25:20 -0400 Subject: [PATCH] =?UTF-8?q?Ajout=20de=20composants=20pour=20la=20gestion?= =?UTF-8?q?=20des=20allerg=C3=A8nes=20et=20des=20=C3=A9l=C3=A9ments=20pers?= =?UTF-8?q?onnalis=C3=A9s=20dans=20l'interface=20utilisateur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screen/profile/ProfileComponents.kt | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 app/src/main/java/com/safebite/app/presentation/screen/profile/ProfileComponents.kt diff --git a/app/src/main/java/com/safebite/app/presentation/screen/profile/ProfileComponents.kt b/app/src/main/java/com/safebite/app/presentation/screen/profile/ProfileComponents.kt new file mode 100644 index 0000000..5258165 --- /dev/null +++ b/app/src/main/java/com/safebite/app/presentation/screen/profile/ProfileComponents.kt @@ -0,0 +1,146 @@ +package com.safebite.app.presentation.screen.profile + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.AssistChip +import androidx.compose.material3.AssistChipDefaults +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FilterChip +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.safebite.app.R +import com.safebite.app.domain.model.AllergenType +import com.safebite.app.domain.model.CustomDietItem +import com.safebite.app.domain.model.CustomItemTag + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun AllergenGrid(selected: Set, onToggle: (AllergenType) -> Unit) { + FlowRow { + AllergenType.values().forEach { a -> + FilterChip( + selected = a in selected, + onClick = { onToggle(a) }, + leadingIcon = { Text(a.icon) }, + label = { Text(a.displayNameFr) }, + modifier = Modifier.padding(4.dp) + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) +@Composable +fun CustomItemAdder(onAdd: (String, CustomItemTag) -> Unit) { + var name by remember { mutableStateOf("") } + var tag by remember { mutableStateOf(CustomItemTag.UNHEALTHY) } + Card(modifier = Modifier.fillMaxWidth()) { + Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { + OutlinedTextField( + value = name, + onValueChange = { name = it }, + label = { Text(stringResource(R.string.profile_custom_name)) }, + modifier = Modifier.fillMaxWidth(), + singleLine = true + ) + Text(stringResource(R.string.profile_custom_tag), style = MaterialTheme.typography.labelLarge) + FlowRow { + CustomItemTag.values().forEach { t -> + FilterChip( + selected = tag == t, + onClick = { tag = t }, + label = { Text(tagLabel(t)) }, + modifier = Modifier.padding(4.dp) + ) + } + } + Button( + onClick = { + onAdd(name, tag) + name = "" + }, + enabled = name.isNotBlank(), + modifier = Modifier.fillMaxWidth() + ) { + Icon(Icons.Filled.Add, null) + Spacer(Modifier.width(6.dp)) + Text(stringResource(R.string.profile_custom_add)) + } + } + } +} + +@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class) +@Composable +fun CustomItemsList(items: List, onRemove: (CustomDietItem) -> Unit) { + if (items.isEmpty()) { + Text(stringResource(R.string.profile_custom_empty), color = MaterialTheme.colorScheme.onSurfaceVariant) + return + } + FlowRow { + items.forEach { item -> + AssistChip( + onClick = { onRemove(item) }, + label = { + Text( + "${tagIcon(item.tag)} ${item.name}", + fontWeight = FontWeight.Medium + ) + }, + trailingIcon = { Icon(Icons.Filled.Close, contentDescription = null, modifier = Modifier.size(16.dp)) }, + colors = AssistChipDefaults.assistChipColors( + containerColor = tagColor(item.tag).copy(alpha = 0.18f) + ), + modifier = Modifier.padding(4.dp) + ) + } + } +} + +@Composable +fun tagLabel(tag: CustomItemTag): String = when (tag) { + CustomItemTag.ALLERGY -> stringResource(R.string.profile_custom_tag_allergy) + CustomItemTag.INTOLERANCE -> stringResource(R.string.profile_custom_tag_intolerance) + CustomItemTag.DIET -> stringResource(R.string.profile_custom_tag_diet) + CustomItemTag.UNHEALTHY -> stringResource(R.string.profile_custom_tag_unhealthy) +} + +fun tagIcon(tag: CustomItemTag): String = when (tag) { + CustomItemTag.ALLERGY -> "⛔" + CustomItemTag.INTOLERANCE -> "⚠️" + CustomItemTag.DIET -> "🥗" + CustomItemTag.UNHEALTHY -> "🍩" +} + +@Composable +fun tagColor(tag: CustomItemTag): Color = when (tag) { + CustomItemTag.ALLERGY -> MaterialTheme.colorScheme.error + CustomItemTag.INTOLERANCE -> Color(0xFFFFA000) + CustomItemTag.DIET -> MaterialTheme.colorScheme.tertiary + CustomItemTag.UNHEALTHY -> Color(0xFF9575CD) +}