From 77ad522ce20631e6da6c52a5a4fbb692e3bc24ab Mon Sep 17 00:00:00 2001 From: ImAliant <111398111+ImAliant@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:39:22 +0100 Subject: [PATCH 1/5] la notification fonctionne correctement --- app/build.gradle.kts | 6 +- .../memorisationapplication/DataStore.kt | 4 ++ .../MemoApplication.kt | 30 ---------- .../memorisationapplication/SettingsScreen.kt | 40 +++++++++++++ .../memorisationapplication/TimeConfig.kt | 7 +++ .../ui/SettingsViewModel.kt | 56 +++++++++++++++++++ 6 files changed, 110 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a7cdee8..c42a35f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -51,14 +51,14 @@ android { } dependencies { - implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") - implementation("androidx.activity:activity-compose:1.8.0") + implementation("androidx.activity:activity-compose:1.8.1") implementation(platform("androidx.compose:compose-bom:2023.03.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") - implementation("androidx.compose.material3:material3") + implementation("androidx.compose.material3:material3:1.1.2") implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.work:work-runtime-ktx:2.8.1") diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt index 22d3187..a078787 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt @@ -23,3 +23,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 ENABLED = "enabled" +const val HOUR = "hour" +const val MINUTE = "minute" diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt index 0ad4780..57b6e80 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt @@ -4,13 +4,8 @@ import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context -import android.content.pm.PackageManager import android.os.Build -import androidx.work.PeriodicWorkRequest -import androidx.work.WorkManager import fr.uparis.diamantkennel.memorisationapplication.data.QuestionsDB -import java.util.Calendar -import java.util.concurrent.TimeUnit const val CHANNEL_ID = "MY_CHANNEL_ID" @@ -20,10 +15,6 @@ class MemoApplication : Application() { override fun onCreate() { super.onCreate() createChannel(this) - - if (this.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { - schedule() - } } private fun createChannel(c: Context) { @@ -39,25 +30,4 @@ class MemoApplication : Application() { notificationManager.createNotificationChannel(channel) } } - - private fun schedule() { - val wm = WorkManager.getInstance(this) - wm.cancelAllWork() - wm.enqueue(request(10, 45)) - } - - private fun request(h: Int, m: Int): PeriodicWorkRequest { - val now = Calendar.getInstance() - val target = Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, h) - set(Calendar.MINUTE, m) - } - if (target.before(now)) - target.add(Calendar.DAY_OF_YEAR, 1) - val delta = target.timeInMillis - now.timeInMillis - - return PeriodicWorkRequest.Builder(RappelWorker::class.java, 1, TimeUnit.DAYS) - .setInitialDelay(delta, TimeUnit.MILLISECONDS) - .build() - } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt index 9ed1951..8336144 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt @@ -1,6 +1,7 @@ package fr.uparis.diamantkennel.memorisationapplication import android.os.Build +import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi @@ -15,10 +16,17 @@ import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.TimeInput +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 @@ -29,8 +37,11 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import fr.uparis.diamantkennel.memorisationapplication.ui.SettingsViewModel +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking @RequiresApi(Build.VERSION_CODES.TIRAMISU) +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel()) { val context = LocalContext.current @@ -38,6 +49,16 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( var deletionDBRequest by model.deletionDB var cleanStatRequest by model.deletionStat var permissionNotif by model.gavePermissionNow + + val prefConfig = runBlocking { model.prefConfig.first() } + + val state = rememberTimePickerState( + initialHour = prefConfig.hour, + initialMinute = prefConfig.minute, + is24Hour = true + ) + var enabled by remember { mutableStateOf(prefConfig.enabled) } + model.checkPermission(context) val permissionLauncher = rememberLauncherForActivityResult( @@ -94,6 +115,25 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( ) { Text(text = context.getString(R.string.permission_button)) } + + Column { + Row { + TimeInput(state = state) + Switch(enabled, { enabled = it }) + } + FloatingActionButton(onClick = { + val newConfig = TimeConfig( + enabled, + state.hour, + state.minute + ) + Log.d("Periodic", "config=$newConfig") + model.save(newConfig) + model.schedule(newConfig, context) + }) { + Text("On y va!") + } + } } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt new file mode 100644 index 0000000..837ce13 --- /dev/null +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt @@ -0,0 +1,7 @@ +package fr.uparis.diamantkennel.memorisationapplication + +data class TimeConfig( + val enabled: Boolean = false, + val hour: Int = 8, + val minute: Int = 0 +) diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt index a80e26b..8a5100b 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt @@ -4,22 +4,33 @@ import android.app.Application import android.content.Context import android.content.pm.PackageManager import android.os.Build +import android.util.Log import androidx.activity.result.ActivityResultLauncher import androidx.annotation.RequiresApi import androidx.compose.runtime.mutableStateOf +import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope +import androidx.work.PeriodicWorkRequest +import androidx.work.WorkManager +import fr.uparis.diamantkennel.memorisationapplication.ENABLED +import fr.uparis.diamantkennel.memorisationapplication.HOUR +import fr.uparis.diamantkennel.memorisationapplication.MINUTE import fr.uparis.diamantkennel.memorisationapplication.MemoApplication +import fr.uparis.diamantkennel.memorisationapplication.RappelWorker 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.TimeConfig import fr.uparis.diamantkennel.memorisationapplication.dataStore import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import java.util.Calendar +import java.util.concurrent.TimeUnit class SettingsViewModel(application: Application) : AndroidViewModel(application) { private val dao = (application as MemoApplication).database.memoDao() @@ -30,6 +41,10 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application private val statsKeyTotalGood = intPreferencesKey(STATS_TOTAL_GOOD) private val statsKeyTotalBad = intPreferencesKey(STATS_TOTAL_BAD) + private val KEY_E = booleanPreferencesKey(ENABLED) + private val KEY_H = intPreferencesKey(HOUR) + private val KEY_M = 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 } @@ -77,4 +92,45 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application gavePermissionNow.value = context.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED } + + fun save(config: TimeConfig) { + viewModelScope.launch { + stats.edit { + it[KEY_E] = config.enabled + it[KEY_H] = config.hour + it[KEY_M] = config.minute + } + } + } + + val prefConfig = stats.data.map { + TimeConfig( + it[KEY_E] ?: false, + it[KEY_H] ?: 8, + it[KEY_M] ?: 0 + ) + } + + fun schedule(config: TimeConfig, context: Context) { + val wm = WorkManager.getInstance(context) + wm.cancelAllWork() + if (config.enabled) + wm.enqueue(request(config.hour, config.minute)) + } + + private fun request(h: Int, m: Int): PeriodicWorkRequest { + val now = Calendar.getInstance() + val target = Calendar.getInstance().apply { + set(Calendar.HOUR_OF_DAY, h) + set(Calendar.MINUTE, m) + } + if (target.before(now)) + target.add(Calendar.DAY_OF_YEAR, 1) + val delta = target.timeInMillis - now.timeInMillis + val request = PeriodicWorkRequest.Builder(RappelWorker::class.java, 1, TimeUnit.DAYS) + .setInitialDelay(delta, TimeUnit.MILLISECONDS) + .build() + Log.d("Periodic", "request: $request") + return request + } } From 7ca1044a96c2e14ac2b4b0c0c2910b86bb5c4a36 Mon Sep 17 00:00:00 2001 From: ImAliant <111398111+ImAliant@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:12:58 +0100 Subject: [PATCH 2/5] choix rappel dans un dialog --- .../memorisationapplication/DataStore.kt | 1 - .../memorisationapplication/SettingsScreen.kt | 109 +++++++++++++----- .../memorisationapplication/TimeConfig.kt | 1 - .../ui/SettingsViewModel.kt | 37 +++--- app/src/main/res/values/strings.xml | 5 +- 5 files changed, 105 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt index a078787..2076663 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt @@ -24,6 +24,5 @@ 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 ENABLED = "enabled" const val HOUR = "hour" const val MINUTE = "minute" diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt index 8336144..a5022ad 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt @@ -1,7 +1,6 @@ package fr.uparis.diamantkennel.memorisationapplication import android.os.Build -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi @@ -11,22 +10,23 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.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.FloatingActionButton -import androidx.compose.material3.Switch import androidx.compose.material3.Text -import androidx.compose.material3.TimeInput +import androidx.compose.material3.TimePicker +import androidx.compose.material3.TimePickerLayoutType +import androidx.compose.material3.TimePickerState 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 @@ -35,6 +35,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog import androidx.lifecycle.viewmodel.compose.viewModel import fr.uparis.diamantkennel.memorisationapplication.ui.SettingsViewModel import kotlinx.coroutines.flow.first @@ -48,6 +49,7 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( var deletionDBRequest by model.deletionDB var cleanStatRequest by model.deletionStat + var choiceTimeNotifRequest by model.notif var permissionNotif by model.gavePermissionNow val prefConfig = runBlocking { model.prefConfig.first() } @@ -57,8 +59,6 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( initialMinute = prefConfig.minute, is24Hour = true ) - var enabled by remember { mutableStateOf(prefConfig.enabled) } - model.checkPermission(context) val permissionLauncher = rememberLauncherForActivityResult( @@ -77,6 +77,15 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( CleanStatDialog(model::cleanStats) { cleanStatRequest = false } } + if (choiceTimeNotifRequest) + { + ChoiceTimeNotifDialog( + { (model::choiceTimeNotif)(state, context) }, + { choiceTimeNotifRequest = false }, + state + ) + } + Column( modifier = Modifier.padding(padding), horizontalAlignment = Alignment.CenterHorizontally @@ -107,31 +116,31 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( } } - Button( - enabled = !permissionNotif, - onClick = { - model.requestNotificationPermission(permissionLauncher) - } - ) { - Text(text = context.getString(R.string.permission_button)) - } + Spacer(modifier = Modifier.padding(top = 10.dp)) + Divider(color = Color.Gray) + Spacer(modifier = Modifier.padding(top = 10.dp)) - Column { - Row { - TimeInput(state = state) - Switch(enabled, { enabled = it }) + Text(text = "Notifications", fontSize = 30.sp) + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.SpaceEvenly + ) { + Button( + enabled = !permissionNotif, + onClick = { + model.requestNotificationPermission(permissionLauncher) + } + ) { + Text(text = context.getString(R.string.permission_button)) } - FloatingActionButton(onClick = { - val newConfig = TimeConfig( - enabled, - state.hour, - state.minute - ) - Log.d("Periodic", "config=$newConfig") - model.save(newConfig) - model.schedule(newConfig, context) - }) { - Text("On y va!") + Button( + enabled = permissionNotif, + onClick = { + choiceTimeNotifRequest = true + } + ) { + Text(text = context.getString(R.string.time_notif_button)) } } } @@ -184,3 +193,41 @@ fun CleanStatDialog(confirm: () -> Unit, dismiss: () -> Unit) = Button(onClick = confirm) { Text(text = LocalContext.current.getString(R.string.yes)) } }, dismissButton = { Button(onClick = dismiss) { Text(text = LocalContext.current.getString(R.string.no)) } }) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChoiceTimeNotifDialog(confirm: () -> Unit, dismiss: () -> Unit, state: TimePickerState) { + Dialog(onDismissRequest = { dismiss() }) { + Card( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + .height(550.dp), + shape = RoundedCornerShape(16.dp), + ) { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = LocalContext.current.getString(R.string.time_notif), fontSize = 30.sp) + Text(text = LocalContext.current.getString(R.string.time_notif_desc)) + + Spacer(modifier = Modifier.padding(top = 10.dp)) + TimePicker(state = state, layoutType = TimePickerLayoutType.Vertical) + Spacer(modifier = Modifier.padding(top = 10.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Button(onClick = dismiss) { + Text(text = LocalContext.current.getString(R.string.no)) + } + Button(onClick = confirm) { + Text(text = LocalContext.current.getString(R.string.yes)) + } + } + } + } + } +} diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt index 837ce13..eaf35c4 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt @@ -1,7 +1,6 @@ package fr.uparis.diamantkennel.memorisationapplication data class TimeConfig( - val enabled: Boolean = false, val hour: Int = 8, val minute: Int = 0 ) diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt index 8a5100b..d0f4413 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt @@ -7,15 +7,15 @@ import android.os.Build import android.util.Log import androidx.activity.result.ActivityResultLauncher import androidx.annotation.RequiresApi +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TimePickerState import androidx.compose.runtime.mutableStateOf -import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import androidx.work.PeriodicWorkRequest import androidx.work.WorkManager -import fr.uparis.diamantkennel.memorisationapplication.ENABLED import fr.uparis.diamantkennel.memorisationapplication.HOUR import fr.uparis.diamantkennel.memorisationapplication.MINUTE import fr.uparis.diamantkennel.memorisationapplication.MemoApplication @@ -41,9 +41,8 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application private val statsKeyTotalGood = intPreferencesKey(STATS_TOTAL_GOOD) private val statsKeyTotalBad = intPreferencesKey(STATS_TOTAL_BAD) - private val KEY_E = booleanPreferencesKey(ENABLED) - private val KEY_H = intPreferencesKey(HOUR) - private val KEY_M = intPreferencesKey(MINUTE) + 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 } @@ -52,6 +51,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application val deletionDB = mutableStateOf(false) val deletionStat = mutableStateOf(false) + var notif = mutableStateOf(false) val gavePermissionNow = mutableStateOf(false) @@ -74,6 +74,18 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application } } + @OptIn(ExperimentalMaterial3Api::class) + fun choiceTimeNotif(state: TimePickerState, context: Context) { + notif.value = false + val newConfig = TimeConfig( + state.hour, + state.minute + ) + Log.d("Periodic", "config=$newConfig") + save(newConfig) + schedule(newConfig, context) + } + fun winrate(good: Int, bad: Int): Int { val total = good + bad if (total == 0) { @@ -96,26 +108,23 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application fun save(config: TimeConfig) { viewModelScope.launch { stats.edit { - it[KEY_E] = config.enabled - it[KEY_H] = config.hour - it[KEY_M] = config.minute + it[notifH] = config.hour + it[notifM] = config.minute } } } val prefConfig = stats.data.map { TimeConfig( - it[KEY_E] ?: false, - it[KEY_H] ?: 8, - it[KEY_M] ?: 0 + it[notifH] ?: 8, + it[notifM] ?: 0 ) } - fun schedule(config: TimeConfig, context: Context) { + private fun schedule(config: TimeConfig, context: Context) { val wm = WorkManager.getInstance(context) wm.cancelAllWork() - if (config.enabled) - wm.enqueue(request(config.hour, config.minute)) + wm.enqueue(request(config.hour, config.minute)) } private fun request(h: Int, m: Int): PeriodicWorkRequest { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ea7ff63..25f66b0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,7 +21,7 @@ Erreur Supprimer un jeu de question Voulez-vous supprimer ce jeu de question ? - Ok + OK Mettre à jour la question Ajouter une question Question @@ -55,4 +55,7 @@ Notifications de rappel Rappel Il est temps de réviser ! + Modifier heure de rappel + Choix heure de rappel + Choisissez l\'heure à laquelle vous souhaitez être notifié From cb9a063e68d0c3c96d7b206a684871ced5324e7e Mon Sep 17 00:00:00 2001 From: Mylloon Date: Fri, 5 Jan 2024 17:26:19 +0100 Subject: [PATCH 3/5] minor changes --- .../MemoApplication.kt | 2 +- .../memorisationapplication/SettingsScreen.kt | 80 +++++++++---------- .../ui/SettingsViewModel.kt | 18 ++--- app/src/main/res/values/strings.xml | 4 +- 4 files changed, 45 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt index 57b6e80..64c2b4e 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt @@ -7,7 +7,7 @@ import android.content.Context import android.os.Build import fr.uparis.diamantkennel.memorisationapplication.data.QuestionsDB -const val CHANNEL_ID = "MY_CHANNEL_ID" +const val CHANNEL_ID = "REMINDERS" class MemoApplication : Application() { val database: QuestionsDB by lazy { QuestionsDB.getDataBase(this) } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt index a5022ad..c206e6c 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt @@ -33,6 +33,7 @@ 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.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog @@ -77,10 +78,9 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( CleanStatDialog(model::cleanStats) { cleanStatRequest = false } } - if (choiceTimeNotifRequest) - { + if (choiceTimeNotifRequest) { ChoiceTimeNotifDialog( - { (model::choiceTimeNotif)(state, context) }, + { model.choiceTimeNotif(state, context) }, { choiceTimeNotifRequest = false }, state ) @@ -96,35 +96,10 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( Divider(color = Color.Gray) Spacer(modifier = Modifier.padding(top = 10.dp)) - Text(text = "Gestion", fontSize = 30.sp) + Text(text = context.getString(R.string.notification), 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)) - } - - Button( - onClick = { cleanStatRequest = true }, - colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.red)) - ) { - Text(text = context.getString(R.string.clean_stat_button)) - } - } - - Spacer(modifier = Modifier.padding(top = 10.dp)) - Divider(color = Color.Gray) - Spacer(modifier = Modifier.padding(top = 10.dp)) - - Text(text = "Notifications", fontSize = 30.sp) - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.SpaceEvenly ) { Button( enabled = !permissionNotif, @@ -143,6 +118,30 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( Text(text = context.getString(R.string.time_notif_button)) } } + + Spacer(modifier = Modifier.padding(top = 10.dp)) + Divider(color = Color.Gray) + Spacer(modifier = Modifier.padding(top = 10.dp)) + + 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)) + } + + Button( + onClick = { cleanStatRequest = true }, + colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.red)) + ) { + Text(text = context.getString(R.string.clean_stat_button)) + } + } } } @@ -197,7 +196,7 @@ fun CleanStatDialog(confirm: () -> Unit, dismiss: () -> Unit) = @OptIn(ExperimentalMaterial3Api::class) @Composable fun ChoiceTimeNotifDialog(confirm: () -> Unit, dismiss: () -> Unit, state: TimePickerState) { - Dialog(onDismissRequest = { dismiss() }) { + Dialog(onDismissRequest = dismiss) { Card( modifier = Modifier .padding(16.dp) @@ -209,23 +208,16 @@ fun ChoiceTimeNotifDialog(confirm: () -> Unit, dismiss: () -> Unit, state: TimeP modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Text(text = LocalContext.current.getString(R.string.time_notif), fontSize = 30.sp) - Text(text = LocalContext.current.getString(R.string.time_notif_desc)) + Text( + text = LocalContext.current.getString(R.string.time_notif), + fontSize = 30.sp, + textAlign = TextAlign.Center + ) - Spacer(modifier = Modifier.padding(top = 10.dp)) TimePicker(state = state, layoutType = TimePickerLayoutType.Vertical) - Spacer(modifier = Modifier.padding(top = 10.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly - ) { - Button(onClick = dismiss) { - Text(text = LocalContext.current.getString(R.string.no)) - } - Button(onClick = confirm) { - Text(text = LocalContext.current.getString(R.string.yes)) - } + Button(onClick = confirm) { + Text(text = LocalContext.current.getString(R.string.confirm)) } } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt index d0f4413..7aa6dfa 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt @@ -4,7 +4,6 @@ import android.app.Application import android.content.Context import android.content.pm.PackageManager import android.os.Build -import android.util.Log import androidx.activity.result.ActivityResultLauncher import androidx.annotation.RequiresApi import androidx.compose.material3.ExperimentalMaterial3Api @@ -49,6 +48,8 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application val statTotalGood = stats.data.map { it[statsKeyTotalGood] ?: 0 } val statTotalBad = stats.data.map { it[statsKeyTotalBad] ?: 0 } + var prefConfig = stats.data.map { TimeConfig(it[notifH] ?: 8, it[notifM] ?: 0) } + val deletionDB = mutableStateOf(false) val deletionStat = mutableStateOf(false) var notif = mutableStateOf(false) @@ -81,7 +82,6 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application state.hour, state.minute ) - Log.d("Periodic", "config=$newConfig") save(newConfig) schedule(newConfig, context) } @@ -105,7 +105,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application context.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED } - fun save(config: TimeConfig) { + private fun save(config: TimeConfig) { viewModelScope.launch { stats.edit { it[notifH] = config.hour @@ -114,13 +114,6 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application } } - val prefConfig = stats.data.map { - TimeConfig( - it[notifH] ?: 8, - it[notifM] ?: 0 - ) - } - private fun schedule(config: TimeConfig, context: Context) { val wm = WorkManager.getInstance(context) wm.cancelAllWork() @@ -136,10 +129,9 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application if (target.before(now)) target.add(Calendar.DAY_OF_YEAR, 1) val delta = target.timeInMillis - now.timeInMillis - val request = PeriodicWorkRequest.Builder(RappelWorker::class.java, 1, TimeUnit.DAYS) + + return PeriodicWorkRequest.Builder(RappelWorker::class.java, 1, TimeUnit.DAYS) .setInitialDelay(delta, TimeUnit.MILLISECONDS) .build() - Log.d("Periodic", "request: $request") - return request } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 25f66b0..e1b0908 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,5 +57,7 @@ Il est temps de réviser ! Modifier heure de rappel Choix heure de rappel - Choisissez l\'heure à laquelle vous souhaitez être notifié + Gestion + Notifications + Confirmer From 920bd24742f4498c9021beb0b5dffdd7f4a907ba Mon Sep 17 00:00:00 2001 From: ImAliant <111398111+ImAliant@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:25:08 +0100 Subject: [PATCH 4/5] =?UTF-8?q?parametrage=20delai=20r=C3=A9ponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../memorisationapplication/DataStore.kt | 2 + .../memorisationapplication/PlayScreen.kt | 6 +- .../memorisationapplication/SettingsScreen.kt | 182 +++++++++++++----- .../ui/PlayViewModel.kt | 19 +- .../ui/SettingsViewModel.kt | 29 ++- app/src/main/res/values/strings.xml | 6 + 6 files changed, 179 insertions(+), 65 deletions(-) diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt index 2076663..d040a39 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt @@ -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" diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt index 6c0589f..d170872 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt @@ -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)) } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt index c206e6c..f5159ae 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt @@ -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, + 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)) +} diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt index f9e6c5a..0d677b8 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt @@ -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>(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(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 } -} +} \ No newline at end of file diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt index 7aa6dfa..4a89afb 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt @@ -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 } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e1b0908..9688800 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -39,6 +39,7 @@ Voulez-vous supprimer la base de données ? Oui Non + Valider Bravo Le set de questions est terminé ! Statistiques @@ -60,4 +61,9 @@ Gestion Notifications Confirmer + Parametre du jeu + Délai avant solution + Réinitialiser les paramètres du jeu + Choix du délai avant solution + Entrez un entier (en ms) From 80310b28558892df949916d81f92fc0ffc485d70 Mon Sep 17 00:00:00 2001 From: ImAliant <111398111+ImAliant@users.noreply.github.com> Date: Sat, 6 Jan 2024 20:15:47 +0100 Subject: [PATCH 5/5] cleaner code --- .../memorisationapplication/HomeScreen.kt | 42 ++++---- .../memorisationapplication/MainActivity.kt | 20 +++- .../ModifySetScreen.kt | 38 +++++--- .../memorisationapplication/PlayScreen.kt | 90 +++++++++++------ .../memorisationapplication/SettingsScreen.kt | 96 +++++++++++-------- .../ui/ModifySetViewModel.kt | 14 +++ .../ui/PlayViewModel.kt | 12 ++- .../ui/SettingsViewModel.kt | 27 +++++- app/src/main/res/values/strings.xml | 1 + 9 files changed, 233 insertions(+), 107 deletions(-) diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/HomeScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/HomeScreen.kt index 44d8990..b7db3c8 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/HomeScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/HomeScreen.kt @@ -68,7 +68,7 @@ fun HomeScreen( val errorEntry by model.error - if (errorEntry != null) { + ShowDialog(errorEntry != null) { ErrorDialog( when (errorEntry!!) { ErrorsAjout.BAD_ENTRY -> context.getString(R.string.error_bad_entry) @@ -76,25 +76,30 @@ fun HomeScreen( }, model::cleanErrors ) } - - if (creationRequest) { - CreationDialog( - dismiss = model::dismissCreation, model = model - ) + ShowDialog(creationRequest) { CreationDialog(model::dismissCreation, model) } + ShowDialog(importationRequest) { ImportDialog(model::dismissImportation, model) } + ShowDialog(deletionRequest) { + DeletionDialog(model::dismissDeleteOne, model::deleteSelected) } - if (importationRequest) { - ImportDialog( - dismiss = model::dismissImportation, model = model - ) - } + Home( + padding, + navController, + model, + setOfQuestions, + currentSelection + ) +} - if (deletionRequest) { - DeletionDialog( - model::dismissDeleteOne, - model::deleteSelected - ) - } +@Composable +private fun Home( + padding: PaddingValues, + navController: NavController, + model: HomeViewModel, + setOfQuestions: List = listOf(), + currentSelection: SetQuestions? = null, +) { + val context = LocalContext.current Column( modifier = Modifier.padding(padding), horizontalAlignment = Alignment.CenterHorizontally @@ -146,7 +151,6 @@ private fun ActionRow(context: Context, model: HomeViewModel, navController: Nav } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun CreationDialog( dismiss: () -> Unit, model: HomeViewModel = viewModel() @@ -172,7 +176,7 @@ fun CreationDialog( }) } -@OptIn(ExperimentalMaterial3Api::class, DelicateCoroutinesApi::class) +@OptIn(DelicateCoroutinesApi::class) @Composable fun ImportDialog( dismiss: () -> Unit, model: HomeViewModel diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MainActivity.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MainActivity.kt index a4b928d..65c24ff 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MainActivity.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MainActivity.kt @@ -1,9 +1,11 @@ package fr.uparis.diamantkennel.memorisationapplication import android.content.Context +import android.os.Build import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.BottomNavigation @@ -39,6 +41,7 @@ import fr.uparis.diamantkennel.memorisationapplication.ui.theme.MemorisationAppl val Context.dataStore: DataStore by preferencesDataStore(name = STATS) class MainActivity : ComponentActivity() { + @RequiresApi(Build.VERSION_CODES.TIRAMISU) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { @@ -54,18 +57,20 @@ class MainActivity : ComponentActivity() { } } +@RequiresApi(Build.VERSION_CODES.TIRAMISU) @Composable fun MainScreenMainActivity() { MainScreen() } +@RequiresApi(Build.VERSION_CODES.TIRAMISU) @Preview(showBackground = true) @Composable fun MainScreenPreview() { MainScreen() } -@OptIn(ExperimentalMaterial3Api::class) +@RequiresApi(Build.VERSION_CODES.TIRAMISU) @Composable fun MainScreen() { 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 ShowDialog( + condition: Boolean, + dialog: @Composable () -> T +) { + if (condition) { + dialog() + } +} + diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ModifySetScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ModifySetScreen.kt index 518089f..a364795 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ModifySetScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ModifySetScreen.kt @@ -36,7 +36,6 @@ import fr.uparis.diamantkennel.memorisationapplication.ui.ActionModifySet import fr.uparis.diamantkennel.memorisationapplication.ui.ModifySetViewModel import kotlin.text.Typography.ellipsis - @Composable fun ModifySetScreen( padding: PaddingValues, @@ -47,20 +46,33 @@ fun ModifySetScreen( model.setId.value = idSet model.updateQuestionList(idSet) - val context = LocalContext.current val currentSelection by model.selection val questions by model.questions.collectAsState(listOf()) - var action by model.action + val action by model.action - if (action == ActionModifySet.AJOUT || action == ActionModifySet.MODIFICATION) { - AjoutModifDialog(action, currentSelection, model::ajoutQuestion) - { action = ActionModifySet.AUCUN } + ShowDialog(action == ActionModifySet.AJOUT || action == ActionModifySet.MODIFICATION) { + AjoutModifDialog(action, currentSelection, model::ajoutQuestion, model::dismissAction) + } + ShowDialog(action == ActionModifySet.SUPPRIMER) { + RemoveDialog(model::removeQuestion, model::dismissAction) } - if (action == ActionModifySet.SUPPRIMER) { - RemoveDialog(model::removeQuestion) - { action = ActionModifySet.AUCUN } - } + Modify( + padding = padding, + model = model, + questions = questions, + currentSelection = currentSelection + ) +} + +@Composable +fun Modify( + padding: PaddingValues, + model: ModifySetViewModel, + questions: List, + currentSelection: Question? +) { + val context = LocalContext.current Column( modifier = Modifier.padding(padding), @@ -71,13 +83,13 @@ fun ModifySetScreen( Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { Button( enabled = currentSelection != null, - onClick = { action = ActionModifySet.MODIFICATION }) { + onClick = model::modifAction) { Text(text = context.getString(R.string.modify)) } Spacer(modifier = Modifier.padding(2.dp)) - Button(onClick = { action = ActionModifySet.AJOUT }) { + Button(onClick = model::ajoutAction) { Text(text = context.getString(R.string.add)) } @@ -85,7 +97,7 @@ fun ModifySetScreen( Button( enabled = currentSelection != null, - onClick = { action = ActionModifySet.SUPPRIMER }) { + onClick = model::supprAction) { Text(text = context.getString(R.string.modify_button_delete)) } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt index d170872..67e3f1b 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/PlayScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState @@ -18,7 +17,6 @@ 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 import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -27,10 +25,10 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController +import fr.uparis.diamantkennel.memorisationapplication.data.Question import fr.uparis.diamantkennel.memorisationapplication.ui.AnswerType import fr.uparis.diamantkennel.memorisationapplication.ui.PlayViewModel -@OptIn(ExperimentalMaterial3Api::class) @Composable fun PlayScreen( padding: PaddingValues, @@ -42,41 +40,54 @@ fun PlayScreen( // First update the list of questions model.updateQuestionList(idSet) - val context = LocalContext.current - val question by model.currentQuestion val reponse by model.proposedAnswer val correction by model.evaluatedAnswer - var giveup by model.showAnswer + val giveup by model.showAnswer 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 - 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) { - EndDialog { navController.navigate(HOME) } - } + SnackbarAnswer( + model, + snackbarHostState, + cpt, + correction + ) - if (giveup && question != null) { + ShowDialog(gameEnded) { EndDialog { navController.navigate(HOME) } } + ShowDialog(giveup && question != null) { SolutionDialog(question!!.reponse, model::newQuestion) } // Update timer if needed - if (!model.isDelayElapsed(delay) && question != null) { - model.updateTime(System.currentTimeMillis()) - } + model.updateTimer(delay) + + 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( modifier = Modifier.padding(padding), @@ -87,7 +98,7 @@ fun PlayScreen( Text(context.getString(R.string.no_question), fontSize = 30.sp) } } 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)) @@ -112,7 +123,8 @@ fun PlayScreen( Button( enabled = model.isDelayElapsed(delay), - onClick = { giveup = true }) { + onClick = model::giveUp + ) { Text(text = context.getString(R.string.see_answer)) } } @@ -145,3 +157,25 @@ fun EndDialog(next: () -> Unit) = confirmButton = { 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() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt index f5159ae..5962d02 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt @@ -8,7 +8,6 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi 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.fillMaxWidth @@ -52,14 +51,13 @@ import kotlinx.coroutines.runBlocking @RequiresApi(Build.VERSION_CODES.TIRAMISU) @OptIn(ExperimentalMaterial3Api::class) @Composable -fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel()) { +fun SettingsScreen(model: SettingsViewModel = viewModel()) { val context = LocalContext.current 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 prefConfigTime = runBlocking { model.prefConfigTime.first() } @@ -71,6 +69,45 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( 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( 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( - modifier = Modifier.padding(padding), + modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Stats(model) - + Stats(model = model) AddSpacedDivider() - - NotificationSettings(context, model, permissionNotif, permissionLauncher) { - choiceTimeNotifRequest = true - } - + NotificationSettings(context, model, permissionNotif, permissionLauncher, onTimeNotifButtonClick) AddSpacedDivider() - - GestionSettings(context, { deletionDBRequest = true }, { cleanStatRequest = true }) - + GestionSettings(context, deletionDBRequest, cleanStatRequest) AddSpacedDivider() - - GameSettings(context) { choiceDelayRequest = true } + GameSettings(context, onDelayButtonClick, onResetButtonClick) } } @@ -179,7 +185,7 @@ fun GestionSettings(context: Context, deletionDBRequest: () -> Unit, cleanStatRe } @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) Row( modifier = Modifier.fillMaxWidth(), @@ -192,6 +198,12 @@ fun GameSettings(context: Context, onDelayButtonClick: () -> Unit) { Button(onClick = onDelayButtonClick) { 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 = { - 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)) } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/ModifySetViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/ModifySetViewModel.kt index e8638e7..c9a7c32 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/ModifySetViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/ModifySetViewModel.kt @@ -63,4 +63,18 @@ class ModifySetViewModel(application: Application) : AndroidViewModel(applicatio 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 + } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt index 0d677b8..5d2e71f 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/PlayViewModel.kt @@ -29,7 +29,7 @@ class PlayViewModel(application: Application) : AndroidViewModel(application) { private val statsKeyTotalBad = intPreferencesKey(STATS_TOTAL_BAD) private val delayKey= intPreferencesKey(DELAY) - val delay = datastore.data.map { it[delayKey] ?: 3000 } + val delay = datastore.data.map { it[delayKey] ?: 5000 } var currentQuestion = mutableStateOf(null) 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 updateTime(time: Long) { currentTime.value = time } + fun giveUp() { + showAnswer.value = true + } + } \ No newline at end of file diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt index 4a89afb..aa63325 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt @@ -53,10 +53,10 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application var prefConfigTime = datastore.data.map { TimeConfig(it[notifH] ?: 8, it[notifM] ?: 0) } - val deletionDB = mutableStateOf(false) - val deletionStat = mutableStateOf(false) + var deletionDB = mutableStateOf(false) + var deletionStat = mutableStateOf(false) var notif = mutableStateOf(false) - val delayRequest = mutableStateOf(false) + var delayRequest = 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 { val total = good + bad if (total == 0) { @@ -147,4 +155,17 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application .setInitialDelay(delta, TimeUnit.MILLISECONDS) .build() } + + fun dismissDeletionDB() { + deletionDB.value = false + } + fun dismissDeletionStat() { + deletionStat.value = false + } + fun dismissNotif() { + notif.value = false + } + fun dismissDelayRequest() { + delayRequest.value = false + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9688800..c9d8cc6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -63,6 +63,7 @@ Confirmer Parametre du jeu Délai avant solution + Réinitialiser par défaut Réinitialiser les paramètres du jeu Choix du délai avant solution Entrez un entier (en ms)