Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix part of #5070: Display empty answer message in text input interaction #5311

Merged
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
40e905f
fixing text input
Vishwajith-Shettigar Jan 18, 2024
0574a21
fixing text input
Vishwajith-Shettigar Jan 18, 2024
13cfbab
fixing text input
Vishwajith-Shettigar Jan 18, 2024
7275077
fixing text input
Vishwajith-Shettigar Jan 18, 2024
2a6a164
text input added error view
Vishwajith-Shettigar Jan 18, 2024
251f695
text input added error view
Vishwajith-Shettigar Jan 18, 2024
1397008
kdoc fix
Vishwajith-Shettigar Jan 18, 2024
86050bd
kdoc fix
Vishwajith-Shettigar Jan 18, 2024
149c0a9
added testcase for blank input
Vishwajith-Shettigar Jan 18, 2024
fbbadcb
added TextParsingUiError and TextParsingUiError to test_file_exemptions
Vishwajith-Shettigar Jan 18, 2024
ffb73a7
test fix
Vishwajith-Shettigar Jan 18, 2024
284d9ad
some changes
Vishwajith-Shettigar Jan 19, 2024
a52c747
some changes
Vishwajith-Shettigar Jan 19, 2024
9aca2a2
Added separate test suite for text input interaction
Vishwajith-Shettigar Jan 19, 2024
d5ebc5b
added tests for test input interaction
Vishwajith-Shettigar Jan 19, 2024
f1a3416
added tests for text input interaction
Vishwajith-Shettigar Jan 19, 2024
70b0360
added TextInputInteractionViewTestActivity to accessibility_label_ex…
Vishwajith-Shettigar Jan 19, 2024
bb483a6
added comment
Vishwajith-Shettigar Jan 19, 2024
c500c1f
some changes
Vishwajith-Shettigar Jan 19, 2024
3b15084
enums shifted to viewmodel
Vishwajith-Shettigar Jan 19, 2024
c2ff231
minor changes
Vishwajith-Shettigar Jan 20, 2024
90c689d
kdoc fix
Vishwajith-Shettigar Jan 21, 2024
6bda7ec
addresses all comments
Vishwajith-Shettigar Jan 26, 2024
4bc227b
addresses all comments
Vishwajith-Shettigar Jan 26, 2024
ff9858c
addressed all comments
Vishwajith-Shettigar Jan 27, 2024
d41f531
fix
Vishwajith-Shettigar Jan 27, 2024
12c448f
fix
Vishwajith-Shettigar Jan 27, 2024
6b53f94
fix
Vishwajith-Shettigar Jan 27, 2024
0a2bbd1
some changes
Vishwajith-Shettigar Jan 27, 2024
e458543
kdoc fix
Vishwajith-Shettigar Jan 28, 2024
70dde7f
Merge branch 'develop' into text_input_empty_answer
Vishwajith-Shettigar Jan 28, 2024
48bc7db
Merge branch 'develop' into text_input_empty_answer
Vishwajith-Shettigar Jan 29, 2024
0f6122c
fix
Vishwajith-Shettigar Jan 29, 2024
d1c6839
some changes
Vishwajith-Shettigar Jan 29, 2024
fba1d7e
Addressed comments
Vishwajith-Shettigar Feb 1, 2024
45504ad
addressed comments
Vishwajith-Shettigar Feb 7, 2024
e73b0d3
Merge branch 'develop' into text_input_empty_answer
Vishwajith-Shettigar Feb 7, 2024
32cb510
resolve conflict
Vishwajith-Shettigar Feb 24, 2024
8f2849f
resolve conflict
Vishwajith-Shettigar Feb 24, 2024
53bda3e
Merge branch 'develop' into text_input_empty_answer
Vishwajith-Shettigar Feb 24, 2024
45d793e
addressed comment
Vishwajith-Shettigar Feb 24, 2024
55977a0
addressed comment
Vishwajith-Shettigar Feb 24, 2024
6c3e8d0
addressed comment
Vishwajith-Shettigar Feb 24, 2024
f994052
fix
Vishwajith-Shettigar Feb 24, 2024
3d978e8
resolve conflict
Vishwajith-Shettigar Mar 1, 2024
1fc7000
resolve conflict
Vishwajith-Shettigar Mar 1, 2024
5af5024
Merge branch 'develop' into text_input_empty_answer
Vishwajith-Shettigar Mar 1, 2024
19f2a4d
resolve conflict
Vishwajith-Shettigar Mar 1, 2024
6206a84
Merge branch 'develop' into text_input_empty_answer
Vishwajith-Shettigar Mar 1, 2024
ca41e77
resolve conflicts
Vishwajith-Shettigar Mar 2, 2024
968b5cd
Merge branch 'develop' into text_input_empty_answer
Vishwajith-Shettigar Mar 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@
android:theme="@style/OppiaThemeWithoutActionBar" />
<activity
android:name=".app.splash.SplashActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:exported="true"
android:theme="@style/SplashScreenTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand All @@ -214,6 +214,7 @@
<activity android:name=".app.testing.ExplorationInjectionActivity" />
<activity android:name=".app.testing.ExplorationTestActivity" />
<activity android:name=".app.testing.FractionInputInteractionViewTestActivity" />
<activity android:name=".app.testing.TextInputInteractionViewTestActivity" />
<activity
android:name=".app.testing.TestFontScaleConfigurationUtilActivity"
android:theme="@style/OppiaThemeWithoutActionBar" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import org.oppia.android.app.testing.SpotlightFragmentTestActivity
import org.oppia.android.app.testing.StateAssemblerMarginBindingAdaptersTestActivity
import org.oppia.android.app.testing.StateAssemblerPaddingBindingAdaptersTestActivity
import org.oppia.android.app.testing.TestFontScaleConfigurationUtilActivity
import org.oppia.android.app.testing.TextInputInteractionViewTestActivity
import org.oppia.android.app.testing.TextViewBindingAdaptersTestActivity
import org.oppia.android.app.testing.TopicRevisionTestActivity
import org.oppia.android.app.testing.TopicTestActivity
Expand Down Expand Up @@ -150,6 +151,7 @@ interface ActivityComponentImpl :
fun inject(imageRegionSelectionTestActivity: ImageRegionSelectionTestActivity)
fun inject(imageViewBindingAdaptersTestActivity: ImageViewBindingAdaptersTestActivity)
fun inject(inputInteractionViewTestActivity: InputInteractionViewTestActivity)
fun inject(textInputInteractionViewTestActivity: TextInputInteractionViewTestActivity)
fun inject(ratioInputInteractionViewTestActivity: RatioInputInteractionViewTestActivity)
fun inject(licenseListActivity: LicenseListActivity)
fun inject(licenseTextViewerActivity: LicenseTextViewerActivity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package org.oppia.android.app.player.state.itemviewmodel

import android.text.Editable
import android.text.TextWatcher
import androidx.annotation.StringRes
import androidx.databinding.Observable
import androidx.databinding.ObservableField
import org.oppia.android.R
import org.oppia.android.app.model.Interaction
import org.oppia.android.app.model.InteractionObject
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.InteractionAnswerHandler
import org.oppia.android.app.player.state.answerhandling.InteractionAnswerReceiver
Expand All @@ -28,20 +30,43 @@ class TextInputViewModel private constructor(
) : StateItemViewModel(ViewType.TEXT_INPUT_INTERACTION), InteractionAnswerHandler {
var answerText: CharSequence = ""
val hintText: CharSequence = deriveHintText(interaction)
private var pendingAnswerError: String? = null

var isAnswerAvailable = ObservableField<Boolean>(false)
val errorMessage = ObservableField<String>("")

init {
val callback: Observable.OnPropertyChangedCallback =
object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable, propertyId: Int) {
interactionAnswerErrorOrAvailabilityCheckReceiver.onPendingAnswerErrorOrAvailabilityCheck(
/* pendingAnswerError= */ null,
answerText.isNotEmpty()
pendingAnswerError = pendingAnswerError,
inputAnswerAvailable = true // Allow submit on empty answer.
)
}
}
isAnswerAvailable.addOnPropertyChangedCallback(callback)
errorMessage.addOnPropertyChangedCallback(callback)

// Initializing with default values so that submit button is enabled by default.
interactionAnswerErrorOrAvailabilityCheckReceiver.onPendingAnswerErrorOrAvailabilityCheck(
adhiamboperes marked this conversation as resolved.
Show resolved Hide resolved
pendingAnswerError = null,
inputAnswerAvailable = true
)
}

override fun checkPendingAnswerError(category: AnswerErrorCategory): String? {
return when (category) {
AnswerErrorCategory.REAL_TIME -> null
AnswerErrorCategory.SUBMIT_TIME -> {
TextParsingUiError.createForText(
answerText.toString()
).createForText(resourceHandler)
}
}.also {
pendingAnswerError = it
errorMessage.set(it)
}
}

fun getAnswerTextWatcher(): TextWatcher {
Expand All @@ -55,6 +80,7 @@ class TextInputViewModel private constructor(
if (isAnswerTextAvailable != isAnswerAvailable.get()) {
isAnswerAvailable.set(isAnswerTextAvailable)
}
checkPendingAnswerError(AnswerErrorCategory.REAL_TIME)
}

override fun afterTextChanged(s: Editable) {
Expand Down Expand Up @@ -121,4 +147,22 @@ class TextInputViewModel private constructor(
)
}
}

private enum class TextParsingUiError(@StringRes private var error: Int?) {
/** Corresponds to non empty input. */
VALID(error = null),

/** Corresponds to empty input. */
EMPTY_INPUT(error = R.string.text_error_empty_input);

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

companion object {
/** Returns the [TextParsingUiError] corresponding to the input. */
fun createForText(text: String): TextParsingUiError =
if (text.isEmpty()) EMPTY_INPUT else VALID
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ 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.NumericInputInteractionView
import org.oppia.android.app.customview.interaction.TextInputInteractionView
import org.oppia.android.app.model.InputInteractionViewTestActivityParams
import org.oppia.android.app.model.InputInteractionViewTestActivityParams.MathInteractionType.ALGEBRAIC_EXPRESSION
import org.oppia.android.app.model.InputInteractionViewTestActivityParams.MathInteractionType.MATH_EQUATION
Expand All @@ -26,7 +25,6 @@ import org.oppia.android.app.player.state.itemviewmodel.MathExpressionInteractio
import org.oppia.android.app.player.state.itemviewmodel.NumericInputViewModel
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
import org.oppia.android.app.player.state.listener.StateKeyboardButtonListener
import org.oppia.android.databinding.ActivityInputInteractionViewTestBinding
import org.oppia.android.util.extensions.getProtoExtra
Expand All @@ -36,7 +34,7 @@ import org.oppia.android.app.player.state.itemviewmodel.MathExpressionInteractio

/**
* This is a dummy activity to test input interaction views.
* It contains [NumericInputInteractionView],and [TextInputInteractionView].
* It contains [NumericInputInteractionView]
*/
class InputInteractionViewTestActivity :
InjectableAutoLocalizedAppCompatActivity(),
Expand All @@ -48,16 +46,11 @@ class InputInteractionViewTestActivity :
@Inject
lateinit var numericInputViewModelFactory: NumericInputViewModel.FactoryImpl

@Inject
lateinit var textInputViewModelFactory: TextInputViewModel.FactoryImpl

@Inject
lateinit var mathExpViewModelFactoryFactory: MathExpViewModelFactoryFactoryImpl

val numericInputViewModel by lazy { numericInputViewModelFactory.create<NumericInputViewModel>() }

val textInputViewModel by lazy { textInputViewModelFactory.create<TextInputViewModel>() }

lateinit var mathExpressionViewModel: MathExpressionInteractionsViewModel
lateinit var writtenTranslationContext: WrittenTranslationContext

Expand Down Expand Up @@ -103,7 +96,6 @@ class InputInteractionViewTestActivity :
}

binding.numericInputViewModel = numericInputViewModel
binding.textInputViewModel = textInputViewModel
binding.mathExpressionInteractionsViewModel = mathExpressionViewModel
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.oppia.android.app.testing

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.TextInputInteractionView
import org.oppia.android.app.model.Interaction
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.StateItemViewModel
import org.oppia.android.app.player.state.itemviewmodel.TextInputViewModel
import org.oppia.android.app.player.state.listener.StateKeyboardButtonListener
import org.oppia.android.databinding.ActivityTextInputInteractionViewTestBinding
import javax.inject.Inject

/**
* This is a dummy activity to test input interaction views.
* It contains [TextInputInteractionView]
*/
class TextInputInteractionViewTestActivity :
InjectableAutoLocalizedAppCompatActivity(),
StateKeyboardButtonListener,
InteractionAnswerErrorOrAvailabilityCheckReceiver,
InteractionAnswerReceiver {

private lateinit var binding: ActivityTextInputInteractionViewTestBinding

@Inject
lateinit var textinputViewModelFactory: TextInputViewModel.FactoryImpl

/** Gives access to the [TextInputViewModel]. */
val textInputViewModel by lazy {
textinputViewModelFactory.create<TextInputViewModel>()
}

/** 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_text_input_interaction_view_test
)

writtenTranslationContext = WrittenTranslationContext.getDefaultInstance()
binding.textInputViewModel = textInputViewModel
}

/** Checks submit-time errors. */
fun getPendingAnswerErrorOnSubmitClick(v: View) {
textInputViewModel.checkPendingAnswerError(AnswerErrorCategory.SUBMIT_TIME)
}

override fun onPendingAnswerErrorOrAvailabilityCheck(
pendingAnswerError: String?,
inputAnswerAvailable: Boolean
) {
}

override fun onAnswerReadyForSubmission(answer: UserAnswer) {
}

override fun onEditorAction(actionCode: Int) {
}

private inline fun <reified T : StateItemViewModel>
StateItemViewModel.InteractionItemFactory.create(
interaction: Interaction = Interaction.getDefaultInstance()
): T {
return create(
entityId = "fake_entity_id",
hasConversationView = false,
interaction = interaction,
interactionAnswerReceiver = this@TextInputInteractionViewTestActivity,
answerErrorReceiver = this@TextInputInteractionViewTestActivity,
hasPreviousButton = false,
isSplitView = false,
writtenTranslationContext,
timeToStartNoticeAnimationMs = null
) as T
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@
name="numericInputViewModel"
type="org.oppia.android.app.player.state.itemviewmodel.NumericInputViewModel" />

<variable
name="textInputViewModel"
type="org.oppia.android.app.player.state.itemviewmodel.TextInputViewModel" />

<variable
name="mathExpressionInteractionsViewModel"
type="org.oppia.android.app.player.state.itemviewmodel.MathExpressionInteractionsViewModel" />
Expand All @@ -23,6 +19,7 @@
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand All @@ -36,18 +33,18 @@
android:id="@+id/test_number_input_interaction_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:layout_margin="8dp"
android:background="@drawable/edit_text_background"
android:focusable="true"
android:hint="@string/test_number_input_interaction_hint"
android:textColor="@color/component_color_shared_primary_text_color"
android:textColorHint="@color/component_color_shared_edit_text_hint_color"
android:longClickable="false"
android:maxLength="200"
android:minHeight="48dp"
android:padding="8dp"
android:singleLine="true"
android:text="@={numericInputViewModel.answerText}"
android:textColor="@color/component_color_shared_primary_text_color"
android:textColorHint="@color/component_color_shared_edit_text_hint_color"
app:textChangedListener="@{numericInputViewModel.answerTextWatcher}" />

<TextView
Expand All @@ -64,33 +61,17 @@
android:textSize="12sp"
android:visibility="@{numericInputViewModel.errorMessage.length() > 0 ? View.VISIBLE : View.INVISIBLE}" />

<org.oppia.android.app.customview.interaction.TextInputInteractionView
android:id="@+id/test_text_input_interaction_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:layout_margin="8dp"
android:background="@drawable/edit_text_background"
android:focusable="true"
android:hint="@string/test_text_input_interaction_hint"
android:inputType="text"
android:longClickable="false"
android:maxLength="200"
android:padding="8dp"
android:singleLine="true"
android:text="@={textInputViewModel.answerText}" />

<org.oppia.android.app.customview.interaction.MathExpressionInteractionsView
android:id="@+id/test_math_expression_input_interaction_view"
style="@style/InputInteractionEditText"
android:minHeight="48dp"
app:placeholder="@{mathExpressionInteractionsViewModel.hintText}"
android:inputType="text"
android:minHeight="48dp"
android:text="@={mathExpressionInteractionsViewModel.answerText}"
app:textChangedListener="@{mathExpressionInteractionsViewModel.answerTextWatcher}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
app:layout_constraintTop_toTopOf="parent"
app:placeholder="@{mathExpressionInteractionsViewModel.hintText}"
app:textChangedListener="@{mathExpressionInteractionsViewModel.answerTextWatcher}" />

<Button
android:id="@+id/submit_button"
Expand Down
Loading
Loading