fix: enforce multi-choice maxSelections limit across all answer UIs, pass questionIds to startGame
This commit is contained in:
parent
4134c4570d
commit
df961e8d94
|
|
@ -64,7 +64,8 @@ private fun parseAnswerConfig(raw: String, questionType: String) = try {
|
|||
"single_choice", "multi_choice" -> {
|
||||
val optionsArr = configObj?.optJSONArray("options")
|
||||
val options = parseOptions(optionsArr)
|
||||
ChoiceAnswerConfigImpl(type = questionType, config = ChoiceAnswerConfig(options = options))
|
||||
val maxSel = if (questionType == "multi_choice") configObj?.optInt("maxSelections", 0) ?: 0 else 0
|
||||
ChoiceAnswerConfigImpl(type = questionType, config = ChoiceAnswerConfig(options = options, maxSelections = maxSel))
|
||||
}
|
||||
"scale" -> ScaleAnswerConfigImpl(
|
||||
config = ScaleAnswerConfig(
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@ object QuestionJsonParser {
|
|||
}
|
||||
}
|
||||
"multi_choice" -> {
|
||||
// For now, treat multi_choice like single_choice (can be extended later)
|
||||
val options = mutableListOf<ChoiceOption>()
|
||||
val optionsArray = obj.optJSONArray("options")
|
||||
if (optionsArray != null) {
|
||||
|
|
@ -188,7 +187,10 @@ object QuestionJsonParser {
|
|||
}
|
||||
ChoiceAnswerConfigImpl(
|
||||
type = "multi_choice",
|
||||
config = ChoiceAnswerConfig(options = options.toList())
|
||||
config = ChoiceAnswerConfig(
|
||||
options = options.toList(),
|
||||
maxSelections = answerConfigObj.optInt("max_selections", 0)
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ data class WrittenAnswerConfig(
|
|||
)
|
||||
|
||||
data class ChoiceAnswerConfig(
|
||||
val options: List<ChoiceOption>
|
||||
val options: List<ChoiceOption>,
|
||||
val maxSelections: Int = 0
|
||||
)
|
||||
|
||||
data class ChoiceOption(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import app.closer.core.crash.CrashReporter
|
||||
import app.closer.data.remote.FirestoreAnswerDataSource
|
||||
import app.closer.domain.model.ChoiceAnswerConfigImpl
|
||||
import app.closer.domain.model.LocalAnswer
|
||||
import app.closer.domain.model.Question
|
||||
import app.closer.domain.repository.AuthRepository
|
||||
|
|
@ -120,10 +121,11 @@ class DailyQuestionViewModel @Inject constructor(
|
|||
_uiState.update { state ->
|
||||
val question = state.question ?: return@update state
|
||||
val updated = if (question.type == "multi_choice") {
|
||||
if (optionId in state.pendingSelectedOptionIds) {
|
||||
state.pendingSelectedOptionIds - optionId
|
||||
} else {
|
||||
state.pendingSelectedOptionIds + optionId
|
||||
val maxSel = (question.answerConfig as? ChoiceAnswerConfigImpl)?.config?.maxSelections ?: 0
|
||||
when {
|
||||
optionId in state.pendingSelectedOptionIds -> state.pendingSelectedOptionIds - optionId
|
||||
maxSel == 0 || state.pendingSelectedOptionIds.size < maxSel -> state.pendingSelectedOptionIds + optionId
|
||||
else -> state.pendingSelectedOptionIds
|
||||
}
|
||||
} else {
|
||||
listOf(optionId)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package app.closer.ui.questions
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.closer.domain.model.ChoiceAnswerConfigImpl
|
||||
import app.closer.domain.repository.LocalAnswerRepository
|
||||
import app.closer.domain.repository.QuestionRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -57,10 +58,11 @@ class QuestionDetailViewModel @Inject constructor(
|
|||
_uiState.update { state ->
|
||||
val question = state.question ?: return@update state
|
||||
val updated = if (question.type == "multi_choice") {
|
||||
if (optionId in state.pendingSelectedOptionIds) {
|
||||
state.pendingSelectedOptionIds - optionId
|
||||
} else {
|
||||
state.pendingSelectedOptionIds + optionId
|
||||
val maxSel = (question.answerConfig as? ChoiceAnswerConfigImpl)?.config?.maxSelections ?: 0
|
||||
when {
|
||||
optionId in state.pendingSelectedOptionIds -> state.pendingSelectedOptionIds - optionId
|
||||
maxSel == 0 || state.pendingSelectedOptionIds.size < maxSel -> state.pendingSelectedOptionIds + optionId
|
||||
else -> state.pendingSelectedOptionIds
|
||||
}
|
||||
} else {
|
||||
listOf(optionId)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import app.closer.data.local.QuestionDao
|
||||
import app.closer.data.local.mapper.toQuestion
|
||||
import app.closer.domain.model.ChoiceAnswerConfigImpl
|
||||
import app.closer.domain.model.Question
|
||||
import app.closer.domain.model.QuestionAnswer
|
||||
import app.closer.domain.model.QuestionMessage
|
||||
|
|
@ -124,6 +125,13 @@ class QuestionThreadViewModel @Inject constructor(
|
|||
val current = state.pendingSelectedOptionIds
|
||||
val updated = if (question.type == "single_choice") {
|
||||
listOf(optionId)
|
||||
} else if (question.type == "multi_choice") {
|
||||
val maxSel = (question.answerConfig as? ChoiceAnswerConfigImpl)?.config?.maxSelections ?: 0
|
||||
when {
|
||||
optionId in current -> current - optionId
|
||||
maxSel == 0 || current.size < maxSel -> current + optionId
|
||||
else -> current
|
||||
}
|
||||
} else {
|
||||
if (optionId in current) current - optionId else current + optionId
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,11 +112,13 @@ class SpinWheelViewModel @Inject constructor(
|
|||
return@launch
|
||||
}
|
||||
|
||||
val questionIds = sessionStore.activeSession?.questions?.map { it.id }
|
||||
val startResult = runCatching {
|
||||
gameSessionManager.startGame(
|
||||
userId = userId,
|
||||
gameType = "wheel",
|
||||
categoryId = categoryId
|
||||
categoryId = categoryId,
|
||||
questionIds = questionIds
|
||||
).getOrNull()
|
||||
}.getOrNull()
|
||||
|
||||
|
|
|
|||
|
|
@ -61,9 +61,15 @@ class WheelSessionViewModel @Inject constructor(
|
|||
fun selectOption(optionId: String) {
|
||||
val question = _uiState.value.questions.getOrNull(_uiState.value.currentIndex) ?: return
|
||||
if (question.type == "multi_choice") {
|
||||
val maxSel = (question.answerConfig as? app.closer.domain.model.ChoiceAnswerConfigImpl)
|
||||
?.config?.maxSelections ?: 0
|
||||
_uiState.update {
|
||||
val current = it.selectedOptionIds.toMutableList()
|
||||
if (optionId in current) current.remove(optionId) else current.add(optionId)
|
||||
if (optionId in current) {
|
||||
current.remove(optionId)
|
||||
} else if (maxSel == 0 || current.size < maxSel) {
|
||||
current.add(optionId)
|
||||
}
|
||||
it.copy(selectedOptionIds = current)
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue