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)