mirror of
https://github.com/AdrianKuta/KahootQuiz.git
synced 2025-09-14 17:24:21 +02:00
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.
This commit is contained in:
@@ -129,7 +129,7 @@ private fun QuizScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Timer below choices
|
// Timer below choices
|
||||||
if (uiState.selectedChoiceIndex == null) {
|
if (uiState.selectedChoiceIndex == null && uiState.timerState.totalTimeSeconds > 0) {
|
||||||
item {
|
item {
|
||||||
TimerBar(
|
TimerBar(
|
||||||
totalSeconds = uiState.timerState.totalTimeSeconds,
|
totalSeconds = uiState.timerState.totalTimeSeconds,
|
||||||
|
@@ -12,10 +12,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -34,7 +31,7 @@ class QuizScreenViewModel @Inject constructor(
|
|||||||
initialValue = QuizUiState.Loading,
|
initialValue = QuizUiState.Loading,
|
||||||
)
|
)
|
||||||
private val _selectedChoiceIndex = MutableStateFlow<Int?>(null)
|
private val _selectedChoiceIndex = MutableStateFlow<Int?>(null)
|
||||||
private val _remainingTimeSeconds = MutableStateFlow(-1)
|
private val _remainingTimeSeconds = MutableStateFlow(0)
|
||||||
private val _currentQuestionIndex = MutableStateFlow(0)
|
private val _currentQuestionIndex = MutableStateFlow(0)
|
||||||
private var timerJob: Job? = null
|
private var timerJob: Job? = null
|
||||||
|
|
||||||
@@ -44,7 +41,7 @@ class QuizScreenViewModel @Inject constructor(
|
|||||||
quiz.collect { quizState ->
|
quiz.collect { quizState ->
|
||||||
if (quizState is QuizUiState.Success) {
|
if (quizState is QuizUiState.Success) {
|
||||||
// Start only if timer hasn't been started yet and we are on the first question
|
// 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()
|
val firstQuestionTime = quizState.quiz.questions.getOrNull(0)?.time?.inWholeSeconds?.toInt()
|
||||||
startCountdown(firstQuestionTime)
|
startCountdown(firstQuestionTime)
|
||||||
}
|
}
|
||||||
@@ -86,6 +83,7 @@ class QuizScreenViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun onChoiceSelected(index: Int) {
|
fun onChoiceSelected(index: Int) {
|
||||||
timerJob?.cancel()
|
timerJob?.cancel()
|
||||||
|
timerJob = null
|
||||||
_selectedChoiceIndex.value = index
|
_selectedChoiceIndex.value = index
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,13 +101,19 @@ class QuizScreenViewModel @Inject constructor(
|
|||||||
} else {
|
} else {
|
||||||
// Last question reached: stop timer and keep state (could navigate to results in the future)
|
// Last question reached: stop timer and keep state (could navigate to results in the future)
|
||||||
timerJob?.cancel()
|
timerJob?.cancel()
|
||||||
|
timerJob = null
|
||||||
|
_remainingTimeSeconds.value = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startCountdown(totalSeconds: Int?) {
|
private fun startCountdown(totalSeconds: Int?) {
|
||||||
timerJob?.cancel()
|
timerJob?.cancel()
|
||||||
if (totalSeconds == null || totalSeconds <= 0) return
|
if (totalSeconds == null || totalSeconds <= 0) {
|
||||||
|
_remainingTimeSeconds.value = 0
|
||||||
|
timerJob = null
|
||||||
|
return
|
||||||
|
}
|
||||||
_remainingTimeSeconds.value = totalSeconds
|
_remainingTimeSeconds.value = totalSeconds
|
||||||
timerJob = viewModelScope.launch {
|
timerJob = viewModelScope.launch {
|
||||||
var remaining = totalSeconds
|
var remaining = totalSeconds
|
||||||
@@ -122,6 +126,7 @@ class QuizScreenViewModel @Inject constructor(
|
|||||||
if (_selectedChoiceIndex.value == null) {
|
if (_selectedChoiceIndex.value == null) {
|
||||||
_selectedChoiceIndex.value = -1
|
_selectedChoiceIndex.value = -1
|
||||||
}
|
}
|
||||||
|
timerJob = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user