From 99f1c497135cf25afafad5d6a985202565c0e596 Mon Sep 17 00:00:00 2001 From: Adrian Kuta Date: Thu, 4 Sep 2025 22:04:40 +0200 Subject: [PATCH] feat: Implement Answer Feedback Banner This commit introduces an `AnswerFeedbackBanner` composable that displays whether a selected answer is correct or wrong. It's integrated into the `Toolbar` section of the `QuizScreen`. Key changes: - **UI Layer (`ui:quiz` module):** - Created `AnswerFeedbackBanner.kt` composable: - Displays "Correct" or "Wrong" text with a green or red background respectively. - Uses `Surface` for elevation and `zIndex` to appear above other elements. - In `QuizScreen.kt`: - Modified the `toolbar` item to include a `Box` that layers the `Toolbar` and the new `AnswerFeedbackBanner`. - The `AnswerFeedbackBanner` is shown when `uiState.isAnswerCorrect` is not null. - In `QuizScreenViewModel.kt`: - Added `isAnswerCorrect: Boolean?` to `ScreenUiState.Success`. - Calculated `isAnswerCorrect` based on the selected choice and the correct answer for the current question. - **Resources (`ui:quiz` module):** - Added new string resources for "Correct" and "Wrong" in `strings.xml`. --- .../kahootquiz/ui/quiz/QuizScreen.kt | 27 +++++++++---- .../kahootquiz/ui/quiz/QuizScreenViewModel.kt | 5 +++ .../ui/quiz/components/CorrectnessBanner.kt | 40 +++++++++++++++++++ ui/quiz/src/main/res/values/strings.xml | 2 + 4 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/components/CorrectnessBanner.kt diff --git a/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreen.kt b/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreen.kt index 349f19d..81137b5 100644 --- a/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreen.kt +++ b/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreen.kt @@ -32,6 +32,7 @@ import dev.adriankuta.kahootquiz.core.designsystem.KahootQuizTheme import dev.adriankuta.kahootquiz.domain.models.Choice import dev.adriankuta.kahootquiz.domain.models.Question import dev.adriankuta.kahootquiz.ui.quiz.components.Choices +import dev.adriankuta.kahootquiz.ui.quiz.components.AnswerFeedbackBanner import dev.adriankuta.kahootquiz.ui.quiz.components.QuestionContent import dev.adriankuta.kahootquiz.ui.quiz.components.TimerBar import dev.adriankuta.kahootquiz.ui.quiz.components.Toolbar @@ -115,16 +116,26 @@ private fun QuizScreenSuccess( private fun LazyListScope.toolbar( uiState: ScreenUiState.Success, + modifier: Modifier = Modifier, ) { item(key = "toolbar") { - Toolbar( - modifier = Modifier - .fillMaxWidth() - .height(72.dp) - .padding(8.dp), - currentQuestionIndex = uiState.currentQuestionIndex, - totalQuestions = uiState.totalQuestions, - ) + Box( + modifier = modifier + .height(72.dp), + ) { + Toolbar( + modifier = Modifier + .fillMaxSize() + .padding(8.dp), + currentQuestionIndex = uiState.currentQuestionIndex, + totalQuestions = uiState.totalQuestions, + ) + uiState.isAnswerCorrect?.let { isCorrect -> + AnswerFeedbackBanner( + isCorrect = isCorrect, + ) + } + } } } diff --git a/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreenViewModel.kt b/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreenViewModel.kt index df4bb1b..9d21bc0 100644 --- a/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreenViewModel.kt +++ b/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/QuizScreenViewModel.kt @@ -61,6 +61,9 @@ class QuizScreenViewModel @Inject constructor( QuizUiState.Loading -> ScreenUiState.Loading is QuizUiState.Success -> { val currentQuestion = quizState.quiz.questions.getOrNull(currentQuestionIndex) + val isAnswerCorrect = selectedChoiceIndex?.let { idx -> + currentQuestion?.choices?.getOrNull(idx)?.correct == true + } ScreenUiState.Success( currentQuestion = currentQuestion, @@ -71,6 +74,7 @@ class QuizScreenViewModel @Inject constructor( remainingTimeSeconds = remainingTimeSeconds, totalTimeSeconds = currentQuestion?.time?.inWholeSeconds?.toInt() ?: 0, ), + isAnswerCorrect = isAnswerCorrect, ) } } @@ -148,6 +152,7 @@ sealed interface ScreenUiState { val currentQuestionIndex: Int = 0, val totalQuestions: Int = 0, val timerState: TimerState = TimerState(), + val isAnswerCorrect: Boolean? = null, ) : ScreenUiState } diff --git a/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/components/CorrectnessBanner.kt b/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/components/CorrectnessBanner.kt new file mode 100644 index 0000000..cb63a3f --- /dev/null +++ b/ui/quiz/src/main/kotlin/dev/adriankuta/kahootquiz/ui/quiz/components/CorrectnessBanner.kt @@ -0,0 +1,40 @@ +package dev.adriankuta.kahootquiz.ui.quiz.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import dev.adriankuta.kahootquiz.core.designsystem.Green +import dev.adriankuta.kahootquiz.core.designsystem.Red +import dev.adriankuta.kahootquiz.ui.quiz.R + +@Composable +fun AnswerFeedbackBanner( + isCorrect: Boolean, + modifier: Modifier = Modifier, +) { + Surface( + modifier = modifier + .fillMaxSize() + .zIndex(10f), + shadowElevation = 8.dp, + color = if (isCorrect) Green else Red, + contentColor = Color.White, + ) { + Box { + Text( + text = stringResource(if (isCorrect) R.string.correct else R.string.wrong), + textAlign = TextAlign.Center, + modifier = Modifier.align(Alignment.Center), + ) + } + } +} diff --git a/ui/quiz/src/main/res/values/strings.xml b/ui/quiz/src/main/res/values/strings.xml index 210bd13..44daf0f 100644 --- a/ui/quiz/src/main/res/values/strings.xml +++ b/ui/quiz/src/main/res/values/strings.xml @@ -2,4 +2,6 @@ Quiz Continue + Correct + Wrong \ No newline at end of file