From 7d38facda575738fe169e6316c7d26dfae2b8650 Mon Sep 17 00:00:00 2001 From: Adrian Kuta Date: Thu, 4 Sep 2025 17:59:36 +0200 Subject: [PATCH] fix: Correct timer behavior and display This commit addresses issues with the question timer in `QuizScreen`. Key changes: - **QuizScreenViewModel:** - Initialize `_remainingTimeSeconds` to `0` instead of `-1` to prevent premature timer display. - Start timer only if `timerJob` is `null` (not already running) and it's the first question. - Set `timerJob` to `null` when it's cancelled (on choice selection, moving to next question, or finishing the quiz). - If a question has no time limit (null or <= 0 seconds), set `_remainingTimeSeconds` to `0` and do not start the `timerJob`. - When the timer finishes and no choice was selected, set `_selectedChoiceIndex` to `-1` (indicating time ran out) and ensure `timerJob` is nullified. - **QuizScreen:** - Conditionally display the `TimerBar` only if `selectedChoiceIndex` is `null` (no choice made yet) AND `timerState.totalTimeSeconds` is greater than `0` (meaning there's a valid timer for the current question). This prevents showing a timer when a question has no time limit. --- .../adriankuta/kahootquiz/ui/quiz/QuizScreen.kt | 2 +- .../kahootquiz/ui/quiz/QuizScreenViewModel.kt | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) 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 a50fc29..3ff99b3 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 @@ -129,7 +129,7 @@ private fun QuizScreen( } // Timer below choices - if (uiState.selectedChoiceIndex == null) { + if (uiState.selectedChoiceIndex == null && uiState.timerState.totalTimeSeconds > 0) { item { TimerBar( totalSeconds = uiState.timerState.totalTimeSeconds, 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 f2aa823..4233ad4 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 @@ -12,10 +12,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject @@ -34,7 +31,7 @@ class QuizScreenViewModel @Inject constructor( initialValue = QuizUiState.Loading, ) private val _selectedChoiceIndex = MutableStateFlow(null) - private val _remainingTimeSeconds = MutableStateFlow(-1) + private val _remainingTimeSeconds = MutableStateFlow(0) private val _currentQuestionIndex = MutableStateFlow(0) private var timerJob: Job? = null @@ -44,7 +41,7 @@ class QuizScreenViewModel @Inject constructor( quiz.collect { quizState -> if (quizState is QuizUiState.Success) { // Start only if timer hasn't been started yet and we are on the first question - if (_remainingTimeSeconds.value == -1 && _currentQuestionIndex.value == 0) { + if (timerJob == null && _currentQuestionIndex.value == 0) { val firstQuestionTime = quizState.quiz.questions.getOrNull(0)?.time?.inWholeSeconds?.toInt() startCountdown(firstQuestionTime) } @@ -86,6 +83,7 @@ class QuizScreenViewModel @Inject constructor( fun onChoiceSelected(index: Int) { timerJob?.cancel() + timerJob = null _selectedChoiceIndex.value = index } @@ -103,13 +101,19 @@ class QuizScreenViewModel @Inject constructor( } else { // Last question reached: stop timer and keep state (could navigate to results in the future) timerJob?.cancel() + timerJob = null + _remainingTimeSeconds.value = 0 } } } private fun startCountdown(totalSeconds: Int?) { timerJob?.cancel() - if (totalSeconds == null || totalSeconds <= 0) return + if (totalSeconds == null || totalSeconds <= 0) { + _remainingTimeSeconds.value = 0 + timerJob = null + return + } _remainingTimeSeconds.value = totalSeconds timerJob = viewModelScope.launch { var remaining = totalSeconds @@ -122,6 +126,7 @@ class QuizScreenViewModel @Inject constructor( if (_selectedChoiceIndex.value == null) { _selectedChoiceIndex.value = -1 } + timerJob = null } } }