test
This commit is contained in:
2
.idea/.name
generated
2
.idea/.name
generated
@@ -1 +1 @@
|
||||
coloricam
|
||||
scan-wich
|
||||
@@ -1,9 +1,12 @@
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.secrets)
|
||||
alias(libs.plugins.google.services)
|
||||
alias(libs.plugins.firebase.appdistribution)
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -21,23 +24,45 @@ android {
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
// On configure la release pour utiliser la même clé que le debug pour l'instant
|
||||
val keystoreProperties = Properties()
|
||||
val keystorePropertiesFile = rootProject.file("local.properties")
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(keystorePropertiesFile.inputStream())
|
||||
}
|
||||
|
||||
getByName("debug") {
|
||||
storeFile = file(System.getProperty("user.home") + "/.android/debug.keystore")
|
||||
storePassword = "android"
|
||||
keyAlias = "androiddebugkey"
|
||||
keyPassword = "android"
|
||||
}
|
||||
|
||||
create("release") {
|
||||
storeFile = file("C:\\Users\\mac\\keys\\keys")
|
||||
storePassword = keystoreProperties.getProperty("RELEASE_STORE_PASSWORD")
|
||||
keyAlias = keystoreProperties.getProperty("RELEASE_KEY_ALIAS") ?: "key0"
|
||||
keyPassword = keystoreProperties.getProperty("RELEASE_KEY_PASSWORD")
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
|
||||
configure<com.google.firebase.appdistribution.gradle.AppDistributionExtension> {
|
||||
artifactType = "APK"
|
||||
}
|
||||
}
|
||||
|
||||
debug {
|
||||
configure<com.google.firebase.appdistribution.gradle.AppDistributionExtension> {
|
||||
artifactType = "APK"
|
||||
}
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
@@ -51,7 +76,6 @@ android {
|
||||
}
|
||||
|
||||
secrets {
|
||||
// A list of keys that should be ignored by the plugin by default.
|
||||
ignoreList.add("properties")
|
||||
}
|
||||
|
||||
@@ -68,24 +92,19 @@ dependencies {
|
||||
implementation(libs.coil.compose)
|
||||
implementation(libs.androidx.exifinterface)
|
||||
|
||||
// Navigation
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
|
||||
// Room
|
||||
implementation(libs.androidx.room.runtime)
|
||||
implementation(libs.androidx.room.ktx)
|
||||
ksp(libs.androidx.room.compiler)
|
||||
|
||||
// Network & Strava Auth
|
||||
implementation(libs.retrofit.core)
|
||||
implementation(libs.retrofit.gson)
|
||||
implementation(libs.okhttp.logging)
|
||||
implementation(libs.androidx.browser)
|
||||
|
||||
// Google Sign-In
|
||||
implementation(libs.play.services.auth)
|
||||
|
||||
// Firebase
|
||||
implementation(platform(libs.firebase.bom))
|
||||
implementation(libs.firebase.analytics)
|
||||
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
"certificate_hash": "2c39e4131dcac8a1d4257b804718ac113f855b04"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "652626507041-i6ne7rt1b711gfpbc5f5hd1q60kd0ntv.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.example.scanwich",
|
||||
"certificate_hash": "ebcc060f9a1fdeb1186536d3828574b42cefa03c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "652626507041-5n42q37adh1guuv9gibfcf5uvekgunbe.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
// Ce fichier est obsolète. Utilisez celui dans le package com.example.scanwich.
|
||||
@@ -1 +0,0 @@
|
||||
// Ce fichier est obsolète. Utilisez celui dans le package com.example.scanwich.
|
||||
@@ -76,7 +76,7 @@ data class N8nMealRequest(
|
||||
)
|
||||
|
||||
interface N8nApi {
|
||||
@POST("webhook-test/v1/gemini-proxy")
|
||||
@POST("webhook/v1/gemini-proxy")
|
||||
suspend fun analyzeMeal(
|
||||
@Header("X-API-KEY") apiKey: String,
|
||||
@Body request: N8nMealRequest
|
||||
@@ -278,7 +278,7 @@ fun AuthWrapper(dao: AppDao) {
|
||||
} catch (e: ApiException) {
|
||||
Log.e("Auth", "Erreur Google Sign-In : ${e.statusCode}")
|
||||
val msg = when(e.statusCode) {
|
||||
10 -> "Erreur 10 : SHA-1 non reconnu dans Firebase. Assurez-vous d'avoir ajouté le SHA-1 de TOUTES vos clés de signature."
|
||||
10 -> "Erreur 10 : SHA-1 non reconnu dans Firebase. Assurez-vous d\u0027avoir ajouté le SHA-1 de TOUTES vos clés de signature."
|
||||
7 -> "Erreur 7 : Problème de réseau."
|
||||
12500 -> "Erreur 12500 : Problème de configuration Google Play Services."
|
||||
else -> "Erreur Google (Code ${e.statusCode})."
|
||||
@@ -333,7 +333,7 @@ fun AccessDeniedScreen(onLogout: () -> Unit) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Text("Accès Refusé", style = MaterialTheme.typography.headlineMedium, color = MaterialTheme.colorScheme.error)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text("Votre compte n'est pas autorisé à utiliser cette application.", style = MaterialTheme.typography.bodyLarge)
|
||||
Text("Votre compte n\u0027est pas autorisé à utiliser cette application.", style = MaterialTheme.typography.bodyLarge)
|
||||
Spacer(Modifier.height(32.dp))
|
||||
Button(onClick = onLogout) { Text("Changer de compte") }
|
||||
}
|
||||
@@ -471,7 +471,7 @@ fun SetupScreen(prefs: SharedPreferences, onComplete: () -> Unit) {
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Text("Niveau d'activité :", style = MaterialTheme.typography.titleMedium, modifier = Modifier.align(Alignment.Start))
|
||||
Text("Niveau d\u0027activité :", style = MaterialTheme.typography.titleMedium, modifier = Modifier.align(Alignment.Start))
|
||||
activityLevels.forEach { level ->
|
||||
Row(
|
||||
Modifier
|
||||
@@ -607,7 +607,7 @@ fun CaptureScreen(dao: AppDao, prefs: SharedPreferences, isDiabetic: Boolean) {
|
||||
currentMealData = data
|
||||
showBottomSheet = true
|
||||
} else {
|
||||
Toast.makeText(context, "L'IA n'a pas pu identifier le repas.", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(context, "L\u0027IA n\u0027a pas pu identifier le repas.", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}, coroutineScope)
|
||||
} catch (e: Exception) {
|
||||
@@ -665,7 +665,7 @@ fun CaptureScreen(dao: AppDao, prefs: SharedPreferences, isDiabetic: Boolean) {
|
||||
OutlinedTextField(
|
||||
value = editableDesc,
|
||||
onValueChange = { editableDesc = it },
|
||||
label = { Text("Description / Précisions pour l'IA") },
|
||||
label = { Text("Description / Précisions pour l\u0027IA") },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
minLines = 3
|
||||
)
|
||||
@@ -686,7 +686,7 @@ fun CaptureScreen(dao: AppDao, prefs: SharedPreferences, isDiabetic: Boolean) {
|
||||
) {
|
||||
Icon(Icons.Default.Refresh, null)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text("Ressoumettre à l'IA")
|
||||
Text("Ressoumettre à l\u0027IA")
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
@@ -771,7 +771,7 @@ fun CaptureScreen(dao: AppDao, prefs: SharedPreferences, isDiabetic: Boolean) {
|
||||
Spacer(Modifier.height(32.dp))
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) {
|
||||
CircularProgressIndicator()
|
||||
Text("Analyse par l'IA en cours...", modifier = Modifier.padding(top = 8.dp))
|
||||
Text("Analyse par l\u0027IA en cours...", modifier = Modifier.padding(top = 8.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,7 +783,7 @@ fun CaptureScreen(dao: AppDao, prefs: SharedPreferences, isDiabetic: Boolean) {
|
||||
OutlinedTextField(
|
||||
value = manualMealName,
|
||||
onValueChange = { manualMealName = it },
|
||||
label = { Text("Qu'avez-vous mangé ?") },
|
||||
label = { Text("Qu\u0027avez-vous mangé ?") },
|
||||
placeholder = { Text("ex: Un sandwich au poulet et une pomme") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
@@ -869,6 +869,7 @@ fun HistoryScreen(dao: AppDao, prefs: SharedPreferences) {
|
||||
val isDiabetic = prefs.getBoolean("is_diabetic", false)
|
||||
var selectedMealForDetail by remember { mutableStateOf<Meal?>(null) }
|
||||
val context = LocalContext.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val tCal = prefs.getString("target_calories", "2000")?.toIntOrNull() ?: 2000
|
||||
val tCarb = prefs.getString("target_carbs", "250")?.toIntOrNull() ?: 250
|
||||
@@ -972,7 +973,15 @@ fun HistoryScreen(dao: AppDao, prefs: SharedPreferences) {
|
||||
if (isDiabetic && beforeGly != null) {
|
||||
item {
|
||||
Surface(color = Color.Blue.copy(alpha = 0.1f), modifier = Modifier.fillMaxWidth().clip(MaterialTheme.shapes.small)) {
|
||||
Text("🩸 Glycémie Avant: ${beforeGly.value} mmol/L", modifier = Modifier.padding(8.dp), style = MaterialTheme.typography.bodyMedium)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(8.dp)) {
|
||||
Text("🩸 Glycémie Avant: ${beforeGly.value} mmol/L", modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium)
|
||||
IconButton(onClick = {
|
||||
coroutineScope.launch {
|
||||
dao.deleteGlycemia(beforeGly)
|
||||
Toast.makeText(context, "Glycémie supprimée", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}) { Icon(Icons.Default.Delete, null, modifier = Modifier.size(20.dp)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -982,7 +991,12 @@ fun HistoryScreen(dao: AppDao, prefs: SharedPreferences) {
|
||||
headlineContent = { Text(meal.name) },
|
||||
supportingContent = { Text("${meal.totalCalories} kcal - G:${meal.carbs}g P:${meal.protein}g L:${meal.fat}g") },
|
||||
trailingContent = {
|
||||
IconButton(onClick = { /* TODO */ }) { Icon(Icons.Default.Delete, null) }
|
||||
IconButton(onClick = {
|
||||
coroutineScope.launch {
|
||||
dao.deleteMeal(meal)
|
||||
Toast.makeText(context, "Repas supprimé", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}) { Icon(Icons.Default.Delete, null) }
|
||||
},
|
||||
modifier = Modifier.clickable { selectedMealForDetail = meal }
|
||||
)
|
||||
@@ -991,7 +1005,15 @@ fun HistoryScreen(dao: AppDao, prefs: SharedPreferences) {
|
||||
if (isDiabetic && afterGly != null) {
|
||||
item {
|
||||
Surface(color = Color.Green.copy(alpha = 0.1f), modifier = Modifier.fillMaxWidth().clip(MaterialTheme.shapes.small)) {
|
||||
Text("🩸 Glycémie Après: ${afterGly.value} mmol/L", modifier = Modifier.padding(8.dp), style = MaterialTheme.typography.bodyMedium)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(8.dp)) {
|
||||
Text("🩸 Glycémie Après: ${afterGly.value} mmol/L", modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium)
|
||||
IconButton(onClick = {
|
||||
coroutineScope.launch {
|
||||
dao.deleteGlycemia(afterGly)
|
||||
Toast.makeText(context, "Glycémie supprimée", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}) { Icon(Icons.Default.Delete, null, modifier = Modifier.size(20.dp)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1033,9 +1055,9 @@ private fun analyzeImage(
|
||||
val prompt = if (bitmap != null && textDescription == null) {
|
||||
"Analyze this food image in FRENCH. Provide ONLY: 1. Name, 2. Summary description in FRENCH, 3. Macros. Format EXACTLY as: {\"name\": \"...\", \"description\": \"...\", \"calories\": int, \"carbs\": int, \"protein\": int, \"fat\": int}"
|
||||
} else if (bitmap != null && textDescription != null) {
|
||||
"Analyze this food image in FRENCH, taking into account these corrections or details: '$textDescription'. Provide ONLY: 1. Name, 2. Summary description in FRENCH, 3. Macros. Format EXACTLY as: {\"name\": \"...\", \"description\": \"...\", \"calories\": int, \"carbs\": int, \"protein\": int, \"fat\": int}"
|
||||
"Analyze this food image in FRENCH, taking into account these corrections or details: \u0027$textDescription\u0027. Provide ONLY: 1. Name, 2. Summary description in FRENCH, 3. Macros. Format EXACTLY as: {\"name\": \"...\", \"description\": \"...\", \"calories\": int, \"carbs\": int, \"protein\": int, \"fat\": int}"
|
||||
} else {
|
||||
"Analyze this meal description in FRENCH: '$textDescription'. Estimate the macros. Provide ONLY a JSON object. Format EXACTLY as: {\"name\": \"...\", \"description\": \"...\", \"calories\": int, \"carbs\": int, \"protein\": int, \"fat\": int}"
|
||||
"Analyze this meal description in FRENCH: \u0027$textDescription\u0027. Estimate the macros. Provide ONLY a JSON object. Format EXACTLY as: {\"name\": \"...\", \"description\": \"...\", \"calories\": int, \"carbs\": int, \"protein\": int, \"fat\": int}"
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
|
||||
@@ -5,4 +5,5 @@ plugins {
|
||||
alias(libs.plugins.ksp) apply false
|
||||
alias(libs.plugins.secrets) apply false
|
||||
alias(libs.plugins.google.services) apply false
|
||||
alias(libs.plugins.firebase.appdistribution) apply false
|
||||
}
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
[versions]
|
||||
agp = "9.0.1"
|
||||
coreKtx = "1.10.1"
|
||||
coreKtx = "1.12.0"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.1.5"
|
||||
espressoCore = "3.5.1"
|
||||
lifecycleRuntimeKtx = "2.6.1"
|
||||
activityCompose = "1.8.0"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
lifecycleRuntimeKtx = "2.8.7"
|
||||
activityCompose = "1.10.0"
|
||||
kotlin = "2.0.21"
|
||||
composeBom = "2024.09.00"
|
||||
composeBom = "2025.02.00"
|
||||
generativeai = "0.9.0"
|
||||
coil = "2.7.0"
|
||||
room = "2.8.4"
|
||||
navigation = "2.7.7"
|
||||
navigation = "2.8.7"
|
||||
ksp = "2.0.21-1.0.27"
|
||||
retrofit = "2.9.0"
|
||||
okhttp = "4.12.0"
|
||||
browser = "1.8.0"
|
||||
exifinterface = "1.3.7"
|
||||
secretsPlugin = "2.0.1"
|
||||
playServicesAuth = "21.2.0"
|
||||
playServicesAuth = "21.3.0"
|
||||
googleServices = "4.4.2"
|
||||
firebaseBom = "34.9.0"
|
||||
firebaseAppDistribution = "5.2.1"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
@@ -58,3 +59,4 @@ kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "ko
|
||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||
secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secretsPlugin" }
|
||||
google-services = { id = "com.google.gms.google-services", version.ref = "googleServices" }
|
||||
firebase-appdistribution = { id = "com.google.firebase.appdistribution", version.ref = "firebaseAppDistribution" }
|
||||
|
||||
@@ -22,5 +22,5 @@ dependencyResolutionManagement {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "coloricam"
|
||||
rootProject.name = "scan-wich"
|
||||
include(":app")
|
||||
|
||||
Reference in New Issue
Block a user