cleaner code

This commit is contained in:
ImAliant 2024-01-06 20:15:47 +01:00
parent 920bd24742
commit 80310b2855
9 changed files with 233 additions and 107 deletions

View file

@ -68,7 +68,7 @@ fun HomeScreen(
val errorEntry by model.error val errorEntry by model.error
if (errorEntry != null) { ShowDialog(errorEntry != null) {
ErrorDialog( ErrorDialog(
when (errorEntry!!) { when (errorEntry!!) {
ErrorsAjout.BAD_ENTRY -> context.getString(R.string.error_bad_entry) ErrorsAjout.BAD_ENTRY -> context.getString(R.string.error_bad_entry)
@ -76,25 +76,30 @@ fun HomeScreen(
}, model::cleanErrors }, model::cleanErrors
) )
} }
ShowDialog(creationRequest) { CreationDialog(model::dismissCreation, model) }
if (creationRequest) { ShowDialog(importationRequest) { ImportDialog(model::dismissImportation, model) }
CreationDialog( ShowDialog(deletionRequest) {
dismiss = model::dismissCreation, model = model DeletionDialog(model::dismissDeleteOne, model::deleteSelected)
)
} }
if (importationRequest) { Home(
ImportDialog( padding,
dismiss = model::dismissImportation, model = model navController,
) model,
} setOfQuestions,
currentSelection
)
}
if (deletionRequest) { @Composable
DeletionDialog( private fun Home(
model::dismissDeleteOne, padding: PaddingValues,
model::deleteSelected navController: NavController,
) model: HomeViewModel,
} setOfQuestions: List<SetOfQuestions> = listOf(),
currentSelection: SetQuestions? = null,
) {
val context = LocalContext.current
Column( Column(
modifier = Modifier.padding(padding), horizontalAlignment = Alignment.CenterHorizontally modifier = Modifier.padding(padding), horizontalAlignment = Alignment.CenterHorizontally
@ -146,7 +151,6 @@ private fun ActionRow(context: Context, model: HomeViewModel, navController: Nav
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun CreationDialog( fun CreationDialog(
dismiss: () -> Unit, model: HomeViewModel = viewModel() dismiss: () -> Unit, model: HomeViewModel = viewModel()
@ -172,7 +176,7 @@ fun CreationDialog(
}) })
} }
@OptIn(ExperimentalMaterial3Api::class, DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
@Composable @Composable
fun ImportDialog( fun ImportDialog(
dismiss: () -> Unit, model: HomeViewModel dismiss: () -> Unit, model: HomeViewModel

View file

@ -1,9 +1,11 @@
package fr.uparis.diamantkennel.memorisationapplication package fr.uparis.diamantkennel.memorisationapplication
import android.content.Context import android.content.Context
import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.BottomNavigation import androidx.compose.material.BottomNavigation
@ -39,6 +41,7 @@ import fr.uparis.diamantkennel.memorisationapplication.ui.theme.MemorisationAppl
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = STATS) val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = STATS)
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
@ -54,18 +57,20 @@ class MainActivity : ComponentActivity() {
} }
} }
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable @Composable
fun MainScreenMainActivity() { fun MainScreenMainActivity() {
MainScreen() MainScreen()
} }
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Preview(showBackground = true) @Preview(showBackground = true)
@Composable @Composable
fun MainScreenPreview() { fun MainScreenPreview() {
MainScreen() MainScreen()
} }
@OptIn(ExperimentalMaterial3Api::class) @RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable @Composable
fun MainScreen() { fun MainScreen() {
val navController = rememberNavController() val navController = rememberNavController()
@ -97,7 +102,7 @@ fun MainScreen() {
) )
} }
} }
composable(SETTINGS) { SettingsScreen(padding) } composable(SETTINGS) { SettingsScreen() }
} }
} }
} }
@ -135,3 +140,14 @@ fun BottomBar(navController: NavHostController) =
) )
}) })
} }
@Composable
fun <T: Any> ShowDialog(
condition: Boolean,
dialog: @Composable () -> T
) {
if (condition) {
dialog()
}
}

View file

@ -36,7 +36,6 @@ import fr.uparis.diamantkennel.memorisationapplication.ui.ActionModifySet
import fr.uparis.diamantkennel.memorisationapplication.ui.ModifySetViewModel import fr.uparis.diamantkennel.memorisationapplication.ui.ModifySetViewModel
import kotlin.text.Typography.ellipsis import kotlin.text.Typography.ellipsis
@Composable @Composable
fun ModifySetScreen( fun ModifySetScreen(
padding: PaddingValues, padding: PaddingValues,
@ -47,20 +46,33 @@ fun ModifySetScreen(
model.setId.value = idSet model.setId.value = idSet
model.updateQuestionList(idSet) model.updateQuestionList(idSet)
val context = LocalContext.current
val currentSelection by model.selection val currentSelection by model.selection
val questions by model.questions.collectAsState(listOf()) val questions by model.questions.collectAsState(listOf())
var action by model.action val action by model.action
if (action == ActionModifySet.AJOUT || action == ActionModifySet.MODIFICATION) { ShowDialog(action == ActionModifySet.AJOUT || action == ActionModifySet.MODIFICATION) {
AjoutModifDialog(action, currentSelection, model::ajoutQuestion) AjoutModifDialog(action, currentSelection, model::ajoutQuestion, model::dismissAction)
{ action = ActionModifySet.AUCUN } }
ShowDialog(action == ActionModifySet.SUPPRIMER) {
RemoveDialog(model::removeQuestion, model::dismissAction)
} }
if (action == ActionModifySet.SUPPRIMER) { Modify(
RemoveDialog(model::removeQuestion) padding = padding,
{ action = ActionModifySet.AUCUN } model = model,
} questions = questions,
currentSelection = currentSelection
)
}
@Composable
fun Modify(
padding: PaddingValues,
model: ModifySetViewModel,
questions: List<Question>,
currentSelection: Question?
) {
val context = LocalContext.current
Column( Column(
modifier = Modifier.padding(padding), modifier = Modifier.padding(padding),
@ -71,13 +83,13 @@ fun ModifySetScreen(
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Button( Button(
enabled = currentSelection != null, enabled = currentSelection != null,
onClick = { action = ActionModifySet.MODIFICATION }) { onClick = model::modifAction) {
Text(text = context.getString(R.string.modify)) Text(text = context.getString(R.string.modify))
} }
Spacer(modifier = Modifier.padding(2.dp)) Spacer(modifier = Modifier.padding(2.dp))
Button(onClick = { action = ActionModifySet.AJOUT }) { Button(onClick = model::ajoutAction) {
Text(text = context.getString(R.string.add)) Text(text = context.getString(R.string.add))
} }
@ -85,7 +97,7 @@ fun ModifySetScreen(
Button( Button(
enabled = currentSelection != null, enabled = currentSelection != null,
onClick = { action = ActionModifySet.SUPPRIMER }) { onClick = model::supprAction) {
Text(text = context.getString(R.string.modify_button_delete)) Text(text = context.getString(R.string.modify_button_delete))
} }
} }

View file

@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
@ -18,7 +17,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@ -27,10 +25,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import fr.uparis.diamantkennel.memorisationapplication.data.Question
import fr.uparis.diamantkennel.memorisationapplication.ui.AnswerType import fr.uparis.diamantkennel.memorisationapplication.ui.AnswerType
import fr.uparis.diamantkennel.memorisationapplication.ui.PlayViewModel import fr.uparis.diamantkennel.memorisationapplication.ui.PlayViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PlayScreen( fun PlayScreen(
padding: PaddingValues, padding: PaddingValues,
@ -42,41 +40,54 @@ fun PlayScreen(
// First update the list of questions // First update the list of questions
model.updateQuestionList(idSet) model.updateQuestionList(idSet)
val context = LocalContext.current
val question by model.currentQuestion val question by model.currentQuestion
val reponse by model.proposedAnswer val reponse by model.proposedAnswer
val correction by model.evaluatedAnswer val correction by model.evaluatedAnswer
var giveup by model.showAnswer val giveup by model.showAnswer
val gameEnded by model.end val gameEnded by model.end
val delay by model.delay.collectAsState(initial = 3000) val delay by model.delay.collectAsState(initial = 5000)
val cpt by model.compteurSb val cpt by model.compteurSb
if (correction != null) {
LaunchedEffect(cpt) {
model.sbUpdate()
snackbarHostState.showSnackbar(
when (correction!!) {
AnswerType.GOOD -> context.getString(R.string.good_answer)
AnswerType.BAD -> context.getString(R.string.bad_answer)
}, duration = SnackbarDuration.Short
)
model.resetAfterSb()
}
}
if (gameEnded) { SnackbarAnswer(
EndDialog { navController.navigate(HOME) } model,
} snackbarHostState,
cpt,
correction
)
if (giveup && question != null) { ShowDialog(gameEnded) { EndDialog { navController.navigate(HOME) } }
ShowDialog(giveup && question != null) {
SolutionDialog(question!!.reponse, model::newQuestion) SolutionDialog(question!!.reponse, model::newQuestion)
} }
// Update timer if needed // Update timer if needed
if (!model.isDelayElapsed(delay) && question != null) { model.updateTimer(delay)
model.updateTime(System.currentTimeMillis())
} Play(
padding,
navController,
idSet,
model,
question,
reponse,
correction,
delay
)
}
@Composable
fun Play(
padding: PaddingValues,
navController: NavController,
idSet: Int,
model: PlayViewModel,
question: Question?,
reponse: String,
correction: AnswerType?,
delay: Int
) {
val context = LocalContext.current
Column( Column(
modifier = Modifier.padding(padding), modifier = Modifier.padding(padding),
@ -87,7 +98,7 @@ fun PlayScreen(
Text(context.getString(R.string.no_question), fontSize = 30.sp) Text(context.getString(R.string.no_question), fontSize = 30.sp)
} }
} else { } else {
Text(text = question!!.enonce, fontSize = 30.sp, textAlign = TextAlign.Center) Text(text = question.enonce, fontSize = 30.sp, textAlign = TextAlign.Center)
Spacer(modifier = Modifier.padding(top = 20.dp)) Spacer(modifier = Modifier.padding(top = 20.dp))
@ -112,7 +123,8 @@ fun PlayScreen(
Button( Button(
enabled = model.isDelayElapsed(delay), enabled = model.isDelayElapsed(delay),
onClick = { giveup = true }) { onClick = model::giveUp
) {
Text(text = context.getString(R.string.see_answer)) Text(text = context.getString(R.string.see_answer))
} }
} }
@ -145,3 +157,25 @@ fun EndDialog(next: () -> Unit) =
confirmButton = { confirmButton = {
Button(onClick = next) { Text(text = LocalContext.current.getString(R.string.ok)) } Button(onClick = next) { Text(text = LocalContext.current.getString(R.string.ok)) }
}) })
@Composable
fun SnackbarAnswer(
model: PlayViewModel,
snackbarHostState: SnackbarHostState,
cpt: Int,
correction: AnswerType?
) {
val context = LocalContext.current
if (correction != null) {
LaunchedEffect(cpt) {
model.sbUpdate()
snackbarHostState.showSnackbar(
when (correction) {
AnswerType.GOOD -> context.getString(R.string.good_answer)
AnswerType.BAD -> context.getString(R.string.bad_answer)
}, duration = SnackbarDuration.Short
)
model.resetAfterSb()
}
}
}

View file

@ -8,7 +8,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -52,14 +51,13 @@ import kotlinx.coroutines.runBlocking
@RequiresApi(Build.VERSION_CODES.TIRAMISU) @RequiresApi(Build.VERSION_CODES.TIRAMISU)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel()) { fun SettingsScreen(model: SettingsViewModel = viewModel()) {
val context = LocalContext.current val context = LocalContext.current
var deletionDBRequest by model.deletionDB var deletionDBRequest by model.deletionDB
var cleanStatRequest by model.deletionStat var cleanStatRequest by model.deletionStat
var choiceTimeNotifRequest by model.notif var choiceTimeNotifRequest by model.notif
var choiceDelayRequest by model.delayRequest var choiceDelayRequest by model.delayRequest
var permissionNotif by model.gavePermissionNow
val prefConfigTime = runBlocking { model.prefConfigTime.first() } val prefConfigTime = runBlocking { model.prefConfigTime.first() }
@ -71,6 +69,45 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel(
model.checkPermission(context) model.checkPermission(context)
ShowDialog(deletionDBRequest) { DeletionDBDialog(model::deleteDb, model::dismissDeletionDB) }
ShowDialog(cleanStatRequest) { CleanStatDialog(model::cleanStats, model::dismissDeletionStat) }
ShowDialog(choiceTimeNotifRequest) {
ChoiceTimeNotifDialog(
{ model.choiceTimeNotif(stateTime, context) },
model::dismissNotif,
stateTime
)
}
ShowDialog(choiceDelayRequest) {
ChoiceDelayDialog(
{ model.choiceDelay(it) },
model::dismissDelayRequest
)
}
Settings(
model,
{ choiceTimeNotifRequest = true },
{ deletionDBRequest = true },
{ cleanStatRequest = true },
{ choiceDelayRequest = true },
model::resetDelay
)
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun Settings(
model: SettingsViewModel = viewModel(),
onTimeNotifButtonClick: () -> Unit,
deletionDBRequest: () -> Unit,
cleanStatRequest: () -> Unit,
onDelayButtonClick: () -> Unit,
onResetButtonClick: () -> Unit,
) {
val context = LocalContext.current
var permissionNotif by model.gavePermissionNow
val permissionLauncher = rememberLauncherForActivityResult( val permissionLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(), contract = ActivityResultContracts.RequestPermission(),
) { ) {
@ -79,48 +116,17 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel(
} }
} }
if (deletionDBRequest) {
DeletionDBDialog(model::deleteDb) { deletionDBRequest = false }
}
if (cleanStatRequest) {
CleanStatDialog(model::cleanStats) { cleanStatRequest = false }
}
if (choiceTimeNotifRequest) {
ChoiceTimeNotifDialog(
{ model.choiceTimeNotif(stateTime, context) },
{ choiceTimeNotifRequest = false },
stateTime
)
}
if (choiceDelayRequest) {
ChoiceDelayDialog(
{ model.choiceDelay(it) },
{ choiceDelayRequest = false },
)
}
Column( Column(
modifier = Modifier.padding(padding), modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Stats(model) Stats(model = model)
AddSpacedDivider() AddSpacedDivider()
NotificationSettings(context, model, permissionNotif, permissionLauncher, onTimeNotifButtonClick)
NotificationSettings(context, model, permissionNotif, permissionLauncher) {
choiceTimeNotifRequest = true
}
AddSpacedDivider() AddSpacedDivider()
GestionSettings(context, deletionDBRequest, cleanStatRequest)
GestionSettings(context, { deletionDBRequest = true }, { cleanStatRequest = true })
AddSpacedDivider() AddSpacedDivider()
GameSettings(context, onDelayButtonClick, onResetButtonClick)
GameSettings(context) { choiceDelayRequest = true }
} }
} }
@ -179,7 +185,7 @@ fun GestionSettings(context: Context, deletionDBRequest: () -> Unit, cleanStatRe
} }
@Composable @Composable
fun GameSettings(context: Context, onDelayButtonClick: () -> Unit) { fun GameSettings(context: Context, onDelayButtonClick: () -> Unit, onResetButtonClick: () -> Unit) {
Text(text = context.getString(R.string.game), fontSize = 30.sp) Text(text = context.getString(R.string.game), fontSize = 30.sp)
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@ -192,6 +198,12 @@ fun GameSettings(context: Context, onDelayButtonClick: () -> Unit) {
Button(onClick = onDelayButtonClick) { Button(onClick = onDelayButtonClick) {
Text(text = context.getString(R.string.choice_delay_button)) Text(text = context.getString(R.string.choice_delay_button))
} }
Button(
onClick = onResetButtonClick,
colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.red))
) {
Text(text = context.getString(R.string.reset_button))
}
} }
} }
} }
@ -295,7 +307,9 @@ fun ChoiceDelayDialog(confirm: (Int) -> Unit, dismiss: () -> Unit) {
) )
}, },
confirmButton = { confirmButton = {
Button(onClick = { if (value.isNotBlank()) { confirm(value.toInt()) } }) { Button(onClick = {
if (value.isNotBlank()) { confirm(value.toInt()) } else dismiss()
}) {
Text(text = LocalContext.current.getString(R.string.confirm)) Text(text = LocalContext.current.getString(R.string.confirm))
} }
} }

View file

@ -63,4 +63,18 @@ class ModifySetViewModel(application: Application) : AndroidViewModel(applicatio
dao.deleteQuestion(selection.value!!) dao.deleteQuestion(selection.value!!)
} }
} }
fun modifAction() {
action.value = ActionModifySet.MODIFICATION
}
fun ajoutAction() {
action.value = ActionModifySet.AJOUT
}
fun supprAction() {
action.value = ActionModifySet.SUPPRIMER
}
fun dismissAction() {
action.value = ActionModifySet.AUCUN
}
} }

View file

@ -29,7 +29,7 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) {
private val statsKeyTotalBad = intPreferencesKey(STATS_TOTAL_BAD) private val statsKeyTotalBad = intPreferencesKey(STATS_TOTAL_BAD)
private val delayKey= intPreferencesKey(DELAY) private val delayKey= intPreferencesKey(DELAY)
val delay = datastore.data.map { it[delayKey] ?: 3000 } val delay = datastore.data.map { it[delayKey] ?: 5000 }
var currentQuestion = mutableStateOf<Question?>(null) var currentQuestion = mutableStateOf<Question?>(null)
private var index = mutableStateOf(0) private var index = mutableStateOf(0)
@ -137,10 +137,20 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) {
} }
} }
fun updateTimer(delay: Int) {
if (!isDelayElapsed(delay) && currentQuestion.value != null) {
updateTime(System.currentTimeMillis())
}
}
fun isDelayElapsed(delay: Int) = currentTime.value - timestampQuestion.value >= delay fun isDelayElapsed(delay: Int) = currentTime.value - timestampQuestion.value >= delay
fun updateTime(time: Long) { fun updateTime(time: Long) {
currentTime.value = time currentTime.value = time
} }
fun giveUp() {
showAnswer.value = true
}
} }

View file

@ -53,10 +53,10 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
var prefConfigTime = datastore.data.map { TimeConfig(it[notifH] ?: 8, it[notifM] ?: 0) } var prefConfigTime = datastore.data.map { TimeConfig(it[notifH] ?: 8, it[notifM] ?: 0) }
val deletionDB = mutableStateOf(false) var deletionDB = mutableStateOf(false)
val deletionStat = mutableStateOf(false) var deletionStat = mutableStateOf(false)
var notif = mutableStateOf(false) var notif = mutableStateOf(false)
val delayRequest = mutableStateOf(false) var delayRequest = mutableStateOf(false)
val gavePermissionNow = mutableStateOf(false) val gavePermissionNow = mutableStateOf(false)
@ -99,6 +99,14 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
} }
} }
fun resetDelay() {
viewModelScope.launch {
datastore.edit {
it[delay] = 5000
}
}
}
fun winrate(good: Int, bad: Int): Int { fun winrate(good: Int, bad: Int): Int {
val total = good + bad val total = good + bad
if (total == 0) { if (total == 0) {
@ -147,4 +155,17 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
.setInitialDelay(delta, TimeUnit.MILLISECONDS) .setInitialDelay(delta, TimeUnit.MILLISECONDS)
.build() .build()
} }
fun dismissDeletionDB() {
deletionDB.value = false
}
fun dismissDeletionStat() {
deletionStat.value = false
}
fun dismissNotif() {
notif.value = false
}
fun dismissDelayRequest() {
delayRequest.value = false
}
} }

View file

@ -63,6 +63,7 @@
<string name="confirm">Confirmer</string> <string name="confirm">Confirmer</string>
<string name="game">Parametre du jeu</string> <string name="game">Parametre du jeu</string>
<string name="choice_delay_button">Délai avant solution</string> <string name="choice_delay_button">Délai avant solution</string>
<string name="reset_button">Réinitialiser par défaut</string>
<string name="reset_game_settings_button">Réinitialiser les paramètres du jeu</string> <string name="reset_game_settings_button">Réinitialiser les paramètres du jeu</string>
<string name="choice_delay">Choix du délai avant solution</string> <string name="choice_delay">Choix du délai avant solution</string>
<string name="enter_integer">Entrez un entier (en ms)</string> <string name="enter_integer">Entrez un entier (en ms)</string>