parametrage delai réponse

This commit is contained in:
ImAliant 2024-01-06 17:25:08 +01:00
parent cb9a063e68
commit 920bd24742
6 changed files with 179 additions and 65 deletions

View file

@ -24,5 +24,7 @@ const val STATS_TOTAL_GOOD = "total_good"
/** DataStore clef lié au nombre de questions mal répondu */
const val STATS_TOTAL_BAD = "total_bad"
const val DELAY = "delay"
const val HOUR = "hour"
const val MINUTE = "minute"

View file

@ -16,6 +16,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
@ -48,6 +49,7 @@ fun PlayScreen(
val correction by model.evaluatedAnswer
var giveup by model.showAnswer
val gameEnded by model.end
val delay by model.delay.collectAsState(initial = 3000)
val cpt by model.compteurSb
if (correction != null) {
@ -72,7 +74,7 @@ fun PlayScreen(
}
// Update timer if needed
if (!model.isDelayElapsed() && question != null) {
if (!model.isDelayElapsed(delay) && question != null) {
model.updateTime(System.currentTimeMillis())
}
@ -109,7 +111,7 @@ fun PlayScreen(
}
Button(
enabled = model.isDelayElapsed(),
enabled = model.isDelayElapsed(delay),
onClick = { giveup = true }) {
Text(text = context.getString(R.string.see_answer))
}

View file

@ -1,7 +1,9 @@
package fr.uparis.diamantkennel.memorisationapplication
import android.content.Context
import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.Arrangement
@ -13,12 +15,14 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TimePicker
import androidx.compose.material3.TimePickerLayoutType
@ -27,12 +31,15 @@ import androidx.compose.material3.rememberTimePickerState
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.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@ -51,15 +58,17 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel(
var deletionDBRequest by model.deletionDB
var cleanStatRequest by model.deletionStat
var choiceTimeNotifRequest by model.notif
var choiceDelayRequest by model.delayRequest
var permissionNotif by model.gavePermissionNow
val prefConfig = runBlocking { model.prefConfig.first() }
val prefConfigTime = runBlocking { model.prefConfigTime.first() }
val state = rememberTimePickerState(
initialHour = prefConfig.hour,
initialMinute = prefConfig.minute,
val stateTime = rememberTimePickerState(
initialHour = prefConfigTime.hour,
initialMinute = prefConfigTime.minute,
is24Hour = true
)
model.checkPermission(context)
val permissionLauncher = rememberLauncherForActivityResult(
@ -80,9 +89,16 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel(
if (choiceTimeNotifRequest) {
ChoiceTimeNotifDialog(
{ model.choiceTimeNotif(state, context) },
{ model.choiceTimeNotif(stateTime, context) },
{ choiceTimeNotifRequest = false },
state
stateTime
)
}
if (choiceDelayRequest) {
ChoiceDelayDialog(
{ model.choiceDelay(it) },
{ choiceDelayRequest = false },
)
}
@ -92,54 +108,89 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel(
) {
Stats(model)
Spacer(modifier = Modifier.padding(top = 10.dp))
Divider(color = Color.Gray)
Spacer(modifier = Modifier.padding(top = 10.dp))
AddSpacedDivider()
Text(text = context.getString(R.string.notification), fontSize = 30.sp)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Button(
enabled = !permissionNotif,
onClick = {
model.requestNotificationPermission(permissionLauncher)
}
) {
Text(text = context.getString(R.string.permission_button))
}
Button(
enabled = permissionNotif,
onClick = {
choiceTimeNotifRequest = true
}
) {
Text(text = context.getString(R.string.time_notif_button))
}
NotificationSettings(context, model, permissionNotif, permissionLauncher) {
choiceTimeNotifRequest = true
}
Spacer(modifier = Modifier.padding(top = 10.dp))
Divider(color = Color.Gray)
Spacer(modifier = Modifier.padding(top = 10.dp))
AddSpacedDivider()
Text(text = context.getString(R.string.gestion), fontSize = 30.sp)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Button(
onClick = { deletionDBRequest = true },
colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.red))
) {
Text(text = context.getString(R.string.main_button_deletebase))
GestionSettings(context, { deletionDBRequest = true }, { cleanStatRequest = true })
AddSpacedDivider()
GameSettings(context) { choiceDelayRequest = true }
}
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun NotificationSettings(
context: Context,
model: SettingsViewModel,
permissionNotif: Boolean,
permissionLauncher: ActivityResultLauncher<String>,
onTimeNotifButtonClick: () -> Unit,
) {
Text(text = context.getString(R.string.notification), fontSize = 30.sp)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Button(
enabled = !permissionNotif,
onClick = {
model.requestNotificationPermission(permissionLauncher)
}
) {
Text(text = context.getString(R.string.permission_button))
}
Button(
enabled = permissionNotif,
onClick = onTimeNotifButtonClick
) {
Text(text = context.getString(R.string.time_notif_button))
}
}
}
Button(
onClick = { cleanStatRequest = true },
colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.red))
) {
Text(text = context.getString(R.string.clean_stat_button))
@Composable
fun GestionSettings(context: Context, deletionDBRequest: () -> Unit, cleanStatRequest: () -> Unit) {
Text(text = context.getString(R.string.gestion), fontSize = 30.sp)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Button(
onClick = deletionDBRequest,
colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.red))
) {
Text(text = context.getString(R.string.main_button_deletebase))
}
Button(
onClick = cleanStatRequest,
colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.red))
) {
Text(text = context.getString(R.string.clean_stat_button))
}
}
}
@Composable
fun GameSettings(context: Context, onDelayButtonClick: () -> Unit) {
Text(text = context.getString(R.string.game), fontSize = 30.sp)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Column (
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
){
Button(onClick = onDelayButtonClick) {
Text(text = context.getString(R.string.choice_delay_button))
}
}
}
@ -223,3 +274,38 @@ fun ChoiceTimeNotifDialog(confirm: () -> Unit, dismiss: () -> Unit, state: TimeP
}
}
}
@Composable
fun ChoiceDelayDialog(confirm: (Int) -> Unit, dismiss: () -> Unit) {
var value by remember { mutableStateOf("") }
AlertDialog(onDismissRequest = dismiss,
title = { Text(text = LocalContext.current.getString(R.string.choice_delay)) },
text = {
OutlinedTextField(
value = value,
onValueChange = {
value = if (it.toIntOrNull() != null) { it } else ""
},
label = { Text(text = LocalContext.current.getString(R.string.enter_integer)) },
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number
),
singleLine = true
)
},
confirmButton = {
Button(onClick = { if (value.isNotBlank()) { confirm(value.toInt()) } }) {
Text(text = LocalContext.current.getString(R.string.confirm))
}
}
)
}
@Composable
fun AddSpacedDivider() {
Spacer(modifier = Modifier.padding(top = 20.dp))
Divider(color = Color.Gray)
Spacer(modifier = Modifier.padding(top = 20.dp))
}

