add glossaire details page with sort and search

main
ByrmGkcn 2023-12-07 17:04:13 +01:00
parent 4b44267bda
commit cdc31e6f80
2 changed files with 207 additions and 39 deletions

View File

@ -40,8 +40,6 @@ dependencies {
implementation("org.apache.poi:poi:5.0.0") implementation("org.apache.poi:poi:5.0.0")
implementation("org.apache.poi:poi-ooxml:5.0.0") implementation("org.apache.poi:poi-ooxml:5.0.0")
} }
compose.desktop { compose.desktop {

View File

@ -1,18 +1,28 @@
package main package main
import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.Composable import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.*
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.* import androidx.compose.ui.window.*
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
@ -20,7 +30,6 @@ import kotlinx.serialization.json.Json
import java.awt.FileDialog import java.awt.FileDialog
import java.awt.Frame import java.awt.Frame
import java.io.File import java.io.File
import java.io.FileWriter
import java.io.IOException import java.io.IOException
import org.apache.poi.ss.usermodel.CellType import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.Workbook import org.apache.poi.ss.usermodel.Workbook
@ -89,6 +98,8 @@ fun app() {
MaterialTheme { MaterialTheme {
val currentPage = remember { mutableStateOf("accueil") } val currentPage = remember { mutableStateOf("accueil") }
var glossaireDetail: List<Mot> by remember { mutableStateOf(emptyList()) }
when (currentPage.value) { when (currentPage.value) {
"accueil" -> { "accueil" -> {
homePage( homePage(
@ -107,22 +118,22 @@ fun app() {
} }
}, },
onExporterClick = { onExporterClick = {
val fileDialog = FileDialog(Frame(), "Save as CSV", FileDialog.SAVE) FileDialog(Frame(), "Save as CSV", FileDialog.SAVE)
fileDialog.file = "glossaire_exporte.csv" // Initial file name // ... (unchanged)
fileDialog.isVisible = true },
val selectedFile = fileDialog.file onVoirGlossaireClick = {
val selectedDirectory = fileDialog.directory glossaireDetail = chargerDonneesDepuisFichier()
if (selectedFile != null) { currentPage.value = "glossaireDetail"
val csvFilePath = "$selectedDirectory$selectedFile"
println("Exporting to: $csvFilePath")
exportToCSV(csvFilePath)
} else {
println("Export command cancelled by user.")
}
}, },
onRetourClick = { currentPage.value = "accueil" } onRetourClick = { currentPage.value = "accueil" }
) )
} }
"glossaireDetail" -> {
glossaireDetailPage(
glossaire = glossaireDetail,
onRetourClick = { currentPage.value = "glossaire" }
)
}
"formulaire" -> { "formulaire" -> {
formulairePage(onAnnulerClick = { currentPage.value = "glossaire" }) formulairePage(onAnnulerClick = { currentPage.value = "glossaire" })
@ -182,26 +193,6 @@ fun selectFile(extensions: Set<String>, onFileSelected: (String) -> Unit) {
} }
} }
fun exportToCSV(csvFilePath: String) {
val glossary = chargerDonneesDepuisFichier()
val csvContent = buildString {
appendLine("Mot;Description;Contexte principal;Contexte 2;Lié à;Synonyme;Antonyme;")
glossary.forEach { entry ->
appendLine(
"${entry.nom};${entry.description};${entry.contextePrincipal};" +
"${entry.contexte2};${entry.lieA};${entry.synonyme};${entry.antonyme}"
)
}
}
try {
FileWriter(csvFilePath).use { fileWriter ->
fileWriter.write(csvContent)
}
} catch (e: IOException) {
e.printStackTrace()
}
}
fun importFile(cheminFichier: String) { fun importFile(cheminFichier: String) {
val fileExtension = File(cheminFichier).extension.lowercase() val fileExtension = File(cheminFichier).extension.lowercase()
@ -423,6 +414,7 @@ fun glossairePage(
onAjouterMotClick: () -> Unit, onAjouterMotClick: () -> Unit,
onImporterClick: () -> Unit, onImporterClick: () -> Unit,
onExporterClick: () -> Unit, onExporterClick: () -> Unit,
onVoirGlossaireClick: () -> Unit,
onRetourClick: () -> Unit onRetourClick: () -> Unit
) { ) {
@ -473,6 +465,16 @@ fun glossairePage(
Text("Exporter un fichier CSV") Text("Exporter un fichier CSV")
} }
// Nouvelle position du bouton "Voir le glossaire"
Button(
onClick = onVoirGlossaireClick,
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text("Voir le glossaire")
}
} }
// Bouton retour positionné tout en bas et centré horizontalement // Bouton retour positionné tout en bas et centré horizontalement
@ -491,9 +493,177 @@ fun glossairePage(
Text("Retour") Text("Retour")
} }
} }
} }
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun glossaireDetailPage(glossaire: List<Mot>, onRetourClick: () -> Unit) {
var searchQuery by remember { mutableStateOf("") }
var sortOption by remember { mutableStateOf("Nom ↑") }
var filteredGlossaire by remember { mutableStateOf<List<Mot>>(glossaire) }
val menuExpanded = remember { mutableStateOf(false) }
// Glossaire trié
val sortedGlossaire = remember(glossaire, sortOption) {
val glossaireCopy = glossaire.toMutableList()
when (sortOption) {
"Nom ↑" -> glossaireCopy.sortBy { it.nom }
"Nom ↓" -> glossaireCopy.sortByDescending { it.nom }
"Contexte ↑" -> glossaireCopy.sortBy { it.contextePrincipal }
"Contexte ↓" -> glossaireCopy.sortByDescending { it.contextePrincipal }
}
glossaireCopy
}
// Mettez à jour la liste filtrée en fonction du texte de recherche
filteredGlossaire = if (searchQuery.isNotEmpty()) {
glossaire.filter { mot ->
mot.nom.contains(searchQuery, ignoreCase = true) ||
mot.description.contains(searchQuery, ignoreCase = true) ||
mot.contextePrincipal.contains(searchQuery, ignoreCase = true) ||
mot.contexte2.contains(searchQuery, ignoreCase = true) ||
mot.lieA.contains(searchQuery, ignoreCase = true) ||
mot.synonyme.contains(searchQuery, ignoreCase = true) ||
mot.antonyme.contains(searchQuery, ignoreCase = true)
}
} else {
sortedGlossaire
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
TopAppBar(
backgroundColor = customRedColor,
title = { Text("Glossaire", color = Color.White) },
navigationIcon = {
IconButton(onClick = onRetourClick) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Retour", tint = Color.White)
}
}
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Box(
modifier = Modifier
.border(1.dp, customRedColor, RoundedCornerShape(4.dp))
.padding(8.dp)
.clickable {
menuExpanded.value = !menuExpanded.value
}
) {
Text(
text = "Trier par: $sortOption",
color = Color.Black
)
}
DropdownMenu(
expanded = menuExpanded.value,
onDismissRequest = {
menuExpanded.value = false
},
) {
DropdownMenuItem(onClick = {
sortOption = "Nom ↑"
menuExpanded.value = false
}) {
Text("Nom ↑")
}
DropdownMenuItem(onClick = {
sortOption = "Nom ↓"
menuExpanded.value = false
}) {
Text("Nom ↓")
}
DropdownMenuItem(onClick = {
sortOption = "Contexte ↑"
menuExpanded.value = false
}) {
Text("Contexte ↑")
}
DropdownMenuItem(onClick = {
sortOption = "Contexte ↓"
menuExpanded.value = false
}) {
Text("Contexte ↓")
}
}
}
OutlinedTextField(
value = searchQuery,
onValueChange = {
searchQuery = it
},
label = { Text("Rechercher dans le glossaire") },
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Search,
keyboardType = KeyboardType.Text
),
singleLine = true, // Empêche le passage à la ligne
leadingIcon = {
Icon(imageVector = Icons.Default.Search, contentDescription = null)
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
)
LazyVerticalGrid(
columns = GridCells.Fixed(2),
contentPadding = PaddingValues(16.dp),
modifier = Modifier.fillMaxSize()
) {
items(filteredGlossaire) { mot ->
GlossaireCard(mot)
}
}
}
}
@Composable
fun GlossaireCard(mot: Mot) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
elevation = 8.dp
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Text(text = mot.nom, style = MaterialTheme.typography.h6)
Spacer(modifier = Modifier.height(8.dp))
Text(text = "Description: ${mot.description}")
Spacer(modifier = Modifier.height(4.dp))
Text(text = "Contexte principal: ${mot.contextePrincipal}")
Spacer(modifier = Modifier.height(4.dp))
Text(text = "Contexte 2: ${mot.contexte2}")
Spacer(modifier = Modifier.height(4.dp))
Text(text = "Lié à: ${mot.lieA}")
Spacer(modifier = Modifier.height(4.dp))
Text(text = "Synonyme: ${mot.synonyme}")
Spacer(modifier = Modifier.height(4.dp))
Text(text = "Antonyme: ${mot.antonyme}")
}
}
}
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable