Skip to content

Commit

Permalink
Nested display item text as subtitle text. (google#1222)
Browse files Browse the repository at this point in the history
* nested display questionnaire item text as subtitle text for parent question item except group type.

* Nested display item as subtitle text for parent questionnaire item.

* Address review comments.
  • Loading branch information
santosh-pingle committed Mar 10, 2022
1 parent 7597789 commit 482847c
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 4 deletions.
9 changes: 8 additions & 1 deletion catalog/src/main/assets/boolean_choice_questionnaire.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
{
"linkId": "1",
"text": "Have you taken a pregnancy test?",
"type": "boolean"
"type": "boolean",
"item": [
{
"linkId": "1-select-one",
"text": "Select one",
"type": "display"
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.google.android.fhir.datacapture

import android.text.Html.FROM_HTML_MODE_COMPACT
import android.text.Spanned
import androidx.core.text.HtmlCompat
import com.google.android.fhir.getLocalizedText
Expand Down Expand Up @@ -154,6 +153,18 @@ fun Questionnaire.QuestionnaireItemComponent.createQuestionnaireResponseItem():
}
}

/**
* A nested questionnaire item of type display (if present) is used as the subtitle of the parent
* question.
*/
internal val Questionnaire.QuestionnaireItemComponent.subtitleText: Spanned?
get() =
item
.firstOrNull { questionnaireItem ->
questionnaireItem.type == Questionnaire.QuestionnaireItemType.DISPLAY
}
?.localizedTextSpanned

/**
* Returns a list of answers from the initial values of the questionnaire item. `null` if no intial
* value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,18 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
) { questionnaireResponseItemChangedCallback(questionnaireItem.linkId) }
) +
getQuestionnaireState(
questionnaireItemList = questionnaireItem.item,
// Nested display item is subtitle text for parent questionnaire item if data type
// is not group.
// If nested display item is identified as subtitle text, then do not create
// questionnaire state for it.
questionnaireItemList =
when (questionnaireItem.type) {
Questionnaire.QuestionnaireItemType.GROUP -> questionnaireItem.item
else ->
questionnaireItem.item.filterNot {
it.type == Questionnaire.QuestionnaireItemType.DISPLAY
}
},
questionnaireResponseItemList =
if (questionnaireResponseItem.answer.isEmpty()) {
questionnaireResponseItem.item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import android.widget.TextView
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.localizedPrefixSpanned
import com.google.android.fhir.datacapture.localizedTextSpanned
import com.google.android.fhir.datacapture.subtitleText
import com.google.android.fhir.datacapture.validation.ValidationResult
import com.google.android.fhir.datacapture.validation.getSingleStringValidationMessage
import org.hl7.fhir.r4.model.BooleanType
Expand All @@ -34,6 +35,7 @@ internal object QuestionnaireItemBooleanTypePickerViewHolderFactory :
object : QuestionnaireItemViewHolderDelegate {
private lateinit var prefixTextView: TextView
private lateinit var questionTextView: TextView
private lateinit var questionSubTextView: TextView
private lateinit var radioGroup: RadioGroup
private lateinit var yesRadioButton: RadioButton
private lateinit var noRadioButton: RadioButton
Expand All @@ -44,6 +46,7 @@ internal object QuestionnaireItemBooleanTypePickerViewHolderFactory :
override fun init(itemView: View) {
prefixTextView = itemView.findViewById(R.id.prefix_text_view)
questionTextView = itemView.findViewById(R.id.question_text_view)
questionSubTextView = itemView.findViewById(R.id.subtitle_text_view)
radioGroup = itemView.findViewById(R.id.radio_group)
yesRadioButton = itemView.findViewById(R.id.yes_radio_button)
noRadioButton = itemView.findViewById(R.id.no_radio_button)
Expand All @@ -54,6 +57,7 @@ internal object QuestionnaireItemBooleanTypePickerViewHolderFactory :
this.questionnaireItemViewItem = questionnaireItemViewItem
val (questionnaireItem, questionnaireResponseItem) = questionnaireItemViewItem
questionTextView.text = questionnaireItem.localizedTextSpanned
questionSubTextView.text = questionnaireItem.subtitleText

if (!questionnaireItem.prefix.isNullOrEmpty()) {
prefixTextView.visibility = View.VISIBLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

</LinearLayout>
<TextView
style="?attr/subtitleTextAppearanceQuestionnaire"
android:id="@+id/subtitle_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

<RadioGroup
android:id="@+id/radio_group"
Expand Down
1 change: 1 addition & 0 deletions datacapture/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<resources>
<attr name="groupHeaderTextAppearanceQuestionnaire" format="reference" />
<attr name="headerTextAppearanceQuestionnaire" format="reference" />
<attr name="subtitleTextAppearanceQuestionnaire" format="reference" />
<attr name="checkBoxStyleQuestionnaire" format="reference" />
<attr name="radioButtonStyleQuestionnaire" format="reference" />
<attr name="dropDownTextAppearanceQuestionnaire" format="reference" />
Expand Down
3 changes: 3 additions & 0 deletions datacapture/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
<item
name="headerTextAppearanceQuestionnaire"
>@style/TextAppearance.MaterialComponents.Body2</item>
<item
name="subtitleTextAppearanceQuestionnaire"
>@style/TextAppearance.MaterialComponents.Body2</item>
<item
name="checkBoxStyleQuestionnaire"
>@style/Questionnaire.Widget.MaterialComponents.CompoundButton.CheckBox
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,26 @@ class MoreQuestionnaireItemComponentsTest {
)
.isEqualTo(true)
}

@Test
fun subtitleText_nestedDisplayItemPresent_returnsNestedDisplayText() {
val questionItemList =
listOf(
Questionnaire.QuestionnaireItemComponent().apply {
linkId = "parent-question"
text = "parent question text"
type = Questionnaire.QuestionnaireItemType.BOOLEAN
item =
listOf(
Questionnaire.QuestionnaireItemComponent().apply {
linkId = "nested-display-question"
text = "subtitle text"
type = Questionnaire.QuestionnaireItemType.DISPLAY
}
)
}
)

assertThat(questionItemList.first().subtitleText.toString()).isEqualTo("subtitle text")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,65 @@ class QuestionnaireViewModelTest(private val questionnaireSource: QuestionnaireS
)
}

@Test
fun nestedDisplayItem_parentQuestionItemIsGroup_createQuestionnaireStateItem() = runBlocking {
val questionnaire =
Questionnaire().apply {
id = "a-questionnaire"
addItem(
Questionnaire.QuestionnaireItemComponent().apply {
linkId = "parent-question"
text = "parent question text"
type = Questionnaire.QuestionnaireItemType.GROUP
item =
listOf(
Questionnaire.QuestionnaireItemComponent().apply {
linkId = "nested-display-question"
text = "subtitle text"
type = Questionnaire.QuestionnaireItemType.DISPLAY
}
)
}
)
}
state.set(EXTRA_QUESTIONNAIRE_JSON_STRING, printer.encodeResourceToString(questionnaire))

val viewModel = QuestionnaireViewModel(context, state)

assertThat(viewModel.getQuestionnaireItemViewItemList().last().questionnaireResponseItem.linkId)
.isEqualTo("nested-display-question")
}

@Test
fun nestedDisplayItem_parentQuestionItemIsNotGroup_doesNotcreateQuestionnaireStateItem() =
runBlocking {
val questionnaire =
Questionnaire().apply {
id = "a-questionnaire"
addItem(
Questionnaire.QuestionnaireItemComponent().apply {
linkId = "parent-question"
text = "parent question text"
type = Questionnaire.QuestionnaireItemType.BOOLEAN
item =
listOf(
Questionnaire.QuestionnaireItemComponent().apply {
linkId = "nested-display-question"
text = "subtitle text"
type = Questionnaire.QuestionnaireItemType.DISPLAY
}
)
}
)
}
state.set(EXTRA_QUESTIONNAIRE_JSON_STRING, printer.encodeResourceToString(questionnaire))

val viewModel = QuestionnaireViewModel(context, state)

assertThat(viewModel.getQuestionnaireItemViewItemList().last().questionnaireResponseItem.linkId)
.isEqualTo("parent-question")
}

private fun createQuestionnaireViewModel(
questionnaire: Questionnaire,
response: QuestionnaireResponse? = null
Expand Down

0 comments on commit 482847c

Please sign in to comment.