diff --git a/src/main/kotlin/main/Main.kt b/src/main/kotlin/main/Main.kt index 598288e..be1cc2f 100644 --- a/src/main/kotlin/main/Main.kt +++ b/src/main/kotlin/main/Main.kt @@ -13,8 +13,10 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.runtime.* import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.key.* import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.* @@ -34,7 +36,7 @@ object AppState { var selectedProject: Project? = null } -@OptIn(ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class) @Composable @Preview fun app() { @@ -53,10 +55,7 @@ fun app() { val isEmptySnackbarVisibleState = remember { mutableStateOf(false) } val containsSpaceSnackbarVisibleState = remember { mutableStateOf(false) } val glossaryAlreadyExistsSnackbarVisibleState = remember { mutableStateOf(false) } - - - - + val invalidCharacterSnackbarVisibleState = remember { mutableStateOf(false) } when (currentPage.value) { @@ -191,10 +190,41 @@ fun app() { TextField( value = nouveauGlossaireName, onValueChange = { nouveauGlossaireName = it }, + singleLine = true, label = { Text("Nom du nouveau glossaire") }, modifier = Modifier .padding(16.dp) - .fillMaxWidth(), + .fillMaxWidth() + .onKeyEvent { event -> + if (event.key == Key.Enter && event.type == KeyEventType.KeyDown) { + // Handle the Enter key event by calling the common function + if (nouveauGlossaireName.isEmpty()) { + println("Veuillez saisir un nom pour le nouveau glossaire") + isEmptySnackbarVisibleState.value = true + } else if (nouveauGlossaireName.contains(" ")) { + println("Le nom du glossaire ne doit pas contenir d'espace") + containsSpaceSnackbarVisibleState.value = true + } else if (glossaries.any { it.name == nouveauGlossaireName }) { + println("Le nom du glossaire existe déjà") + glossaryAlreadyExistsSnackbarVisibleState.value = true + } else if (!isValidFileName(nouveauGlossaireName)) { + println("Le nom du glossaire contient des caractères non autorisés") + invalidCharacterSnackbarVisibleState.value = true + } else { + val newGlossary = Glossary(nouveauGlossaireName, "$nouveauGlossaireName.json") + glossaries = glossaries + newGlossary + // create new json file + val newFile = File(glossaryPath + (appState.selectedProject?.name) + "/" + newGlossary.jsonFilePath) + newFile.createNewFile() + // update glossaries list + glossaries = loadGlossaries(appState.selectedProject!!) + currentPage.value = "glossaires" // Revenir à la liste des glossaires + } + true + } else { + false + } + }, colors = TextFieldDefaults.textFieldColors( backgroundColor = Color.White, focusedIndicatorColor = customRedColor, @@ -204,34 +234,30 @@ fun app() { 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 + // Handle the Enter key event by calling the common function if (nouveauGlossaireName.isEmpty()) { println("Veuillez saisir un nom pour le nouveau glossaire") isEmptySnackbarVisibleState.value = true - return@Button - } - if (nouveauGlossaireName.contains(" ")) { + } else if (nouveauGlossaireName.contains(" ")) { println("Le nom du glossaire ne doit pas contenir d'espace") containsSpaceSnackbarVisibleState.value = true - return@Button + } else if (glossaries.any { it.name == nouveauGlossaireName }) { + println("Le nom du glossaire existe déjà") + glossaryAlreadyExistsSnackbarVisibleState.value = true + } else if (!isValidFileName(nouveauGlossaireName)) { + println("Le nom du glossaire contient des caractères non autorisés") + invalidCharacterSnackbarVisibleState.value = true + } else { + val newGlossary = Glossary(nouveauGlossaireName, "$nouveauGlossaireName.json") + glossaries = glossaries + newGlossary + // create new json file + val newFile = + File(glossaryPath + (appState.selectedProject?.name) + "/" + newGlossary.jsonFilePath) + newFile.createNewFile() + // update glossaries list + glossaries = loadGlossaries(appState.selectedProject!!) + currentPage.value = "glossaires" // Revenir à la liste des glossaires } - 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(glossaryPath + (appState.selectedProject?.name ) + "/" + newGlossary.jsonFilePath) - newFile.createNewFile() - //update glossaries list - glossaries = loadGlossaries(appState.selectedProject!!) - currentPage.value = "glossaires" // Revenir à la liste des glossaires }, modifier = Modifier .width(200.dp), @@ -425,10 +451,33 @@ fun app() { Text("Ce glossaire existe déjà.") } } + if (invalidCharacterSnackbarVisibleState.value) { + Snackbar( + modifier = Modifier.padding(16.dp), + action = { + Button( + onClick = { invalidCharacterSnackbarVisibleState.value = false }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("OK") + } + } + ) { + Text("Le nom du glossaire contient des caractères non autorisés (caractères spéciaux).") + } + } } } +fun isValidFileName(name: String): Boolean { + val regex = Regex("[^a-zA-Z0-9._-]") + return !regex.containsMatchIn(name) +} + fun loadGlossaries(project: Project): List { val glossaries = mutableListOf() //Récupérer tous les fichiers json à la racine du projet diff --git a/src/main/kotlin/main/projects.kt b/src/main/kotlin/main/projects.kt index 9ec6949..a2e9771 100644 --- a/src/main/kotlin/main/projects.kt +++ b/src/main/kotlin/main/projects.kt @@ -9,8 +9,10 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.runtime.* import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.key.* import androidx.compose.ui.unit.dp import java.io.File @@ -123,12 +125,18 @@ fun projectsPage( } } +@OptIn(ExperimentalComposeUiApi::class) @Composable fun newProject( currentPage: MutableState ){ var projectName by remember { mutableStateOf("") } + val isEmptySnackbarVisibleState = remember { mutableStateOf(false) } + val containsSpaceSnackbarVisibleState = remember { mutableStateOf(false) } + val glossaryAlreadyExistsSnackbarVisibleState = remember { mutableStateOf(false) } + val invalidCharacterSnackbarVisibleState = remember { mutableStateOf(false) } + Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, @@ -137,24 +145,65 @@ fun newProject( Text("Nom du projet", style = MaterialTheme.typography.h5) Spacer(modifier = Modifier.height(16.dp)) + val projectsList = loadProjects() TextField( value = projectName, + singleLine = true, onValueChange = { projectName = it }, label = { Text("Nom du projet") }, modifier = Modifier .width(300.dp) .fillMaxWidth() + .onKeyEvent { event -> + if (event.key == Key.Enter && event.type == KeyEventType.KeyDown) { + if (projectName.isEmpty()) { + println("Veuillez saisir un nom pour le nouveau projet") + isEmptySnackbarVisibleState.value = true + } else if (projectName.contains(" ")) { + println("Le nom du projet ne doit pas contenir d'espace") + containsSpaceSnackbarVisibleState.value = true + } else if (projectsList.any { it.name == projectName }) { + println("Le nom du projet existe déjà") + glossaryAlreadyExistsSnackbarVisibleState.value = true + } else if (!isValidFileName(projectName)) { + println("Le nom du projet contient des caractères non autorisés") + invalidCharacterSnackbarVisibleState.value = true + } else { + val directory = File("src/main/resources/projects/$projectName/") + directory.mkdirs() + println("Project $projectName created") + currentPage.value = "projects" + } + true + } else { + false + } + } ) Spacer(modifier = Modifier.height(16.dp)) Button( onClick = { - val directory = File("src/main/resources/projects/$projectName/") - directory.mkdirs() - println("Project $projectName created") - currentPage.value = "projects" + if (projectName.isEmpty()) { + println("Veuillez saisir un nom pour le nouveau projet") + isEmptySnackbarVisibleState.value = true + } else if (projectName.contains(" ")) { + println("Le nom du projet ne doit pas contenir d'espace") + containsSpaceSnackbarVisibleState.value = true + } else if (projectsList.any { it.name == projectName }) { + println("Le nom du projet existe déjà") + glossaryAlreadyExistsSnackbarVisibleState.value = true + } else if (!isValidFileName(projectName)) { + println("Le nom du projet contient des caractères non autorisés") + invalidCharacterSnackbarVisibleState.value = true + } else { + val directory = File("src/main/resources/projects/$projectName/") + directory.mkdirs() + println("Project $projectName created") + currentPage.value = "projects" + } }, modifier = Modifier .width(300.dp), @@ -181,6 +230,79 @@ fun newProject( ) { Text("Retour") } + + 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à.") + } + } + if (invalidCharacterSnackbarVisibleState.value) { + Snackbar( + modifier = Modifier.padding(16.dp), + action = { + Button( + onClick = { invalidCharacterSnackbarVisibleState.value = false }, + colors = ButtonDefaults.buttonColors( + backgroundColor = customRedColor, + contentColor = Color.White + ) + ) { + Text("OK") + } + } + ) { + Text("Le nom du glossaire contient des caractères non autorisés (caractères spéciaux).") + } + } } }