From 190380dc4a172e71d1f95af7920e2e9cab4388ca Mon Sep 17 00:00:00 2001 From: MalcuitEmile Date: Wed, 17 Dec 2025 17:58:53 +0100 Subject: [PATCH] V1 fonctionnelle --- app/build.gradle.kts | 1 + .../com/dev/collectiondvd/MainActivity.kt | 312 ++++++++++++++---- gradle/libs.versions.toml | 2 + 3 files changed, 243 insertions(+), 72 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ac661b7..1d17403 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.material3) + implementation(libs.androidx.ui.graphics) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/java/com/dev/collectiondvd/MainActivity.kt b/app/src/main/java/com/dev/collectiondvd/MainActivity.kt index 5657d17..d1ef7c5 100644 --- a/app/src/main/java/com/dev/collectiondvd/MainActivity.kt +++ b/app/src/main/java/com/dev/collectiondvd/MainActivity.kt @@ -4,7 +4,8 @@ import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity 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.Box import androidx.compose.foundation.layout.Column @@ -14,13 +15,17 @@ 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.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Button -import androidx.compose.material3.Divider +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.Text +import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -29,22 +34,28 @@ 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.platform.LocalContext import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp 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.SupprDvdActivity 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 -import java.nio.file.WatchEvent -import kotlin.system.exitProcess +import androidx.compose.material3.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem + class MainActivity : ComponentActivity() { private lateinit var viewModel: LocalDvdViewModel @@ -55,11 +66,32 @@ class MainActivity : ComponentActivity() { val repository = LocalDvdRepository(dvdDao) val factory = LocalDvdViewModelFactory(repository) viewModel = ViewModelProvider(this, factory).get(LocalDvdViewModel::class.java) - setContent { MenuScreen(onQuit = { finish() }, viewModel = viewModel) } + 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 fun MenuScreen( viewModel: LocalDvdViewModel, @@ -69,86 +101,222 @@ fun MenuScreen( val dvds by viewModel.dvds.collectAsState(initial = emptyList()) var searchQuery by remember { mutableStateOf("") } - // 🔍 Filtrage 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) } - Column( - modifier = Modifier - .fillMaxSize() - .padding(8.dp) - ) { - Spacer(modifier = Modifier.height(15.dp)) + var sortType by remember { mutableStateOf(SortType.TITLE_ASC) } - Text( - "Votre collection", - fontSize = 24.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(bottom = 8.dp) - ) + val filteredAndSortedDvds = when (sortType) { + SortType.TITLE_ASC -> + filteredDvds.sortedBy { it.titre.orEmpty().lowercase() } - OutlinedTextField( - value = searchQuery, - onValueChange = { searchQuery = it }, - label = { Text("Rechercher un DVD") }, + 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() } + } + + // 🔍 Filtrage + + + Scaffold( + floatingActionButtonPosition = FabPosition.Center, + floatingActionButton = { + ExtendedFloatingActionButton( + text = { Text("Ajouter") }, + icon = { Text("+") }, + onClick = { + context.startActivity( + Intent(context, AjoutDvdActivity::class.java) + ) + } + ) + } + + + + ) { padding -> + + Column( modifier = Modifier - .fillMaxWidth() - .padding(bottom = 8.dp), - singleLine = true + .fillMaxSize() + .padding(padding) + .padding(12.dp) + ) { + + TopBar() + + SearchBar(searchQuery) { searchQuery = it } + + Spacer(modifier = Modifier.height(8.dp)) + + SortChip( + currentSort = sortType, + onSortSelected = { sortType = it } + ) + + Spacer(modifier = Modifier.height(8.dp)) + + DvdList(filteredAndSortedDvds) + } + } +} + +@Composable +fun TopBar() { + 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 ) - if (filteredDvds.isEmpty()) { - Box( - modifier = Modifier.weight(1f), - contentAlignment = Alignment.Center +// Row { +// Text("ⓘ", fontSize = 20.sp) +// } + } +} + +@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) } + + 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) + } + ) + } + } +} + +@Composable +fun DvdList( + dvds: List +) { + LazyColumn { + items(dvds, key = { it.id }) { dvd -> + Card( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 6.dp), + shape = RoundedCornerShape(16.dp) ) { - Text("Aucun DVD correspondant") - } - } else { - LazyColumn(modifier = Modifier.weight(1f)) { - items(filteredDvds, key = { it.id }) { dvd -> - Column(modifier = Modifier.padding(8.dp)) { - Text(dvd.titre.orEmpty(), fontWeight = FontWeight.Bold) - Text("Réalisateur : ${dvd.realisateur.orEmpty()}") - Text("Année : ${dvd.annee.orEmpty()}") - Text("Genre : ${dvd.genre.orEmpty()}") - Divider() + Row( + modifier = Modifier.padding(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + // 📀 Affiche (image fictive si pas encore stockée) + Box( + modifier = Modifier + .height(90.dp) + .width(60.dp) + .background( + MaterialTheme.colorScheme.surfaceVariant, + RoundedCornerShape(8.dp) + ) + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Column { + Text( + dvd.titre.orEmpty().uppercase(), + fontWeight = FontWeight.SemiBold, + fontSize = 16.sp, + color = Color(0xFFFFA405) + + ) + + Spacer(modifier = Modifier.height(4.dp)) + + Text( + "Réalisateur: ${dvd.realisateur.orEmpty().uppercase()}", + fontSize = 13.sp, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Text( + "Année: ${dvd.annee.orEmpty()}", + fontSize = 13.sp, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Text( + "Genre: ${dvd.genre.orEmpty().uppercase()}", + fontSize = 13.sp, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) } } } } - Row(modifier = Modifier.fillMaxWidth()){ - MyButton("+ Ajouter") { - context.startActivity( - Intent( - context, - AjoutDvdActivity::class.java - ) - ) - } - MyButton("- Supprimer") { - context.startActivity( - (Intent( - context, - SupprDvdActivity::class.java - )) - ) - } - } - - Spacer(modifier = Modifier.height(16.dp)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - MyButton("Quitter") { onQuit() } - } } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c7882b6..0cb414e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ espressoCore = "3.7.0" lifecycleRuntimeKtx = "2.10.0" activityCompose = "1.12.1" composeBom = "2024.09.00" +uiGraphics = "1.10.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -24,6 +25,7 @@ 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-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics", version.ref = "uiGraphics" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }