Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ab0b504
Closes #10
ma-r-s Oct 3, 2024
7b79bb4
Partial
ma-r-s Oct 9, 2024
e0225a9
Partial
ma-r-s Oct 10, 2024
122cf5c
Partial
ma-r-s Oct 11, 2024
c308977
Update README.md
LuimarcoCarrascalDiaz Oct 16, 2024
18674fb
Update README.md
LuimarcoCarrascalDiaz Oct 17, 2024
c180dab
Merge branch 'main' into feature/add-cart-api-#25
LuimarcoCarrascalDiaz Oct 17, 2024
31aded3
Merge pull request #6 from LuimarcoCarrascalDiaz/feature/add-cart-api…
LuimarcoCarrascalDiaz Oct 17, 2024
0738d71
agregando sensor de huellas digitales
LuimarcoCarrascalDiaz Oct 17, 2024
d99afaf
agregando sensor de huellas digitales
LuimarcoCarrascalDiaz Oct 17, 2024
723b7ab
Merge branch 'feature/add-cart-api-#25' of https://github.com/Luimarc…
LuimarcoCarrascalDiaz Oct 17, 2024
875afe3
Update README.md
LuimarcoCarrascalDiaz Oct 18, 2024
ee4df16
huella
LuimarcoCarrascalDiaz Oct 19, 2024
99c3eb7
description
LuimarcoCarrascalDiaz Oct 20, 2024
d0578bb
agregando gestión de mapas
LuimarcoCarrascalDiaz Oct 21, 2024
5704383
funcionalidad del mapa
LuimarcoCarrascalDiaz Oct 22, 2024
733bd4f
autocompletar
LuimarcoCarrascalDiaz Oct 22, 2024
e1284d6
animacion interactiva
LuimarcoCarrascalDiaz Oct 22, 2024
3c22ca4
update de puntos en el mapa
LuimarcoCarrascalDiaz Oct 22, 2024
0db8b43
Merge pull request #8 from LuimarcoCarrascalDiaz/feature/restaurant_map
LuimarcoCarrascalDiaz Oct 22, 2024
7430eab
notas al pie de página
LuimarcoCarrascalDiaz Oct 23, 2024
e1d66ad
Update README.md
LuimarcoCarrascalDiaz Oct 23, 2024
688cd13
Update README.md
LuimarcoCarrascalDiaz Oct 28, 2024
70b155f
multithreading added
LuimarcoCarrascalDiaz Oct 28, 2024
9475a25
Merge pull request #9 from LuimarcoCarrascalDiaz/feature/restaurant_map
LuimarcoCarrascalDiaz Oct 28, 2024
af37940
actualización
LuimarcoCarrascalDiaz Oct 30, 2024
ea2ce09
añadiendo las dependencias necesarias para crear una base de datos local
LuimarcoCarrascalDiaz Oct 30, 2024
dbfa995
local storage funcional
LuimarcoCarrascalDiaz Oct 30, 2024
f905c41
funcionalidad completada
LuimarcoCarrascalDiaz Oct 30, 2024
606cf35
Merge pull request #11 from LuimarcoCarrascalDiaz/develop/local-storage
LuimarcoCarrascalDiaz Oct 30, 2024
6d2d7c4
toast de la pantalla de login eliminado
LuimarcoCarrascalDiaz Oct 30, 2024
fe10f55
context aware mejorado
LuimarcoCarrascalDiaz Oct 30, 2024
18180af
campo de fecha de cumpleaños para los perfiles eliminado
LuimarcoCarrascalDiaz Nov 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .kotlin/errors/errors-1729205467831.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
kotlin version: 2.0.20
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
1. Kotlin compile daemon is ready

