recherche #2

Open
emile.lalorcey wants to merge 4 commits from recherche into main
34 changed files with 971 additions and 369 deletions

View File

@@ -53,6 +53,17 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3) implementation(libs.androidx.compose.material3)
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) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
@@ -61,13 +72,15 @@ dependencies {
debugImplementation(libs.androidx.compose.ui.tooling) debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest) debugImplementation(libs.androidx.compose.ui.test.manifest)
//implementation pour RETROFIT (API) // Retrofit
implementation("com.squareup.retrofit2:retrofit:3.0.0") implementation("com.squareup.retrofit2:retrofit:3.0.0")
implementation("com.squareup.retrofit2:converter-gson: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-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion") implementation("androidx.room:room-ktx:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion") kapt("androidx.room:room-compiler:$roomVersion")
// ML Kit
implementation("com.google.mlkit:barcode-scanning:17.2.0")
} }

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.CAMERA"/>
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
@@ -23,8 +23,10 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".ui.screen.AjoutDvdActivity"/> <activity android:name=".ui.screen.AjoutDvdActivity"/>
<activity android:name=".ui.screen.ListDvdActivity"/> <activity android:name=".ui.screen.StatDvdActivity"/>
<activity android:name=".ui.screen.SupprDvdActivity"/> <activity android:name=".ui.screen.SupprDvdActivity"/>
<activity android:name=".ui.screen.ScanCodeActivity"/>
</application> </application>
</manifest> </manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -1,66 +1,392 @@
package com.dev.collectiondvd package com.dev.collectiondvd
import android.Manifest
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize 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.padding
import androidx.compose.material3.Button import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable 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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.ViewModelProvider
import com.dev.collectiondvd.data.local.AppDatabase
import com.dev.collectiondvd.data.local.entities.Dvd
import com.dev.collectiondvd.data.repository.LocalDvdRepository
import com.dev.collectiondvd.ui.screen.AjoutDvdActivity import com.dev.collectiondvd.ui.screen.AjoutDvdActivity
import com.dev.collectiondvd.ui.screen.ListDvdActivity
import com.dev.collectiondvd.ui.screen.SupprDvdActivity
import com.dev.collectiondvd.ui.theme.CollectionDvdTheme import com.dev.collectiondvd.ui.theme.CollectionDvdTheme
import com.dev.collectiondvd.viewmodel.LocalDvdViewModel
import com.dev.collectiondvd.viewmodel.factory.LocalDvdViewModelFactory
import androidx.compose.material3.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.MoreVert
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 import com.dev.collectiondvd.ui.theme.MyButton
import kotlin.system.exitProcess
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private lateinit var viewModel: LocalDvdViewModel
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { MenuScreen() } 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) {
MenuScreen(
onQuit = { finish() },
viewModel = viewModel
)
} }
} }
}
}
enum class SortType(
val label: String
) {
TITLE_ASC("Titre (ascendant)"),
TITLE_DESC("Titre (descendant)"),
DIRECTOR_ASC("Réalisateur (ascendant)"),
DIRECTOR_DESC("Réalisateur (descendant)"),
YEAR_ASC("Année (ascendant)"),
YEAR_DESC("Année (descendant)")
}
@Composable @Composable
fun MenuScreen() { fun MenuScreen(
viewModel: LocalDvdViewModel,
onQuit: () -> Unit
) {
val context = LocalContext.current val context = LocalContext.current
val dvds by viewModel.dvds.collectAsState(initial = emptyList())
var searchQuery by remember { mutableStateOf("") }
val filteredDvds = dvds.filter { dvd ->
val query = searchQuery.lowercase()
dvd.titre.orEmpty().lowercase().contains(query) ||
dvd.realisateur.orEmpty().lowercase().contains(query) ||
dvd.genre.orEmpty().lowercase().contains(query) ||
dvd.annee.orEmpty().lowercase().contains(query)
}
var sortType by remember { mutableStateOf(SortType.TITLE_ASC) }
val filteredAndSortedDvds = when (sortType) {
SortType.TITLE_ASC ->
filteredDvds.sortedBy { it.titre.orEmpty().lowercase() }
SortType.TITLE_DESC ->
filteredDvds.sortedByDescending { it.titre.orEmpty() }
SortType.DIRECTOR_ASC ->
filteredDvds.sortedBy { it.realisateur.orEmpty() }
SortType.DIRECTOR_DESC ->
filteredDvds.sortedByDescending { it.realisateur.orEmpty() }
SortType.YEAR_ASC ->
filteredDvds.sortedBy { it.annee.orEmpty() }
SortType.YEAR_DESC ->
filteredDvds.sortedByDescending { it.annee.orEmpty() }
}
Scaffold(
floatingActionButtonPosition = FabPosition.Center,
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Ajouter") },
icon = { Text("+") },
onClick = {
context.startActivity(
Intent(context, AjoutDvdActivity::class.java)
)
}
)
}
) { padding ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(16.dp), .padding(padding)
verticalArrangement = Arrangement.spacedBy(12.dp), .padding(12.dp)
horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Text("Gestion la collection de DVD", fontSize = 28.sp)
MyButton("Liste des DVDs") { context.startActivity(Intent(context, ListDvdActivity::class.java)) }
MyButton("Ajouter un DVD") { context.startActivity(Intent(context, AjoutDvdActivity::class.java)) } TopBar()
MyButton("Supprimer un DVD") { context.startActivity((Intent(context, SupprDvdActivity::class.java)))} SearchBar(searchQuery) { searchQuery = it }
Spacer(modifier = Modifier.height(8.dp))
SortChip(
currentSort = sortType,
onSortSelected = { sortType = it }
)
Spacer(modifier = Modifier.height(8.dp))
DvdList(
dvds = filteredAndSortedDvds,
onDelete = { dvd ->
viewModel.deleteDvd(dvd)
}
)
}
} }
} }
@Preview(showBackground = true)
@Composable @Composable
fun MenuScreenPreview() { fun TopBar() {
CollectionDvdTheme { val context = LocalContext.current
com.dev.collectiondvd.MenuScreen() Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Votre Vidéothèque",
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleLarge
)
Row {
MyButton (""){
context.startActivity(
Intent(context, StatDvdActivity::class.java) )
}
}
}
}
@Composable
fun SearchBar(
value: String,
onValueChange: (String) -> Unit
) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
placeholder = { Text("Chercher votre film (Par: titre, réal, etc)") },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
shape = RoundedCornerShape(50),
colors = TextFieldDefaults.colors(
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
)
)
}
@Composable
fun SortChip(
currentSort: SortType,
onSortSelected: (SortType) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
val context = LocalContext.current
Card(
modifier = Modifier.clickable { expanded = true },
shape = RoundedCornerShape(50),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant
)
) {
Text(
text = "${currentSort.label}",
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
fontSize = 14.sp
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
SortType.values().forEach { sort ->
DropdownMenuItem(
text = { Text(sort.label) },
onClick = {
expanded = false
onSortSelected(sort)
}
)
}
}
MyButton("Scanner") {
val intent = Intent(context, ScanCodeActivity::class.java)
context.startActivity(intent)
}
}
@Composable
fun DvdList(
dvds: List<Dvd>,
onDelete: (Dvd) -> Unit
) {
LazyColumn {
items(dvds, key = { it.id }) { dvd ->
DvdItem(dvd = dvd, onDelete = onDelete)
}
}
}
@Composable
fun DvdItem(
dvd: Dvd,
onDelete: (Dvd) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 6.dp),
shape = RoundedCornerShape(12.dp)
) {
Column {
// Ligne du haut : titre + menu
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.Top
) {
Text(
dvd.titre.orEmpty().uppercase(),
fontWeight = FontWeight.SemiBold,
fontSize = 16.sp,
color = Color(0xFFFFA405)
)
Box {
IconButton(onClick = { expanded = true }) {
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = "Menu"
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
text = { Text("Supprimer") },
leadingIcon = {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = null
)
},
onClick = {
expanded = false
onDelete(dvd)
}
)
DropdownMenuItem(
text = { Text("Modifier") },
leadingIcon = {
Icon(
imageVector = Icons.Default.Edit,
contentDescription = null
)
},
onClick = {}
)
}
}
}
Divider()
// 📀 Contenu
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("Réalisateur: ${dvd.realisateur.orEmpty().uppercase()}")
Text("Année: ${dvd.annee.orEmpty()}")
Text("Genre: ${dvd.genre.orEmpty().uppercase()}")
}
}
}
} }
} }

