Skip to content

Commit

Permalink
Merge branch 'master' into add-empty-response-items-for-repeat-groups
Browse files Browse the repository at this point in the history
  • Loading branch information
allan-on authored Nov 27, 2024
2 parents b6b4900 + b59acf2 commit 63cc2f3
Show file tree
Hide file tree
Showing 98 changed files with 4,453 additions and 704 deletions.
11 changes: 0 additions & 11 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,6 @@ object Dependencies {
const val playServicesLocation =
"com.google.android.gms:play-services-location:${Versions.playServicesLocation}"

const val androidFhirGroup = "com.google.android.fhir"
const val androidFhirEngineModule = "engine"
const val androidFhirKnowledgeModule = "knowledge"
const val androidFhirCommon = "$androidFhirGroup:common:${Versions.androidFhirCommon}"
const val androidFhirEngine =
"$androidFhirGroup:$androidFhirEngineModule:${Versions.androidFhirEngine}"
const val androidFhirKnowledge = "$androidFhirGroup:knowledge:${Versions.androidFhirKnowledge}"

const val apacheCommonsCompress =
"org.apache.commons:commons-compress:${Versions.apacheCommonsCompress}"

Expand Down Expand Up @@ -131,9 +123,6 @@ object Dependencies {
const val xmlUnit = "org.xmlunit:xmlunit-core:${Versions.xmlUnit}"

object Versions {
const val androidFhirCommon = "0.1.0-alpha05"
const val androidFhirEngine = "0.1.0-beta05"
const val androidFhirKnowledge = "0.1.0-alpha03"
const val apacheCommonsCompress = "1.21"
const val desugarJdkLibs = "2.0.3"
const val caffeine = "2.9.1"
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Releases.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ object Releases {

object Workflow : LibraryArtifact {
override val artifactId = "workflow"
override val version = "0.1.0-alpha04"
override val version = "0.1.0-beta01"
override val name = "Android FHIR Workflow Library"
}

Expand Down
60 changes: 18 additions & 42 deletions catalog/src/main/assets/component_modal.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
"resourceType": "Questionnaire",
"item": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/questionnaire-item-control",
"code": "check-box",
"display": "Check Box"
}
],
"text": "Check box"
}
},
{
"url": "https://github.com/google/android-fhir/StructureDefinition/dialog"
}
],
"linkId": "1.1",
"type": "choice",
"repeats": true,
Expand Down Expand Up @@ -44,48 +62,6 @@
"code": "diarrhoea",
"display": "Diarrhoea"
}
},
{
"valueCoding": {
"code": "fever",
"display": "Fever"
}
},
{
"valueCoding": {
"code": "injury",
"display": "Injury"
}
},
{
"valueCoding": {
"code": "jaundice",
"display": "Jaundice"
}
},
{
"valueCoding": {
"code": "mental-health",
"display": "Mental health"
}
},
{
"valueCoding": {
"code": "nausea",
"display": "Nausea"
}
},
{
"valueCoding": {
"code": "pain",
"display": "Pain"
}
},
{
"valueCoding": {
"code": "bleeding",
"display": "Bleeding"
}
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions datacapture/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ dependencies {
exclude(module = "commons-logging")
exclude(module = "httpclient")
}
implementation(Dependencies.androidFhirCommon)
implementation(Dependencies.material)
implementation(Dependencies.timber)
implementation(libs.android.fhir.common)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.core)
Expand All @@ -106,7 +106,7 @@ dependencies {
testImplementation(Dependencies.mockitoKotlin)
testImplementation(Dependencies.robolectric)
testImplementation(project(":knowledge")) {
exclude(group = Dependencies.androidFhirGroup, module = Dependencies.androidFhirEngineModule)
exclude(group = "com.google.android.fhir", module = "engine")
}
testImplementation(libs.androidx.test.core)
testImplementation(libs.androidx.fragment.testing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.fhir.datacapture.contrib.views.PhoneNumberViewHolderFactory
import com.google.android.fhir.datacapture.extensions.inflate
import com.google.android.fhir.datacapture.extensions.itemControl
import com.google.android.fhir.datacapture.extensions.shouldUseDialog
import com.google.android.fhir.datacapture.views.NavigationViewHolder
import com.google.android.fhir.datacapture.views.QuestionnaireViewItem
import com.google.android.fhir.datacapture.views.factories.AttachmentViewHolderFactory
Expand Down Expand Up @@ -241,8 +242,11 @@ internal class QuestionnaireEditAdapter(
): QuestionnaireViewHolderType {
val questionnaireItem = questionnaireViewItem.questionnaireItem

// Use the view type that the client wants if they specified an itemControl
return questionnaireItem.itemControl?.viewHolderType
// Use the view type that the client wants if they specified an itemControl or dialog extension
return when {
questionnaireItem.shouldUseDialog -> QuestionnaireViewHolderType.DIALOG_SELECT
else -> questionnaireItem.itemControl?.viewHolderType
}
// Otherwise, choose a sensible UI element automatically
?: run {
val numOptions = questionnaireViewItem.enabledAnswerOptions.size
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ internal const val EXTENSION_ITEM_CONTROL_URL_ANDROID_FHIR =
internal const val EXTENSION_ITEM_CONTROL_SYSTEM_ANDROID_FHIR =
"https://github.com/google/android-fhir/questionnaire-item-control"

internal const val EXTENSION_DIALOG_URL_ANDROID_FHIR =
"https://github.com/google/android-fhir/StructureDefinition/dialog"

internal enum class StyleUrl(val url: String) {
BASE("https://github.com/google/android-fhir/tree/master/datacapture/android-style"),
PREFIX_TEXT_VIEW("prefix_text_view"),
Expand Down Expand Up @@ -237,6 +240,15 @@ val QuestionnaireItemComponent.itemControlCode: String?
val QuestionnaireItemComponent.itemControl: ItemControlTypes?
get() = ItemControlTypes.values().firstOrNull { it.extensionCode == itemControlCode }

private val QuestionnaireItemComponent.hasDialogExtension: Boolean
get() = this.extension.any { it.url == EXTENSION_DIALOG_URL_ANDROID_FHIR }

val QuestionnaireItemComponent.shouldUseDialog: Boolean
get() =
this.hasDialogExtension &&
(this.itemControl?.viewHolderType == QuestionnaireViewHolderType.CHECK_BOX_GROUP ||
this.itemControl?.viewHolderType == QuestionnaireViewHolderType.RADIO_GROUP)

/**
* The desired orientation for the list of choices.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,8 @@ private fun List<QuestionnaireResponse.QuestionnaireResponseItemComponent>.packR

val questionnaireItem = questionnaireItems.single()

questionnaireResponseItems.forEach { it ->
if (questionnaireItem.type == Questionnaire.QuestionnaireItemType.GROUP) {
if (questionnaireItem.repeats) {
it.answer.forEach { it.item = it.item.packRepeatedGroups(questionnaireItem.item) }
} else {
it.item = it.item.packRepeatedGroups(questionnaireItem.item)
}
} else {
it.answer.forEach { it.item = it.item.packRepeatedGroups(questionnaireItem.item) }
}
questionnaireResponseItems.forEach {
it.item = it.item.packRepeatedGroups(questionnaireItem.item)
}

if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.android.fhir.datacapture.extensions

import android.content.Context
import android.text.Spanned
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.views.factories.localDate
import com.google.android.fhir.datacapture.views.factories.localTime
Expand Down Expand Up @@ -57,6 +58,8 @@ fun Type.asStringValue(): String {
fun Type.displayString(context: Context): String =
getDisplayString(this, context) ?: context.getString(R.string.not_answered)

fun Type.displayStringSpanned(context: Context): Spanned = displayString(context).toSpanned()

/** Returns value as string depending on the [Type] of element. */
fun Type.getValueAsString(context: Context): String =
getValueString(this) ?: context.getString(R.string.not_answered)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
import com.google.android.fhir.datacapture.extensions.optionExclusive
import com.google.android.fhir.datacapture.extensions.toSpanned
import com.google.android.fhir.datacapture.views.factories.OptionSelectOption
import com.google.android.fhir.datacapture.views.factories.QuestionnaireItemDialogSelectViewModel
import com.google.android.fhir.datacapture.views.factories.SelectedOptions
Expand Down Expand Up @@ -208,7 +209,7 @@ private class OptionSelectAdapter(val multiSelectEnabled: Boolean) :
} else {
(holder as OptionSelectViewHolder.OptionSingle).radioButton
}
compoundButton.text = item.option.displayString
compoundButton.text = item.option.displayString.toSpanned()
compoundButton.setCompoundDrawablesRelative(
item.option.item.itemAnswerOptionImage(compoundButton.context),
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import androidx.lifecycle.lifecycleScope
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.ChoiceOrientationTypes
import com.google.android.fhir.datacapture.extensions.choiceOrientation
import com.google.android.fhir.datacapture.extensions.displayString
import com.google.android.fhir.datacapture.extensions.displayStringSpanned
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
import com.google.android.fhir.datacapture.extensions.optionExclusive
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
Expand Down Expand Up @@ -104,7 +104,7 @@ internal object CheckBoxGroupViewHolderFactory :
val checkbox =
checkboxLayout.findViewById<CheckBox>(R.id.check_box).apply {
id = viewId
text = answerOption.value.displayString(header.context)
text = answerOption.value.displayStringSpanned(header.context)
setCompoundDrawablesRelative(
answerOption.itemAnswerOptionImage(checkboxGroup.context),
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.google.android.fhir.datacapture.extensions.getRequiredOrOptionalText
import com.google.android.fhir.datacapture.extensions.getValidationErrorMessage
import com.google.android.fhir.datacapture.extensions.itemControl
import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned
import com.google.android.fhir.datacapture.extensions.toSpanned
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
import com.google.android.fhir.datacapture.validation.ValidationResult
import com.google.android.fhir.datacapture.views.HeaderView
Expand Down Expand Up @@ -76,12 +77,12 @@ internal object QuestionnaireItemDialogSelectViewHolderFactory :

val questionnaireItem = questionnaireViewItem.questionnaireItem
val selectedOptions = questionnaireViewItem.extractInitialOptions(holder.header.context)
holder.summary.text = selectedOptions.selectedSummary
holder.summary.text = selectedOptions.selectedSummary.toSpanned()
selectedOptionsJob =
activity.lifecycleScope.launch {
// Listen for changes to selected options to update summary + FHIR data model
viewModel.getSelectedOptionsFlow(questionnaireItem.linkId).collect { selectedOptions ->
holder.summary.text = selectedOptions.selectedSummary
holder.summary.text = selectedOptions.selectedSummary.toSpanned()
updateAnswers(selectedOptions)
}
}
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.factories

import android.content.Context
import android.graphics.drawable.Drawable
import android.text.Spanned
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand All @@ -33,6 +34,7 @@ import com.google.android.fhir.datacapture.extensions.getValidationErrorMessage
import com.google.android.fhir.datacapture.extensions.identifierString
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned
import com.google.android.fhir.datacapture.extensions.toSpanned
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
import com.google.android.fhir.datacapture.validation.ValidationResult
import com.google.android.fhir.datacapture.views.HeaderView
Expand Down Expand Up @@ -92,8 +94,8 @@ internal object DropDownViewHolderFactory :
answerOptionList
.firstOrNull { it.answerId == selectedAnswerIdentifier }
?.let {
autoCompleteTextView.setText(it.answerOptionString)
autoCompleteTextView.setSelection(it.answerOptionString.length)
autoCompleteTextView.setText(it.answerOptionStringSpanned())
autoCompleteTextView.setSelection(it.answerOptionStringSpanned().length)
autoCompleteTextView.setCompoundDrawablesRelative(
it.answerOptionImage,
null,
Expand All @@ -105,7 +107,7 @@ internal object DropDownViewHolderFactory :
autoCompleteTextView.onItemClickListener =
AdapterView.OnItemClickListener { _, _, position, _ ->
val selectedItem = adapter.getItem(position)
autoCompleteTextView.setText(selectedItem?.answerOptionString, false)
autoCompleteTextView.setText(selectedItem?.answerOptionStringSpanned(), false)
autoCompleteTextView.setCompoundDrawablesRelative(
adapter.getItem(position)?.answerOptionImage,
null,
Expand Down Expand Up @@ -165,7 +167,7 @@ internal class AnswerOptionDropDownArrayAdapter(
val answerOption: DropDownAnswerOption? = getItem(position)
val answerOptionTextView =
listItemView?.findViewById<View>(R.id.answer_option_textview) as TextView
answerOptionTextView.text = answerOption?.answerOptionString
answerOptionTextView.text = answerOption?.answerOptionStringSpanned()
answerOptionTextView.setCompoundDrawablesRelative(
answerOption?.answerOptionImage,
null,
Expand All @@ -187,4 +189,6 @@ internal data class DropDownAnswerOption(
override fun toString(): String {
return this.answerOptionString
}

fun answerOptionStringSpanned(): Spanned = answerOptionString.toSpanned()
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import androidx.lifecycle.lifecycleScope
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.ChoiceOrientationTypes
import com.google.android.fhir.datacapture.extensions.choiceOrientation
import com.google.android.fhir.datacapture.extensions.displayString
import com.google.android.fhir.datacapture.extensions.displayStringSpanned
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
import com.google.android.fhir.datacapture.validation.Invalid
Expand Down Expand Up @@ -113,7 +113,7 @@ internal object RadioGroupViewHolderFactory :
val radioButton =
radioButtonItem.findViewById<RadioButton>(R.id.radio_button).apply {
id = viewId
text = answerOption.value.displayString(header.context)
text = answerOption.value.displayStringSpanned(header.context)
setCompoundDrawablesRelative(
answerOption.itemAnswerOptionImage(radioGroup.context),
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.google.android.fhir.datacapture.extensions.getHeaderViewVisibility
import com.google.android.fhir.datacapture.extensions.getLocalizedInstructionsSpanned
import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned
import com.google.android.fhir.datacapture.extensions.localizedPrefixSpanned
import com.google.android.fhir.datacapture.extensions.toSpanned
import com.google.android.fhir.datacapture.extensions.updateTextAndVisibility
import com.google.android.fhir.datacapture.validation.Invalid
import com.google.android.fhir.datacapture.views.QuestionnaireViewItem
Expand Down Expand Up @@ -90,7 +91,7 @@ internal object ReviewViewHolderFactory : QuestionnaireItemViewHolderFactory(R.l
answerView.visibility = GONE
}
else -> {
answerView.text = questionnaireViewItem.answerString(answerView.context)
answerView.text = questionnaireViewItem.answerString(answerView.context).toSpanned()
answerView.visibility = VISIBLE
if (questionnaireViewItem.validationResult is Invalid) {
errorView.findViewById<TextView>(R.id.error_text_view).text =
Expand Down
Loading

0 comments on commit 63cc2f3

Please sign in to comment.