4 changes: 4 additions & 0 deletions .kotlin/errors/errors-1730660052865.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
kotlin version: 2.0.20
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
1. Kotlin compile daemon is ready

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
### Visit the android developers website
[Compila apps adaptables con las nuevas APIs de Compose, ahora estables](https://developer.android.com/?hl=es-419#:~:text=Discover%20the%20latest%20app%20development%20tools,)
# [Compila apps adaptables con las nuevas APIs de Compose, ahora estables](https://developer.android.com/?hl=es-419#:~:text=Discover%20the%20latest%20app%20development%20tools,)
no olvides configurar el gradle para una exitosa ejecución..
26 changes: 23 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
plugins {
id("com.android.application") version "8.6.1" // AGP version
id("org.jetbrains.kotlin.android") version "1.9.0" // Kotlin plugin for Android
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.0" // Kotlin serialization plugin
id("org.jetbrains.kotlin.android") version "2.0.20" // Kotlin plugin for Android
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.20" // Kotlin serialization plugin
id("org.jetbrains.kotlin.plugin.compose") version "2.0.20"
id ("kotlin-kapt") // Asegúrate de que kapt esté habilitado
}

android {
Expand Down Expand Up @@ -69,14 +71,32 @@ dependencies {
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3:1.3.0")
implementation("androidx.navigation:navigation-runtime-ktx:2.8.2")
implementation("androidx.navigation:navigation-compose:2.8.2")
Comment on lines +74 to +75
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Align Navigation and Accompanist library versions with Compose

The versions of Navigation and Accompanist libraries should be compatible with your Compose version to prevent runtime issues.

Verify that these libraries are compatible with your Compose BOM version:

  • androidx.navigation:navigation-*
  • com.google.accompanist:accompanist-permissions
  • com.google.maps.android:maps-compose

Also applies to: 80-80, 82-82

implementation ("androidx.biometric:biometric:1.1.0")
implementation("androidx.fragment:fragment-ktx:1.8.4")
implementation("com.google.android.gms:play-services-maps:19.0.0")
implementation("com.google.android.libraries.places:places:4.0.0")
implementation ("com.google.accompanist:accompanist-permissions:0.28.0")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation ("com.google.maps.android:maps-compose:2.2.0")
implementation("androidx.room:room-common:2.6.1")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure consistent Room library versions

The Room dependencies are using different versions:

  • room-common:2.6.1 (line 83)
  • room-runtime:2.4.3 (line 85)
  • room-compiler:2.5.1 (line 87)

Mixing different versions of Room components can lead to unexpected behavior or compatibility issues. It's recommended to align all Room dependencies to the same version.

Apply this diff to synchronize the Room library versions:

 implementation("androidx.room:room-common:2.6.1")
-implementation("androidx.room:room-runtime:2.4.3")
+implementation("androidx.room:room-runtime:2.6.1")
-kapt ("androidx.room:room-compiler:2.5.1")
+kapt ("androidx.room:room-compiler:2.6.1") // Annotation processor for Room

Also applies to: 85-85, 87-87


implementation ("androidx.room:room-runtime:2.4.3")
implementation("androidx.compose.runtime:runtime-livedata:1.7.4")
kapt ("androidx.room:room-compiler:2.5.1") // Procesador de anotaciones para Room
implementation ("com.github.bumptech.glide:glide:4.12.") // Glide estándar
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct the incomplete Glide version number

The Glide dependency on line 88 has an incomplete version number "4.12.". This could cause build failures due to an unresolved dependency.

Apply this diff to specify the full version number:

-implementation ("com.github.bumptech.glide:glide:4.12.") // Standard Glide
+implementation ("com.github.bumptech.glide:glide:4.12.0") // Standard Glide
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
implementation ("com.github.bumptech.glide:glide:4.12.") // Glide estándar
implementation ("com.github.bumptech.glide:glide:4.12.0") // Glide estándar

implementation ("com.github.bumptech.glide:compose:1.0.0-alpha.1") // Glide para Jetpack Compose
kapt ("com.github.bumptech.glide:compiler:4.12.0") // Para anotar métodos de Glide
// Testing dependencies
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.03"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")

testImplementation ("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
testImplementation ("junit:junit:4.13.2")
Comment on lines +97 to +98
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove duplicate JUnit dependency

The testImplementation("junit:junit:4.13.2") dependency is declared twice on lines 96 and 98. Duplicate dependencies can lead to confusion and potential conflicts.

Apply this diff to remove the duplicate entry:

 testImplementation("junit:junit:4.13.2")
-testImplementation ("junit:junit:4.13.2")

Committable suggestion skipped: line range outside the PR's diff.

testImplementation ("io.mockk:mockk:1.13.3") // revisa la última versión
// Debug dependencies
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />

<uses-permission android:name="android.permission.USE_FINGERPRINT" />
Comment on lines +5 to +7
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove deprecated USE_FINGERPRINT permission

The USE_FINGERPRINT permission is deprecated since Android 9.0 (API level 28). The USE_BIOMETRIC permission alone is sufficient for all biometric authentication methods including fingerprint.

Apply this diff:

    <uses-permission android:name="android.permission.USE_BIOMETRIC" />
-   <uses-permission android:name="android.permission.USE_FINGERPRINT" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Comment on lines +8 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Remove redundant COARSE_LOCATION permission

The code only checks for and uses ACCESS_FINE_LOCATION permission. Since ACCESS_FINE_LOCATION already includes coarse location capabilities, the ACCESS_COARSE_LOCATION permission declaration is redundant and can be safely removed. The evidence shows:

  • Only ACCESS_FINE_LOCATION is checked in permission verification: checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
  • Location is obtained through FusedLocationProviderClient.lastLocation without any specific accuracy requirements
  • No fallback to coarse location is implemented
🔗 Analysis chain

Verify location permission requirements

While requesting both ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION works, ACCESS_FINE_LOCATION already includes the capabilities of ACCESS_COARSE_LOCATION. Consider your actual location precision needs:

  • Keep both if you need to gracefully fall back to coarse location
  • Use only ACCESS_FINE_LOCATION if you always need precise location
  • Use only ACCESS_COARSE_LOCATION if approximate location is sufficient
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how location is used in the codebase

# Search for location-related API calls to determine precision needs
echo "Searching for location API usage..."
rg -l "getLastLocation|requestLocationUpdates|FusedLocationProviderClient"

# Check for location permission checks
echo "Searching for permission checks..."
rg -l "checkSelfPermission.*FINE_LOCATION|checkSelfPermission.*COARSE_LOCATION"

Length of output: 476


Script:

#!/bin/bash
# Check the specific location usage in RestaurantMapScreen.kt
echo "Checking location usage in RestaurantMapScreen.kt..."
rg -A 5 -B 5 "getLastLocation|requestLocationUpdates|FusedLocationProviderClient" "app/src/main/java/com/uniandes/ecobites/ui/screens/maps/RestaurantMapScreen.kt"

echo "\nChecking permission checks..."
rg -A 5 -B 5 "checkSelfPermission.*FINE_LOCATION|checkSelfPermission.*COARSE_LOCATION" "app/src/main/java/com/uniandes/ecobites/ui/screens/maps/RestaurantMapScreen.kt"

# Check if there's any location accuracy requirements mentioned
echo "\nChecking for location accuracy requirements..."
rg "accuracy|precise|approximate" "app/src/main/java/com/uniandes/ecobites/ui/screens/maps/RestaurantMapScreen.kt"

Length of output: 2982



<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -12,6 +19,10 @@
android:supportsRtl="true"
android:theme="@style/Theme.EcoBites"
tools:targetApi="31">
<!-- Clave de la API de Google Maps -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyCTHkA6PG3Zr_nhxq8N7dlX-vrmEM4mltY"/>
Comment on lines +22 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security: Protect Google Maps API key

The Google Maps API key is exposed in plain text. While it's normal for this key to be in the manifest, it needs proper security measures:

  1. Move the API key to a secure location:

    • Store it in local.properties (git-ignored)
    • Reference it in build.gradle.kts using the manifest placeholder pattern
  2. Ensure the key is restricted in Google Cloud Console:

    • Limit to Android apps
    • Add your app's package name
    • Add your app's SHA-1 signing certificate fingerprint
    • Enable only the necessary Google Maps APIs
  3. Consider using different keys for debug and release builds

Apply these changes:

  1. In local.properties (create if doesn't exist):
MAPS_API_KEY=AIzaSyCTHkA6PG3Zr_nhxq8N7dlX-vrmEM4mltY
  1. In build.gradle.kts:
android {
    defaultConfig {
        manifestPlaceholders["MAPS_API_KEY"] = properties.getOrDefault("MAPS_API_KEY", "")
    }
}
  1. In AndroidManifest.xml:
-        <meta-data
-            android:name="com.google.android.geo.API_KEY"
-            android:value="AIzaSyCTHkA6PG3Zr_nhxq8N7dlX-vrmEM4mltY"/>
+        <meta-data
+            android:name="com.google.android.geo.API_KEY"
+            android:value="${MAPS_API_KEY}"/>
  1. Update .gitignore:
+ local.properties
🧰 Tools
🪛 Gitleaks

25-25: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

<activity
android:name=".MainActivity"
android:exported="true"
Expand Down
63 changes: 14 additions & 49 deletions app/src/main/java/com/uniandes/ecobites/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,75 +8,40 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import com.uniandes.ecobites.ui.screens.ProfileScreen
import com.uniandes.ecobites.ui.screens.CartScreen
import com.uniandes.ecobites.ui.screens.home.HomeScreen
import com.uniandes.ecobites.ui.theme.AppTheme
import com.uniandes.ecobites.ui.components.NavBar
import androidx.navigation.compose.rememberNavController
import com.uniandes.ecobites.ui.SplashScreen
import com.uniandes.ecobites.ui.screens.LoginScreen
import io.github.jan.supabase.createSupabaseClient
import com.uniandes.ecobites.ui.components.BiometricAuth
import com.uniandes.ecobites.ui.navigation.NavigationHost
import com.uniandes.ecobites.ui.theme.AppTheme
import kotlinx.coroutines.delay
import io.github.jan.supabase.auth.Auth
import io.github.jan.supabase.postgrest.Postgrest

val supabase = createSupabaseClient(
supabaseUrl = "https://nlhcaanwwchxdzdiyizf.supabase.co",
supabaseKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im5saGNhYW53d2NoeGR6ZGl5aXpmIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mjc5MDc0OTQsImV4cCI6MjA0MzQ4MzQ5NH0.LrcRGkVH1qjPE09xDngX7wrtrUmfIYbTGrgbPKarTeM"
) {
install(Auth)
install(Postgrest)
//install other modules
}

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val biometricAuth = BiometricAuth(this)

setContent {
AppTheme {
MyApp()
MyApp(biometricAuth)
Comment on lines +21 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid passing Activity context to Composables to prevent memory leaks

Passing the Activity context via biometricAuth into Composables can lead to memory leaks or unexpected behavior due to the Composable lifecycle. Consider initializing BiometricAuth within the Composable using LocalContext or managing it through a ViewModel.

Apply this diff to move the initialization of BiometricAuth into the Composable:

 class MainActivity : ComponentActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

-        val biometricAuth = BiometricAuth(this)

         setContent {
             AppTheme {
-                MyApp(biometricAuth)
+                MyApp()
             }
         }
     }
 }

 @Composable
-fun MyApp(biometricAuth: BiometricAuth) {
+fun MyApp() {
     val navController = rememberNavController()
+    val context = LocalContext.current
+    val biometricAuth = remember { BiometricAuth(context) }
     // Rest of the code...
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val biometricAuth = BiometricAuth(this)
setContent {
AppTheme {
MyApp()
MyApp(biometricAuth)
setContent {
AppTheme {
MyApp()

}
}
}
}

@Composable
fun MyApp() {
fun MyApp(biometricAuth: BiometricAuth) {
val navController = rememberNavController() // Create the NavController
var showSplashScreen by remember { mutableStateOf(true) }
var isLoggedIn by remember { mutableStateOf(false) } // Track login state

// Show splash screen for 3 seconds before navigating to the main content
// Show splash screen for 1.5 seconds before navigating to the main content
LaunchedEffect(Unit) {
delay(3000) // 3 seconds delay
showSplashScreen = false // Hide splash screen after the delay
delay(1500)
showSplashScreen = false
}

if (showSplashScreen) {
SplashScreen() // Show splash screen
} else if (!isLoggedIn) {
LoginScreen(onLoginSuccess = { isLoggedIn = true }) // Pass a callback to update isLoggedIn
SplashScreen()
} else {
MainContent() // Show main content if logged in
NavigationHost(navController = navController, biometricAuth = biometricAuth) // Pass the NavController here
}
}


@Composable
fun MainContent() {
var selectedTab by remember { mutableIntStateOf(0) }

Scaffold(
bottomBar = {
NavBar(selectedTab = selectedTab, onTabSelected = { tab -> selectedTab = tab })
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
when (selectedTab) {
0 -> HomeScreen()
1 -> CartScreen()
3 -> ProfileScreen()
}
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.uniandes.ecobites.ui.components

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
import android.os.CancellationSignal
import androidx.core.app.ActivityCompat
import androidx.navigation.NavController

class BiometricAuth(private val context: Context) {
Comment on lines +1 to +12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Migrate to BiometricPrompt API for better security and user experience.

The implementation uses the deprecated FingerprintManager API. Consider migrating to the modern BiometricPrompt API which:

  • Provides a standardized UI across different Android versions
  • Supports multiple biometric authentication methods
  • Offers better security features
  • Is actively maintained by Google

Here's how to refactor using BiometricPrompt:

import androidx.biometric.BiometricPrompt
import androidx.biometric.BiometricManager
import androidx.fragment.app.FragmentActivity

class BiometricAuth(private val context: Context) {
    private val biometricManager = BiometricManager.from(context)
    private val executor = ContextCompat.getMainExecutor(context)


private var cancellationSignal: CancellationSignal? = null

// agregamos el navController para la navegación
private var navController: NavController? = null


private val authenticationCallback: FingerprintManager.AuthenticationCallback =
object : FingerprintManager.AuthenticationCallback() {
@Deprecated("Deprecated in Java")
override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
// Aquí manejo el éxito de la autenticación
navController?.navigate("home") {
popUpTo("login") { inclusive = true}
}
}

@Deprecated("Deprecated in Java")
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
// Aquí manejo la autenticación fallida
}
}
Comment on lines +14 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve code robustness and maintainability.

Several improvements needed:

  1. NavController shouldn't be nullable since it's required for navigation
  2. Comments should be in English for international collaboration
  3. Error handling in authentication callback is incomplete

Apply these improvements:

-    private var navController: NavController? = null
+    private lateinit var navController: NavController

-    // agregamos el navController para la navegación
-    private val authenticationCallback: FingerprintManager.AuthenticationCallback =
+    private val authenticationCallback = BiometricPrompt.AuthenticationCallback() {
+        override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
+            super.onAuthenticationSucceeded(result)
+            navController.navigate("home") {
+                popUpTo("login") { inclusive = true }
+            }
+        }
+
+        override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
+            super.onAuthenticationError(errorCode, errString)
+            // Handle specific error codes
+        }
+
+        override fun onAuthenticationFailed() {
+            super.onAuthenticationFailed()
+            // Show error message to user
+        }
     }

Committable suggestion skipped: line range outside the PR's diff.


// Función para verificar si la autenticación por huella está soportada en el dispositivo
fun isFingerprintSupported(): Boolean {
val fingerprintManager = context.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager

return if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
false
} else {
fingerprintManager.isHardwareDetected && fingerprintManager.hasEnrolledFingerprints()
}
}
Comment on lines +38 to +47
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update biometric support check for better security and error handling.

Current implementation has several issues:

  1. Uses deprecated USE_FINGERPRINT permission
  2. Lacks proper error handling for system service
  3. Direct casting could cause crashes

Implement proper error handling and use modern APIs:

fun isBiometricSupported(): Boolean {
    return when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)) {
        BiometricManager.BIOMETRIC_SUCCESS -> true
        BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE,
        BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
        BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> false
        else -> false
    }
}


// Función para iniciar la autenticación por huella y navegar a la pantalla de home si la navegación es exitosa
fun authenticate(navController: NavController) {
this.navController = navController // guardamos el navController para poder navegar después
val fingerprintManager = context.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager

if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
context as Activity,
arrayOf(Manifest.permission.USE_FINGERPRINT,Manifest.permission.USE_BIOMETRIC),
101
)// Permisos de huella no están concedidos, manejo de caso
return
}

cancellationSignal = CancellationSignal()

fingerprintManager.authenticate(null, cancellationSignal, 0, authenticationCallback, null)
}
Comment on lines +49 to +66
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address security vulnerabilities in authentication implementation.

Several critical security issues need attention:

  1. Unsafe context casting could crash the app
  2. Missing cryptographic authentication (allowing replay attacks)
  3. No proper error handling for permission denials

Implement secure authentication:

fun authenticate(activity: FragmentActivity, onError: (String) -> Unit) {
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Biometric Authentication")
        .setSubtitle("Log in using your biometric credential")
        .setNegativeButtonText("Cancel")
        .build()

    BiometricPrompt(activity, executor, authenticationCallback)
        .authenticate(promptInfo)
}

Consider implementing these security improvements:

  1. Use BiometricPrompt.CryptoObject for cryptographic authentication
  2. Implement proper error handling for all authentication states
  3. Add timeout handling for authentication attempts
  4. Consider implementing a fallback authentication method

}
Comment on lines +1 to +67
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Security concerns identified in biometric authentication implementation

The current implementation has several security issues:

  1. The biometric authentication directly navigates to "home" without any additional validation or token management
  2. No error handling or security state management in onAuthenticationFailed()
  3. Uses deprecated FingerprintManager API instead of the newer, more secure BiometricPrompt
  4. Lacks proper cryptographic binding between biometric authentication and user session

Recommendations:

  • Implement proper session management after successful biometric authentication
  • Add proper error handling and security state tracking
  • Migrate to BiometricPrompt API with proper cryptographic key attestation
  • Ensure biometric auth is used as a second factor, not a standalone auth method
🔗 Analysis chain

Verify the security context of biometric authentication usage.

Since this is a security-critical component, we should verify how it's being used in the authentication flow.


Let me gather more information about the authentication flow and security checks.


Let me check one more aspect about the login screen implementation to understand how biometric auth is integrated with other authentication methods.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how BiometricAuth is used in the codebase
echo "Checking BiometricAuth usage patterns..."

# Look for direct instantiations
rg "BiometricAuth\(" -A 5

# Check navigation patterns to understand the authentication flow
rg "navigate\(\"login\"|navigate\(\"home\"" -A 5

# Look for other security checks around these routes
ast-grep --pattern 'fun $_(navController: NavController) {
  $$$
  navigate("home")
  $$$
}'

Length of output: 4563


Script:

#!/bin/bash
# Check the NavigationHost implementation to understand the auth flow
rg -g "NavigationHost.kt" "composable\(\"login\"|composable\(\"home\"" -B 2 -A 10

# Look for any authentication state management
rg "authenticate|login|signIn" -t kt -A 5

# Check for any security-related configurations
rg -g "*.kt" "SecurityConfig|Authentication|@Secure" -A 5

Length of output: 4976


Script:

#!/bin/bash
# Check LoginScreen implementation
rg -g "LoginScreen.kt" "BiometricAuth|authenticate" -B 5 -A 10

# Look for any credential validation or auth state management
rg -g "LoginScreen.kt" "onLoginSuccess|password|credentials" -B 2 -A 5

Length of output: 7399

30 changes: 21 additions & 9 deletions app/src/main/java/com/uniandes/ecobites/ui/components/NavBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,46 @@ import androidx.compose.material.icons.rounded.Home
import androidx.compose.material.icons.rounded.ShoppingCart
import androidx.compose.material.icons.rounded.List
import androidx.compose.material.icons.rounded.Person
import androidx.compose.material.icons.rounded.LocationOn // Nuevo ícono de ubicación
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState

@Composable
fun NavBar(selectedTab: Int, onTabSelected: (Int) -> Unit) {
fun NavBar(navController: NavController) {
val currentRoute = navController.currentBackStackEntryAsState()?.value?.destination?.route

NavigationBar {
NavigationBarItem(
icon = { Icon(Icons.Rounded.Home, contentDescription = "Home") },
label = { Text("Home") },
selected = selectedTab == 0,
onClick = { onTabSelected(0) }
selected = currentRoute == "home",
onClick = { navController.navigate("home") }
Comment on lines +22 to +23
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract route names into constants to prevent typos.

Using hardcoded strings for routes across multiple places is error-prone. Consider creating a sealed class or object to manage route constants.

object NavRoutes {
    const val HOME = "home"
    const val CART = "cart"
    const val ORDERS = "orders"
    const val PROFILE = "profile"
    const val LOCATION = "location"
}

Then use it like:

-    selected = currentRoute == "home",
-    onClick = { navController.navigate("home") }
+    selected = currentRoute == NavRoutes.HOME,
+    onClick = { navController.navigate(NavRoutes.HOME) }

Also applies to: 28-29, 34-35, 40-41

)
NavigationBarItem(
icon = { Icon(Icons.Rounded.ShoppingCart, contentDescription = "Cart") },
label = { Text("Cart") },
selected = selectedTab == 1,
onClick = { onTabSelected(1) }
selected = currentRoute == "cart",
onClick = { navController.navigate("cart") }
)
NavigationBarItem(
icon = { Icon(Icons.Rounded.List, contentDescription = "Orders") },
label = { Text("Orders") },
selected = selectedTab == 2,
onClick = { onTabSelected(2) }
selected = currentRoute == "orders",
onClick = { navController.navigate("orders") }
)
NavigationBarItem(
icon = { Icon(Icons.Rounded.Person, contentDescription = "Profile") },
label = { Text("Profile") },
selected = selectedTab == 3,
onClick = { onTabSelected(3) }
selected = currentRoute == "profile",
onClick = { navController.navigate("profile") }
)
// Nuevo ítem de Location
NavigationBarItem(
icon = { Icon(Icons.Rounded.LocationOn, contentDescription = "Location") }, // Ícono de ubicación
label = { Text("Location") },
selected = currentRoute == "location",
onClick = { navController.navigate("location") }
)
}
}
19 changes: 19 additions & 0 deletions app/src/main/java/com/uniandes/ecobites/ui/data/MenuDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.uniandes.ecobites.ui.data

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query

@Dao
interface MenuDao {
@Query("SELECT * FROM MenuItem")
fun getAllMenuItems(): LiveData<List<MenuItem>>

@Insert
fun saveMenuItem(menuItem: MenuItem)
Comment on lines +14 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add conflict resolution and coroutine support.

The current implementation lacks:

  1. Conflict resolution strategy for duplicate items
  2. Coroutine support for background thread execution
-@Insert
-fun saveMenuItem(menuItem: MenuItem)
+@Insert(onConflict = OnConflictStrategy.REPLACE)
+suspend fun saveMenuItem(menuItem: MenuItem)

Don't forget to add the import:

import androidx.room.OnConflictStrategy


@Delete
fun deleteMenuItem(menuItem: MenuItem)
Comment on lines +17 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add coroutine support and bulk delete operation.

Enhance the delete functionality with:

  1. Coroutine support for background thread execution
  2. Bulk delete operation for better performance
-@Delete
-fun deleteMenuItem(menuItem: MenuItem)
+@Delete
+suspend fun deleteMenuItem(menuItem: MenuItem)
+
+@Delete
+suspend fun deleteMenuItems(menuItems: List<MenuItem>)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Delete
fun deleteMenuItem(menuItem: MenuItem)
@Delete
suspend fun deleteMenuItem(menuItem: MenuItem)
@Delete
suspend fun deleteMenuItems(menuItems: List<MenuItem>)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.uniandes.ecobites.ui.data

import androidx.room.Database
import androidx.room.RoomDatabase

@Database(entities = [MenuItem::class], version = 1)
abstract class MenuDatabase : RoomDatabase() {
abstract fun menuDao(): MenuDao
}
Comment on lines +6 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

🛠️ Refactor suggestion

Database implementation needs improvement - issues found in current setup

The verification revealed several issues with the current database implementation:

  1. Database instance is being created directly in the NavigationHost instead of using a singleton pattern:
// In NavigationHost.kt
val menuDatabase = Room.databaseBuilder(
    LocalContext.current,
    MenuDatabase::class.java,
    "menu.db"
).build()
  1. Missing configurations:

    • No schema export configuration in build.gradle
    • No migration strategy
    • Database creation is not thread-safe
    • Multiple database instances can be created
  2. Room dependencies need updating:

    • Using inconsistent versions (2.4.3 runtime, 2.5.1 compiler)
    • Newer stable versions are available (2.6.1)

The original review comment's suggestions are valid and necessary for a production-ready implementation. Please implement the suggested changes, particularly:

  • Move database initialization to the MenuDatabase companion object
  • Implement proper thread synchronization
  • Update Room dependencies to consistent versions
  • Add schema export configuration
🔗 Analysis chain

Essential improvements needed for production-ready database implementation.

While the basic setup is correct, several critical components are missing for a robust Room database implementation:

  1. Add singleton pattern to prevent multiple database instances
  2. Configure database name and export schema
  3. Implement migration strategy
  4. Add thread synchronization for database operations

Apply these improvements:

+@Database(
+    entities = [MenuItem::class],
+    version = 1,
+    exportSchema = true
+)
-@Database(entities = [MenuItem::class], version = 1)
 abstract class MenuDatabase : RoomDatabase() {
     abstract fun menuDao(): MenuDao
+
+    companion object {
+        @Volatile
+        private var INSTANCE: MenuDatabase? = null
+        private const val DATABASE_NAME = "menu_database"
+
+        fun getDatabase(context: Context): MenuDatabase {
+            return INSTANCE ?: synchronized(this) {
+                val instance = Room.databaseBuilder(
+                    context.applicationContext,
+                    MenuDatabase::class.java,
+                    DATABASE_NAME
+                )
+                .addMigrations() // Add migrations here when updating version
+                .build()
+                INSTANCE = instance
+                instance
+            }
+        }
+    }
 }

Don't forget to:

  1. Create a migrations package to maintain database migrations
  2. Add schema location in your build.gradle:
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += [
                    "room.schemaLocation": "$projectDir/schemas".toString()
                ]
            }
        }
    }
}