View File

@@ -7,7 +7,7 @@ import androidx.room.RoomDatabase
import com.dev.collectiondvd.data.local.dao.DvdDao import com.dev.collectiondvd.data.local.dao.DvdDao
import com.dev.collectiondvd.data.local.entities.Dvd 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 class AppDatabase : RoomDatabase(){
abstract fun dvdDao(): DvdDao abstract fun dvdDao(): DvdDao
@@ -21,7 +21,7 @@ abstract class AppDatabase : RoomDatabase(){
context.applicationContext, context.applicationContext,
AppDatabase::class.java, AppDatabase::class.java,
"dvd_manager" "dvd_manager"
).build().also { INSTANCE = it } ).fallbackToDestructiveMigration().build().also { INSTANCE = it }
} }
} }

View File

@@ -22,5 +22,8 @@ interface DvdDao{
@Query("SELECT * FROM dvds WHERE id = :numero") @Query("SELECT * FROM dvds WHERE id = :numero")
fun getDvdById(numero: Long): Flow<Dvd?> fun getDvdById(numero: Long): Flow<Dvd?>
@Query("SELECT * FROM dvds WHERE barcode = :barcode LIMIT 1")
suspend fun getByBarcode(barcode: String): Dvd?
} }

View File

@@ -11,5 +11,7 @@ data class Dvd (
val annee: String, val annee: String,
val realisateur: String, val realisateur: String,
val genre: String, val genre: String,
val synced: Boolean = false val synced: Boolean = false,
val barcode: String? = null,
val poster: String? = null
) )

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -12,9 +12,16 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding 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 import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -22,14 +29,17 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.dev.collectiondvd.data.local.AppDatabase import com.dev.collectiondvd.data.local.AppDatabase
import com.dev.collectiondvd.data.local.entities.Dvd import com.dev.collectiondvd.data.local.entities.Dvd
import com.dev.collectiondvd.data.repository.LocalDvdRepository 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.ui.theme.MyButton
import com.dev.collectiondvd.viewmodel.LocalDvdViewModel import com.dev.collectiondvd.viewmodel.LocalDvdViewModel
import com.dev.collectiondvd.viewmodel.factory.LocalDvdViewModelFactory import com.dev.collectiondvd.viewmodel.factory.LocalDvdViewModelFactory
import org.intellij.lang.annotations.JdkConstants
class AjoutDvdActivity : ComponentActivity() { class AjoutDvdActivity : ComponentActivity() {
@@ -43,67 +53,71 @@ class AjoutDvdActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val barcode = intent.getStringExtra("barcode")
setContent { setContent {
AjoutDvdScreen(onQuit = { finish() }, onAdd = CollectionDvdTheme(darkTheme = true) {
{ dvd -> AjoutDvdScreen(
onQuit = { finish() },
onAdd = { dvd ->
viewModel.addDvd(dvd) viewModel.addDvd(dvd)
finish() finish()
} },
preFilledBarcode = barcode
) )
} }
} }
}
} }
@Composable @Composable
fun AjoutDvdScreen(onQuit: () -> Unit, onAdd: (Dvd) -> Unit){ fun AjoutDvdScreen(
//val context = LocalContext.current onQuit: () -> Unit,
var titre by remember() { mutableStateOf("") } onAdd: (Dvd) -> Unit,
var annee by remember() { mutableStateOf("") } preFilledBarcode: String? = null
var realisateur by remember() { mutableStateOf("") } ) {
var genre by remember() { mutableStateOf("") } 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
) { padding ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(16.dp), .padding(padding)
.padding(horizontal = 16.dp, vertical = 12.dp),
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text("Ajouter un dvd",
Text(
"Ajouter un DVD",
fontSize = 26.sp, fontSize = 26.sp,
style = MaterialTheme.typography.titleLarge, style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(bottom = 20.dp) color = MaterialTheme.colorScheme.onBackground
) )
OutlinedTextField( // Champs stylisés
value = titre, StyledTextField(value = titre, onValueChange = { titre = it }, label = "Titre")
onValueChange = { newValue -> titre = newValue },
label = {Text("Titre")},
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = realisateur,
onValueChange = { newValue -> realisateur = newValue },
label = {Text("Réalisateur")},
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = annee,
onValueChange = { newValue -> annee = newValue },
label = {Text("Année")},
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = genre,
onValueChange = { newValue -> genre = newValue },
label = {Text("Genre")},
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(20.dp)) StyledTextField(value = barcode, onValueChange = { barcode = it }, label = "Code-barres")
Column { StyledTextField(value = realisateur, onValueChange = { realisateur = it }, label = "Réalisateur")
MyButton("Ajouter") { StyledTextField(value = annee, onValueChange = { annee = it }, label = "Année")
StyledTextField(value = genre, onValueChange = { genre = it }, label = "Genre")
Spacer(modifier = Modifier.height(16.dp))
Row{
MyButton("Valider") {
if (titre.isNotBlank()) { if (titre.isNotBlank()) {
onAdd( onAdd(
Dvd( Dvd(
@@ -115,7 +129,42 @@ fun AjoutDvdScreen(onQuit: () -> Unit, onAdd: (Dvd) -> Unit){
) )
} }
} }
MyButton("Quitter") { onQuit() }
Button(
onClick = { }
) {
Text("Scanner un DVD")
}
}
}
}
} }
} @Composable
fun StyledTextField(
value: String,
onValueChange: (String) -> Unit,
label: String
) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
placeholder = { Text(label, color = MaterialTheme.colorScheme.onSurfaceVariant) },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(50),
colors = TextFieldDefaults.colors(
focusedTextColor = MaterialTheme.colorScheme.onSurface,
unfocusedTextColor = MaterialTheme.colorScheme.onSurface,
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,
unfocusedPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,
cursorColor = MaterialTheme.colorScheme.primary
)
)
} }

