diff --git a/src/main/kotlin/main/Compare.kt b/src/main/kotlin/main/Compare.kt new file mode 100644 index 0000000..d68a303 --- /dev/null +++ b/src/main/kotlin/main/Compare.kt @@ -0,0 +1,75 @@ +package main + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun compareResults( + glossaryWords: List, + codeWords: List, + onBackClick: () -> Unit + +) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Top, // Align content at the top + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Le code contient ${compareWords(glossaryWords, codeWords)}% des mots du glossaire\"", + style = MaterialTheme.typography.h3 + ) + } + + Column( + modifier = Modifier + .fillMaxSize() // Fills the maximum available width + .padding(16.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + + ) { + Text(text = "Le code contient ${compareWords(glossaryWords, codeWords)}% des mots du glossaire") + } + + Column( + modifier = Modifier.fillMaxSize().padding(20.dp), + verticalArrangement = Arrangement.Bottom, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Button( + onClick = onBackClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Retour") + } + } + +} + +fun compareWords(glossaryWord: List, wordsCode: List): Int { + var foundWords = 0 + wordsCode.forEach { wordCode -> + glossaryWord.forEach { word -> + if (wordCode.equals(word.name, ignoreCase = true)) { + foundWords++ + } + } + } + println(foundWords * 100 / wordsCode.size) + return foundWords * 100 / wordsCode.size +} \ No newline at end of file diff --git a/src/main/kotlin/main/Detail.kt b/src/main/kotlin/main/Detail.kt new file mode 100644 index 0000000..763f3d2 --- /dev/null +++ b/src/main/kotlin/main/Detail.kt @@ -0,0 +1,223 @@ +package main + +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +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.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Search +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp + +@Composable +fun glossaryDetailedPage(glossary: List, onBackClick: () -> Unit) { + var searchQuery by remember { mutableStateOf("") } + var sortOption by remember { mutableStateOf("Nom ↑") } + + var filteredGlossary by remember { mutableStateOf(glossary) } + + val menuExpanded = remember { mutableStateOf(false) } + + // Sort the glossary according to the selected option + val sortedGlossaire = remember(glossary, sortOption) { + val glossaireCopy = glossary.toMutableList() + + when (sortOption) { + "Nom ↑" -> glossaireCopy.sortBy { it.name } + "Nom ↓" -> glossaireCopy.sortByDescending { it.name } + "Contexte ↑" -> glossaireCopy.sortBy { it.mainContext } + "Contexte ↓" -> glossaireCopy.sortByDescending { it.mainContext } + } + + glossaireCopy + } + + // Update the filtered glossary when the search query changes + filteredGlossary = if (searchQuery.isNotEmpty()) { + glossary.filter { mot -> + mot.name.contains(searchQuery, ignoreCase = true) || + mot.description.contains(searchQuery, ignoreCase = true) || + mot.mainContext.contains(searchQuery, ignoreCase = true) || + mot.secondaryContext.contains(searchQuery, ignoreCase = true) || + mot.relatedTo.contains(searchQuery, ignoreCase = true) || + mot.synonymous.contains(searchQuery, ignoreCase = true) || + mot.antonym.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 = onBackClick) { + 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, // Single line text field + 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(filteredGlossary) { mot -> + glossaryCard(mot, onDeleteClick = { wordToDelete -> + deleteWordOfGlossary(wordToDelete) + // Display the updated glossary + filteredGlossary = loadDatasFromFile() + + }) + } + } + } +} + +@Composable +fun glossaryCard(word: Word, onDeleteClick: (Word) -> Unit) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + + elevation = 8.dp + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ) { + Text(text = word.name, style = MaterialTheme.typography.h6) + Spacer(modifier = Modifier.height(8.dp)) + Text(text = "Description: ${word.description}") + Spacer(modifier = Modifier.height(4.dp)) + Text(text = "Contexte principal: ${word.mainContext}") + Spacer(modifier = Modifier.height(4.dp)) + Text(text = "Contexte 2: ${word.secondaryContext}") + Spacer(modifier = Modifier.height(4.dp)) + Text(text = "Lié à: ${word.relatedTo}") + Spacer(modifier = Modifier.height(4.dp)) + Text(text = "Synonyme: ${word.synonymous}") + Spacer(modifier = Modifier.height(4.dp)) + Text(text = "Antonyme: ${word.antonym}") + + // Add a delete button to delete the word + IconButton( + onClick = { onDeleteClick(word) }, + modifier = Modifier + .align(Alignment.End) + .padding(top = 8.dp) + ) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = "Supprimer", + tint = customRedColor + ) + } + } + } +} + +fun deleteWordOfGlossary(word: Word) { + val wordsList = loadDatasFromFile().toMutableList() + + // Delete the word from the list + wordsList.remove(word) + + // Save the updated list to the file + saveDatasInFile(wordsList) + + println("Mot supprimé avec succès : ${word.name}") +} \ No newline at end of file diff --git a/src/main/kotlin/main/Form.kt b/src/main/kotlin/main/Form.kt new file mode 100644 index 0000000..1b297bf --- /dev/null +++ b/src/main/kotlin/main/Form.kt @@ -0,0 +1,282 @@ +package main + +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Close +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import java.io.File +import java.io.IOException + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun formPage(onCancelClick: () -> Unit) { + // State to track whether to show the snackbar + val requiredFieldsSnackbarVisibleState = remember { mutableStateOf(false) } + val alreadyExistSnackbarVisibleState = remember { mutableStateOf(false) } + + val name = remember { mutableStateOf("") } + val description = remember { mutableStateOf("") } + val mainContext = remember { mutableStateOf("") } + val secondaryContext = remember { mutableStateOf("") } + val relatedTo = remember { mutableStateOf("") } + val synonymous = remember { mutableStateOf("") } + val antonym = remember { mutableStateOf("") } + + val openDialog = remember { mutableStateOf(false) } + if (openDialog.value) { + AlertDialog( + onDismissRequest = { + openDialog.value = false + }, + title = { + Text(text = "Confirmation d'ajout de mot") + }, + text = { + Text("Le mot a bien été ajouté au glossaire.") + }, + confirmButton = { + Button( + onClick = { + openDialog.value = false + resetFields(name, description, mainContext, secondaryContext, relatedTo, synonymous, antonym) + + }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Fermer") + + } + } + ) + } + + MaterialTheme { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = "Nouveau mot", style = MaterialTheme.typography.h5) + + TextField( + value = name.value, + onValueChange = { name.value = it }, + label = { Text("Mot *") }, + ) + + TextField( + value = description.value, + onValueChange = { description.value = it }, + label = { Text("Description") }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = customRedColor, + unfocusedIndicatorColor = Color.Gray + ) + ) + + TextField( + value = mainContext.value, + onValueChange = { mainContext.value = it }, + label = { Text("Contexte principal *") }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = customRedColor, + unfocusedIndicatorColor = Color.Gray + ) + ) + + TextField( + value = secondaryContext.value, + onValueChange = { secondaryContext.value = it }, + label = { Text("Contexte 2") }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = customRedColor, + unfocusedIndicatorColor = Color.Gray + ) + ) + + TextField( + value = relatedTo.value, + onValueChange = { relatedTo.value = it }, + label = { Text("Lié à") }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = customRedColor, + unfocusedIndicatorColor = Color.Gray + ) + ) + + TextField( + value = synonymous.value, + onValueChange = { synonymous.value = it }, + label = { Text("Synonyme") }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = customRedColor, + unfocusedIndicatorColor = Color.Gray + ) + ) + + TextField( + value = antonym.value, + onValueChange = { antonym.value = it }, + label = { Text("Antonyme") }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = customRedColor, + unfocusedIndicatorColor = Color.Gray + ) + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Button( + onClick = onCancelClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Icon(imageVector = Icons.Default.Close, contentDescription = null) + Text("Annuler") + } + Button( + onClick = { + // Validate the fields + if (name.value.isBlank() || mainContext.value.isBlank()) { + // Show the snackbar when validation fails + requiredFieldsSnackbarVisibleState.value = true + return@Button + } + + val wordsList = loadDatasFromFile().toMutableList() + + // Verify if the word already exists in the glossary + if (wordsList.any { it.name.equals(name.value, ignoreCase = true) }) { + println("Le mot '${name.value}' existe déjà dans le glossaire. Ajout annulé.") + alreadyExistSnackbarVisibleState.value = true + return@Button + } + + val newWord = Word( + name = name.value, + description = description.value, + mainContext = mainContext.value, + secondaryContext = secondaryContext.value, + relatedTo = relatedTo.value, + synonymous = synonymous.value, + antonym = antonym.value + ) + + addWordToGlossary(newWord) + openDialog.value = true + + }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Icon(imageVector = Icons.Default.Check, contentDescription = null) + Text("Valider") + } + } + + // Show the snackbar when the state is true + if (requiredFieldsSnackbarVisibleState.value) { + Snackbar( + modifier = Modifier.padding(16.dp), + action = { + Button(onClick = { requiredFieldsSnackbarVisibleState.value = false }) { + Text("OK") + } + } + ) { + Text("Les champs 'Mot' et 'Contexte principal' sont obligatoires.") + } + } + if (alreadyExistSnackbarVisibleState.value) { + Snackbar( + modifier = Modifier.padding(16.dp), + action = { + Button(onClick = { alreadyExistSnackbarVisibleState.value = false }) { + Text("OK") + } + } + ) { + Text("Le mot '${name.value}' existe déjà dans le glossaire. Ajout annulé.") + } + } + } + } +} + +fun resetFields( + name: MutableState, + description: MutableState, + mainContext: MutableState, + secondaryContext: MutableState, + relatedTo: MutableState, + synonymous: MutableState, + antonym: MutableState +) { + name.value = "" + description.value = "" + mainContext.value = "" + secondaryContext.value = "" + relatedTo.value = "" + synonymous.value = "" + antonym.value = "" +} + +fun addWordToGlossary(newWord: Word) { + val wordsList = loadDatasFromFile().toMutableList() + + // Verify if the word already exists in the glossary + if (wordsList.any { it.name.equals(newWord.name, ignoreCase = true) }) { + println("Le mot '${newWord.name}' existe déjà dans le glossaire. Ajout annulé.") + return + } + + // Add the new word to the glossary + wordsList.add(newWord) + saveDatasInFile(wordsList) + + println("Mot ajouté avec succès : ${newWord.name}") +} + +fun saveDatasInFile(listeWords: List) { + val json = Json { prettyPrint = true } + try { + val content = json.encodeToString(listeWords) + File("glossaire.json").writeText(content) + } catch (e: IOException) { + e.printStackTrace() + } +} + +fun loadDatasFromFile(): List { + // If file is empty, return empty list + if (!File("glossaire.json").exists() || File("glossaire.json").length() == 0L) { + return emptyList() + } + return try { + val content = File("glossaire.json").readText() + Json.decodeFromString>(content) + } catch (e: IOException) { + e.printStackTrace() + emptyList() // Handle the exception as needed + } +} \ No newline at end of file diff --git a/src/main/kotlin/main/Glossary.kt b/src/main/kotlin/main/Glossary.kt new file mode 100644 index 0000000..0b02c8d --- /dev/null +++ b/src/main/kotlin/main/Glossary.kt @@ -0,0 +1,295 @@ +package main + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import org.apache.poi.ss.usermodel.CellType +import org.apache.poi.ss.usermodel.Workbook +import org.apache.poi.xssf.usermodel.XSSFWorkbook +import java.awt.FileDialog +import java.awt.Frame +import java.io.File +import java.io.FileInputStream +import java.io.FileWriter +import java.io.IOException + +@Composable +fun glossaryPage( + onAddWordClick: () -> Unit, + onImportClick: () -> Unit, + onExportClick: () -> Unit, + onSeeGlossaryClick: () -> Unit, + onBackClick: () -> Unit +) { + + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Top, // Align content at the top + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = "Glossaire", style = MaterialTheme.typography.h3) + } + + Column( + modifier = Modifier + .fillMaxSize() // Fills the maximum available width + .padding(16.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + + ) { + + Button( + onClick = onAddWordClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Ajouter un mot") + } + + Button( + onClick = onImportClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Importer un fichier CSV ou XLSX") + } + + Button( + onClick = onExportClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Exporter un fichier CSV") + } + + Button( + onClick = onSeeGlossaryClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Voir le glossaire") + } + } + + Column( + modifier = Modifier.fillMaxSize().padding(20.dp), + verticalArrangement = Arrangement.Bottom, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Button( + onClick = onBackClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Retour") + } + } +} + +fun selectFile(extensions: Set, onFileSelected: (String) -> Unit) { + val fileDialog = FileDialog(Frame(), "Select a file", FileDialog.LOAD) + fileDialog.isMultipleMode = true // To enable selecting only one file + fileDialog.file = "*." + extensions.joinToString(";*.") + fileDialog.isVisible = true + + + val selectedFiles = fileDialog.files + + if (selectedFiles != null) { + for (file in selectedFiles) { + println("Selected file: $file") + // Verify that the file extension is valid + val fileExtension = File(file.absolutePath).extension.lowercase() + if (extensions.contains(fileExtension)) { + println("Opening: $file") + onFileSelected(file.absolutePath) + } else { + println("Invalid file extension.") + } + } + } else { + println("Open command cancelled by user.") + } +} + +fun exportToCSV(csvFilePath: String) { + val glossary = loadDatasFromFile() + val csvContent = buildString { + appendLine("Mot;Description;Contexte principal;Contexte 2;Lié à;Synonyme;Antonyme;") + glossary.forEach { entry -> + appendLine( + "${entry.name};${entry.description};${entry.mainContext};" + + "${entry.secondaryContext};${entry.relatedTo};${entry.synonymous};${entry.antonym}" + ) + } + } + try { + FileWriter(csvFilePath).use { fileWriter -> + fileWriter.write(csvContent) + } + } catch (e: IOException) { + e.printStackTrace() + } +} + +fun importFile(filePath: String) { + val fileExtension = File(filePath).extension.lowercase() + + when (fileExtension) { + "csv" -> { + importCSVFile(filePath) + } + + "xlsx" -> { + importXLSXFile(filePath) + } + + else -> { + println("Unsupported file format.") + } + } +} + +fun importCSVFile(filePath: String) { + val file = File(filePath).readText(Charsets.UTF_8) + + val lines = file.split("\n") + val header = lines.first().split(";") + val dataLines = lines.drop(1) + + dataLines.forEach { line -> + // Check if the line is not empty or blank + if (line.isNotBlank()) { + val values = line.replace("\r", "").replace("\n", "").split(";") + + values.forEach { value -> + println(value) + } + val mot = header.zip(values).toMap().toMutableMap() + val nouveauWord = Word( + name = mot["Mot"]!!, + description = mot["Description"]!!, + mainContext = mot["Contexte principal"]!!, + secondaryContext = mot["Contexte 2"]!!, + relatedTo = mot["Lié à"]!!, + synonymous = mot["Synonyme"]!!, + antonym = mot["Antonyme"]!! + ) + + if (mot["Antonyme"] == "\r") { + mot["Antonyme"] = "" + } + if (mot["Mot"] == null || mot["Mot"] == "") { + return + } + if (!verifyRequiredFields(mot)) { + return + } + addWordToGlossary(nouveauWord) + } + } +} + +private fun importXLSXFile(cheminFichier: String) { + val workbook: Workbook + try { + FileInputStream(cheminFichier).use { fileInputStream -> + workbook = XSSFWorkbook(fileInputStream) + } + + val sheet = workbook.getSheetAt(0) // Assuming the data is in the first sheet + + val headerRow = sheet.getRow(0) + val header = mutableListOf() + for (i in 0 until headerRow.lastCellNum) { + header.add(headerRow.getCell(i).stringCellValue) + } + + val dataLines = mutableListOf>() + + for (i in 1 until sheet.physicalNumberOfRows) { + val currentRow = sheet.getRow(i) + val data = mutableMapOf() + + for (j in 0 until currentRow.lastCellNum) { + val cell = currentRow.getCell(j) + val cellValue = when (cell.cellType) { + CellType.STRING -> cell.stringCellValue + CellType.NUMERIC -> cell.numericCellValue.toString() + else -> "" + } + data[header[j]] = cellValue + } + + dataLines.add(data) + } + + dataLines.forEach { line -> + // Check if the line is not empty or blank + if (line.isNotEmpty()) { + // Process each line as needed + val newWord = Word( + name = line["Mot"] ?: "", + description = line["Description"] ?: "", + mainContext = line["Contexte principal"] ?: "", + secondaryContext = line["Contexte 2"] ?: "", + relatedTo = line["Lié à"] ?: "", + synonymous = line["Synonyme"] ?: "", + antonym = line["Antonyme"] ?: "" + ) + + if (newWord.name.isNotBlank() && verifyRequiredFields(line)) { + addWordToGlossary(newWord) + } + } + } + } catch (e: IOException) { + e.printStackTrace() + } +} + +fun verifyRequiredFields(mot: Map): Boolean { + //Verify that the required fields are present + val requiredFields = listOf( + "Mot", + "Description", + "Contexte principal", + "Contexte 2", + "Lié à", + "Synonyme", + "Antonyme" + ) + + val motKeys = mot.keys.map { it.trim() } + + motKeys.forEach { key -> + if (!requiredFields.contains(key)) { + println("Le champ $key n'est pas reconnu") + return false + } + } + + return true + +} \ No newline at end of file diff --git a/src/main/kotlin/main/Home.kt b/src/main/kotlin/main/Home.kt new file mode 100644 index 0000000..c65baf1 --- /dev/null +++ b/src/main/kotlin/main/Home.kt @@ -0,0 +1,80 @@ +package main + +import androidx.compose.foundation.layout.* +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +var mostUsedWordList = mutableMapOf() + +@Composable +fun homePage( + onGlossaryClick: () -> Unit, + onCodeToVerifyClick: () -> Unit +) { + + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + + ) { + Text("Quali'Nomme", style = MaterialTheme.typography.h3) + + var isCompareClicked by remember { mutableStateOf(false) } + + Spacer(modifier = Modifier.height(16.dp)) + + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + Button( + onClick = onGlossaryClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Glossaire") + } + + Button( + onClick = onCodeToVerifyClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Code à Vérifier") + } + + Button( + onClick = { + isCompareClicked = true + + }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Comparer") + } + + if (isCompareClicked) { + println(mostUsedWordList.keys.toList()) + compareResults( + glossaryWords = loadDatasFromFile(), + codeWords = mostUsedWordList.keys.toList(), + onBackClick = { isCompareClicked = false } + ) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/main/Main.kt b/src/main/kotlin/main/Main.kt index 27b4dff..1f4f15e 100644 --- a/src/main/kotlin/main/Main.kt +++ b/src/main/kotlin/main/Main.kt @@ -1,205 +1,44 @@ package main 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.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.icons.Icons -import androidx.compose.material.icons.filled.* +import androidx.compose.material.MaterialTheme import androidx.compose.runtime.* import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color 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.window.* -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import org.apache.poi.ss.usermodel.CellType -import org.apache.poi.ss.usermodel.Workbook -import org.apache.poi.xssf.usermodel.XSSFWorkbook import java.awt.FileDialog import java.awt.Frame -import java.io.File -import java.io.FileInputStream -import java.io.FileWriter -import java.io.IOException val customRedColor = Color(0xFFB70D1B) -fun supprimerMotDuGlossaire(mot: Mot) { - val listeMots = chargerDonneesDepuisFichier().toMutableList() - - // Retirer le mot de la liste - listeMots.remove(mot) - - // Sauvegarder la liste mise à jour - sauvegarderDonneesDansFichier(listeMots) - - println("Mot supprimé avec succès : ${mot.nom}") -} - -@Composable -fun homePage( - onGlossaireClick: () -> Unit, - onCodeAVerifierClick: () -> Unit -) { - - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - - ) { - Text("Quali'Nomme", style = MaterialTheme.typography.h3) - - var isCompareClicked by remember { mutableStateOf(false) } - - Spacer(modifier = Modifier.height(16.dp)) - - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp) - ) { - Button( - onClick = onGlossaireClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Glossaire") - } - - Button( - onClick = onCodeAVerifierClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Code à Vérifier") - } - - Button( - onClick = { - isCompareClicked = true - - }, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Comparer") - } - - if (isCompareClicked) { - println(mostUsedWordList.keys.toList()) - compareResults( - motsGlossaire = chargerDonneesDepuisFichier(), - motsCode = mostUsedWordList.keys.toList(), - onRetourClick = { isCompareClicked = false } - ) - } - } - } -} - - - -@Composable -fun compareResults( - motsGlossaire: List, - motsCode: List, - onRetourClick: () -> Unit - -) { - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Top, // Align content at the top - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text(text = "Le code contient ${comparerMots(motsGlossaire, motsCode)}% des mots du glossaire\"", style = MaterialTheme.typography.h3) - } - - Column( - modifier = Modifier - .fillMaxSize() // Fills the maximum available width - .padding(16.dp), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - - ) { - Text(text = "Le code contient ${comparerMots(motsGlossaire, motsCode)}% des mots du glossaire") - } - - // Bouton retour positionné tout en bas et centré horizontalement - Column( - modifier = Modifier.fillMaxSize().padding(20.dp), - verticalArrangement = Arrangement.Bottom, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Button( - onClick = onRetourClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Retour") - } - } - -} - -fun comparerMots(motsGlossaire: List, motsCode: List): Int { - var motsTrouves = 0 - motsCode.forEach { motCode -> - motsGlossaire.forEach { mot -> - if (motCode.equals(mot.nom, ignoreCase = true)) { - motsTrouves++ - } - } - } - println(motsTrouves*100/motsCode.size) - return motsTrouves*100/motsCode.size -} - -var mostUsedWordList = mutableMapOf() @Composable @Preview fun app() { MaterialTheme { val currentPage = remember { mutableStateOf("accueil") } - var glossaireDetail: List by remember { mutableStateOf(emptyList()) } + var glossaryDetail: List by remember { mutableStateOf(emptyList()) } when (currentPage.value) { "accueil" -> { homePage( - onGlossaireClick = { currentPage.value = "glossaire" }, - onCodeAVerifierClick = { currentPage.value = "choixLangage" } + onGlossaryClick = { currentPage.value = "glossaire" }, + onCodeToVerifyClick = { currentPage.value = "choixLangage" } ) } "glossaire" -> { - glossairePage( - onAjouterMotClick = { currentPage.value = "formulaire" }, - onImporterClick = { + glossaryPage( + onAddWordClick = { currentPage.value = "formulaire" }, + onImportClick = { selectFile(setOf("csv", "xlsx")) { filePath -> println("Importing file: $filePath") importFile(filePath) } }, - onExporterClick = { + onExportClick = { val fileDialog = FileDialog(Frame(), "Save as CSV", FileDialog.SAVE) fileDialog.file = "glossaire_exporte.csv" // Initial file name fileDialog.isVisible = true @@ -213,22 +52,22 @@ fun app() { println("Export command cancelled by user.") } }, - onVoirGlossaireClick = { - glossaireDetail = chargerDonneesDepuisFichier() + onSeeGlossaryClick = { + glossaryDetail = loadDatasFromFile() currentPage.value = "glossaireDetail" }, - onRetourClick = { currentPage.value = "accueil" } + onBackClick = { currentPage.value = "accueil" } ) } "glossaireDetail" -> { - glossaireDetailPage( - glossaire = glossaireDetail, - onRetourClick = { currentPage.value = "glossaire" } + glossaryDetailedPage( + glossary = glossaryDetail, + onBackClick = { currentPage.value = "glossaire" } ) } "formulaire" -> { - formulairePage(onAnnulerClick = { currentPage.value = "glossaire" }) + formPage(onCancelClick = { currentPage.value = "glossaire" }) } "choixLangage" -> { @@ -236,7 +75,7 @@ fun app() { val javaExtensions = setOf("java") val jsExtensions = setOf("js", "html") choixLangagePage( - onRetourClick = { currentPage.value = "accueil" }, + onBackClick = { currentPage.value = "accueil" }, onPythonClick = { selectFile(pythonExtensions) { filePath -> println("Python file selected: $filePath") // Change by parser functions @@ -254,814 +93,11 @@ fun app() { } ) } - // ... Ajoutez d'autres cas pour les pages "glossaire," "code a verifier," et "comparer" + // ... Add other pages here ... } } } -fun selectFile(extensions: Set, onFileSelected: (String) -> Unit) { - val fileDialog = FileDialog(Frame(), "Select a file", FileDialog.LOAD) - fileDialog.isMultipleMode = true // To enable selecting only one file - fileDialog.file = "*." + extensions.joinToString(";*.") - fileDialog.isVisible = true - - - val selectedFiles = fileDialog.files - - if (selectedFiles != null) { - for (file in selectedFiles) { - println("Selected file: $file") - // Vérifier si l'extension est autorisée - val fileExtension = File(file.absolutePath).extension.lowercase() - if (extensions.contains(fileExtension)) { - println("Opening: $file") - onFileSelected(file.absolutePath) - } else { - println("Invalid file extension.") - } - } - } else { - println("Open command cancelled by user.") - } -} - -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) { - val fileExtension = File(cheminFichier).extension.lowercase() - - when (fileExtension) { - "csv" -> { - importCSVFile(cheminFichier) - } - "xlsx" -> { - importXLSXFile(cheminFichier) - } - else -> { - println("Unsupported file format.") - } - } -} - -fun importCSVFile(cheminFichier: String) { - val file = File(cheminFichier).readText(Charsets.UTF_8) - - val lines = file.split("\n") - val header = lines.first().split(";") - val dataLines = lines.drop(1) - - dataLines.forEach { line -> - // Check if the line is not empty or blank - if (line.isNotBlank()) { - val values = line.replace("\r", "").replace("\n", "").split(";") - - values.forEach { value -> - println(value) - } - val mot = header.zip(values).toMap().toMutableMap() - val nouveauMot = Mot( - nom = mot["Mot"]!!, - description = mot["Description"]!!, - contextePrincipal = mot["Contexte principal"]!!, - contexte2 = mot["Contexte 2"]!!, - lieA = mot["Lié à"]!!, - synonyme = mot["Synonyme"]!!, - antonyme = mot["Antonyme"]!! - ) - - if (mot["Antonyme"] == "\r") { - mot["Antonyme"] = "" - } - if (mot["Mot"] == null || mot["Mot"] == "") { - return - } - if (!verifierChampsRequis(mot)) { - return - } - ajouterMotAuGlossaire(nouveauMot) - } - } -} - -private fun importXLSXFile(cheminFichier: String) { - val workbook: Workbook - try { - FileInputStream(cheminFichier).use { fileInputStream -> - workbook = XSSFWorkbook(fileInputStream) - } - - val sheet = workbook.getSheetAt(0) // Assuming the data is in the first sheet - - val headerRow = sheet.getRow(0) - val header = mutableListOf() - for (i in 0 until headerRow.lastCellNum) { - header.add(headerRow.getCell(i).stringCellValue) - } - - val dataLines = mutableListOf>() - - for (i in 1 until sheet.physicalNumberOfRows) { - val currentRow = sheet.getRow(i) - val data = mutableMapOf() - - for (j in 0 until currentRow.lastCellNum) { - val cell = currentRow.getCell(j) - val cellValue = when (cell.cellType) { - CellType.STRING -> cell.stringCellValue - CellType.NUMERIC -> cell.numericCellValue.toString() - else -> "" - } - data[header[j]] = cellValue - } - - dataLines.add(data) - } - - dataLines.forEach { line -> - // Check if the line is not empty or blank - if (line.isNotEmpty()) { - // Process each line as needed - val nouveauMot = Mot( - nom = line["Mot"] ?: "", - description = line["Description"] ?: "", - contextePrincipal = line["Contexte principal"] ?: "", - contexte2 = line["Contexte 2"] ?: "", - lieA = line["Lié à"] ?: "", - synonyme = line["Synonyme"] ?: "", - antonyme = line["Antonyme"] ?: "" - ) - - if (nouveauMot.nom.isNotBlank() && verifierChampsRequis(line)) { - ajouterMotAuGlossaire(nouveauMot) - } - } - } - } catch (e: IOException) { - e.printStackTrace() - } -} - -fun verifierChampsRequis(mot: Map): Boolean { - //Vérifier que les headers sont égales aux champs requis - val champsRequis = listOf( - "Mot", - "Description", - "Contexte principal", - "Contexte 2", - "Lié à", - "Synonyme", - "Antonyme" - ) - - val motKeys = mot.keys.map { it.trim() } - - motKeys.forEach { key -> - if (!champsRequis.contains(key)) { - println("Le champ $key n'est pas reconnu") - return false - } - } - - return true - -} - - - -@Composable -fun choixLangagePage( - onRetourClick: () -> Unit, - onPythonClick: () -> Unit, - onJavaClick: () -> Unit, - onJavaScriptClick: () -> Unit -) { - - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Top, // Align content at the top - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text(text = "Choix du langage", style = MaterialTheme.typography.h3) - } - - Column( - modifier = Modifier - .fillMaxSize() // Fills the maximum available width - .padding(50.dp), - // allign the content in the center vertically and horizontally - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - - ) { - Button( - onClick = onPythonClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Python") - } - - Button( - onClick = onJavaClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Java") - } - - Button( - onClick = onJavaScriptClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("JavaScript") - } - } - - // Bouton retour positionné tout en bas et centré horizontalement - Column( - modifier = Modifier.fillMaxSize().padding(20.dp), - verticalArrangement = Arrangement.Bottom, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Button( - onClick = onRetourClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Retour") - } - } - -} - -@Composable -fun glossairePage( - onAjouterMotClick: () -> Unit, - onImporterClick: () -> Unit, - onExporterClick: () -> Unit, - onVoirGlossaireClick: () -> Unit, - onRetourClick: () -> Unit -) { - - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Top, // Align content at the top - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text(text = "Glossaire", style = MaterialTheme.typography.h3) - } - - Column( - modifier = Modifier - .fillMaxSize() // Fills the maximum available width - .padding(16.dp), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - - ) { - - Button( - onClick = onAjouterMotClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Ajouter un mot") - } - - Button( - onClick = onImporterClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Importer un fichier CSV ou XLSX") - } - - Button( - onClick = onExporterClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - 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 - Column( - modifier = Modifier.fillMaxSize().padding(20.dp), - verticalArrangement = Arrangement.Bottom, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Button( - onClick = onRetourClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Retour") - } - } -} - -@Composable -fun glossaireDetailPage(glossaire: List, onRetourClick: () -> Unit) { - var searchQuery by remember { mutableStateOf("") } - var sortOption by remember { mutableStateOf("Nom ↑") } - - var filteredGlossaire by remember { mutableStateOf(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, onSupprimerClick = { motASupprimer -> - supprimerMotDuGlossaire(motASupprimer) - //afficher à nouveau les mots du glossaire - filteredGlossaire = chargerDonneesDepuisFichier() - - }) - } - } - } -} - -@Composable -fun glossaireCard(mot: Mot, onSupprimerClick: (Mot) -> Unit) { - 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}") - - // Ajouter le bouton de suppression - IconButton( - onClick = { onSupprimerClick(mot) }, - modifier = Modifier - .align(Alignment.End) - .padding(top = 8.dp) - ) { - Icon( - imageVector = Icons.Default.Delete, - contentDescription = "Supprimer", - tint = customRedColor - ) - } - } - } -} - -fun resetFields( - nom: MutableState, - description: MutableState, - contextePrincipal: MutableState, - contexte2: MutableState, - lieA: MutableState, - synonyme: MutableState, - antonyme: MutableState -) { - nom.value = "" - description.value = "" - contextePrincipal.value = "" - contexte2.value = "" - lieA.value = "" - synonyme.value = "" - antonyme.value = "" -} - -@OptIn(ExperimentalMaterialApi::class) -@Composable -fun formulairePage(onAnnulerClick: () -> Unit) { - // State to track whether to show the snackbar - val champsObligatoireSnackbarVisibleState = remember { mutableStateOf(false) } - val existeDejaSnackbarVisibleState = remember { mutableStateOf(false) } - - val nom = remember { mutableStateOf("") } - val description = remember { mutableStateOf("") } - val contextePrincipal = remember { mutableStateOf("") } - val contexte2 = remember { mutableStateOf("") } - val lieA = remember { mutableStateOf("") } - val synonyme = remember { mutableStateOf("") } - val antonyme = remember { mutableStateOf("") } - - val openDialog = remember { mutableStateOf(false) } - if (openDialog.value) { - AlertDialog( - onDismissRequest = { - openDialog.value = false - }, - title = { - Text(text = "Confirmation d'ajout de mot") - }, - text = { - Text("Le mot a bien été ajouté au glossaire.") - }, - confirmButton = { - Button( - onClick = { - openDialog.value = false - resetFields(nom, description, contextePrincipal, contexte2, lieA, synonyme, antonyme) - - }, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Text("Fermer") - - } - } - ) - } - - MaterialTheme { - Column( - modifier = Modifier.padding(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text(text = "Nouveau mot", style = MaterialTheme.typography.h5) - - TextField( - value = nom.value, - onValueChange = { nom.value = it }, - label = { Text("Mot *") }, - ) - - TextField( - value = description.value, - onValueChange = { description.value = it }, - label = { Text("Description") }, - colors = TextFieldDefaults.textFieldColors( - focusedIndicatorColor = customRedColor, - unfocusedIndicatorColor = Color.Gray - ) - ) - - TextField( - value = contextePrincipal.value, - onValueChange = { contextePrincipal.value = it }, - label = { Text("Contexte principal *") }, - colors = TextFieldDefaults.textFieldColors( - focusedIndicatorColor = customRedColor, - unfocusedIndicatorColor = Color.Gray - ) - ) - - TextField( - value = contexte2.value, - onValueChange = { contexte2.value = it }, - label = { Text("Contexte 2") }, - colors = TextFieldDefaults.textFieldColors( - focusedIndicatorColor = customRedColor, - unfocusedIndicatorColor = Color.Gray - ) - ) - - TextField( - value = lieA.value, - onValueChange = { lieA.value = it }, - label = { Text("Lié à") }, - colors = TextFieldDefaults.textFieldColors( - focusedIndicatorColor = customRedColor, - unfocusedIndicatorColor = Color.Gray - ) - ) - - TextField( - value = synonyme.value, - onValueChange = { synonyme.value = it }, - label = { Text("Synonyme") }, - colors = TextFieldDefaults.textFieldColors( - focusedIndicatorColor = customRedColor, - unfocusedIndicatorColor = Color.Gray - ) - ) - - TextField( - value = antonyme.value, - onValueChange = { antonyme.value = it }, - label = { Text("Antonyme") }, - colors = TextFieldDefaults.textFieldColors( - focusedIndicatorColor = customRedColor, - unfocusedIndicatorColor = Color.Gray - ) - ) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly - ) { - Button( - onClick = onAnnulerClick, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Icon(imageVector = Icons.Default.Close, contentDescription = null) - Text("Annuler") - } - Button( - onClick = { - // Validation du formulaire - if (nom.value.isBlank() || contextePrincipal.value.isBlank()) { - // Show the snackbar when validation fails - champsObligatoireSnackbarVisibleState.value = true - return@Button - } - - val listeMots = chargerDonneesDepuisFichier().toMutableList() - - // Vérifier si le mot existe déjà dans le glossaire - if (listeMots.any { it.nom.equals(nom.value, ignoreCase = true) }) { - println("Le mot '${nom.value}' existe déjà dans le glossaire. Ajout annulé.") - existeDejaSnackbarVisibleState.value = true - return@Button - } - - val nouveauMot = Mot( - nom = nom.value, - description = description.value, - contextePrincipal = contextePrincipal.value, - contexte2 = contexte2.value, - lieA = lieA.value, - synonyme = synonyme.value, - antonyme = antonyme.value - ) - - ajouterMotAuGlossaire(nouveauMot) - openDialog.value = true - - }, - colors = ButtonDefaults.buttonColors( - backgroundColor = customRedColor, - contentColor = Color.White - ) - ) { - Icon(imageVector = Icons.Default.Check, contentDescription = null) - Text("Valider") - } - } - - // Show the snackbar when the state is true - if (champsObligatoireSnackbarVisibleState.value) { - Snackbar( - modifier = Modifier.padding(16.dp), - action = { - Button(onClick = { champsObligatoireSnackbarVisibleState.value = false }) { - Text("OK") - } - } - ) { - Text("Les champs 'Mot' et 'Contexte principal' sont obligatoires.") - } - } - if (existeDejaSnackbarVisibleState.value) { - Snackbar( - modifier = Modifier.padding(16.dp), - action = { - Button(onClick = { existeDejaSnackbarVisibleState.value = false }) { - Text("OK") - } - } - ) { - Text("Le mot '${nom.value}' existe déjà dans le glossaire. Ajout annulé.") - } - } - } - } -} - - -fun chargerDonneesDepuisFichier(): List { - //if file is empty, return empty list - if (!File("glossaire.json").exists() || File("glossaire.json").length() == 0L) { - return emptyList() - } - return try { - val content = File("glossaire.json").readText() - Json.decodeFromString>(content) - } catch (e: IOException) { - e.printStackTrace() - emptyList() // Handle the exception as needed - } -} - -private val json = Json { prettyPrint = true } - -fun sauvegarderDonneesDansFichier(listeMots: List) { - try { - val content = json.encodeToString(listeMots) - File("glossaire.json").writeText(content) - } catch (e: IOException) { - e.printStackTrace() - } -} - -fun ajouterMotAuGlossaire(nouveauMot: Mot) { - val listeMots = chargerDonneesDepuisFichier().toMutableList() - - // Vérifier si le mot existe déjà dans le glossaire - if (listeMots.any { it.nom.equals(nouveauMot.nom, ignoreCase = true) }) { - println("Le mot '${nouveauMot.nom}' existe déjà dans le glossaire. Ajout annulé.") - return - } - - // Ajouter le nouveau mot seulement s'il n'existe pas déjà - listeMots.add(nouveauMot) - sauvegarderDonneesDansFichier(listeMots) - - println("Mot ajouté avec succès : ${nouveauMot.nom}") -} - - fun main() = application { val state = rememberWindowState( placement = WindowPlacement.Floating, diff --git a/src/main/kotlin/main/Mot.kt b/src/main/kotlin/main/Mot.kt deleted file mode 100644 index 8af2d7c..0000000 --- a/src/main/kotlin/main/Mot.kt +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class Mot( - val nom: String, - val description: String, - val contextePrincipal: String, - val contexte2: String, - val lieA: String, - val synonyme: String, - val antonyme: String -) diff --git a/src/main/kotlin/main/Verify.kt b/src/main/kotlin/main/Verify.kt new file mode 100644 index 0000000..a22e404 --- /dev/null +++ b/src/main/kotlin/main/Verify.kt @@ -0,0 +1,89 @@ +package main + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun choixLangagePage( + onBackClick: () -> Unit, + onPythonClick: () -> Unit, + onJavaClick: () -> Unit, + onJavaScriptClick: () -> Unit +) { + + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Top, // Align content at the top + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = "Choix du langage", style = MaterialTheme.typography.h3) + } + + Column( + modifier = Modifier + .fillMaxSize() // Fills the maximum available width + .padding(50.dp), + // Align the content in the center vertically and horizontally + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + + ) { + Button( + onClick = onPythonClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Python") + } + + Button( + onClick = onJavaClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Java") + } + + Button( + onClick = onJavaScriptClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("JavaScript") + } + } + + Column( + modifier = Modifier.fillMaxSize().padding(20.dp), + verticalArrangement = Arrangement.Bottom, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Button( + onClick = onBackClick, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Retour") + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/main/Word.kt b/src/main/kotlin/main/Word.kt new file mode 100644 index 0000000..55e2a06 --- /dev/null +++ b/src/main/kotlin/main/Word.kt @@ -0,0 +1,14 @@ +package main + +import kotlinx.serialization.Serializable + +@Serializable +data class Word( + val name: String, + val description: String, + val mainContext: String, + val secondaryContext: String, + val relatedTo: String, + val synonymous: String, + val antonym: String +)