mirror of
				https://github.com/AdrianKuta/KahootQuiz.git
				synced 2025-10-31 00:43:40 +01:00 
			
		
		
		
	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`.
			
			
This commit is contained in:
		| @@ -32,6 +32,7 @@ import dev.adriankuta.kahootquiz.core.designsystem.KahootQuizTheme | |||||||
| import dev.adriankuta.kahootquiz.domain.models.Choice | import dev.adriankuta.kahootquiz.domain.models.Choice | ||||||
| import dev.adriankuta.kahootquiz.domain.models.Question | import dev.adriankuta.kahootquiz.domain.models.Question | ||||||
| import dev.adriankuta.kahootquiz.ui.quiz.components.Choices | 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.QuestionContent | ||||||
| import dev.adriankuta.kahootquiz.ui.quiz.components.TimerBar | import dev.adriankuta.kahootquiz.ui.quiz.components.TimerBar | ||||||
| import dev.adriankuta.kahootquiz.ui.quiz.components.Toolbar | import dev.adriankuta.kahootquiz.ui.quiz.components.Toolbar | ||||||
| @@ -115,16 +116,26 @@ private fun QuizScreenSuccess( | |||||||
|  |  | ||||||
| private fun LazyListScope.toolbar( | private fun LazyListScope.toolbar( | ||||||
|     uiState: ScreenUiState.Success, |     uiState: ScreenUiState.Success, | ||||||
|  |     modifier: Modifier = Modifier, | ||||||
| ) { | ) { | ||||||
|     item(key = "toolbar") { |     item(key = "toolbar") { | ||||||
|  |         Box( | ||||||
|  |             modifier = modifier | ||||||
|  |                 .height(72.dp), | ||||||
|  |         ) { | ||||||
|             Toolbar( |             Toolbar( | ||||||
|                 modifier = Modifier |                 modifier = Modifier | ||||||
|                 .fillMaxWidth() |                     .fillMaxSize() | ||||||
|                 .height(72.dp) |  | ||||||
|                     .padding(8.dp), |                     .padding(8.dp), | ||||||
|                 currentQuestionIndex = uiState.currentQuestionIndex, |                 currentQuestionIndex = uiState.currentQuestionIndex, | ||||||
|                 totalQuestions = uiState.totalQuestions, |                 totalQuestions = uiState.totalQuestions, | ||||||
|             ) |             ) | ||||||
|  |             uiState.isAnswerCorrect?.let { isCorrect -> | ||||||
|  |                 AnswerFeedbackBanner( | ||||||
|  |                     isCorrect = isCorrect, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -61,6 +61,9 @@ class QuizScreenViewModel @Inject constructor( | |||||||
|             QuizUiState.Loading -> ScreenUiState.Loading |             QuizUiState.Loading -> ScreenUiState.Loading | ||||||
|             is QuizUiState.Success -> { |             is QuizUiState.Success -> { | ||||||
|                 val currentQuestion = quizState.quiz.questions.getOrNull(currentQuestionIndex) |                 val currentQuestion = quizState.quiz.questions.getOrNull(currentQuestionIndex) | ||||||
|  |                 val isAnswerCorrect = selectedChoiceIndex?.let { idx -> | ||||||
|  |                     currentQuestion?.choices?.getOrNull(idx)?.correct == true | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 ScreenUiState.Success( |                 ScreenUiState.Success( | ||||||
|                     currentQuestion = currentQuestion, |                     currentQuestion = currentQuestion, | ||||||
| @@ -71,6 +74,7 @@ class QuizScreenViewModel @Inject constructor( | |||||||
|                         remainingTimeSeconds = remainingTimeSeconds, |                         remainingTimeSeconds = remainingTimeSeconds, | ||||||
|                         totalTimeSeconds = currentQuestion?.time?.inWholeSeconds?.toInt() ?: 0, |                         totalTimeSeconds = currentQuestion?.time?.inWholeSeconds?.toInt() ?: 0, | ||||||
|                     ), |                     ), | ||||||
|  |                     isAnswerCorrect = isAnswerCorrect, | ||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -148,6 +152,7 @@ sealed interface ScreenUiState { | |||||||
|         val currentQuestionIndex: Int = 0, |         val currentQuestionIndex: Int = 0, | ||||||
|         val totalQuestions: Int = 0, |         val totalQuestions: Int = 0, | ||||||
|         val timerState: TimerState = TimerState(), |         val timerState: TimerState = TimerState(), | ||||||
|  |         val isAnswerCorrect: Boolean? = null, | ||||||
|     ) : ScreenUiState |     ) : ScreenUiState | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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), | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -2,4 +2,6 @@ | |||||||
| <resources> | <resources> | ||||||
|     <string name="quiz">Quiz</string> |     <string name="quiz">Quiz</string> | ||||||
|     <string name="continue_text">Continue</string> |     <string name="continue_text">Continue</string> | ||||||
|  |     <string name="correct">Correct</string> | ||||||
|  |     <string name="wrong">Wrong</string> | ||||||
| </resources> | </resources> | ||||||
		Reference in New Issue
	
	Block a user