View File

@@ -1,90 +0,0 @@
package com.dev.collectiondvd.ui.screen
import android.graphics.ColorSpace
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Divider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.dev.collectiondvd.data.local.AppDatabase
import com.dev.collectiondvd.data.repository.LocalDvdRepository
import com.dev.collectiondvd.ui.theme.MyButton
import com.dev.collectiondvd.viewmodel.LocalDvdViewModel
import com.dev.collectiondvd.viewmodel.factory.LocalDvdViewModelFactory
class ListDvdActivity : 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 { ListDvdScreen(onQuit = { finish() }, viewModel = viewModel) }
}
}
@Composable
fun ListDvdScreen(
viewModel: LocalDvdViewModel,
onQuit: ()-> Unit
){
val dvds by viewModel.dvds.collectAsState(initial = emptyList())
Column(
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
)
{
Text(
"Vos Dvds",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = 8.dp)
)
if(dvds.isEmpty()){
Box(
modifier = Modifier.weight(1f),
contentAlignment = Alignment.Center
){
Text("Aucun Dvd dans votre collection")
}
} else {
LazyColumn(modifier = Modifier.weight(1f)) {
items ( dvds, key = { it.id}) { dvd ->
Column(modifier = Modifier.padding(8.dp)) {
Text(dvd.titre.orEmpty())
Text(dvd.realisateur.orEmpty())
Text(dvd.annee.orEmpty())
Text(dvd.genre.orEmpty())
Divider()
}
}
}
}
MyButton("Quitter") { onQuit() }
}
}

View File

@@ -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())
}

View File

@@ -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} ")
}
}
}
}
}

View File

@@ -3,8 +3,6 @@ package com.dev.collectiondvd.ui.screen
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@@ -97,7 +95,7 @@ fun SupprDvdScreen(onQuit: () -> Unit, viewModel: LocalDvdViewModel){
MyButton("Supprimer le Dvd") MyButton("Supprimer le Dvd")
{ {
viewModel.deleteDvd() viewModel.deleteDvd(dvd)
selectedId = null selectedId = null
} }
} }

View File

@@ -3,7 +3,9 @@ package com.dev.collectiondvd.ui.theme
import android.app.Activity import android.app.Activity
import android.os.Build import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -65,17 +67,15 @@ fun CollectionDvdTheme(
} }
@Composable @Composable
fun MyButton( fun MyButton(text: String, onClick: () -> Unit) {
text: String,
onClick: () -> Unit
) {
Button( Button(
onClick = onClick, onClick = onClick,
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color.Blue, // Couleur de fond containerColor = Color(0xFFFFA405), // ton orange
contentColor = Color.White // Couleur du texte contentColor = Color.Black
), ),
modifier = Modifier.size(width = 200.dp, height = 50.dp) // Taille uniforme shape = RoundedCornerShape(50),
modifier = Modifier.padding(horizontal = 8.dp)
) { ) {
Text(text) Text(text)
} }

View File

@@ -38,13 +38,21 @@ class LocalDvdViewModel (
} }
} }
fun deleteDvd() { fun deleteDvd(dvd: Dvd) {
viewModelScope.launch { viewModelScope.launch {
_selectedDvd.value?.let { dvd ->
repository.deleteDvd(dvd) repository.deleteDvd(dvd)
_selectedDvd.value = null
}
} }
} }
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)
// }
// }
} }

View File

@@ -1,170 +1,74 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector
android:width="108dp"
android:height="108dp" android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> xmlns:android="http://schemas.android.com/apk/res/android">
<path <path android:fillColor="#3DDC84"
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/> android:pathData="M0,0h108v108h-108z"/>
<path <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:fillColor="#00000000" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:pathData="M9,0L9,108" <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
<path android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:fillColor="#00000000" <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:pathData="M19,0L19,108" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeWidth="0.8" <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" /> android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:fillColor="#00000000" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:pathData="M29,0L29,108" <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
<path android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:fillColor="#00000000" <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:pathData="M39,0L39,108" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeWidth="0.8" <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" /> android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:fillColor="#00000000" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:pathData="M49,0L49,108" <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
<path android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:fillColor="#00000000" <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:pathData="M59,0L59,108" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeWidth="0.8" <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" /> android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:fillColor="#00000000" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:pathData="M69,0L69,108" <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
<path android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:fillColor="#00000000" <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:pathData="M79,0L79,108" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeWidth="0.8" <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" /> android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:fillColor="#00000000" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:pathData="M89,0L89,108" <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
<path android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:fillColor="#00000000" <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:pathData="M99,0L99,108" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeWidth="0.8" <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" /> android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:fillColor="#00000000" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:pathData="M0,9L108,9" <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
<path android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:fillColor="#00000000" <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:pathData="M0,19L108,19" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeWidth="0.8" <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" /> android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:fillColor="#00000000" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:pathData="M0,29L108,29" <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector> </vector>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -8,6 +8,11 @@ espressoCore = "3.7.0"
lifecycleRuntimeKtx = "2.10.0" lifecycleRuntimeKtx = "2.10.0"
activityCompose = "1.12.1" activityCompose = "1.12.1"
composeBom = "2024.09.00" 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] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -24,6 +29,11 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } 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] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }