add comprehensive logging for exercise setup and state transitions across screens and ViewModels
This commit is contained in:
@@ -58,6 +58,7 @@ import eu.gaudian.translator.model.Language
|
||||
import eu.gaudian.translator.model.TagCategory
|
||||
import eu.gaudian.translator.model.VocabularyCategory
|
||||
import eu.gaudian.translator.model.VocabularyStage
|
||||
import eu.gaudian.translator.utils.Log
|
||||
import eu.gaudian.translator.utils.findActivity
|
||||
import eu.gaudian.translator.view.composable.AppButton
|
||||
import eu.gaudian.translator.view.composable.AppIcons
|
||||
@@ -117,6 +118,7 @@ fun StartExerciseScreen(
|
||||
var amount by remember { mutableStateOf(0) }
|
||||
androidx.compose.runtime.LaunchedEffect(totalItemCount) {
|
||||
amount = totalItemCount
|
||||
Log.d("StartExercise", "Items to show updated: total=$totalItemCount, amount=$amount")
|
||||
}
|
||||
|
||||
val updateConfig: (eu.gaudian.translator.viewmodel.ExerciseConfig) -> Unit = { config ->
|
||||
@@ -213,12 +215,15 @@ fun StartExerciseScreen(
|
||||
enabled = totalItemCount > 0 && amount > 0,
|
||||
amount = amount,
|
||||
onStart = {
|
||||
Log.d("StartExercise", "Start pressed. shuffleCards=${exerciseConfig.shuffleCards}, selectedAmount=$amount, items=${itemsToShow.size}, origin=${selectedOriginLanguage?.nameResId}, target=${selectedTargetLanguage?.nameResId}, pairs=${selectedPairsIds.size}, categories=${selectedCategoryIds.size}, stages=${selectedStages.size}")
|
||||
val finalItems = if (exerciseConfig.shuffleCards) {
|
||||
itemsToShow.shuffled().take(amount)
|
||||
} else {
|
||||
itemsToShow.take(amount)
|
||||
}
|
||||
|
||||
Log.d("StartExercise", "Final items prepared: count=${finalItems.size}")
|
||||
|
||||
exerciseViewModel.startExerciseWithConfig(
|
||||
finalItems,
|
||||
exerciseConfig.copy(
|
||||
@@ -229,6 +234,7 @@ fun StartExerciseScreen(
|
||||
)
|
||||
)
|
||||
|
||||
Log.d("StartExercise", "Navigating to vocabulary_exercise/false")
|
||||
navController.navigate("vocabulary_exercise/false")
|
||||
}
|
||||
)
|
||||
|
||||
@@ -27,6 +27,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.navigation.NavController
|
||||
import eu.gaudian.translator.R
|
||||
import eu.gaudian.translator.utils.Log
|
||||
import eu.gaudian.translator.utils.findActivity
|
||||
import eu.gaudian.translator.view.composable.AppAlertDialog
|
||||
import eu.gaudian.translator.viewmodel.ScreenState
|
||||
@@ -67,8 +68,10 @@ fun VocabularyExerciseHostScreen(
|
||||
}
|
||||
|
||||
LaunchedEffect(categoryIdsAsJson, stageNamesAsJson, languageIdsAsJson, dailyOnly) {
|
||||
Log.d("ExerciseHost", "LaunchedEffect filters: categories=$categoryIdsAsJson, stages=$stageNamesAsJson, languages=$languageIdsAsJson, dailyOnly=$dailyOnly")
|
||||
// Only reset and prepare if the host is opened via explicit filters.
|
||||
if (!categoryIdsAsJson.isNullOrBlank() || !stageNamesAsJson.isNullOrBlank() || !languageIdsAsJson.isNullOrBlank() || dailyOnly) {
|
||||
Log.d("ExerciseHost", "Preparing exercise from filters")
|
||||
exerciseViewModel.resetExercise()
|
||||
vocabularyViewModel.prepareExercise(
|
||||
categoryIdsAsJson,
|
||||
@@ -76,10 +79,13 @@ fun VocabularyExerciseHostScreen(
|
||||
languageIdsAsJson,
|
||||
dailyOnly = dailyOnly,
|
||||
)
|
||||
} else {
|
||||
Log.d("ExerciseHost", "No filters provided; skipping prepareExercise")
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(cardSet, screenState, pendingConfig) {
|
||||
Log.d("ExerciseHost", "State update: screenState=$screenState, cardSet=${cardSet?.cards?.size ?: 0}, pendingCount=${pendingConfig.exerciseItemCount}")
|
||||
if (cardSet != null && screenState == ScreenState.START) {
|
||||
val items = cardSet?.cards.orEmpty()
|
||||
if (items.isNotEmpty()) {
|
||||
@@ -91,6 +97,7 @@ fun VocabularyExerciseHostScreen(
|
||||
} else {
|
||||
items.take(selectedCount)
|
||||
}
|
||||
Log.d("ExerciseHost", "Auto-starting exercise with ${finalItems.size} items")
|
||||
exerciseViewModel.startExerciseWithConfig(
|
||||
finalItems,
|
||||
pendingConfig.copy(
|
||||
@@ -98,52 +105,51 @@ fun VocabularyExerciseHostScreen(
|
||||
originalExerciseItems = finalItems
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Log.d("ExerciseHost", "CardSet present but empty")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cardSet == null && screenState != ScreenState.START) {
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
CircularProgressIndicator()
|
||||
when (screenState) {
|
||||
ScreenState.START -> {
|
||||
Log.d("ExerciseHost", "Rendering START screen")
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (screenState) {
|
||||
ScreenState.START -> {
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
ScreenState.EXERCISE -> {
|
||||
ExerciseScreen(
|
||||
viewModel = exerciseViewModel,
|
||||
onClose = onClose,
|
||||
onFinish = { score, wrong ->
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
finalScore = score
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
finalWrongAnswers = wrong
|
||||
exerciseViewModel.finishExercise(score, wrong)
|
||||
},
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
ScreenState.RESULT -> {
|
||||
val totalItems by exerciseViewModel.totalItems.collectAsState()
|
||||
val originalItems by exerciseViewModel.originalItems.collectAsState()
|
||||
ResultScreen(
|
||||
score = finalScore,
|
||||
wrongAnswers = finalWrongAnswers,
|
||||
totalItems = totalItems,
|
||||
onRestart = {
|
||||
vocabularyViewModel.clearCardSet()
|
||||
exerciseViewModel.resetExercise()
|
||||
},
|
||||
onRetryWrong = { _ ->
|
||||
exerciseViewModel.retryWrongAnswers(originalItems)
|
||||
},
|
||||
onClose = onClose
|
||||
)
|
||||
}
|
||||
ScreenState.EXERCISE -> {
|
||||
Log.d("ExerciseHost", "Rendering EXERCISE screen")
|
||||
ExerciseScreen(
|
||||
viewModel = exerciseViewModel,
|
||||
onClose = onClose,
|
||||
onFinish = { score, wrong ->
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
finalScore = score
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
finalWrongAnswers = wrong
|
||||
exerciseViewModel.finishExercise(score, wrong)
|
||||
},
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
ScreenState.RESULT -> {
|
||||
Log.d("ExerciseHost", "Rendering RESULT screen")
|
||||
val totalItems by exerciseViewModel.totalItems.collectAsState()
|
||||
val originalItems by exerciseViewModel.originalItems.collectAsState()
|
||||
ResultScreen(
|
||||
score = finalScore,
|
||||
wrongAnswers = finalWrongAnswers,
|
||||
totalItems = totalItems,
|
||||
onRestart = {
|
||||
vocabularyViewModel.clearCardSet()
|
||||
exerciseViewModel.resetExercise()
|
||||
},
|
||||
onRetryWrong = { _ ->
|
||||
exerciseViewModel.retryWrongAnswers(originalItems)
|
||||
},
|
||||
onClose = onClose
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
types: Set<VocabularyExerciseType>,
|
||||
shuffleLanguages: Boolean
|
||||
) {
|
||||
Log.d("ExerciseVM", "startExercise called: items=${items.size}, types=$types, shuffleLanguages=$shuffleLanguages")
|
||||
// Reset counters for the new exercise session
|
||||
_correctAnswers.value = 0
|
||||
_wrongAnswers.value = 0
|
||||
@@ -161,6 +162,7 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadExercise() {
|
||||
Log.d("ExerciseVM", "loadExercise: index=$currentIndex, total=${currentItems.size}")
|
||||
if (currentIndex < currentItems.size) {
|
||||
// Ensure item categories align with exercise type by attempting a swap instead of replacement
|
||||
val randomType = exerciseTypes.random()
|
||||
@@ -276,8 +278,10 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
}
|
||||
Log.d("ExerciseVM", "exerciseState set: type=$randomType, itemId=${itemToUse.id}")
|
||||
} else {
|
||||
_exerciseState.value = null // End of exercise
|
||||
Log.d("ExerciseVM", "loadExercise: end of exercise, state cleared")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,6 +398,7 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun onTrainingModeChanged(value: Boolean) {
|
||||
Log.d("ExerciseVM", "onTrainingModeChanged: $value")
|
||||
_trainingMode.value = value
|
||||
}
|
||||
|
||||
@@ -401,24 +406,29 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
items: List<VocabularyItem>,
|
||||
config: ExerciseConfig
|
||||
) {
|
||||
Log.d("ExerciseVM", "startExerciseWithConfig called: items=${items.size}, configCount=${config.exerciseItemCount}, shuffleCards=${config.shuffleCards}, shuffleLanguages=${config.shuffleLanguages}, trainingMode=${config.trainingMode}, dueTodayOnly=${config.dueTodayOnly}, types=${config.selectedExerciseTypes}")
|
||||
_exerciseConfig.value = config
|
||||
_pendingExerciseConfig.value = config
|
||||
_totalItems.value = items.size
|
||||
_originalItems.value = items
|
||||
startExercise(items, config.selectedExerciseTypes, config.shuffleLanguages)
|
||||
_screenState.value = ScreenState.EXERCISE
|
||||
Log.d("ExerciseVM", "screenState set to EXERCISE; totalItems=${_totalItems.value}")
|
||||
}
|
||||
|
||||
fun updatePendingExerciseConfig(config: ExerciseConfig) {
|
||||
Log.d("ExerciseVM", "updatePendingExerciseConfig: count=${config.exerciseItemCount}, shuffleCards=${config.shuffleCards}, shuffleLanguages=${config.shuffleLanguages}, trainingMode=${config.trainingMode}, dueTodayOnly=${config.dueTodayOnly}, types=${config.selectedExerciseTypes}")
|
||||
_pendingExerciseConfig.value = config
|
||||
}
|
||||
|
||||
|
||||
fun finishExercise(score: Int, wrongAnswers: Int) {
|
||||
_exerciseResults.value = ExerciseResults(score, wrongAnswers)
|
||||
_screenState.value = ScreenState.RESULT
|
||||
}
|
||||
|
||||
fun resetExercise() {
|
||||
Log.d("ExerciseVM", "resetExercise called")
|
||||
_screenState.value = ScreenState.START
|
||||
_exerciseConfig.value = ExerciseConfig()
|
||||
_exerciseResults.value = ExerciseResults()
|
||||
@@ -428,6 +438,7 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
_exerciseState.value = null
|
||||
_totalItems.value = 0
|
||||
_originalItems.value = emptyList()
|
||||
Log.d("ExerciseVM", "resetExercise completed; screenState=START")
|
||||
}
|
||||
|
||||
fun retryWrongAnswers(originalItems: List<VocabularyItem>) {
|
||||
|
||||
@@ -714,6 +714,7 @@ class VocabularyViewModel @Inject constructor(
|
||||
languageIdsAsJson: String?,
|
||||
dailyOnly: Boolean = false
|
||||
) {
|
||||
Log.d("VocabularyVM", "prepareExercise: categories=$categoryIdsAsJson, stages=$stageNamesAsJson, languages=$languageIdsAsJson, dailyOnly=$dailyOnly")
|
||||
viewModelScope.launch {
|
||||
val categoryList = categoryIdsAsJson?.takeIf { it.isNotBlank() }
|
||||
?.split(",")
|
||||
@@ -732,6 +733,7 @@ class VocabularyViewModel @Inject constructor(
|
||||
allLangs.filter { it.nameResId in ids }
|
||||
} ?: emptyList()
|
||||
|
||||
Log.d("VocabularyVM", "prepareExercise parsed: categories=${categoryList.size}, stages=${stageList.size}, languages=${languageList.size}")
|
||||
loadCardSet(categoryList, stageList, languageList, dailyOnly)
|
||||
}
|
||||
}
|
||||
@@ -743,6 +745,7 @@ class VocabularyViewModel @Inject constructor(
|
||||
languages: List<Language>? = null,
|
||||
dailyOnly: Boolean = false
|
||||
) {
|
||||
Log.d(TAG, "loadCardSet invoked: categories=${categories?.size ?: 0}, stages=${stages?.size ?: 0}, languages=${languages?.map { it.nameResId }}, dailyOnly=$dailyOnly")
|
||||
Log.d(TAG, "Loading card set with languages: $languages, categories: ${categories?.size}, stages: ${stages?.size}")
|
||||
viewModelScope.launch {
|
||||
statusService.showLoadingMessage("Loading card set")
|
||||
@@ -802,6 +805,8 @@ class VocabularyViewModel @Inject constructor(
|
||||
dueTodayOnly = dailyOnly
|
||||
).first()
|
||||
|
||||
Log.d(TAG, "loadCardSet: filterVocabularyItems returned ${filteredItems.size} items")
|
||||
|
||||
Log.d(TAG, "loadCardSet: Filtering completed, found ${filteredItems.size} items")
|
||||
|
||||
if (filteredItems.isNotEmpty()) {
|
||||
|
||||
Reference in New Issue
Block a user