feat: set modification
This commit is contained in:
parent
b5922d7280
commit
871c29d487
9 changed files with 305 additions and 9 deletions
|
@ -151,6 +151,8 @@ private fun DeleteRow(
|
|||
|
||||
@Composable
|
||||
private fun ActionRow(context: Context, model: HomeViewModel, navController: NavController) {
|
||||
val selection by model.selected
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||||
Button(onClick = { (model::doAction)(ActionHome.CREATION) }) {
|
||||
Text(text = context.getString(R.string.main_button_create))
|
||||
|
@ -158,7 +160,9 @@ private fun ActionRow(context: Context, model: HomeViewModel, navController: Nav
|
|||
|
||||
Spacer(modifier = Modifier.padding(2.dp))
|
||||
|
||||
Button(onClick = { navController.navigate(MODIFY_SET) }) {
|
||||
Button(
|
||||
enabled = selection != null,
|
||||
onClick = { navController.navigate("$MODIFY_SET/${selection?.idSet}") }) {
|
||||
Text(text = context.getString(R.string.main_button_modify))
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,14 @@ fun MainScreen() {
|
|||
modifier = Modifier.padding(padding)
|
||||
) {
|
||||
composable(HOME) { HomeScreen(padding, navController) }
|
||||
composable(MODIFY_SET) { ModifySetScreen(padding, navController) }
|
||||
composable("$MODIFY_SET/{$MODIFY_SET_ARGS}") {
|
||||
it.arguments?.getString(MODIFY_SET_ARGS)?.let { idSet ->
|
||||
ModifySetScreen(
|
||||
padding,
|
||||
idSet.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
composable(PLAY) { PlayScreen(padding, navController) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,212 @@
|
|||
package fr.uparis.diamantkennel.memorisationapplication
|
||||
|
||||
import android.widget.Toast
|
||||
import android.content.res.Resources
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.navigation.NavController
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import fr.uparis.diamantkennel.memorisationapplication.data.Question
|
||||
import fr.uparis.diamantkennel.memorisationapplication.ui.ActionModifySet
|
||||
import fr.uparis.diamantkennel.memorisationapplication.ui.ModifySetViewModel
|
||||
import kotlin.text.Typography.ellipsis
|
||||
|
||||
|
||||
@Composable
|
||||
fun ModifySetScreen(padding: PaddingValues, navController: NavController) {
|
||||
fun ModifySetScreen(
|
||||
padding: PaddingValues,
|
||||
idSet: Int,
|
||||
model: ModifySetViewModel = viewModel()
|
||||
) {
|
||||
// First update the list and set ID
|
||||
model.setId.value = idSet
|
||||
model.updateQuestionList(idSet)
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
Toast.makeText(context, "Modify", Toast.LENGTH_SHORT).show()
|
||||
val currentSelection by model.selection
|
||||
val questions by model.questions.collectAsState(listOf())
|
||||
var action by model.action
|
||||
|
||||
if (action == ActionModifySet.AJOUT || action == ActionModifySet.MODIFICATION) {
|
||||
AjoutModifDialog(action, currentSelection, model::ajoutQuestion)
|
||||
{ action = ActionModifySet.AUCUN }
|
||||
}
|
||||
|
||||
if (action == ActionModifySet.SUPPRIMER) {
|
||||
RemoveDialog(model::removeQuestion)
|
||||
{ action = ActionModifySet.AUCUN }
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(padding),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
showList(model, questions, currentSelection)
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||||
Button(
|
||||
enabled = currentSelection != null,
|
||||
onClick = { action = ActionModifySet.MODIFICATION }) {
|
||||
Text(text = context.getString(R.string.modify_button_modify))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.padding(2.dp))
|
||||
|
||||
Button(onClick = { action = ActionModifySet.AJOUT }) {
|
||||
Text(text = context.getString(R.string.modify_button_add))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.padding(2.dp))
|
||||
|
||||
Button(
|
||||
enabled = currentSelection != null,
|
||||
onClick = { action = ActionModifySet.SUPPRIMER }) {
|
||||
Text(text = context.getString(R.string.modify_button_delete))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun showList(model: ModifySetViewModel, questions: List<Question>, currentSelection: Question?) {
|
||||
LazyColumn(
|
||||
Modifier.fillMaxHeight(0.6f)
|
||||
) {
|
||||
itemsIndexed(questions) { index, item ->
|
||||
listItem(index, item, currentSelection, model::updateSelection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun listItem(
|
||||
index: Int,
|
||||
question: Question,
|
||||
currentSelection: Question?,
|
||||
updateSelection: (Question) -> Unit
|
||||
) {
|
||||
|
||||
val maxLength = Resources.getSystem().displayMetrics.widthPixels / 33
|
||||
|
||||
val containerColor = when {
|
||||
currentSelection == question -> colorResource(id = R.color.selected)
|
||||
index % 2 == 0 -> colorResource(id = R.color.list_alternate)
|
||||
else -> colorResource(id = R.color.list)
|
||||
}
|
||||
|
||||
Card(
|
||||
onClick = { updateSelection(question) },
|
||||
Modifier.fillMaxSize(),
|
||||
colors = CardDefaults.cardColors(containerColor)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
Text(
|
||||
question.enonce.take(maxLength)
|
||||
.let { if (question.enonce.length > maxLength) it + ellipsis else it },
|
||||
modifier = Modifier.padding(2.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AjoutModifDialog(
|
||||
type: ActionModifySet,
|
||||
selection: Question?,
|
||||
confirm: (String, String) -> Unit,
|
||||
dismiss: () -> Unit
|
||||
) {
|
||||
var enonce by remember {
|
||||
mutableStateOf(
|
||||
if (type == ActionModifySet.MODIFICATION) {
|
||||
selection?.enonce!!
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)
|
||||
}
|
||||
var reponse by remember {
|
||||
mutableStateOf(
|
||||
if (type == ActionModifySet.MODIFICATION) {
|
||||
selection?.reponse!!
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
AlertDialog(onDismissRequest = dismiss,
|
||||
title = {
|
||||
Text(
|
||||
text = if (selection != null) {
|
||||
"Mettre à jour la question"
|
||||
} else {
|
||||
"Ajouter une question"
|
||||
}
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
Row {
|
||||
OutlinedTextField(
|
||||
value = enonce,
|
||||
onValueChange = { enonce = it },
|
||||
label = { Text(text = "Question") })
|
||||
}
|
||||
|
||||
Row {
|
||||
OutlinedTextField(
|
||||
value = reponse,
|
||||
onValueChange = { reponse = it },
|
||||
label = { Text(text = "Réponse") })
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(onClick = {
|
||||
confirm(enonce, reponse)
|
||||
dismiss()
|
||||
}) { Text(text = "Ok") }
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RemoveDialog(confirm: () -> Unit, dismiss: () -> Unit) =
|
||||
AlertDialog(onDismissRequest = dismiss,
|
||||
title = { Text(text = "Supprimer la question") },
|
||||
text = { Text(text = "Voulez-vous supprimer la question ?") },
|
||||
confirmButton = {
|
||||
Button(onClick = {
|
||||
confirm()
|
||||
dismiss()
|
||||
}) { Text(text = "Ok") }
|
||||
})
|
||||
|
|
|
@ -2,4 +2,5 @@ package fr.uparis.diamantkennel.memorisationapplication
|
|||
|
||||
const val HOME = "home"
|
||||
const val MODIFY_SET = "modify_set"
|
||||
const val MODIFY_SET_ARGS = "id_set"
|
||||
const val PLAY = "play"
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.room.Dao
|
|||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
|
@ -14,12 +15,24 @@ interface MemoDao {
|
|||
@Insert
|
||||
suspend fun insertQuestion(question: Question)
|
||||
|
||||
@Update
|
||||
fun updateQuestion(question: Question)
|
||||
|
||||
@Query("SELECT * FROM SetQuestions")
|
||||
fun loadAllSets(): Flow<List<SetOfQuestions>>
|
||||
|
||||
@Query("SELECT * FROM Question WHERE setId = :idSet")
|
||||
fun loadQuestions(idSet: Int): Flow<List<Question>>
|
||||
|
||||
@Query("SELECT * FROM SetQuestions WHERE idSet = :requestedId")
|
||||
fun getSet(requestedId: Int): SetOfQuestions
|
||||
|
||||
@Query("DELETE FROM SetQuestions")
|
||||
fun deleteTable()
|
||||
|
||||
@Delete
|
||||
fun delete(set: SetQuestions)
|
||||
|
||||
@Delete
|
||||
fun deleteQuestion(question: Question)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,6 @@ import androidx.room.PrimaryKey
|
|||
data class Question(
|
||||
@PrimaryKey(autoGenerate = true) val idQuestion: Int = 0,
|
||||
val setId: Int, // Foreign key linking to SetQuestions
|
||||
val enonce: String,
|
||||
val reponse: String
|
||||
var enonce: String,
|
||||
var reponse: String
|
||||
)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package fr.uparis.diamantkennel.memorisationapplication.ui
|
||||
|
||||
enum class ActionModifySet {
|
||||
AJOUT, AUCUN, MODIFICATION, SUPPRIMER
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package fr.uparis.diamantkennel.memorisationapplication.ui
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import fr.uparis.diamantkennel.memorisationapplication.MemoApplication
|
||||
import fr.uparis.diamantkennel.memorisationapplication.data.Question
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ModifySetViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val dao = (application as MemoApplication).database.memoDao()
|
||||
|
||||
var setId = mutableStateOf(-1)
|
||||
var questions = dao.loadQuestions(setId.value)
|
||||
var selection = mutableStateOf<Question?>(null)
|
||||
var action = mutableStateOf(ActionModifySet.AUCUN)
|
||||
|
||||
fun updateQuestionList(setId: Int) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
questions = dao.loadQuestions(setId)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSelection(question: Question) {
|
||||
if (selection.value == question) {
|
||||
selection.value = null
|
||||
} else {
|
||||
selection.value = question
|
||||
}
|
||||
}
|
||||
|
||||
fun ajoutQuestion(enonce: String, reponse: String) {
|
||||
when (action.value) {
|
||||
ActionModifySet.AJOUT -> viewModelScope.launch(Dispatchers.IO) {
|
||||
dao.insertQuestion(
|
||||
Question(
|
||||
setId = setId.value,
|
||||
enonce = enonce,
|
||||
reponse = reponse
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ActionModifySet.MODIFICATION -> viewModelScope.launch(Dispatchers.IO) {
|
||||
val question = selection.value!!
|
||||
question.enonce = enonce
|
||||
question.reponse = reponse
|
||||
|
||||
dao.updateQuestion(question)
|
||||
}
|
||||
|
||||
else -> {
|
||||
/* Ce cas n'arrivera jamais */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeQuestion() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
dao.deleteQuestion(selection.value!!)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,4 +9,7 @@
|
|||
<string name="main_button_start">Lancer</string>
|
||||
<string name="error_bad_entry">Erreur : entrée invalide</string>
|
||||
<string name="error_duplicate">Erreur : doublon</string>
|
||||
<string name="modify_button_add">Ajouter</string>
|
||||
<string name="modify_button_modify">Modifier</string>
|
||||
<string name="modify_button_delete">Supprimer</string>
|
||||
</resources>
|
||||
|
|
Reference in a new issue