diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index d63fe80..4076d86 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -56,6 +56,14 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.material3)
implementation("androidx.compose.material:material-icons-extended:1.4.3")
+ implementation(libs.androidx.compose.runtime)
+
+ // CameraX
+ implementation("androidx.camera:camera-core:1.2.3")
+ implementation("androidx.camera:camera-camera2:1.2.3") // ⚠ Obligatoire
+ implementation(libs.androidx.camera.lifecycle)
+ implementation(libs.androidx.camera.view)
+
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
@@ -64,13 +72,15 @@ dependencies {
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)
- //implementation pour RETROFIT (API)
+ // Retrofit
implementation("com.squareup.retrofit2:retrofit:3.0.0")
implementation("com.squareup.retrofit2:converter-gson:3.0.0")
- //pour Room
+
+ // Room
implementation("androidx.room:room-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion")
-
+ // ML Kit
+ implementation("com.google.mlkit:barcode-scanning:17.2.0")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 91fa271..9861072 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,7 +1,7 @@
-
+
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/dev/collectiondvd/MainActivity.kt b/app/src/main/java/com/dev/collectiondvd/MainActivity.kt
index 6ea7c0f..2c65a83 100644
--- a/app/src/main/java/com/dev/collectiondvd/MainActivity.kt
+++ b/app/src/main/java/com/dev/collectiondvd/MainActivity.kt
@@ -1,6 +1,8 @@
package com.dev.collectiondvd
+import android.Manifest
import android.content.Intent
+import android.content.pm.PackageManager
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@@ -56,6 +58,11 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import com.dev.collectiondvd.ui.screen.ScanCodeActivity
+import com.dev.collectiondvd.ui.screen.StatDvdActivity
+import com.dev.collectiondvd.ui.theme.MyButton
class MainActivity : ComponentActivity() {
@@ -132,7 +139,6 @@ fun MenuScreen(
filteredDvds.sortedByDescending { it.annee.orEmpty() }
}
- // 🔍 Filtrage
Scaffold(
@@ -185,6 +191,7 @@ fun MenuScreen(
@Composable
fun TopBar() {
+ val context = LocalContext.current
Row(
modifier = Modifier
.fillMaxWidth()
@@ -195,12 +202,16 @@ fun TopBar() {
Text(
text = "Votre Vidéothèque",
fontSize = 22.sp,
- fontWeight = FontWeight.Bold
+ fontWeight = FontWeight.Bold,
+ style = MaterialTheme.typography.titleLarge
)
-// Row {
-// Text("ⓘ", fontSize = 20.sp)
-// }
+ Row {
+ MyButton ("ⓘ"){
+ context.startActivity(
+ Intent(context, StatDvdActivity::class.java) )
+ }
+ }
}
}
@@ -231,7 +242,7 @@ fun SortChip(
onSortSelected: (SortType) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
-
+ val context = LocalContext.current
Card(
modifier = Modifier.clickable { expanded = true },
shape = RoundedCornerShape(50),
@@ -260,6 +271,13 @@ fun SortChip(
)
}
}
+
+ MyButton("Scanner") {
+ val intent = Intent(context, ScanCodeActivity::class.java)
+ context.startActivity(intent)
+ }
+
+
}
@Composable
diff --git a/app/src/main/java/com/dev/collectiondvd/data/local/AppDatabase.kt b/app/src/main/java/com/dev/collectiondvd/data/local/AppDatabase.kt
index cff73ac..df73645 100644
--- a/app/src/main/java/com/dev/collectiondvd/data/local/AppDatabase.kt
+++ b/app/src/main/java/com/dev/collectiondvd/data/local/AppDatabase.kt
@@ -7,7 +7,7 @@ import androidx.room.RoomDatabase
import com.dev.collectiondvd.data.local.dao.DvdDao
import com.dev.collectiondvd.data.local.entities.Dvd
-@Database( entities = [Dvd::class], version = 1)
+@Database( entities = [Dvd::class], version = 2)
abstract class AppDatabase : RoomDatabase(){
abstract fun dvdDao(): DvdDao
@@ -21,7 +21,7 @@ abstract class AppDatabase : RoomDatabase(){
context.applicationContext,
AppDatabase::class.java,
"dvd_manager"
- ).build().also { INSTANCE = it }
+ ).fallbackToDestructiveMigration().build().also { INSTANCE = it }
}
}
diff --git a/app/src/main/java/com/dev/collectiondvd/data/local/dao/DvdDao.kt b/app/src/main/java/com/dev/collectiondvd/data/local/dao/DvdDao.kt
index 363b246..b275c64 100644
--- a/app/src/main/java/com/dev/collectiondvd/data/local/dao/DvdDao.kt
+++ b/app/src/main/java/com/dev/collectiondvd/data/local/dao/DvdDao.kt
@@ -22,5 +22,8 @@ interface DvdDao{
@Query("SELECT * FROM dvds WHERE id = :numero")
fun getDvdById(numero: Long): Flow
+ @Query("SELECT * FROM dvds WHERE barcode = :barcode LIMIT 1")
+ suspend fun getByBarcode(barcode: String): Dvd?
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/dev/collectiondvd/data/local/entities/Dvd.kt b/app/src/main/java/com/dev/collectiondvd/data/local/entities/Dvd.kt
index 5c4f30a..7e0d5e4 100644
--- a/app/src/main/java/com/dev/collectiondvd/data/local/entities/Dvd.kt
+++ b/app/src/main/java/com/dev/collectiondvd/data/local/entities/Dvd.kt
@@ -11,5 +11,7 @@ data class Dvd (
val annee: String,
val realisateur: String,
val genre: String,
- val synced: Boolean = false
+ val synced: Boolean = false,
+ val barcode: String? = null,
+ val poster: String? = null
)
\ No newline at end of file
diff --git a/app/src/main/java/com/dev/collectiondvd/ui/screen/AjoutDvdActivity.kt b/app/src/main/java/com/dev/collectiondvd/ui/screen/AjoutDvdActivity.kt
index baf4024..ac9a6b2 100644
--- a/app/src/main/java/com/dev/collectiondvd/ui/screen/AjoutDvdActivity.kt
+++ b/app/src/main/java/com/dev/collectiondvd/ui/screen/AjoutDvdActivity.kt
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FabPosition
import androidx.compose.material3.MaterialTheme
@@ -52,6 +53,7 @@ class AjoutDvdActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ val barcode = intent.getStringExtra("barcode")
setContent {
CollectionDvdTheme(darkTheme = true) {
AjoutDvdScreen(
@@ -59,7 +61,8 @@ class AjoutDvdActivity : ComponentActivity() {
onAdd = { dvd ->
viewModel.addDvd(dvd)
finish()
- }
+ },
+ preFilledBarcode = barcode
)
}
}
@@ -71,12 +74,14 @@ class AjoutDvdActivity : ComponentActivity() {
@Composable
fun AjoutDvdScreen(
onQuit: () -> Unit,
- onAdd: (Dvd) -> Unit
+ onAdd: (Dvd) -> Unit,
+ preFilledBarcode: String? = null
) {
var titre by remember { mutableStateOf("") }
var annee by remember { mutableStateOf("") }
var realisateur by remember { mutableStateOf("") }
var genre by remember { mutableStateOf("") }
+ var barcode by remember { mutableStateOf(preFilledBarcode?: "") }
Scaffold(
containerColor = MaterialTheme.colorScheme.background, // fond sombre
@@ -100,10 +105,15 @@ fun AjoutDvdScreen(
// Champs stylisés
StyledTextField(value = titre, onValueChange = { titre = it }, label = "Titre")
+
+ StyledTextField(value = barcode, onValueChange = { barcode = it }, label = "Code-barres")
+
StyledTextField(value = realisateur, onValueChange = { realisateur = it }, label = "Réalisateur")
StyledTextField(value = annee, onValueChange = { annee = it }, label = "Année")
StyledTextField(value = genre, onValueChange = { genre = it }, label = "Genre")
+
+
Spacer(modifier = Modifier.height(16.dp))
Row{
@@ -120,6 +130,12 @@ fun AjoutDvdScreen(
}
}
MyButton("Quitter") { onQuit() }
+
+ Button(
+ onClick = { }
+ ) {
+ Text("Scanner un DVD")
+ }
}
}
}
diff --git a/app/src/main/java/com/dev/collectiondvd/ui/screen/ScanCodeActivity.kt b/app/src/main/java/com/dev/collectiondvd/ui/screen/ScanCodeActivity.kt
new file mode 100644
index 0000000..75a4a77
--- /dev/null
+++ b/app/src/main/java/com/dev/collectiondvd/ui/screen/ScanCodeActivity.kt
@@ -0,0 +1,134 @@
+package com.dev.collectiondvd.ui.screen
+
+import android.Manifest
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageAnalysis
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.view.PreviewView
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.compose.LocalLifecycleOwner
+import com.google.mlkit.vision.barcode.BarcodeScanning
+import com.google.mlkit.vision.common.InputImage
+
+class ScanCodeActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // Permission launcher moderne
+ val requestPermissionLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
+ if (isGranted) startScan()
+ else finish() // permission refusée
+ }
+
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
+ != android.content.pm.PackageManager.PERMISSION_GRANTED
+ ) {
+ requestPermissionLauncher.launch(Manifest.permission.CAMERA)
+ } else {
+ startScan()
+ }
+ }
+
+ private fun startScan() {
+ setContent {
+ ScanBarcodeScreen(
+ onBarcodeDetected = { code ->
+ Log.d("SCAN", "Barcode détecté: $code")
+ val intent = Intent(this, AjoutDvdActivity::class.java)
+ intent.putExtra("barcode", code)
+ startActivity(intent)
+ finish()
+ },
+ onBack = { finish() }
+ )
+ }
+ }
+}
+
+@Composable
+fun ScanBarcodeScreen(
+ onBarcodeDetected: (String) -> Unit,
+ onBack: () -> Unit
+) {
+ val context = LocalContext.current
+ val lifecycleOwner = LocalLifecycleOwner.current
+ val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) }
+
+ // State pour éviter double scan
+ val scanned = remember { mutableStateOf(false) }
+
+ AndroidView(factory = { ctx ->
+ val previewView = PreviewView(ctx)
+
+ cameraProviderFuture.addListener({
+ try {
+ val cameraProvider = cameraProviderFuture.get()
+
+ val preview = Preview.Builder().build().also {
+ it.setSurfaceProvider(previewView.surfaceProvider)
+ }
+
+ val barcodeScanner = BarcodeScanning.getClient()
+
+ val imageAnalyzer = ImageAnalysis.Builder()
+ .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
+ .build()
+ .also { analysis ->
+ analysis.setAnalyzer(ContextCompat.getMainExecutor(ctx)) { imageProxy ->
+ val mediaImage = imageProxy.image
+ if (mediaImage != null) {
+ val inputImage = InputImage.fromMediaImage(
+ mediaImage,
+ imageProxy.imageInfo.rotationDegrees
+ )
+ barcodeScanner.process(inputImage)
+ .addOnSuccessListener { barcodes ->
+ if (!scanned.value) {
+ barcodes.forEach { barcode ->
+ barcode.rawValue?.let { code ->
+ scanned.value = true
+ onBarcodeDetected(code)
+ }
+ }
+ }
+ }
+ .addOnFailureListener { e ->
+ Log.e("SCAN", "Erreur ML Kit: ${e.message}")
+ }
+ .addOnCompleteListener { imageProxy.close() }
+ } else {
+ imageProxy.close()
+ }
+ }
+ }
+
+ val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+ cameraProvider.unbindAll()
+ cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalyzer)
+ Log.d("SCAN", "CameraX bound")
+ } catch (e: Exception) {
+ Log.e("SCAN", "Erreur CameraX: ${e.message}")
+ e.printStackTrace()
+ }
+ }, ContextCompat.getMainExecutor(ctx))
+
+ previewView
+ }, modifier = Modifier.fillMaxSize())
+}
diff --git a/app/src/main/java/com/dev/collectiondvd/ui/screen/StatDvdActivity.kt b/app/src/main/java/com/dev/collectiondvd/ui/screen/StatDvdActivity.kt
new file mode 100644
index 0000000..0d6330f
--- /dev/null
+++ b/app/src/main/java/com/dev/collectiondvd/ui/screen/StatDvdActivity.kt
@@ -0,0 +1,245 @@
+package com.dev.collectiondvd.ui.screen
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.statusBars
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.Divider
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+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.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.lifecycle.ViewModelProvider
+import com.dev.collectiondvd.MenuScreen
+import com.dev.collectiondvd.data.local.AppDatabase
+import com.dev.collectiondvd.data.repository.LocalDvdRepository
+import com.dev.collectiondvd.ui.theme.CollectionDvdTheme
+import com.dev.collectiondvd.ui.theme.MyButton
+import com.dev.collectiondvd.viewmodel.LocalDvdViewModel
+import com.dev.collectiondvd.viewmodel.factory.LocalDvdViewModelFactory
+
+class StatDvdActivity: ComponentActivity() {
+ private lateinit var viewModel: LocalDvdViewModel
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val database = AppDatabase.getDatabase(applicationContext)
+ val dvdDao = database.dvdDao()
+ val repository = LocalDvdRepository(dvdDao)
+ val factory = LocalDvdViewModelFactory(repository)
+ viewModel = ViewModelProvider(this, factory).get(LocalDvdViewModel::class.java)
+ setContent {
+ CollectionDvdTheme(darkTheme = true) {
+ StatDvdScreen(
+ onQuit = { finish() },
+ viewModel = viewModel
+ )
+ }
+ }
+ }
+}
+
+
+@Composable
+fun StatDvdScreen(
+ viewModel: LocalDvdViewModel,
+ onQuit: () -> Unit
+) {
+ val dvds by viewModel.dvds.collectAsState(initial = emptyList())
+
+ val totalDvds = dvds.size
+
+ val genresCount = dvds.groupingBy { it.genre }.eachCount()
+ val directorsCount = dvds.groupingBy { it.realisateur }.eachCount()
+
+ val numberOfGenres = genresCount.size
+ val favoriteGenre = genresCount.maxByOrNull { it.value }?.key ?: "Aucun"
+ val favoriteDirector = directorsCount.maxByOrNull { it.value }?.key ?: "Aucun"
+
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
+ ) {
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(
+ top = WindowInsets.statusBars
+ .asPaddingValues()
+ .calculateTopPadding()
+ )
+ .padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = "Mes Statistiques",
+ style = MaterialTheme.typography.titleLarge.copy(
+ fontWeight = FontWeight.Bold
+ )
+ )
+ }
+
+
+ StatCardDvd(totalDvds)
+ StatCard("Réalisateur", directorsCount.size, favoriteDirector)
+ StatCard("Genre", numberOfGenres, favoriteGenre)
+
+ Text("La suite est en développement...")
+
+ //Spacer(modifier = Modifier.weight(0.5f))
+
+ MyButton("Quitter") {
+ onQuit()
+ }
+ }
+ }
+}
+
+@Composable
+fun StatCardDvd(
+ totalDvd :Int,
+){
+ var expended by remember { mutableStateOf(false) }
+
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 6.dp),
+ shape = RoundedCornerShape(12.dp)
+ ){
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(8.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.Top
+ ) {
+ Text(
+ "Films",
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 16.sp,
+ color = Color(0xFFFFA405)
+ )
+ }
+
+ Divider()
+
+ Row(
+ modifier = Modifier.padding(12.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ){
+
+// Box(
+// modifier = Modifier
+// .height(90.dp)
+// .width(60.dp)
+// .background(
+// MaterialTheme.colorScheme.surfaceVariant,
+// RoundedCornerShape(8.dp)
+// )
+// )
+
+ Spacer(modifier = Modifier.width(12.dp))
+
+ Column {
+ Text("Vous possedez: ${totalDvd} Dvds")
+ }
+
+ }
+ }
+ }
+}
+
+@Composable
+fun StatCard(
+ name: String,
+ total :Int,
+ preferer: String
+){
+ var expended by remember { mutableStateOf(false) }
+
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 6.dp),
+ shape = RoundedCornerShape(12.dp)
+ ){
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(8.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.Top
+ ) {
+ Text(
+ "${name}",
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 16.sp,
+ color = Color(0xFFFFA405)
+ )
+ }
+
+ Divider()
+
+ Row(
+ modifier = Modifier.padding(12.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ){
+
+// Box(
+// modifier = Modifier
+// .height(90.dp)
+// .width(60.dp)
+// .background(
+// MaterialTheme.colorScheme.surfaceVariant,
+// RoundedCornerShape(8.dp)
+// )
+// )
+
+ Spacer(modifier = Modifier.width(12.dp))
+
+ Column {
+ Text("Vous avez: ${total} ${name}")
+ Text("Votre ${name} preferé est: ${preferer} ")
+ }
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dev/collectiondvd/viewmodel/LocalDvdViewModel.kt b/app/src/main/java/com/dev/collectiondvd/viewmodel/LocalDvdViewModel.kt
index 39af12e..feda7fc 100644
--- a/app/src/main/java/com/dev/collectiondvd/viewmodel/LocalDvdViewModel.kt
+++ b/app/src/main/java/com/dev/collectiondvd/viewmodel/LocalDvdViewModel.kt
@@ -44,4 +44,15 @@ class LocalDvdViewModel (
}
}
+ fun addDvdFromBarcode(barcode: String, titre: String, realisateur: String, annee: String, genre: String) {
+ addDvd(Dvd(titre = titre, realisateur = realisateur, annee = annee, genre = genre, barcode = barcode))
+ }
+
+// fun getDvdByBarcode(barcode: String, onResult: (Dvd?) -> Unit) {
+// viewModelScope.launch {
+// val dvd = repository.getDvdByBarcode(barcode)
+// onResult(dvd)
+// }
+// }
+
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 01870cc..b4ad44d 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -10,6 +10,9 @@ activityCompose = "1.12.1"
composeBom = "2024.09.00"
uiGraphics = "1.10.0"
material3 = "1.4.0"
+runtime = "1.10.0"
+cameraLifecycle = "1.5.2"
+cameraView = "1.5.2"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -28,6 +31,9 @@ androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-te
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics", version.ref = "uiGraphics" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
+androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime", version.ref = "runtime" }
+androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "cameraLifecycle" }
+androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraView" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }