recherche #2
@@ -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")
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
BIN
app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
@@ -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()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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?
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
)
|
)
|
||||||
BIN
app/src/main/java/com/dev/collectiondvd/ui/img/Collec.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
@@ -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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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())
|
||||||
|
}
|
||||||
@@ -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} ")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 982 B After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 4.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 6.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 12 KiB |
@@ -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" }
|
||||||
|
|||||||