Skip to content

Commit

Permalink
Add empty answer support
Browse files Browse the repository at this point in the history
  • Loading branch information
theMr17 committed Jan 18, 2024
1 parent bb69b22 commit 676cfb9
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.oppia.android.app.player.state.itemviewmodel

import androidx.annotation.StringRes
import androidx.databinding.Observable
import androidx.databinding.ObservableBoolean
import androidx.databinding.ObservableField
Expand All @@ -18,6 +19,7 @@ import org.oppia.android.app.player.state.answerhandling.InteractionAnswerReceiv
import org.oppia.android.app.translation.AppLanguageResourceHandler
import org.oppia.android.app.viewmodel.ObservableArrayList
import org.oppia.android.domain.translation.TranslationController
import org.oppia.android.app.player.state.answerhandling.AnswerErrorCategory
import javax.inject.Inject

/** Corresponds to the type of input that should be used for an item selection interaction view. */
Expand All @@ -26,6 +28,18 @@ enum class SelectionItemInputType {
RADIO_BUTTONS
}

/** Enum to the store the errors of selection input */
enum class SelectionInputError(@StringRes private var error: Int?) {
VALID(error = null),
EMPTY_INPUT(error = R.string.selection_error_empty_input);

/**
* Returns the string corresponding to this error's string resources, or null if there is none.
*/
fun getErrorMessageFromStringRes(resourceHandler: AppLanguageResourceHandler): String? =
error?.let(resourceHandler::getStringInLocale)
}

/** [StateItemViewModel] for multiple or item-selection input choice list. */
class SelectionInteractionViewModel private constructor(
val entityId: String,
Expand Down Expand Up @@ -64,7 +78,9 @@ class SelectionInteractionViewModel private constructor(
val choiceItems: ObservableList<SelectionInteractionContentViewModel> =
computeChoiceItems(choiceSubtitledHtmls, hasConversationView, this, enabledItemsList)

private var pendingAnswerError: String? = null
private val isAnswerAvailable = ObservableField(false)
var errorMessage = ObservableField<String>("")
val selectedItemText =
ObservableField(
resourceHandler.getStringInLocale(
Expand All @@ -77,12 +93,19 @@ class SelectionInteractionViewModel private constructor(
object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable, propertyId: Int) {
interactionAnswerErrorOrAvailabilityCheckReceiver.onPendingAnswerErrorOrAvailabilityCheck(
pendingAnswerError = null,
inputAnswerAvailable = selectedItems.isNotEmpty()
pendingAnswerError,
inputAnswerAvailable = true // Allow blank answer submission.
)
}
}
errorMessage.addOnPropertyChangedCallback(callback)
isAnswerAvailable.addOnPropertyChangedCallback(callback)

// Initializing with default values so that submit button is enabled by default.
interactionAnswerErrorOrAvailabilityCheckReceiver.onPendingAnswerErrorOrAvailabilityCheck(
pendingAnswerError = null,
inputAnswerAvailable = true
)
}

override fun getPendingAnswer(): UserAnswer = UserAnswer.newBuilder().apply {
Expand Down Expand Up @@ -113,6 +136,20 @@ class SelectionInteractionViewModel private constructor(
writtenTranslationContext = translationContext
}.build()

/**
* It checks the pending error for the current selection input, and correspondingly
* updates the error string based on the specified error category.
*/
override fun checkPendingAnswerError(category: AnswerErrorCategory): String? {
pendingAnswerError = when (category) {
AnswerErrorCategory.REAL_TIME -> null
AnswerErrorCategory.SUBMIT_TIME ->
getSubmitTimeError().getErrorMessageFromStringRes(resourceHandler)
}
errorMessage.set(pendingAnswerError)
return pendingAnswerError
}

/** Returns an HTML list containing all of the HTML string elements as items in the list. */
private fun convertSelectedItemsToHtmlString(itemHtmls: Collection<String>): String {
return when (itemHtmls.size) {
Expand All @@ -135,6 +172,7 @@ class SelectionInteractionViewModel private constructor(

/** Catalogs an item being clicked by the user and returns whether the item should be considered selected. */
fun updateSelection(itemIndex: Int, isCurrentlySelected: Boolean): Boolean {
checkPendingAnswerError(AnswerErrorCategory.REAL_TIME)
return when {
isCurrentlySelected -> {
selectedItems -= itemIndex
Expand Down Expand Up @@ -208,6 +246,13 @@ class SelectionInteractionViewModel private constructor(
}
}

private fun getSubmitTimeError(): SelectionInputError {
return if (selectedItems.isEmpty())
SelectionInputError.EMPTY_INPUT
else
SelectionInputError.VALID
}

/** Implementation of [StateItemViewModel.InteractionItemFactory] for this view model. */
class FactoryImpl @Inject constructor(
private val translationController: TranslationController,
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/layout/selection_interaction_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,15 @@
app:selectionData="@{viewModel.choiceItems}"
app:writtenTranslationContext="@{viewModel.writtenTranslationContext}" />
</LinearLayout>

<TextView
android:id="@+id/selection_input_error"
style="@style/InputInteractionErrorTextView"
android:text="@{viewModel.errorMessage}"
android:textColor="@color/component_color_shared_input_error_color"
android:visibility="@{viewModel.errorMessage.length()>0? View.VISIBLE : View.GONE}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/interaction_container_linear_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@
<string name="ratio_error_invalid_size" description="The error message for ratio when there is less number of terms than the creator has specified in customization arg.">Number of terms is not equal to the required terms.</string>
<string name="ratio_error_includes_zero" description="The error message for ratio when there is 0 term in the ratio.">Ratios cannot have 0 as an element.</string>
<string name="ratio_error_empty_input" description="The error message for ratio when the answer is empty">Enter a ratio to continue.</string>
<string name="selection_error_empty_input">Choose an answer to continue.</string>
<string name="unknown_size">Unknown size</string>
<string name="size_bytes">%s Bytes</string>
<string name="size_kb">%s KB</string>
Expand Down

0 comments on commit 676cfb9

Please sign in to comment.