Skip to content

Commit

Permalink
Add Reference class to display string function (#1740)
Browse files Browse the repository at this point in the history
  • Loading branch information
omarismail94 committed Jan 3, 2023
1 parent 991102d commit 1b08b55
Show file tree
Hide file tree
Showing 15 changed files with 242 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,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.Coding
import org.hl7.fhir.r4.model.DateType
import org.hl7.fhir.r4.model.IntegerType
import org.hl7.fhir.r4.model.Questionnaire
import org.hl7.fhir.r4.model.Reference
import org.hl7.fhir.r4.model.StringType
import org.hl7.fhir.r4.model.TimeType

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

/**
* Text value for answer option [Questionnaire.QuestionnaireItemAnswerOptionComponent] if answer
* option is [IntegerType], [StringType], [Coding], or [Reference] type.
*/
internal val Questionnaire.QuestionnaireItemAnswerOptionComponent.displayString: String
get() {
return when (value) {
is IntegerType,
is DateType,
is TimeType -> value.primitiveValue()
is StringType -> (value as StringType).getLocalizedText() ?: value.toString()
is Reference -> valueReference.display ?: valueReference.reference
is Coding -> {
val display = valueCoding.displayElement.getLocalizedText() ?: valueCoding.display
if (display.isNullOrEmpty()) {
valueCoding.code
} else {
display
}
}
else -> throw IllegalArgumentException("$value is not supported.")
}
}

/** Indicates that if this answerOption is selected, no other possible answers may be selected. */
internal val Questionnaire.QuestionnaireItemAnswerOptionComponent.optionExclusive: Boolean
get() {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.datacapture

import org.hl7.fhir.r4.model.QuestionnaireResponse
import org.hl7.fhir.r4.model.Type

internal fun List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>
.hasDifferentAnswerSet(answers: List<Type>) =
this.size != answers.size ||
this.map { it.value }.zip(answers).any { (v1, v2) -> v1.equalsDeep(v2).not() }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Google LLC
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,8 +16,29 @@

package com.google.android.fhir.datacapture.common.datatype

import android.content.Context
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.utilities.localizedString
import com.google.android.fhir.datacapture.utilities.toLocalizedString
import com.google.android.fhir.datacapture.views.localDate
import com.google.android.fhir.datacapture.views.localTime
import com.google.android.fhir.getLocalizedText
import org.hl7.fhir.r4.model.Attachment
import org.hl7.fhir.r4.model.BooleanType
import org.hl7.fhir.r4.model.Coding
import org.hl7.fhir.r4.model.DateTimeType
import org.hl7.fhir.r4.model.DateType
import org.hl7.fhir.r4.model.DecimalType
import org.hl7.fhir.r4.model.IntegerType
import org.hl7.fhir.r4.model.PrimitiveType
import org.hl7.fhir.r4.model.Quantity
import org.hl7.fhir.r4.model.Questionnaire
import org.hl7.fhir.r4.model.QuestionnaireResponse
import org.hl7.fhir.r4.model.Reference
import org.hl7.fhir.r4.model.StringType
import org.hl7.fhir.r4.model.TimeType
import org.hl7.fhir.r4.model.Type
import org.hl7.fhir.r4.model.UriType

/**
* Returns the string representation of a [PrimitiveType].
Expand All @@ -28,3 +49,46 @@ fun Type.asStringValue(): String {
if (!isPrimitive) return ""
return (this as PrimitiveType<*>).asStringValue()
}

/**
* Returns what to display on the UI depending on the [Type]. Used to get the display representation
* for response item answer options such as
* [QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent] or
* [Questionnaire.QuestionnaireItemAnswerOptionComponent].
*/
fun Type.displayString(context: Context): String =
when (this) {
is Attachment -> this.url ?: context.getString(R.string.not_answered)
is BooleanType -> {
when (this.value) {
true -> context.getString(R.string.yes)
false -> context.getString(R.string.no)
null -> context.getString(R.string.not_answered)
}
}
is Coding -> {
val display = this.displayElement.getLocalizedText() ?: this.display
if (display.isNullOrEmpty()) {
this.code ?: context.getString(R.string.not_answered)
} else display
}
is DateType -> this.localDate?.localizedString ?: context.getString(R.string.not_answered)
is DateTimeType ->
"${this.localDate.localizedString} ${this.localTime.toLocalizedString(context)}"
is DecimalType,
is IntegerType -> (this as PrimitiveType<*>).valueAsString
?: context.getString(R.string.not_answered)
is Quantity -> this.value.toString()
is Reference -> {
val display = this.display
if (display.isNullOrEmpty()) {
this.reference ?: context.getString(R.string.not_answered)
} else display
}
is StringType -> this.getLocalizedText()
?: this.valueAsString ?: context.getString(R.string.not_answered)
is TimeType,
is UriType -> (this as PrimitiveType<*>).valueAsString
?: context.getString(R.string.not_answered)
else -> context.getString(R.string.not_answered)
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import com.google.android.fhir.datacapture.R
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.util.concurrent.atomic.AtomicInteger
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

internal class OptionSelectDialogFragment(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import androidx.core.view.children
import androidx.core.view.get
import androidx.core.view.isEmpty
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.displayString
import com.google.android.fhir.datacapture.common.datatype.displayString
import com.google.android.fhir.datacapture.validation.Invalid
import com.google.android.fhir.datacapture.validation.NotValidated
import com.google.android.fhir.datacapture.validation.Valid
Expand Down Expand Up @@ -62,7 +62,8 @@ internal object QuestionnaireItemAutoCompleteViewHolderFactory :
value =
questionnaireItemViewItem.answerOption
.first {
it.displayString == autoCompleteTextView.adapter.getItem(position) as String
it.value.displayString(header.context) ==
autoCompleteTextView.adapter.getItem(position) as String
}
.valueCoding
}
Expand All @@ -75,7 +76,8 @@ internal object QuestionnaireItemAutoCompleteViewHolderFactory :
override fun bind(questionnaireItemViewItem: QuestionnaireItemViewItem) {
header.bind(questionnaireItemViewItem.questionnaireItem)

val answerOptionString = questionnaireItemViewItem.answerOption.map { it.displayString }
val answerOptionString =
questionnaireItemViewItem.answerOption.map { it.value.displayString(header.context) }
val adapter =
ArrayAdapter(
header.context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.fhir.datacapture.ChoiceOrientationTypes
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.choiceOrientation
import com.google.android.fhir.datacapture.displayString
import com.google.android.fhir.datacapture.common.datatype.displayString
import com.google.android.fhir.datacapture.optionExclusive
import com.google.android.fhir.datacapture.validation.Invalid
import com.google.android.fhir.datacapture.validation.NotValidated
Expand Down Expand Up @@ -104,7 +104,7 @@ internal object QuestionnaireItemCheckBoxGroupViewHolderFactory :
val checkbox =
checkboxLayout.findViewById<CheckBox>(R.id.check_box).apply {
id = viewId
text = answerOption.displayString
text = answerOption.value.displayString(header.context)
isChecked = questionnaireItemViewItem.isAnswerOptionSelected(answerOption)
layoutParams =
ViewGroup.LayoutParams(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.android.fhir.datacapture.views

import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.widget.TextView
import androidx.activity.viewModels
Expand All @@ -26,7 +27,7 @@ import androidx.lifecycle.lifecycleScope
import com.google.android.fhir.datacapture.ItemControlTypes
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.common.datatype.asStringValue
import com.google.android.fhir.datacapture.displayString
import com.google.android.fhir.datacapture.common.datatype.displayString
import com.google.android.fhir.datacapture.itemControl
import com.google.android.fhir.datacapture.localizedFlyoverSpanned
import com.google.android.fhir.datacapture.localizedTextSpanned
Expand Down Expand Up @@ -76,7 +77,7 @@ internal object QuestionnaireItemDialogSelectViewHolderFactory :
// Set the initial selected options state from the FHIR data model
viewModel.updateSelectedOptions(
item.linkId,
questionnaireItemViewItem.extractInitialOptions()
questionnaireItemViewItem.extractInitialOptions(holder.header.context)
)

// Listen for changes to selected options to update summary + FHIR data model
Expand Down Expand Up @@ -179,14 +180,19 @@ data class SelectedOptions(
data class OptionSelectOption(
val item: Questionnaire.QuestionnaireItemAnswerOptionComponent,
val selected: Boolean,
val context: Context,
) {
val displayString: String = item.displayString
val displayString: String = item.value.displayString(context)
}

private fun QuestionnaireItemViewItem.extractInitialOptions(): SelectedOptions {
private fun QuestionnaireItemViewItem.extractInitialOptions(context: Context): SelectedOptions {
val options =
answerOption.map { answerOption ->
OptionSelectOption(item = answerOption, selected = isAnswerOptionSelected(answerOption))
OptionSelectOption(
item = answerOption,
selected = isAnswerOptionSelected(answerOption),
context = context
)
}
return SelectedOptions(
options = options,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.displayString
import com.google.android.fhir.datacapture.common.datatype.displayString
import com.google.android.fhir.datacapture.localizedFlyoverSpanned
import com.google.android.fhir.datacapture.validation.Invalid
import com.google.android.fhir.datacapture.validation.NotValidated
Expand Down Expand Up @@ -53,20 +53,28 @@ internal object QuestionnaireItemDropDownViewHolderFactory :
header.bind(questionnaireItemViewItem.questionnaireItem)
textInputLayout.hint = questionnaireItemViewItem.questionnaireItem.localizedFlyoverSpanned
val answerOptionString =
this.questionnaireItemViewItem.answerOption.map { it.displayString }.toMutableList()
this.questionnaireItemViewItem.answerOption
.map { it.value.displayString(context) }
.toMutableList()
answerOptionString.add(0, context.getString(R.string.hyphen))
val adapter =
ArrayAdapter(context, R.layout.questionnaire_item_drop_down_list, answerOptionString)
questionnaireItemViewItem.answers.singleOrNull()?.displayString(header.context)?.let {
autoCompleteTextView.setText(it)
autoCompleteTextView.setSelection(it.length)
}
questionnaireItemViewItem.answers
.singleOrNull()
?.value
?.displayString(header.context)
?.let {
autoCompleteTextView.setText(it)
autoCompleteTextView.setSelection(it.length)
}
autoCompleteTextView.setAdapter(adapter)
autoCompleteTextView.onItemClickListener =
AdapterView.OnItemClickListener { _, _, position, _ ->
val selectedAnswer =
questionnaireItemViewItem.answerOption
.firstOrNull { it.displayString == autoCompleteTextView.adapter.getItem(position) }
.firstOrNull {
it.value.displayString(context) == autoCompleteTextView.adapter.getItem(position)
}
?.value

if (selectedAnswer == null) {
Expand Down
Loading

0 comments on commit 1b08b55

Please sign in to comment.