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

1001 fix form validation opensrp #4

Draft
wants to merge 84 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
3b79082
[1001] removed validation from bind
aurangzaibumer Feb 1, 2022
eeaa485
issue [1001] removed validation from bind view of list
aurangzaibumer Feb 2, 2022
1b676ac
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Feb 2, 2022
1b27b55
spotless ran
aurangzaibumer Feb 2, 2022
03799de
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Feb 2, 2022
40ba1f8
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Feb 8, 2022
978e205
added new implementation and fixed test cases
aurangzaibumer Feb 8, 2022
85f97f4
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Feb 8, 2022
4be9813
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Feb 8, 2022
38db22d
implementation changed
aurangzaibumer Feb 15, 2022
5851824
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Feb 15, 2022
49f66bf
test case fixed
aurangzaibumer Feb 21, 2022
36cc9e3
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Feb 21, 2022
4952c7c
spotless checks fixed
aurangzaibumer Feb 21, 2022
3cee530
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Feb 21, 2022
505cc9d
test case fixed
aurangzaibumer Feb 21, 2022
c2c48ba
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Feb 22, 2022
1d5a948
test case fixed
aurangzaibumer Feb 22, 2022
0434601
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Feb 23, 2022
c5c7d67
Merge branch 'master' into 1001-fix-form-validation
f-odhiambo Feb 24, 2022
a2ebd24
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Feb 25, 2022
c956902
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Feb 25, 2022
25de7e8
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Feb 25, 2022
91c020d
WIP validation
aurangzaibumer Feb 25, 2022
a8ebdb9
wip
jingtang10 Feb 25, 2022
20d1813
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 1, 2022
dd74225
completed discussed changes on request validator
aurangzaibumer Mar 1, 2022
a54d569
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 1, 2022
b4bfd9d
test cases fixed
aurangzaibumer Mar 2, 2022
4659f24
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Mar 2, 2022
1c004fd
test cases WIP
aurangzaibumer Mar 3, 2022
37719fd
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 3, 2022
3c83c2c
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Mar 4, 2022
7bc27ce
replaced test cases
aurangzaibumer Mar 7, 2022
63ea04a
fixed typo
aurangzaibumer Mar 7, 2022
1af781b
spotless fixes
aurangzaibumer Mar 7, 2022
fb44b2f
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 10, 2022
6bb5532
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 10, 2022
6d2354f
Merge branch 'master' into 1001-fix-form-validation
f-odhiambo Mar 15, 2022
bfea5c1
resolving PR comments
aurangzaibumer Mar 16, 2022
a2befbb
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 16, 2022
9e8a3f1
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 16, 2022
54b9088
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Mar 16, 2022
81e29b0
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 21, 2022
c3561bc
Merge branch 'master' into 1001-fix-form-validation
ndegwamartin Mar 29, 2022
c8ba3c1
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
aurangzaibumer Mar 29, 2022
1697499
Merge branch 'master' into 1001-fix-form-validation
f-odhiambo Mar 30, 2022
d94bbdb
feedback incorporated
aurangzaibumer Mar 30, 2022
ae03e42
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Mar 30, 2022
63dfbb8
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 30, 2022
ffc55cb
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 30, 2022
247799f
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Mar 31, 2022
cac0227
feedback incorporated for RequiredConstraintValidator
aurangzaibumer Apr 5, 2022
f17f193
feedback incorporated for test cases name
aurangzaibumer Apr 5, 2022
a1b2c2c
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Apr 5, 2022
3249e92
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 5, 2022
c22e5ae
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 5, 2022
d440ada
feedback incorporated for RequiredConstraintValidator
aurangzaibumer Apr 6, 2022
522e807
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 6, 2022
f3b29f9
added new test cases on QuestionnaireItemAutoCompleteViewHolderFactor…
aurangzaibumer Apr 6, 2022
099c080
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Apr 6, 2022
81d3b5f
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 6, 2022
89ff01e
Update datacapture/src/test/java/com/google/android/fhir/datacapture/…
aurangzaibumer Apr 6, 2022
b9c1384
PR feedback incorporated related to test cases
aurangzaibumer Apr 6, 2022
3bc8479
Update datacapture/src/androidTest/java/com/google/android/fhir/datac…
aurangzaibumer Apr 6, 2022
0879578
PR feedback incorporated related to test cases
aurangzaibumer Apr 6, 2022
938647c
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 8, 2022
8387ff6
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 8, 2022
5ffb60b
Merge branch '1001-fix-form-validation' of https://github.com/google/…
aurangzaibumer Apr 11, 2022
2485a34
restrict triggering validation when form opens
aurangzaibumer Apr 19, 2022
a967e93
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 19, 2022
313066e
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 19, 2022
aff6cab
implementation updated on ViewHolderFactory and fixed test cases
aurangzaibumer Apr 20, 2022
d1ddeef
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 20, 2022
a797c65
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 21, 2022
d2d4a68
some test cases added
aurangzaibumer Apr 21, 2022
096b64e
docs added for the newly changes
aurangzaibumer Apr 22, 2022
081750e
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 22, 2022
3ce477d
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 25, 2022
ce33159
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer Apr 26, 2022
85a9fbb
Merge branch 'master' into 1001-fix-form-validation
aurangzaibumer May 6, 2022
46579e4
PR feedback incorporated
aurangzaibumer May 9, 2022
d7e1e61
test cases updated
aurangzaibumer May 9, 2022
3776080
Merge pull request #3 from aurangzaibumer/1001-fix-form-validation
ndegwamartin May 10, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ internal object RequiredConstraintValidator : ConstraintValidator {
questionnaireResponseItem: QuestionnaireResponse.QuestionnaireResponseItemComponent,
context: Context
): ConstraintValidator.ConstraintValidationResult {
if (questionnaireItem.required && questionnaireResponseItem.answer.isEmpty()) {
return ConstraintValidator.ConstraintValidationResult(
false,
context.getString(R.string.required_constraint_validation_error_msg)
)
if (!questionnaireItem.required || questionnaireResponseItem.answer.any { it.hasValue() }) {
return ConstraintValidator.ConstraintValidationResult(true, null)
}
return ConstraintValidator.ConstraintValidationResult(true, null)
return ConstraintValidator.ConstraintValidationResult(
false,
context.getString(R.string.required_constraint_validation_error_msg)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,8 @@ internal class QuestionnaireItemEditTextStringViewHolderDelegate(isSingleLine: B
override fun getValue(
text: String
): QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent? {
return text.let {
if (it.isEmpty()) {
null
} else {
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().setValue(StringType(it))
}
}
return QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent()
.setValue(StringType(text))
}

override fun getText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.google.android.fhir.datacapture.views

import android.content.Context
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.View.FOCUS_DOWN
import android.view.inputmethod.EditorInfo
Expand Down Expand Up @@ -45,23 +46,30 @@ internal abstract class QuestionnaireItemEditTextViewHolderDelegate(
private lateinit var textInputLayout: TextInputLayout
private lateinit var textInputEditText: TextInputEditText
override lateinit var questionnaireItemViewItem: QuestionnaireItemViewItem
private var textWatcher: TextWatcher? = null

override fun init(itemView: View) {
header = itemView.findViewById(R.id.header)
textInputLayout = itemView.findViewById(R.id.text_input_layout)
textInputEditText = itemView.findViewById(R.id.text_input_edit_text)
textInputEditText.setRawInputType(rawInputType)
textInputEditText.isSingleLine = isSingleLine
textInputEditText.doAfterTextChanged { editable: Editable? ->
questionnaireItemViewItem.singleAnswerOrNull = getValue(editable.toString())
onAnswerChanged(textInputEditText.context)
}
}

override fun bind(questionnaireItemViewItem: QuestionnaireItemViewItem) {
header.bind(questionnaireItemViewItem.questionnaireItem)
textInputLayout.hint = questionnaireItemViewItem.questionnaireItem.localizedFlyoverSpanned
textInputEditText.setText(getText(questionnaireItemViewItem.singleAnswerOrNull))
textInputEditText.removeTextChangedListener(textWatcher)

val answer = questionnaireItemViewItem.singleAnswerOrNull
if (answer == null) {
// Clear the text input and any error message if the question has not been answered.
textInputEditText.setText("")
displayValidationResult(ValidationResult(true, listOf()))
} else {
textInputEditText.setText(getText(answer))
onAnswerChanged(textInputEditText.context)
}
textInputEditText.setOnFocusChangeListener { view, focused ->
if (!focused) {
(view.context.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE) as
Expand All @@ -79,6 +87,11 @@ internal abstract class QuestionnaireItemEditTextViewHolderDelegate(
}
view.focusSearch(FOCUS_DOWN)?.requestFocus(FOCUS_DOWN) ?: false
}
textWatcher =
textInputEditText.doAfterTextChanged { editable: Editable? ->
questionnaireItemViewItem.singleAnswerOrNull = getValue(editable.toString())
onAnswerChanged(textInputEditText.context)
}
}

override fun displayValidationResult(validationResult: ValidationResult) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,16 @@ open class QuestionnaireItemViewHolder(
delegate.questionnaireItemViewItem = questionnaireItemViewItem
delegate.bind(questionnaireItemViewItem)
delegate.setReadOnly(questionnaireItemViewItem.questionnaireItem.readOnly)
delegate.displayValidationResult(delegate.getValidationResult(itemView.context))
// Only validate questionnaire items with answer(s). This is so that we do not show all the
// validation errors at once when the user opens a new questionnaire for the first time.
// Instead, the validation errors are shown when the user goes through each question.
// Notice the difference between a questionnaire response item without answer, and a
// questionnaire with an answer without value.
if (delegate.questionnaireItemViewItem.modified ||
delegate.questionnaireItemViewItem.questionnaireResponseItem.answer.size > 0
) {
delegate.displayValidationResult(delegate.getValidationResult(itemView.context))
}
}
}

Expand Down Expand Up @@ -101,6 +110,9 @@ interface QuestionnaireItemViewHolderDelegate {
*/
fun onAnswerChanged(context: Context) {
questionnaireItemViewItem.questionnaireResponseItemChangedCallback()
// purpose of this field is to let the validation execute ( if the answer has been added, this
// tells that the User has made an interaction to that particular input field
questionnaireItemViewItem.modified = true
displayValidationResult(getValidationResult(context))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ import org.hl7.fhir.r4.model.QuestionnaireResponse
* @param questionnaireResponseItemChangedCallback function that should be called whenever the
* `questionnaireResponseItemBuilder` is changed to inform the rest of the questionnaire to be
* updated
*
* @param modified True once user has interacted with the questionnaire item (when `onAnswerChanged`
* triggers). Only modified fields will be validated. This is to avoid an influx of validation
* errors when the user first opens the questionnaire.
*/
data class QuestionnaireItemViewItem(
val questionnaireItem: Questionnaire.QuestionnaireItemComponent,
Expand All @@ -44,6 +48,7 @@ data class QuestionnaireItemViewItem(
{
emptyList()
},
var modified: Boolean = false,
val questionnaireResponseItemChangedCallback: () -> Unit
) {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,25 @@ class RequiredConstraintValidatorTest {
assertThat(validationResult.isValid).isFalse()
assertThat(validationResult.message).isEqualTo("Missing answer for required field.")
}

@Test
fun shouldReturnInvalidResult_noAnswerHasValue() {
val questionnaireItem = Questionnaire.QuestionnaireItemComponent().apply { required = true }
val questionnaireResponseItem =
QuestionnaireResponse.QuestionnaireResponseItemComponent().apply {
// one answer with no value
addAnswer(QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent())
// second answer with no value
addAnswer(QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent())
}

val validationResult =
RequiredConstraintValidator.validate(
questionnaireItem,
questionnaireResponseItem,
InstrumentationRegistry.getInstrumentation().context
)
assertThat(validationResult.isValid).isFalse()
assertThat(validationResult.message).isEqualTo("Missing answer for required field.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ package com.google.android.fhir.datacapture.views
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import androidx.core.view.children
import androidx.core.view.get
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.displayString
import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputLayout
import com.google.common.truth.Truth.assertThat
import org.hl7.fhir.r4.model.Coding
Expand Down Expand Up @@ -162,14 +164,44 @@ class QuestionnaireItemAutoCompleteViewHolderFactoryInstrumentedTest {
viewHolder.bind(
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply { required = true },
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

assertThat(viewHolder.itemView.findViewById<TextInputLayout>(R.id.text_input_layout).error)
.isEqualTo("Missing answer for required field.")
}

@Test
fun displayValidationResult_showErrorWhenAnswersAreRemoved() {
val questionnaire =
Questionnaire.QuestionnaireItemComponent().apply {
required = true
addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "display" }
}
)
}
val questionnaireResponseWithAnswer =
QuestionnaireResponse.QuestionnaireResponseItemComponent().apply {
addAnswer(
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
value = Coding().apply { display = "display" }
}
)
}

viewHolder.bind(QuestionnaireItemViewItem(questionnaire, questionnaireResponseWithAnswer) {})

(viewHolder.itemView.findViewById<ViewGroup>(R.id.flexboxLayout).children.first() as Chip)
.performCloseIconClick()

assertThat(viewHolder.itemView.findViewById<TextInputLayout>(R.id.text_input_layout).error)
.isEqualTo("Missing answer for required field.")
}

@Test
fun displayValidationResult_noError_shouldShowNoErrorMessage() {
viewHolder.bind(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ class QuestionnaireItemBooleanTypePickerViewHolderFactoryTest {
viewHolder.bind(
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply { required = true },
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ class QuestionnaireItemCheckBoxGroupViewHolderFactoryTest {
repeats = true
required = true
},
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ class QuestionnaireItemDateTimePickerViewHolderFactoryTest {
viewHolder.bind(
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply { required = true },
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ class QuestionnaireItemDropDownViewHolderFactoryTest {
viewHolder.bind(
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply { required = true },
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ class QuestionnaireItemEditTextMultiLineViewHolderFactoryTest {
) {}

viewHolder.bind(questionnaireItemViewItem)
viewHolder.itemView.findViewById<TextInputEditText>(R.id.text_input_edit_text).setText("")

assertThat(questionnaireItemViewItem.questionnaireResponseItem.answer.size).isEqualTo(0)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ class QuestionnaireItemEditTextQuantityViewHolderFactoryTest {
viewHolder.bind(
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply { required = true },
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ class QuestionnaireItemEditTextSingleLineViewHolderFactoryTest {
) {}

viewHolder.bind(questionnaireItemViewItem)
viewHolder.itemView.findViewById<TextInputEditText>(R.id.text_input_edit_text).setText("")

assertThat(questionnaireItemViewItem.questionnaireResponseItem.answer.size).isEqualTo(0)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class QuestionnaireItemGroupViewHolderFactoryTest {
viewHolder.bind(
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply { required = true },
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ class QuestionnaireItemRadioGroupViewHolderFactoryTest {
viewHolder.bind(
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply { required = true },
QuestionnaireResponse.QuestionnaireResponseItemComponent()
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
modified = true
) {}
)

Expand Down
68 changes: 68 additions & 0 deletions demo/src/main/assets/new-patient-registration-paginated.json
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,74 @@
}
]
}
},
{
"type": "choice",
"repeats": true,
"code": [],
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/questionnaire-item-control",
"code": "autocomplete",
"display": "Auto-complete"
}
],
"text": "Auto-complete"
}
}
],
"required": true,
"linkId": "4",
"text": "Do you have any existing conditions",
"prefix": "Q4:",
"answerOption": [
{
"valueCoding": {
"code": "asthma",
"display": "Asthma"
}
},
{
"valueCoding": {
"code": "copd",
"display": "Chronic Lung Disease"
}
},
{
"valueCoding": {
"code": "depression",
"display": "Depression"
}
},
{
"valueCoding": {
"code": "t2dm",
"display": "Diabetes"
}
},
{
"valueCoding": {
"code": "hypertension",
"display": "Hypertension"
}
},
{
"valueCoding": {
"code": "hypertension",
"display": "High Blood Pressure"
}
},
{
"valueCoding": {
"code": "hypercholesterolaemia",
"display": "High Cholesterol"
}
}
]
}
]
}
Expand Down