diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 76102786288..820522d91e7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -221,6 +221,7 @@ + diff --git a/app/src/main/java/org/oppia/android/app/activity/ActivityComponentImpl.kt b/app/src/main/java/org/oppia/android/app/activity/ActivityComponentImpl.kt index 14645028aa5..53f0f35955f 100644 --- a/app/src/main/java/org/oppia/android/app/activity/ActivityComponentImpl.kt +++ b/app/src/main/java/org/oppia/android/app/activity/ActivityComponentImpl.kt @@ -77,6 +77,7 @@ import org.oppia.android.app.testing.NavigationDrawerTestActivity import org.oppia.android.app.testing.PoliciesFragmentTestActivity import org.oppia.android.app.testing.ProfileChooserFragmentTestActivity import org.oppia.android.app.testing.ProfileEditFragmentTestActivity +import org.oppia.android.app.testing.RatioInputInteractionViewTestActivity import org.oppia.android.app.testing.SplashTestActivity import org.oppia.android.app.testing.SpotlightFragmentTestActivity import org.oppia.android.app.testing.StateAssemblerMarginBindingAdaptersTestActivity @@ -149,6 +150,7 @@ interface ActivityComponentImpl : fun inject(imageRegionSelectionTestActivity: ImageRegionSelectionTestActivity) fun inject(imageViewBindingAdaptersTestActivity: ImageViewBindingAdaptersTestActivity) fun inject(inputInteractionViewTestActivity: InputInteractionViewTestActivity) + fun inject(ratioInputInteractionViewTestActivity: RatioInputInteractionViewTestActivity) fun inject(licenseListActivity: LicenseListActivity) fun inject(licenseTextViewerActivity: LicenseTextViewerActivity) fun inject(listItemLeadingMarginSpanTestActivity: ListItemLeadingMarginSpanTestActivity) diff --git a/app/src/main/java/org/oppia/android/app/parser/StringToRatioParser.kt b/app/src/main/java/org/oppia/android/app/parser/StringToRatioParser.kt index 31895402263..ebb62121372 100644 --- a/app/src/main/java/org/oppia/android/app/parser/StringToRatioParser.kt +++ b/app/src/main/java/org/oppia/android/app/parser/StringToRatioParser.kt @@ -29,6 +29,7 @@ class StringToRatioParser { val normalized = text.normalizeWhitespace() val ratio = parseRatioOrNull(normalized) return when { + normalized.isBlank() -> RatioParsingError.EMPTY_INPUT !normalized.matches(invalidRatioRegex) || ratio == null -> RatioParsingError.INVALID_FORMAT numberOfTerms != 0 && ratio.ratioComponentCount != numberOfTerms -> { RatioParsingError.INVALID_SIZE @@ -77,7 +78,8 @@ class StringToRatioParser { INVALID_FORMAT(error = R.string.ratio_error_invalid_format), INVALID_COLONS(error = R.string.ratio_error_invalid_colons), INVALID_SIZE(error = R.string.ratio_error_invalid_size), - INCLUDES_ZERO(error = R.string.ratio_error_includes_zero); + INCLUDES_ZERO(error = R.string.ratio_error_includes_zero), + EMPTY_INPUT(error = R.string.ratio_error_empty_input); /** * Returns the string corresponding to this error's string resources, or null if there is none. diff --git a/app/src/main/java/org/oppia/android/app/player/state/itemviewmodel/RatioExpressionInputInteractionViewModel.kt b/app/src/main/java/org/oppia/android/app/player/state/itemviewmodel/RatioExpressionInputInteractionViewModel.kt index 49f64619702..f5c0f323bec 100644 --- a/app/src/main/java/org/oppia/android/app/player/state/itemviewmodel/RatioExpressionInputInteractionViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/itemviewmodel/RatioExpressionInputInteractionViewModel.kt @@ -46,12 +46,18 @@ class RatioExpressionInputInteractionViewModel private constructor( override fun onPropertyChanged(sender: Observable, propertyId: Int) { errorOrAvailabilityCheckReceiver.onPendingAnswerErrorOrAvailabilityCheck( pendingAnswerError, - answerText.isNotEmpty() + inputAnswerAvailable = true // Allow blank answer submission. ) } } errorMessage.addOnPropertyChangedCallback(callback) isAnswerAvailable.addOnPropertyChangedCallback(callback) + + // Initializing with default values so that submit button is enabled by default. + errorOrAvailabilityCheckReceiver.onPendingAnswerErrorOrAvailabilityCheck( + pendingAnswerError = null, + inputAnswerAvailable = true + ) } override fun getPendingAnswer(): UserAnswer = UserAnswer.newBuilder().apply { @@ -67,23 +73,24 @@ class RatioExpressionInputInteractionViewModel private constructor( } }.build() - /** It checks the pending error for the current ratio input, and correspondingly updates the error string based on the specified error category. */ + /** + * It checks the pending error for the current ratio input, and correspondingly + * updates the error string based on the specified error category. + */ override fun checkPendingAnswerError(category: AnswerErrorCategory): String? { - if (answerText.isNotEmpty()) { - when (category) { - AnswerErrorCategory.REAL_TIME -> - pendingAnswerError = - stringToRatioParser.getRealTimeAnswerError(answerText.toString()) - .getErrorMessageFromStringRes(resourceHandler) - AnswerErrorCategory.SUBMIT_TIME -> - pendingAnswerError = - stringToRatioParser.getSubmitTimeError( - answerText.toString(), - numberOfTerms = numberOfTerms - ).getErrorMessageFromStringRes(resourceHandler) - } - errorMessage.set(pendingAnswerError) + pendingAnswerError = when (category) { + AnswerErrorCategory.REAL_TIME -> + if (answerText.isNotEmpty()) + stringToRatioParser.getRealTimeAnswerError(answerText.toString()) + .getErrorMessageFromStringRes(resourceHandler) + else null + AnswerErrorCategory.SUBMIT_TIME -> + stringToRatioParser.getSubmitTimeError( + answerText.toString(), + numberOfTerms = numberOfTerms + ).getErrorMessageFromStringRes(resourceHandler) } + errorMessage.set(pendingAnswerError) return pendingAnswerError } diff --git a/app/src/main/java/org/oppia/android/app/testing/InputInteractionViewTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/InputInteractionViewTestActivity.kt index ac786bb146a..f033c023d61 100644 --- a/app/src/main/java/org/oppia/android/app/testing/InputInteractionViewTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/InputInteractionViewTestActivity.kt @@ -17,7 +17,6 @@ import org.oppia.android.app.model.InputInteractionViewTestActivityParams.MathIn import org.oppia.android.app.model.InputInteractionViewTestActivityParams.MathInteractionType.NUMERIC_EXPRESSION import org.oppia.android.app.model.InputInteractionViewTestActivityParams.MathInteractionType.UNRECOGNIZED import org.oppia.android.app.model.Interaction -import org.oppia.android.app.model.SchemaObject import org.oppia.android.app.model.UserAnswer import org.oppia.android.app.model.WrittenTranslationContext import org.oppia.android.app.player.state.answerhandling.AnswerErrorCategory @@ -25,7 +24,6 @@ import org.oppia.android.app.player.state.answerhandling.InteractionAnswerErrorO import org.oppia.android.app.player.state.answerhandling.InteractionAnswerReceiver import org.oppia.android.app.player.state.itemviewmodel.MathExpressionInteractionsViewModel import org.oppia.android.app.player.state.itemviewmodel.NumericInputViewModel -import org.oppia.android.app.player.state.itemviewmodel.RatioExpressionInputInteractionViewModel import org.oppia.android.app.player.state.itemviewmodel.StateItemViewModel import org.oppia.android.app.player.state.itemviewmodel.StateItemViewModel.InteractionItemFactory import org.oppia.android.app.player.state.itemviewmodel.TextInputViewModel @@ -53,9 +51,6 @@ class InputInteractionViewTestActivity : @Inject lateinit var textInputViewModelFactory: TextInputViewModel.FactoryImpl - @Inject - lateinit var ratioViewModelFactory: RatioExpressionInputInteractionViewModel.FactoryImpl - @Inject lateinit var mathExpViewModelFactoryFactory: MathExpViewModelFactoryFactoryImpl @@ -63,15 +58,6 @@ class InputInteractionViewTestActivity : val textInputViewModel by lazy { textInputViewModelFactory.create() } - val ratioExpressionInputInteractionViewModel by lazy { - ratioViewModelFactory.create( - interaction = Interaction.newBuilder().putCustomizationArgs( - "numberOfTerms", - SchemaObject.newBuilder().setSignedInt(3).build() - ).build() - ) - } - lateinit var mathExpressionViewModel: MathExpressionInteractionsViewModel lateinit var writtenTranslationContext: WrittenTranslationContext @@ -118,14 +104,11 @@ class InputInteractionViewTestActivity : binding.numericInputViewModel = numericInputViewModel binding.textInputViewModel = textInputViewModel - binding.ratioInteractionInputViewModel = ratioExpressionInputInteractionViewModel binding.mathExpressionInteractionsViewModel = mathExpressionViewModel } fun getPendingAnswerErrorOnSubmitClick(v: View) { numericInputViewModel.checkPendingAnswerError(AnswerErrorCategory.SUBMIT_TIME) - ratioExpressionInputInteractionViewModel - .checkPendingAnswerError(AnswerErrorCategory.SUBMIT_TIME) } override fun onPendingAnswerErrorOrAvailabilityCheck( diff --git a/app/src/main/java/org/oppia/android/app/testing/RatioInputInteractionViewTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/RatioInputInteractionViewTestActivity.kt new file mode 100644 index 00000000000..a16d8e7c12c --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/testing/RatioInputInteractionViewTestActivity.kt @@ -0,0 +1,120 @@ +package org.oppia.android.app.testing + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.View +import androidx.databinding.DataBindingUtil +import org.oppia.android.R +import org.oppia.android.app.activity.ActivityComponentImpl +import org.oppia.android.app.activity.InjectableAutoLocalizedAppCompatActivity +import org.oppia.android.app.customview.interaction.RatioInputInteractionView +import org.oppia.android.app.model.InputInteractionViewTestActivityParams +import org.oppia.android.app.model.Interaction +import org.oppia.android.app.model.SchemaObject +import org.oppia.android.app.model.UserAnswer +import org.oppia.android.app.model.WrittenTranslationContext +import org.oppia.android.app.player.state.answerhandling.AnswerErrorCategory +import org.oppia.android.app.player.state.answerhandling.InteractionAnswerErrorOrAvailabilityCheckReceiver +import org.oppia.android.app.player.state.answerhandling.InteractionAnswerReceiver +import org.oppia.android.app.player.state.itemviewmodel.RatioExpressionInputInteractionViewModel +import org.oppia.android.app.player.state.itemviewmodel.StateItemViewModel +import org.oppia.android.app.player.state.itemviewmodel.StateItemViewModel.InteractionItemFactory +import org.oppia.android.app.player.state.listener.StateKeyboardButtonListener +import org.oppia.android.databinding.ActivityRatioInputInteractionViewTestBinding +import org.oppia.android.util.extensions.getProtoExtra +import org.oppia.android.util.extensions.putProtoExtra +import javax.inject.Inject + +/** + * This is a dummy activity to test [RatioInputInteractionView]. + */ +class RatioInputInteractionViewTestActivity : + InjectableAutoLocalizedAppCompatActivity(), + StateKeyboardButtonListener, + InteractionAnswerErrorOrAvailabilityCheckReceiver, + InteractionAnswerReceiver { + private lateinit var binding: ActivityRatioInputInteractionViewTestBinding + + @Inject + lateinit var ratioViewModelFactory: RatioExpressionInputInteractionViewModel.FactoryImpl + + /** + * Gives access to the [RatioExpressionInputInteractionViewModel]. + */ + val ratioExpressionInputInteractionViewModel by lazy { + ratioViewModelFactory.create( + interaction = Interaction.newBuilder().putCustomizationArgs( + "numberOfTerms", + SchemaObject.newBuilder().setSignedInt(3).build() + ).build() + ) + } + + /** + * Gives access to the translation context. + */ + lateinit var writtenTranslationContext: WrittenTranslationContext + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + (activityComponent as ActivityComponentImpl).inject(this) + binding = DataBindingUtil.setContentView( + this, R.layout.activity_ratio_input_interaction_view_test + ) + + val params = + intent.getProtoExtra( + TEST_ACTIVITY_PARAMS_ARGUMENT_KEY, + InputInteractionViewTestActivityParams.getDefaultInstance() + ) + writtenTranslationContext = params.writtenTranslationContext + + binding.ratioInteractionInputViewModel = ratioExpressionInputInteractionViewModel + } + + /** + * Checks for submit time errors. + */ + fun getPendingAnswerErrorOnSubmitClick(v: View) { + ratioExpressionInputInteractionViewModel + .checkPendingAnswerError(AnswerErrorCategory.SUBMIT_TIME) + } + + override fun onAnswerReadyForSubmission(answer: UserAnswer) { } + + override fun onEditorAction(actionCode: Int) { } + + private inline fun InteractionItemFactory.create( + interaction: Interaction = Interaction.getDefaultInstance() + ): T { + return create( + entityId = "fake_entity_id", + hasConversationView = false, + interaction = interaction, + interactionAnswerReceiver = this@RatioInputInteractionViewTestActivity, + answerErrorReceiver = this@RatioInputInteractionViewTestActivity, + hasPreviousButton = false, + isSplitView = false, + writtenTranslationContext, + timeToStartNoticeAnimationMs = null + ) as T + } + + companion object { + private const val TEST_ACTIVITY_PARAMS_ARGUMENT_KEY = + "RatioInputInteractionViewTestActivity.params" + + /** + * Creates an intent to open [RatioInputInteractionViewTestActivity]. + */ + fun createIntent( + context: Context, + extras: InputInteractionViewTestActivityParams + ): Intent { + return Intent(context, RatioInputInteractionViewTestActivity::class.java).also { + it.putProtoExtra(TEST_ACTIVITY_PARAMS_ARGUMENT_KEY, extras) + } + } + } +} diff --git a/app/src/main/res/layout/activity_input_interaction_view_test.xml b/app/src/main/res/layout/activity_input_interaction_view_test.xml index a8e798252c0..780294fa6b4 100644 --- a/app/src/main/res/layout/activity_input_interaction_view_test.xml +++ b/app/src/main/res/layout/activity_input_interaction_view_test.xml @@ -15,10 +15,6 @@ name="textInputViewModel" type="org.oppia.android.app.player.state.itemviewmodel.TextInputViewModel" /> - - @@ -36,43 +32,6 @@ android:orientation="vertical" tools:context=".testing.InputInteractionViewTestActivity"> - - - - + + + + + + + + + + + + + + + + +