View file

@ -11,21 +11,26 @@ import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_BAD
import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_DONE
import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_GOOD
import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_TRIED
import fr.uparis.diamantkennel.memorisationapplication.DELAY
import fr.uparis.diamantkennel.memorisationapplication.data.Question
import fr.uparis.diamantkennel.memorisationapplication.dataStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
class PlayViewModel(application: Application) : AndroidViewModel(application) {
private val dao = (application as MemoApplication).database.memoDao()
private var questions = mutableStateOf<List<Question>>(listOf())
private val stats = application.dataStore
private val datastore = application.dataStore
private val statsKeyTotal = intPreferencesKey(STATS_TOTAL_TRIED)
private val statsKeyTotalDone = intPreferencesKey(STATS_TOTAL_DONE)
private val statsKeyTotalGood = intPreferencesKey(STATS_TOTAL_GOOD)
private val statsKeyTotalBad = intPreferencesKey(STATS_TOTAL_BAD)
private val delayKey= intPreferencesKey(DELAY)
val delay = datastore.data.map { it[delayKey] ?: 3000 }
var currentQuestion = mutableStateOf<Question?>(null)
private var index = mutableStateOf(0)
var proposedAnswer = mutableStateOf("")
@ -42,7 +47,7 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) {
dao.loadQuestions(setId).collect { questionList ->
questions.value = questionList.shuffled()
if (questions.value.isNotEmpty()) {
stats.edit { it[statsKeyTotal] = (it[statsKeyTotal] ?: 0) + 1 }
datastore.edit { it[statsKeyTotal] = (it[statsKeyTotal] ?: 0) + 1 }
}
updateQuestion()
}
@ -58,7 +63,7 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) {
/* Fin des questions */
end.value = true
viewModelScope.launch {
stats.edit {
datastore.edit {
it[statsKeyTotalDone] = (it[statsKeyTotalDone] ?: 0) + 1
}
}
@ -114,7 +119,7 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) {
when (evaluatedAnswer.value!!) {
AnswerType.GOOD -> {
viewModelScope.launch {
stats.edit {
datastore.edit {
it[statsKeyTotalGood] = (it[statsKeyTotalGood] ?: 0) + 1
}
}
@ -123,7 +128,7 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) {
AnswerType.BAD -> {
viewModelScope.launch {
stats.edit {
datastore.edit {
it[statsKeyTotalBad] = (it[statsKeyTotalBad] ?: 0) + 1
}
}
@ -132,10 +137,10 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) {
}
}
fun isDelayElapsed() = currentTime.value - timestampQuestion.value >= 3000
fun isDelayElapsed(delay: Int) = currentTime.value - timestampQuestion.value >= delay
fun updateTime(time: Long) {
currentTime.value = time
}
}
}

View file

@ -17,6 +17,7 @@ import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import fr.uparis.diamantkennel.memorisationapplication.HOUR
import fr.uparis.diamantkennel.memorisationapplication.MINUTE
import fr.uparis.diamantkennel.memorisationapplication.DELAY
import fr.uparis.diamantkennel.memorisationapplication.MemoApplication
import fr.uparis.diamantkennel.memorisationapplication.RappelWorker
import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_BAD
@ -34,7 +35,7 @@ import java.util.concurrent.TimeUnit
class SettingsViewModel(application: Application) : AndroidViewModel(application) {
private val dao = (application as MemoApplication).database.memoDao()
private val stats = application.dataStore
private val datastore = application.dataStore
private val statsKeyTotal = intPreferencesKey(STATS_TOTAL_TRIED)
private val statsKeyTotalDone = intPreferencesKey(STATS_TOTAL_DONE)
private val statsKeyTotalGood = intPreferencesKey(STATS_TOTAL_GOOD)
@ -43,16 +44,19 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
private val notifH = intPreferencesKey(HOUR)
private val notifM = intPreferencesKey(MINUTE)
val statTotal = stats.data.map { it[statsKeyTotal] ?: 0 }
val statTotalDone = stats.data.map { it[statsKeyTotalDone] ?: 0 }
val statTotalGood = stats.data.map { it[statsKeyTotalGood] ?: 0 }
val statTotalBad = stats.data.map { it[statsKeyTotalBad] ?: 0 }
private val delay = intPreferencesKey(DELAY)
var prefConfig = stats.data.map { TimeConfig(it[notifH] ?: 8, it[notifM] ?: 0) }
val statTotal = datastore.data.map { it[statsKeyTotal] ?: 0 }
val statTotalDone = datastore.data.map { it[statsKeyTotalDone] ?: 0 }
val statTotalGood = datastore.data.map { it[statsKeyTotalGood] ?: 0 }
val statTotalBad = datastore.data.map { it[statsKeyTotalBad] ?: 0 }
var prefConfigTime = datastore.data.map { TimeConfig(it[notifH] ?: 8, it[notifM] ?: 0) }
val deletionDB = mutableStateOf(false)
val deletionStat = mutableStateOf(false)
var notif = mutableStateOf(false)
val delayRequest = mutableStateOf(false)
val gavePermissionNow = mutableStateOf(false)
@ -66,7 +70,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
fun cleanStats() {
deletionStat.value = false
viewModelScope.launch {
stats.edit {
datastore.edit {
it[statsKeyTotal] = 0
it[statsKeyTotalDone] = 0
it[statsKeyTotalGood] = 0
@ -86,6 +90,15 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
schedule(newConfig, context)
}
fun choiceDelay(value: Int) {
delayRequest.value = false
viewModelScope.launch {
datastore.edit {
it[delay] = value
}
}
}
fun winrate(good: Int, bad: Int): Int {
val total = good + bad
if (total == 0) {
@ -107,7 +120,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
private fun save(config: TimeConfig) {
viewModelScope.launch {
stats.edit {
datastore.edit {
it[notifH] = config.hour
it[notifM] = config.minute
}

View file

@ -39,6 +39,7 @@
<string name="delete_db_desc">Voulez-vous supprimer la base de données ?</string>
<string name="yes">Oui</string>
<string name="no">Non</string>
<string name="validate">Valider</string>
<string name="bravo">Bravo</string>
<string name="set_ended">Le set de questions est terminé !</string>
<string name="stats">Statistiques</string>
@ -60,4 +61,9 @@
<string name="gestion">Gestion</string>
<string name="notification">Notifications</string>
<string name="confirm">Confirmer</string>
<string name="game">Parametre du jeu</string>
<string name="choice_delay_button">Délai avant solution</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="enter_integer">Entrez un entier (en ms)</string>
</resources>