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

OptionExclusive extension support. #1284

Merged
merged 6 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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 @@ -29,10 +29,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.android.fhir.datacapture.ChoiceOrientationTypes
import com.google.android.fhir.datacapture.EXTENSION_CHOICE_ORIENTATION_URL
import com.google.android.fhir.datacapture.EXTENSION_OPTION_EXCLUSIVE_URL
import com.google.android.fhir.datacapture.R
import com.google.common.truth.Truth.assertThat
import org.hl7.fhir.r4.model.BooleanType
import org.hl7.fhir.r4.model.CodeType
import org.hl7.fhir.r4.model.Coding
import org.hl7.fhir.r4.model.Extension
import org.hl7.fhir.r4.model.Questionnaire
import org.hl7.fhir.r4.model.QuestionnaireResponse
import org.junit.Test
Expand Down Expand Up @@ -254,6 +257,85 @@ class QuestionnaireItemCheckBoxGroupViewHolderFactoryInstrumentedTest {
assertThat(answer[0].valueCoding.display).isEqualTo("Coding 1")
}

@Test
@UiThreadTest
fun optionExclusiveAnswerOption_click_deselectsOtherAnswerOptions() {
val questionnaireItemViewItem =
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply {
repeats = true
addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value =
Coding().apply {
code = "code-1"
display = "display-1"
}
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
}
)
addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value =
Coding().apply {
code = "code-2"
display = "display-2"
}
}
)
},
QuestionnaireResponse.QuestionnaireResponseItemComponent()
) {}
viewHolder.bind(questionnaireItemViewItem)
val checkBoxGroup = viewHolder.itemView.findViewById<ConstraintLayout>(R.id.checkbox_group)
(checkBoxGroup.getChildAt(2) as CheckBox).performClick()
(checkBoxGroup.getChildAt(1) as CheckBox).performClick()
val answer = questionnaireItemViewItem.questionnaireResponseItem.answer

assertThat(answer).hasSize(1)
assertThat(answer[0].valueCoding.display).isEqualTo("display-1")
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
}

@Test
@UiThreadTest
fun answerOption_click_deselectsOptionExclusiveAnswerOption() {
val questionnaireItemViewItem =
QuestionnaireItemViewItem(
Questionnaire.QuestionnaireItemComponent().apply {
repeats = true
addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value =
Coding().apply {
code = "code-1"
display = "display-1"
}
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
}
)
addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value =
Coding().apply {
code = "code-2"
display = "display-2"
}
}
)
},
QuestionnaireResponse.QuestionnaireResponseItemComponent()
) {}

viewHolder.bind(questionnaireItemViewItem)
val checkBoxGroup = viewHolder.itemView.findViewById<ConstraintLayout>(R.id.checkbox_group)
(checkBoxGroup.getChildAt(1) as CheckBox).performClick()
(checkBoxGroup.getChildAt(2) as CheckBox).performClick()
val answer = questionnaireItemViewItem.questionnaireResponseItem.answer

assertThat(answer).hasSize(1)
assertThat(answer[0].valueCoding.display).isEqualTo("display-2")
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
}

@Test
@UiThreadTest
fun click_shouldRemoveQuestionnaireResponseItemAnswer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@
package com.google.android.fhir.datacapture

import com.google.android.fhir.getLocalizedText
import org.hl7.fhir.r4.model.BooleanType
import org.hl7.fhir.r4.model.Questionnaire

internal const val EXTENSION_OPTION_EXCLUSIVE_URL =
"http://hl7.org/fhir/StructureDefinition/questionnaire-optionExclusive"

val Questionnaire.QuestionnaireItemAnswerOptionComponent.displayString: String
get() {
if (!hasValueCoding()) {
Expand All @@ -31,3 +35,15 @@ val Questionnaire.QuestionnaireItemAnswerOptionComponent.displayString: String
display
}
}

/** Indicates that if this answerOption is selected, no other possible answers may be selected. */
internal val Questionnaire.QuestionnaireItemAnswerOptionComponent.optionExclusive: Boolean
get() {
val extension =
this.extension.singleOrNull { it.url == EXTENSION_OPTION_EXCLUSIVE_URL } ?: return false
val value = extension.value
if (value is BooleanType) {
return value.booleanValue()
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.choiceOrientation
import com.google.android.fhir.datacapture.localizedPrefixSpanned
import com.google.android.fhir.datacapture.localizedTextSpanned
import com.google.android.fhir.datacapture.optionExclusive
import com.google.android.fhir.datacapture.subtitleText
import com.google.android.fhir.datacapture.validation.ValidationResult
import com.google.android.fhir.datacapture.validation.getSingleStringValidationMessage
Expand Down Expand Up @@ -124,18 +125,49 @@ internal object QuestionnaireItemCheckBoxGroupViewHolderFactory :
)
setOnClickListener {
when (isChecked) {
true ->
true -> {
questionnaireItemViewItem.addAnswer(
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
value = answerOption.value
}
)
false ->
if (answerOption.optionExclusive) {
// if this answer option has optionExclusive extension, then deselect other
// answer options.
val optionExclusiveIndex = checkboxGroup.indexOfChild(it) - 1
for (i in 0 until questionnaireItemViewItem.answerOption.size) {
if (optionExclusiveIndex == i) {
continue
}
(checkboxGroup.getChildAt(i + 1) as CheckBox).isChecked = false
questionnaireItemViewItem.removeAnswer(
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
value = questionnaireItemViewItem.answerOption[i].value
}
)
}
} else {
// deselect optionExclusive answer option.
for (i in 0 until questionnaireItemViewItem.answerOption.size) {
if (!questionnaireItemViewItem.answerOption[i].optionExclusive) {
continue
}
(checkboxGroup.getChildAt(i + 1) as CheckBox).isChecked = false
questionnaireItemViewItem.removeAnswer(
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
value = questionnaireItemViewItem.answerOption[i].value
}
)
}
}
}
false -> {
questionnaireItemViewItem.removeAnswer(
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
value = answerOption.value
}
)
}
}

onAnswerChanged(checkboxGroup.context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import android.os.Build
import com.google.common.truth.Truth.assertThat
import java.util.Locale
import kotlin.test.assertFailsWith
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.BooleanType
import org.hl7.fhir.r4.model.Coding
import org.hl7.fhir.r4.model.Extension
import org.hl7.fhir.r4.model.Questionnaire
Expand Down Expand Up @@ -102,4 +104,25 @@ class MoreAnswerOptionsTest {

assertThat(answerOption.displayString).isEqualTo("Test Code")
}

@Test
fun optionExclusiveExtension_valueTrue_returnsTrue() = runBlocking {
val answerOptionTest = Coding("test", "option", "1")
val questionnaire =
Questionnaire().apply {
id = "a-questionnaire"
addItem(
Questionnaire.QuestionnaireItemComponent().apply {
answerOption =
listOf(
Questionnaire.QuestionnaireItemAnswerOptionComponent(answerOptionTest).apply {
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
)
}
)
}

assertThat(questionnaire.item[0].answerOption[0].optionExclusive).isTrue()
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
}
}