Let's verify if any migrations exist in the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for existing migration files and schema tracking

# Test 1: Look for migration files
echo "Checking for migration files..."
fd -e kt -e java --full-path ".*[Mm]igration.*"

# Test 2: Check build.gradle for schema location configuration
echo "Checking build.gradle for schema configuration..."
rg "room.schemaLocation" -A 3 -B 3

Length of output: 266


Script:

#!/bin/bash
# Let's verify the current database implementation and usage

# Check for database instance creation and configuration
echo "Checking database instance creation patterns..."
rg -A 10 "RoomDatabase\(\)" 

# Look for database builder configurations
echo "Checking database builder patterns..."
rg -A 10 "Room\.databaseBuilder"

# Check if there's any schema directory or configuration
echo "Checking for schema related configurations..."
fd "schemas"

# Check build.gradle files for Room configuration
echo "Checking build.gradle files for Room setup..."
fd "build.gradle" --exec cat {}

Length of output: 6325

11 changes: 11 additions & 0 deletions app/src/main/java/com/uniandes/ecobites/ui/data/MenuItem.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.uniandes.ecobites.ui.data

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class MenuItem(
@PrimaryKey val id: String,
val name: String,
val price: Double
)
Comment on lines +6 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance the Room entity with additional annotations and constraints.

The current implementation could benefit from several Room best practices and data validation improvements:

Apply these enhancements:

-@Entity
+@Entity(
+    tableName = "menu_items",
+    indices = [Index(value = ["name"])]
+)
 data class MenuItem(
-    @PrimaryKey val id: String,
-    val name: String,
-    val price: Double
+    @PrimaryKey
+    @ColumnInfo(name = "id")
+    val id: String,
+
+    @ColumnInfo(name = "name")
+    @NonNull
+    val name: String,
+
+    @ColumnInfo(name = "price")
+    @NonNull
+    val price: Double
 ) {
+    init {
+        require(price >= 0) { "Price must be non-negative" }
+        require(name.isNotBlank()) { "Name must not be blank" }
+    }
 }

Don't forget to add these imports:

import androidx.room.ColumnInfo
import androidx.room.Index
import androidx.annotation.NonNull

Loading