diff --git a/src/main/kotlin/main/Detail.kt b/src/main/kotlin/main/Detail.kt index cc64b0b..6ad5b7d 100644 --- a/src/main/kotlin/main/Detail.kt +++ b/src/main/kotlin/main/Detail.kt @@ -162,7 +162,7 @@ fun glossaryDetailedPage(glossary: List, onBackClick: () -> Unit) { glossaryCard(mot, onDeleteClick = { wordToDelete -> deleteWordOfGlossary(wordToDelete) // Display the updated glossary - filteredGlossary = loadDatasFromFile() + filteredGlossary = loadDatasFromFile("glossaire.json") }) } @@ -216,13 +216,13 @@ fun glossaryCard(word: Word, onDeleteClick: (Word) -> Unit) { } fun deleteWordOfGlossary(word: Word) { - val wordsList = loadDatasFromFile().toMutableList() + val wordsList = loadDatasFromFile("glossaire.json").toMutableList() // Delete the word from the list wordsList.remove(word) // Save the updated list to the file - saveDatasInFile(wordsList) + //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 index 3ec356b..22725ca 100644 --- a/src/main/kotlin/main/Form.kt +++ b/src/main/kotlin/main/Form.kt @@ -20,7 +20,7 @@ import java.io.IOException @OptIn(ExperimentalMaterialApi::class) @Composable -fun formPage(onCancelClick: () -> Unit) { +fun formPage(glossary: Glossary, onCancelClick: () -> Unit) { // State to track whether to show the snackbar val requiredFieldsSnackbarVisibleState = remember { mutableStateOf(false) } val alreadyExistSnackbarVisibleState = remember { mutableStateOf(false) } @@ -172,7 +172,7 @@ fun formPage(onCancelClick: () -> Unit) { return@Button } - val wordsList = loadDatasFromFile().toMutableList() + val wordsList = loadDatasFromFile(glossary.jsonFilePath).toMutableList() // Transform name to lowercase to avoid duplicates name.value = name.value.lowercase() @@ -194,7 +194,7 @@ fun formPage(onCancelClick: () -> Unit) { antonym = antonym.value ) - addWordToGlossary(newWord) + addWordToGlossary(glossary.jsonFilePath, newWord) openDialog.value = true }, @@ -267,8 +267,8 @@ fun resetFields( antonym.value = "" } -fun addWordToGlossary(newWord: Word) { - val wordsList = loadDatasFromFile().toMutableList() +fun addWordToGlossary(filePath: String, newWord: Word) { + val wordsList = loadDatasFromFile(filePath).toMutableList() // Verify if the word already exists in the glossary if (wordsList.any { it.name.equals(newWord.name, ignoreCase = true) }) { @@ -278,28 +278,28 @@ fun addWordToGlossary(newWord: Word) { // Add the new word to the glossary wordsList.add(newWord) - saveDatasInFile(wordsList) + saveDatasInFile(filePath, wordsList) println("Mot ajouté avec succès : ${newWord.name}") } -fun saveDatasInFile(listeWords: List) { +fun saveDatasInFile(filePath: String, listeWords: List) { val json = Json { prettyPrint = true } try { val content = json.encodeToString(listeWords) - File("glossaire.json").writeText(content) + File(filePath).writeText(content) } catch (e: IOException) { e.printStackTrace() } } -fun loadDatasFromFile(): List { +fun loadDatasFromFile(filePath: String): List { // If file is empty, return empty list - if (!File("glossaire.json").exists() || File("glossaire.json").length() == 0L) { + if (!File(filePath).exists() || File(filePath).length() == 0L) { return emptyList() } return try { - val content = File("glossaire.json").readText() + val content = File(filePath).readText() Json.decodeFromString>(content) } catch (e: IOException) { e.printStackTrace() diff --git a/src/main/kotlin/main/Glossary.kt b/src/main/kotlin/main/Glossary.kt index c695faa..63b65f4 100644 --- a/src/main/kotlin/main/Glossary.kt +++ b/src/main/kotlin/main/Glossary.kt @@ -5,7 +5,7 @@ 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.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -20,15 +20,20 @@ import java.io.FileInputStream import java.io.FileWriter import java.io.IOException +data class Glossary(val name: String, val jsonFilePath: String) + + @Composable fun glossaryPage( onAddWordClick: () -> Unit, onImportClick: () -> Unit, onExportClick: () -> Unit, onSeeGlossaryClick: () -> Unit, - onBackClick: () -> Unit + onBackClick: () -> Unit, + selectedGlossary: Glossary ) { + Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Top, // Align content at the top @@ -138,8 +143,8 @@ fun selectFile(extensions: Set, onFileSelected: (String) -> Unit) { } } -fun exportToCSV(csvFilePath: String) { - val glossary = loadDatasFromFile() +fun exportToCSV(glossary: Glossary, csvFilePath: String) { + val glossary = loadDatasFromFile(glossary.jsonFilePath) val csvContent = buildString { appendLine("Mot;Description;Contexte principal;Contexte 2;Lié à;Synonyme;Antonyme;") glossary.forEach { entry -> @@ -158,16 +163,16 @@ fun exportToCSV(csvFilePath: String) { } } -fun importFile(filePath: String) { +fun importFile(glossary: Glossary, filePath: String) { val fileExtension = File(filePath).extension.lowercase() when (fileExtension) { "csv" -> { - importCSVFile(filePath) + importCSVFile(glossary, filePath) } "xlsx" -> { - importXLSXFile(filePath) + importXLSXFile(glossary, filePath) } else -> { @@ -176,7 +181,7 @@ fun importFile(filePath: String) { } } -fun importCSVFile(filePath: String) { +fun importCSVFile(glossary : Glossary, filePath: String) { val file = File(filePath).readText(Charsets.UTF_8) val lines = file.split("\n") @@ -211,12 +216,12 @@ fun importCSVFile(filePath: String) { if (!verifyRequiredFields(mot)) { return } - addWordToGlossary(nouveauWord) + addWordToGlossary(glossary.jsonFilePath, nouveauWord) } } } -private fun importXLSXFile(cheminFichier: String) { +private fun importXLSXFile(glossary: Glossary, cheminFichier: String) { val workbook: Workbook try { FileInputStream(cheminFichier).use { fileInputStream -> @@ -265,7 +270,7 @@ private fun importXLSXFile(cheminFichier: String) { ) if (newWord.name.isNotBlank() && verifyRequiredFields(line)) { - addWordToGlossary(newWord) + addWordToGlossary(glossary.jsonFilePath, newWord) } } } diff --git a/src/main/kotlin/main/Home.kt b/src/main/kotlin/main/Home.kt index fe971c5..e702371 100644 --- a/src/main/kotlin/main/Home.kt +++ b/src/main/kotlin/main/Home.kt @@ -104,7 +104,7 @@ fun homePage( if (isCompareClicked) { println(mostUsedWordList.keys.toList()) compareResults( - glossaryWords = loadDatasFromFile(), + glossaryWords = loadDatasFromFile("glossaire.json"), codeWords = mostUsedWordList.keys.toList(), onBackClick = { isCompareClicked = false } ) diff --git a/src/main/kotlin/main/Main.kt b/src/main/kotlin/main/Main.kt index 4dd3cde..56e8e02 100644 --- a/src/main/kotlin/main/Main.kt +++ b/src/main/kotlin/main/Main.kt @@ -1,15 +1,21 @@ package main import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material.* 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.unit.dp import androidx.compose.ui.window.* import java.awt.FileDialog import java.awt.Frame +import java.io.File +import java.util.* val customRedColor = Color(0xFFB70D1B) @@ -23,21 +29,181 @@ fun app() { var glossaryDetail: List by remember { mutableStateOf(emptyList()) } var isJavaScriptFileSelected by remember { mutableStateOf(false) } + var glossaries by remember { mutableStateOf(emptyList()) } + + var selectedGlossary by remember { mutableStateOf(null) } + + val isEmptySnackbarVisibleState = remember { mutableStateOf(false) } + val containsSpaceSnackbarVisibleState = remember { mutableStateOf(false) } + val glossaryAlreadyExistsSnackbarVisibleState = remember { mutableStateOf(false) } + + + + //Récupérer tous les glossaires à la racine du projet et les ajouter à la liste glossaries + glossaries = loadGlossaries() + + when (currentPage.value) { "accueil" -> { homePage( - onGlossaryClick = { currentPage.value = "glossaire" }, + onGlossaryClick = { currentPage.value = "glossaires" }, onCodeToVerifyClick = { currentPage.value = "choixLangage" } ) } - "glossaire" -> { + "glossaires" -> { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Sélectionnez un glossaire", style = MaterialTheme.typography.h5) + + Spacer(modifier = Modifier.height(16.dp)) + + LazyColumn( + modifier = Modifier.padding(10.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + items(glossaries) { glossary -> + Button( + onClick = { + selectedGlossary = glossary + currentPage.value = "glossaireOptions" + }, + modifier = Modifier + .width(200.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text(glossary.name) + } + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + onClick = { + currentPage.value = "nouveauGlossaire" + }, + modifier = Modifier + .width(300.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Créer un nouveau glossaire") + } + + Spacer(modifier = Modifier.height(6.dp)) + + Button( + onClick = { + currentPage.value = "accueil" + }, + modifier = Modifier + .width(250.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Retour") + } + } + } + + // Nouvelle page pour créer un nouveau glossaire + "nouveauGlossaire" -> { + var nouveauGlossaireName by remember { mutableStateOf("") } + + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + TextField( + value = nouveauGlossaireName, + onValueChange = { nouveauGlossaireName = it }, + label = { Text("Nom du nouveau glossaire") }, + modifier = Modifier + .padding(16.dp) + .fillMaxWidth(), + colors = TextFieldDefaults.textFieldColors( + backgroundColor = Color.White, + focusedIndicatorColor = customRedColor, + unfocusedIndicatorColor = Color.Gray + ) + ) + + Button( + onClick = { + // Ajouter le code pour créer un nouveau glossaire avec le nom saisi + //first check if the name is not empty, if there is space or if the name already exists + if (nouveauGlossaireName.isEmpty()) { + println("Veuillez saisir un nom pour le nouveau glossaire") + isEmptySnackbarVisibleState.value = true + return@Button + } + if (nouveauGlossaireName.contains(" ")) { + println("Le nom du glossaire ne doit pas contenir d'espace") + containsSpaceSnackbarVisibleState.value = true + return@Button + } + glossaries.forEach { glossary -> + nouveauGlossaireName = nouveauGlossaireName.lowercase(Locale.getDefault()) + if (glossary.name == nouveauGlossaireName) { + println("Le nom du glossaire existe déjà") + glossaryAlreadyExistsSnackbarVisibleState.value = true + return@Button + } + } + val newGlossary = Glossary(nouveauGlossaireName, "$nouveauGlossaireName.json") + glossaries = glossaries + newGlossary + //create new json file + val newFile = File(newGlossary.jsonFilePath) + newFile.createNewFile() + //update glossaries list + glossaries = loadGlossaries() + currentPage.value = "glossaires" // Revenir à la liste des glossaires + }, + modifier = Modifier + .width(200.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Créer") + } + + Button( + onClick = { + currentPage.value = "glossaires" + }, + modifier = Modifier + .width(200.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("Annuler") + } + } + } + + "glossaireOptions" -> { glossaryPage( onAddWordClick = { currentPage.value = "formulaire" }, onImportClick = { selectFile(setOf("csv", "xlsx")) { filePath -> println("Importing file: $filePath") - importFile(filePath) + selectedGlossary?.let { importFile(it, filePath) } } }, onExportClick = { @@ -49,27 +215,28 @@ fun app() { if (selectedFile != null) { val csvFilePath = "$selectedDirectory$selectedFile" println("Exporting to: $csvFilePath") - exportToCSV(csvFilePath) + selectedGlossary?.let { exportToCSV(it, csvFilePath) } } else { println("Export command cancelled by user.") } }, onSeeGlossaryClick = { - glossaryDetail = loadDatasFromFile() + glossaryDetail = selectedGlossary?.let { loadDatasFromFile(it.jsonFilePath) }!! currentPage.value = "glossaireDetail" }, - onBackClick = { currentPage.value = "accueil" } + onBackClick = { currentPage.value = "glossaires" }, + selectedGlossary = selectedGlossary!! ) } "glossaireDetail" -> { glossaryDetailedPage( glossary = glossaryDetail, - onBackClick = { currentPage.value = "glossaire" } + onBackClick = { currentPage.value = "glossaireOptions" } ) } "formulaire" -> { - formPage(onCancelClick = { currentPage.value = "glossaire" }) + selectedGlossary?.let { formPage(it, onCancelClick = { currentPage.value = "glossaireOptions" }) } } "choixLangage" -> { @@ -126,9 +293,78 @@ fun app() { } ) } + if (isEmptySnackbarVisibleState.value) { + Snackbar( + modifier = Modifier.padding(16.dp), + action = { + Button( + onClick = { isEmptySnackbarVisibleState.value = false }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("OK") + } + } + ) { + Text("Veuillez entrer un nom de glossaire.") + } + } + if (containsSpaceSnackbarVisibleState.value) { + Snackbar( + modifier = Modifier.padding(16.dp), + action = { + Button( + onClick = { containsSpaceSnackbarVisibleState.value = false }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("OK") + } + } + ) { + Text("Veuillez ne pas mettre d'espace dans le nom du glossaire.") + } + } + if (glossaryAlreadyExistsSnackbarVisibleState.value) { + Snackbar( + modifier = Modifier.padding(16.dp), + action = { + Button( + onClick = { glossaryAlreadyExistsSnackbarVisibleState.value = false }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("OK") + } + } + ) { + Text("Ce glossaire existe déjà.") + } + } } } +fun loadGlossaries(): List { + val glossaries = mutableListOf() + //Récupérer tous les fichiers json à la racine du projet + val glossaryFiles = File(".").listFiles { file -> + file.extension == "json" + } + glossaryFiles?.forEach { file -> + val glossary = Glossary(file.nameWithoutExtension, file.name) + glossaries.add(glossary) + } + println(glossaries) + return glossaries +} + + fun main() = application { val state = rememberWindowState( placement = WindowPlacement.Floating,