Skip to content

Commit 9d0c4e2

Browse files
committed
Added strings for wine description screen, with automatic translation of fields
1 parent 93ca6b2 commit 9d0c4e2

5 files changed

Lines changed: 151 additions & 14 deletions

File tree

app/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,7 @@ dependencies {
8484

8585
implementation("androidx.documentfile:documentfile:1.0.1")
8686

87+
// pour le tri des champs de wineentity lors de l'export
88+
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.22")
89+
8790
}

app/src/main/java/com/mouton/openwinemer/ui/detail/WineDetailScreen.kt

Lines changed: 115 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import com.mouton.openwinemer.R
2121
// import pour le scroll
2222
import androidx.compose.foundation.rememberScrollState
2323
import androidx.compose.foundation.verticalScroll
24-
24+
// import pour le remplissage auto des champs
25+
import kotlin.reflect.full.memberProperties
26+
import androidx.compose.ui.platform.LocalContext
2527

2628

2729
/**
@@ -32,6 +34,45 @@ import androidx.compose.foundation.verticalScroll
3234
* - Permet de supprimer le vin (avec confirmation)
3335
*/
3436

37+
/**
38+
* Génère automatiquement les champs supplémentaires d'un vin,
39+
* en utilisant les traductions si disponibles.
40+
*/
41+
@Composable
42+
private fun autoTranslatedFields(wine: WineEntity): List<Pair<String, String>> {
43+
val context = LocalContext.current
44+
45+
// Champs déjà affichés manuellement
46+
val excluded = setOf(
47+
"name", "producer", "region", "color", "vintage",
48+
"stockQuantity", "generalDescription"
49+
)
50+
51+
return WineEntity::class.memberProperties
52+
.filter { it.name !in excluded }
53+
.mapNotNull { prop ->
54+
val value = prop.get(wine) ?: return@mapNotNull null
55+
val textValue = value.toString().takeIf { it.isNotBlank() } ?: return@mapNotNull null
56+
57+
// Nom de la clé dans strings.xml
58+
val key = "wine_${prop.name.replace(Regex("([A-Z])"), "_$1").lowercase()}"
59+
60+
// Essayer de trouver la ressource string correspondante
61+
val resId = context.resources.getIdentifier(key, "string", context.packageName)
62+
63+
val label =
64+
if (resId != 0)
65+
stringResource(resId) // traduction trouvée
66+
else
67+
// fallback : transformer "mainGrape" → "Main grape"
68+
prop.name.replace(Regex("([a-z])([A-Z])"), "$1 $2")
69+
.replaceFirstChar { it.uppercase() }
70+
71+
label to textValue
72+
}
73+
}
74+
75+
3576
// fonction utile pour ajouter les champs supplémentaires
3677
private fun buildDynamicFields(wine: WineEntity): List<Pair<String, String>> {
3778
val fields = mutableListOf<Pair<String, String>>()
@@ -89,6 +130,33 @@ private fun buildDynamicFields(wine: WineEntity): List<Pair<String, String>> {
89130
return fields
90131
}
91132

133+
/**
134+
* Génère automatiquement une liste (label, valeur) pour tous les champs non nuls
135+
* de WineEntity, sauf ceux déjà affichés manuellement.
136+
*/
137+
private fun autoFields(wine: WineEntity): List<Pair<String, String>> {
138+
139+
// Champs que tu affiches déjà dans l'écran
140+
val excluded = setOf(
141+
"name", "producer", "region", "color", "vintage",
142+
"stockQuantity", "generalDescription"
143+
)
144+
145+
return WineEntity::class.memberProperties
146+
.filter { it.name !in excluded } // ignorer les champs déjà affichés
147+
.mapNotNull { prop ->
148+
val value = prop.get(wine) ?: return@mapNotNull null
149+
val text = value.toString().takeIf { it.isNotBlank() } ?: return@mapNotNull null
150+
151+
// Convertir "mainGrape" → "Main grape"
152+
val label = prop.name
153+
.replace(Regex("([a-z])([A-Z])"), "$1 $2")
154+
.replaceFirstChar { it.uppercase() }
155+
156+
label to text
157+
}
158+
}
159+
92160

93161
@Composable
94162
fun WineDetailScreen(
@@ -134,17 +202,17 @@ fun WineDetailScreen(
134202
.padding(16.dp)
135203
.fillMaxSize()
136204
) {
137-
// --- CHAMPS PRINCIPAUX (ceux que tu avais déjà) ---
138-
DetailRow("Nom", current.name)
139-
DetailRow("Producteur", current.producer)
140-
DetailRow("Région", current.region)
141-
DetailRow("Couleur", current.color)
142-
DetailRow("Année", current.vintage?.toString())
205+
// --- CHAMPS PRINCIPAUX (ceux à toujours afficher) ---
206+
//"${wine?.name ?: stringResource(R.string.wine_details)}"
207+
Text(stringResource(R.string.name) + " : " + (current.name ?: "-"))
208+
Text(stringResource(R.string.wine_producer, " : ", current.producer ?: "-"))
209+
Text(stringResource(R.string.region_label, " : ", current.region ?: "-"))
210+
Text(stringResource(R.string.color_label, " : ", current.color ?: "-"))
211+
Text(stringResource(R.string.year_label, " : ", current.vintage ?: "-"))
143212

144213
Spacer(Modifier.height(16.dp))
145214

146-
// --- STOCK ---
147-
DetailRow("Stock", (current.stockQuantity ?: 0).toString())
215+
Text(stringResource(R.string.wine_stock, " : ", current.stockQuantity ?: 0))
148216

149217
Row {
150218
Button(onClick = { viewModel.updateStock(-1) }) { Text("-") }
@@ -155,16 +223,33 @@ fun WineDetailScreen(
155223
Spacer(Modifier.height(24.dp))
156224

157225
// --- DESCRIPTION GÉNÉRALE ---
158-
DetailRow("Description", current.generalDescription)
226+
Text(stringResource(R.string.wine_general_desc, " : ", current.generalDescription ?: "-"))
159227

160228
Spacer(Modifier.height(24.dp))
161229

230+
// --- CHAMPS AUTOMATIQUES MULTILINGUES ---
231+
val extraFields = autoTranslatedFields(current)
232+
233+
if (extraFields.isNotEmpty()) {
234+
Spacer(Modifier.height(24.dp))
235+
Text(
236+
stringResource(R.string.additional_information),
237+
style = MaterialTheme.typography.titleMedium
238+
)
239+
Spacer(Modifier.height(8.dp))
240+
241+
extraFields.forEach { (label, value) ->
242+
DetailRow(label, value)
243+
}
244+
}
245+
246+
/*
162247
// --- CHAMPS DYNAMIQUES (tous les autres renseignés) ---
163248
val dynamicFields = buildDynamicFields(current)
164249
165250
if (dynamicFields.isNotEmpty()) {
166251
Text(
167-
"Informations supplémentaires",
252+
stringResource(R.string.additional_information),
168253
style = MaterialTheme.typography.titleMedium
169254
)
170255
Spacer(Modifier.height(8.dp))
@@ -173,6 +258,7 @@ fun WineDetailScreen(
173258
DetailRow(label, value)
174259
}
175260
}
261+
*/
176262
}
177263
} ?: Box(
178264
modifier = Modifier
@@ -211,7 +297,24 @@ fun WineDetailScreen(
211297
}
212298

213299
@Composable
214-
private fun DetailRow(label: String, value: String?) {
300+
private fun DetailRow(label: String, value: String) {
301+
Column(Modifier.padding(vertical = 6.dp)) {
302+
Text(
303+
text = label,
304+
style = MaterialTheme.typography.labelLarge,
305+
color = MaterialTheme.colorScheme.primary
306+
)
307+
Text(
308+
text = value,
309+
style = MaterialTheme.typography.bodyLarge
310+
)
311+
Divider(Modifier.padding(top = 6.dp))
312+
}
313+
}
314+
315+
316+
@Composable
317+
private fun old_DetailRow(label: String, value: String?) {
215318
if (value.isNullOrBlank()) return
216319

217320
Column(Modifier.padding(vertical = 6.dp)) {

app/src/main/res/values-en/strings.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
<string name="wine_name">Wine name</string>
4141
<string name="wine_producer">Producer</string>
4242
<string name="wine_batch">Cuvée</string>
43+
<string name="wine_cuvee">Cuvée</string>
4344
<string name="wine_type">Wine type</string>
45+
<string name="wine_wine_type">Wine type</string>
4446
<string name="wine_aging_potential">Aging potential</string>
4547
<string name="wine_optimal_date">Optimal drink date</string>
4648
<string name="wine_label_state">Label state</string>
@@ -64,14 +66,17 @@
6466
<string name="wine_sub_region">Sub region</string>
6567
<string name="wine_designation">Designation</string>
6668
<string name="wine_rankings">Ranking (Grand Cru, Premier Cru…)</string>
69+
<string name="wine_classifications">Ranking (Grand Cru, Premier Cru…)</string>
6770
<string name="wine_visual_aspect">Visual aspect</string>
6871
<string name="wine_aroma">Aroma(s)</string>
6972
<string name="wine_flavor">Flavor(s)</string>
7073
<string name="wine_structure">Body</string>
7174
<string name="wine_final">Final note</string>
7275
<string name="wine_grade">Global grade</string>
76+
<string name="wine_global_rating">Global grade</string>
7377
<string name="wine_alcohol">Alcohol percent (%%)</string>
74-
<string name="wine_sugar">Residual sugars (g)</string>
78+
<string name="wine_sugar">Residual sugar (g)</string>
79+
<string name="wine_residual_sugar">Residual sugar (g)</string>
7580
<string name="wine_acidity">Acidity</string>
7681
<string name="wine_ph">pH level</string>
7782
<string name="wine_vol">Volume (mL)</string>
@@ -90,4 +95,14 @@
9095
<string name="wrong_pwd_or_file">Incorrect password or invalid encrypted file</string>
9196
<string name="cant_read_file">Unable to read the selected file.</string>
9297
<string name="cant_create_here">Unable to create the file in this folder.</string>
98+
<string name="additional_information">Additional information:</string>
99+
<string name="wine_vinification_method">Vinification method</string>
100+
<string name="wine_fermentation_type">Fermentation type</string>
101+
<string name="wine_ageing_duration">Ageing duration</string>
102+
<string name="wine_barrel_type">Barrel type</string>
103+
<string name="wine_barrel_time">Barrel time</string>
104+
<string name="wine_recommended_dishes">Recommended dishes</string>
105+
<string name="wine_cuisine_type">Cuisine type</string>
106+
<string name="wine_occasions">Occasions</string>
107+
<string name="wine_volume_ml">Volume (mL)</string>
93108
</resources>

app/src/main/res/values/strings.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
<string name="wine_name">Nom du vin</string>
4141
<string name="wine_producer">Producteur</string>
4242
<string name="wine_batch">Cuvée</string>
43+
<string name="wine_cuvee">Cuvée</string>
4344
<string name="wine_type">Type de vin</string>
45+
<string name="wine_wine_type">Type de vin</string>
4446
<string name="wine_aging_potential">Potentiel de garde</string>
4547
<string name="wine_optimal_date">Date optimale de consommation</string>
4648
<string name="wine_label_state">Etat de l\'étiquette</string>
@@ -64,14 +66,17 @@
6466
<string name="wine_sub_region">Sous-région</string>
6567
<string name="wine_designation">Appelation</string>
6668
<string name="wine_rankings">Classement (Grand Cru, Premier Cru…)</string>
69+
<string name="wine_classifications">Classement (Grand Cru, Premier Cru…)</string>
6770
<string name="wine_visual_aspect">Aspect visual</string>
6871
<string name="wine_aroma">Arôme(s)</string>
6972
<string name="wine_flavor">Saveur(s)</string>
7073
<string name="wine_structure">Structure</string>
7174
<string name="wine_final">Finale</string>
7275
<string name="wine_grade">Note globale</string>
76+
<string name="wine_global_rating">Note globale</string>
7377
<string name="wine_alcohol">Teneur en alcool (%%)</string>
7478
<string name="wine_sugar">Sucre résiduel (g)</string>
79+
<string name="wine_residual_sugar">Sucre résiduel (g)</string>
7580
<string name="wine_acidity">Acidité</string>
7681
<string name="wine_ph">pH</string>
7782
<string name="wine_vol">Volume (mL)</string>
@@ -86,8 +91,18 @@
8691
<string name="cancel_button">Annuler</string>
8792
<string name="invalid_save_file">Fichier de sauvegarde invalide ou mot de passe incorrect</string>
8893
<string name="cant_make_csv">Impossible de créer le fichier CSV.</string>
89-
<string name="cant_access_folder">Impossible d'accéder au dossier sélectionné.</string>
94+
<string name="cant_access_folder">Impossible d\'accéder au dossier sélectionné.</string>
9095
<string name="wrong_pwd_or_file">Mot de passe incorrect ou fichier chiffré invalide</string>
9196
<string name="cant_read_file">Impossible de lire le fichier sélectionné.</string>
9297
<string name="cant_create_here">Impossible de créer le fichier dans ce dossier.</string>
98+
<string name="additional_information">Informations additionnelles</string>
99+
<string name="wine_vinification_method">Méthode de vinification</string>
100+
<string name="wine_fermentation_type">Type de fermentation</string>
101+
<string name="wine_ageing_duration">Durée d\'élevage</string>
102+
<string name="wine_barrel_type">Type de fût</string>
103+
<string name="wine_barrel_time">Temps en barrique</string>
104+
<string name="wine_recommended_dishes">Plats recommandés</string>
105+
<string name="wine_cuisine_type">Type de cuisine</string>
106+
<string name="wine_occasions">Occasions</string>
107+
<string name="wine_volume_ml">Volume (mL)</string>
93108
</resources>

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
2525
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
2626
androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
2727
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
28+
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
2829

2930
[plugins]
3031
android-application = { id = "com.android.application", version.ref = "agp" }

0 commit comments

Comments
 (0)