Add AutoCompletion, Projects and correction

main
Thomas Breil 2023-12-21 09:08:18 +01:00
parent c5de79c00a
commit d02ffb5e00
7 changed files with 471 additions and 47 deletions

View File

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

View File

@ -21,6 +21,7 @@ fun compareResults(
codeWords: List<String>,
onBackClick: () -> Unit
) {
println(glossaryWords)
val commonWords = findCommonWords(glossaryWords, codeWords)
Column(

View File

@ -1,16 +1,18 @@
package main
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Check
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlinx.serialization.encodeToString
@ -18,10 +20,12 @@ import kotlinx.serialization.json.Json
import java.io.File
import java.io.IOException
var appState = AppState
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun formPage(glossary: Glossary, onCancelClick: () -> Unit) {
// State to track whether to show the snackbar
var appState = AppState
val requiredFieldsSnackbarVisibleState = remember { mutableStateOf(false) }
val alreadyExistSnackbarVisibleState = remember { mutableStateOf(false) }
@ -83,6 +87,7 @@ fun formPage(glossary: Glossary, onCancelClick: () -> Unit) {
)
)
TextField(
value = description.value,
onValueChange = { description.value = it },
@ -94,16 +99,84 @@ fun formPage(glossary: Glossary, onCancelClick: () -> Unit) {
)
)
var expanded by remember { mutableStateOf(false) }
val glossaryWords = loadDatasFromFile(glossary.jsonFilePath)
var contextList: List<String> = emptyList()
glossaryWords.forEach { word: Word ->
contextList = contextList + word.mainContext
}
var listToShow by remember(mainContext.value) {
mutableStateOf(contextList.filter { it.startsWith(mainContext.value, ignoreCase = true) })
}
TextField(
value = mainContext.value,
onValueChange = { mainContext.value = it },
onValueChange = {
mainContext.value = it
expanded = true
listToShow = contextList.filter { word -> word.startsWith(mainContext.value, ignoreCase = true) }
},
label = { Text("Contexte principal *") },
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = customRedColor,
unfocusedIndicatorColor = Color.Gray,
focusedLabelColor = customRedColor
)
)
var dropHeight = (listToShow.count() * 60 + 30)
if (dropHeight > 300){
dropHeight = 300
}
if (expanded && mainContext.value.isNotBlank() && listToShow.isNotEmpty()) {
Box(
modifier = Modifier
.height(dropHeight.dp)
.padding(10.dp)
.border(1.dp, Color.Black)
) {
val scrollState = rememberLazyListState()
LazyColumn(
state = scrollState,
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
listToShow.forEach { word ->
item {
Box(
modifier = Modifier
.width(300.dp)
.clickable {
mainContext.value = word
expanded = false
}
.border(1.dp, Color.Black)
.height(50.dp)
.padding(10.dp)
.clip(MaterialTheme.shapes.medium)
) {
Text(text = word)
}
}
}
}
}
}
TextField(
value = secondaryContext.value,
@ -219,7 +292,7 @@ fun formPage(glossary: Glossary, onCancelClick: () -> Unit) {
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
) {
Text("OK")
}
}
@ -237,7 +310,7 @@ fun formPage(glossary: Glossary, onCancelClick: () -> Unit) {
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
) {
Text("OK")
}
}
@ -249,6 +322,7 @@ fun formPage(glossary: Glossary, onCancelClick: () -> Unit) {
}
}
fun resetFields(
name: MutableState<String>,
description: MutableState<String>,
@ -287,7 +361,7 @@ fun saveDatasInFile(filePath: String, listeWords: List<Word>) {
val json = Json { prettyPrint = true }
try {
val content = json.encodeToString(listeWords)
File(filePath).writeText(content)
File(glossaryPath + (appState.selectedProject?.name ) + "/" + filePath).writeText(content)
} catch (e: IOException) {
e.printStackTrace()
}
@ -295,11 +369,12 @@ fun saveDatasInFile(filePath: String, listeWords: List<Word>) {
fun loadDatasFromFile(filePath: String): List<Word> {
// If file is empty, return empty list
if (!File(filePath).exists() || File(filePath).length() == 0L) {
if (!File(glossaryPath + (appState.selectedProject?.name ) + "/" + filePath).exists() || File(glossaryPath + (appState.selectedProject?.name ) + "/" + filePath).length() == 0L) {
return emptyList()
}
return try {
val content = File(filePath).readText()
val content = File(glossaryPath + (appState.selectedProject?.name ) + "/" + filePath).readText()
Json.decodeFromString<List<Word>>(content)
} catch (e: IOException) {
e.printStackTrace()

View File

@ -85,7 +85,7 @@ fun glossaryPage(
onClick = {
importedSuccessfully.value = false
frame.dispose()
},
},
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
@ -95,9 +95,33 @@ fun glossaryPage(
}
}
)
}
Button(
if (errorImportation.value) {
AlertDialog(
onDismissRequest = { errorImportation.value = false },
title = { Text("Importation Echouée") },
text = { Text("Le fichier n'a pas pu être importé") },
confirmButton = {
Button(
onClick = {
errorImportation.value = false
frame.dispose()
},
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text("OK")
}
}
)
}
Button(
onClick = onExportClick,
modifier = Modifier
.width(300.dp),
@ -159,6 +183,7 @@ fun glossaryPage(
}
var importedSuccessfully = mutableStateOf(false)
var errorImportation = mutableStateOf(false)
var exportedSuccessfully = mutableStateOf(false)
fun selectFile(extensions: Set<String>, onFileSelected: (String) -> Unit) {
@ -243,26 +268,31 @@ fun importCSVFile(glossary : Glossary, filePath: String) {
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"]!!
)
try {
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["Antonyme"] == "\r") {
mot["Antonyme"] = ""
}
if (mot["Mot"] == null || mot["Mot"] == "") {
return
}
if (!verifyRequiredFields(mot)) {
return
}
addWordToGlossary(glossary.jsonFilePath, nouveauWord)
}catch(e : NullPointerException){
errorImportation.value = true
}
if (mot["Mot"] == null || mot["Mot"] == "") {
return
}
if (!verifyRequiredFields(mot)) {
return
}
addWordToGlossary(glossary.jsonFilePath, nouveauWord)
}
importedSuccessfully.value = true
}

View File

@ -22,14 +22,16 @@ enum class Language {
@Composable
fun homePage(
languageManager: LanguageManager,
onGlossaryClick: () -> Unit,
onProjectClick: () -> Unit,
onCodeToVerifyClick: () -> Unit
) {
val appState = AppState
val noFileSnackbarVisibleState = remember { mutableStateOf(false) }
var isCompareClicked by remember { mutableStateOf(false) }
var selectedGlossary by remember { mutableStateOf<Glossary?>(null) }
if (!isCompareClicked && selectedGlossary == null) {
// Utilisez un Box pour placer le drapeau en haut à droite
Box(
@ -61,7 +63,7 @@ fun homePage(
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
Button(
onClick = onGlossaryClick,
onClick = onProjectClick,
modifier = Modifier.width(200.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
@ -124,24 +126,44 @@ fun homePage(
}
}
}
var selectedProject by remember { mutableStateOf<Project?>(null) }
if (isCompareClicked && selectedGlossary == null) {
GlossaryList(glossaries = loadGlossaries()) { glossary ->
selectedGlossary = glossary
}
if (isCompareClicked && selectedProject == null && selectedGlossary == null) {
ProjectList(
projects = loadProjects(),
onProjectSelected = { project ->
selectedProject = project
appState.selectedProject = selectedProject
println("selectedProject = $selectedProject")
},
onBackClick = { isCompareClicked = false; selectedGlossary = null; selectedProject = null }
)
} else if (isCompareClicked && selectedGlossary == null) {
GlossaryList(
glossaries = loadGlossaries(appState.selectedProject!!),
onGlossarySelected = { glossary ->
selectedGlossary = glossary
println("selectedGlossary = $selectedGlossary")
},
onBackClick = { isCompareClicked = false; selectedGlossary = null; selectedProject = null }
)
} else if (isCompareClicked) {
selectedGlossary?.let {
compareResults(
glossaryWords = loadDatasFromFile(it.jsonFilePath),
codeWords = mostUsedWordList.keys.toList(),
onBackClick = { isCompareClicked = false; selectedGlossary = null }
onBackClick = { isCompareClicked = false; selectedGlossary = null; selectedProject = null }
)
}
}
}
@Composable
fun GlossaryList(glossaries: List<Glossary>, onGlossarySelected: (Glossary) -> Unit) {
fun GlossaryList(glossaries: List<Glossary>, onGlossarySelected: (Glossary) -> Unit, onBackClick: () -> Unit) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
@ -190,5 +212,81 @@ fun GlossaryList(glossaries: List<Glossary>, onGlossarySelected: (Glossary) -> U
)
Spacer(modifier = Modifier.height(6.dp))
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = onBackClick,
colors = androidx.compose.material.ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text("Retour")
}
}
}
@Composable
fun ProjectList(projects: List<Project>, onProjectSelected: (Project) -> Unit, onBackClick: () -> Unit) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Sélectionnez un Projet", style = MaterialTheme.typography.h5)
Spacer(modifier = Modifier.height(16.dp))
Box(
modifier = Modifier
.height(500.dp)
.padding(10.dp)
) {
val scrollState = rememberLazyListState()
LazyColumn(
state = scrollState,
modifier = Modifier.padding(10.dp).border(1.dp, Color.Black),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(projects) { project: Project ->
Row(
modifier = Modifier.width(200.dp).fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(
onClick = {
onProjectSelected(project)
},
modifier = Modifier
.width(150.dp)
.padding(10.dp, 0.dp, 0.dp, 0.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text(project.name)
}
}
}
}
VerticalScrollbar(
modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
adapter = rememberScrollbarAdapter(scrollState)
)
Spacer(modifier = Modifier.height(6.dp))
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = onBackClick,
colors = androidx.compose.material.ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text("Retour")
}
}
}

View File

@ -27,6 +27,13 @@ import java.util.*
val customRedColor = Color(0xFFB70D1B)
val currentPage = mutableStateOf("accueil")
val glossaryPath : String = "src/main/resources/projects/"
// Classe pour stocker l'état global
object AppState {
var selectedProject: Project? = null
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
@Preview
@ -41,21 +48,22 @@ fun app() {
var selectedGlossary by remember { mutableStateOf<Glossary?>(null) }
val appState = AppState
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(
languageManager,
onGlossaryClick = { currentPage.value = "glossaires" },
onProjectClick = { currentPage.value = "projects" },
onCodeToVerifyClick = { currentPage.value = "choixLangage" },
)
}
@ -82,6 +90,8 @@ fun app() {
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
glossaries = loadGlossaries(appState.selectedProject!!)
println(glossaries)
items(glossaries) { glossary ->
Row(
modifier = Modifier.width(200.dp).fillMaxWidth(),
@ -106,7 +116,7 @@ fun app() {
onClick = {
// Handle delete glossary action
glossaries = glossaries.filterNot { it == glossary }
val file = File(glossary.jsonFilePath)
val file = File(glossaryPath + (appState.selectedProject?.name ) + "/" + glossary.jsonFilePath)
file.delete()
}
) {
@ -208,10 +218,10 @@ fun app() {
val newGlossary = Glossary(nouveauGlossaireName, "$nouveauGlossaireName.json")
glossaries = glossaries + newGlossary
//create new json file
val newFile = File(newGlossary.jsonFilePath)
val newFile = File(glossaryPath + (appState.selectedProject?.name ) + "/" + newGlossary.jsonFilePath)
newFile.createNewFile()
//update glossaries list
glossaries = loadGlossaries()
glossaries = loadGlossaries(appState.selectedProject!!)
currentPage.value = "glossaires" // Revenir à la liste des glossaires
},
modifier = Modifier
@ -240,6 +250,18 @@ fun app() {
}
}
"projects" -> {
projectsPage(
currentPage = currentPage
)
}
"nouveauProjet" ->{
newProject(
currentPage = currentPage
)
}
"glossaireOptions" -> {
glossaryPage(
languageManager,
@ -398,10 +420,10 @@ fun app() {
}
}
fun loadGlossaries(): List<Glossary> {
fun loadGlossaries(project: Project): List<Glossary> {
val glossaries = mutableListOf<Glossary>()
//Récupérer tous les fichiers json à la racine du projet
val glossaryFiles = File(".").listFiles { file ->
val glossaryFiles = File(glossaryPath + project.name).listFiles { file ->
file.extension == "json"
}
glossaryFiles?.forEach { file ->
@ -413,6 +435,7 @@ fun loadGlossaries(): List<Glossary> {
}
fun main() = application {
val state = rememberWindowState(
placement = WindowPlacement.Floating,

View File

@ -0,0 +1,198 @@
package main
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.*
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.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import java.io.File
data class Project(val name: String)
fun loadProjects(): List<Project> {
val projectsDirectory = File("src/main/resources/projects/")
return projectsDirectory.listFiles()?.map { Project(it.name) } ?: emptyList()
}
@Composable
fun projectsPage(
currentPage: MutableState<String>
) {
val appState = AppState
var selectedProject: Project? by remember { mutableStateOf(null) }
var projects: List<Project> by remember { mutableStateOf(loadProjects()) }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Sélectionnez un projet", style = MaterialTheme.typography.h5)
Spacer(modifier = Modifier.height(16.dp))
LazyColumn(
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(projects, key = { project -> project.name }) { project ->
Row(
modifier = Modifier.width(200.dp).fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(
onClick = {
appState.selectedProject = project
currentPage.value = "glossaires"
},
modifier = Modifier
.width(150.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text(project.name)
}
IconButton(
onClick = {
// Handle delete project action
projects = projects.filterNot { it.name == project.name }
println(projects)
val directory = File("src/main/resources/projects/${project.name}/")
directory.deleteRecursively()
currentPage.value = "projects"
}
) {
Icon(imageVector = Icons.Default.Delete, contentDescription = "Delete Project")
}
}
}
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
currentPage.value = "nouveauProjet"
},
modifier = Modifier
.width(300.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text("Créer un nouveau project")
}
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")
}
}
}
@Composable
fun mySuperCoolButton(
project: Project,
){
var projects: List<Project> = loadProjects()
IconButton(
onClick = {
// Handle delete glossary action
projects = projects.filterNot { it == project }
val directory = File("src/main/resources/projects/${project.name}/")
directory.deleteRecursively()
}
) {
Icon(imageVector = Icons.Default.Delete, contentDescription = "Delete Project")
}
}
@Composable
fun newProject(
currentPage: MutableState<String>
){
var projectName by remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
){
Text("Nom du projet", style = MaterialTheme.typography.h5)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = projectName,
onValueChange = { projectName = it },
label = { Text("Nom du projet") },
modifier = Modifier
.width(300.dp)
.fillMaxWidth()
)
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"
},
modifier = Modifier
.width(300.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text("Créer")
}
Spacer(modifier = Modifier.height(6.dp))
Button(
onClick = {
currentPage.value = "projects"
},
modifier = Modifier
.width(250.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = customRedColor,
contentColor = Color.White
)
) {
Text("Retour")
}
}
}