Skip to content

Commit 1b27ad7

Browse files
committed
Merge branch 'master' into master-release
2 parents fbb0b0a + 11ed6f0 commit 1b27ad7

12 files changed

+152
-31
lines changed

datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireResponses.kt

+2-10
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,8 @@ private fun List<QuestionnaireResponse.QuestionnaireResponseItemComponent>.packR
6767

6868
val questionnaireItem = questionnaireItems.single()
6969

70-
questionnaireResponseItems.forEach { it ->
71-
if (questionnaireItem.type == Questionnaire.QuestionnaireItemType.GROUP) {
72-
if (questionnaireItem.repeats) {
73-
it.answer.forEach { it.item = it.item.packRepeatedGroups(questionnaireItem.item) }
74-
} else {
75-
it.item = it.item.packRepeatedGroups(questionnaireItem.item)
76-
}
77-
} else {
78-
it.answer.forEach { it.item = it.item.packRepeatedGroups(questionnaireItem.item) }
79-
}
70+
questionnaireResponseItems.forEach {
71+
it.item = it.item.packRepeatedGroups(questionnaireItem.item)
8072
}
8173

8274
if (

datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreTypes.kt

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.google.android.fhir.datacapture.extensions
1818

1919
import android.content.Context
20+
import android.text.Spanned
2021
import com.google.android.fhir.datacapture.R
2122
import com.google.android.fhir.datacapture.views.factories.localDate
2223
import com.google.android.fhir.datacapture.views.factories.localTime
@@ -57,6 +58,8 @@ fun Type.asStringValue(): String {
5758
fun Type.displayString(context: Context): String =
5859
getDisplayString(this, context) ?: context.getString(R.string.not_answered)
5960

61+
fun Type.displayStringSpanned(context: Context): Spanned = displayString(context).toSpanned()
62+
6063
/** Returns value as string depending on the [Type] of element. */
6164
fun Type.getValueAsString(context: Context): String =
6265
getValueString(this) ?: context.getString(R.string.not_answered)

datacapture/src/main/java/com/google/android/fhir/datacapture/views/OptionSelectDialogFragment.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import androidx.recyclerview.widget.RecyclerView
4141
import com.google.android.fhir.datacapture.R
4242
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
4343
import com.google.android.fhir.datacapture.extensions.optionExclusive
44+
import com.google.android.fhir.datacapture.extensions.toSpanned
4445
import com.google.android.fhir.datacapture.views.factories.OptionSelectOption
4546
import com.google.android.fhir.datacapture.views.factories.QuestionnaireItemDialogSelectViewModel
4647
import com.google.android.fhir.datacapture.views.factories.SelectedOptions
@@ -208,7 +209,7 @@ private class OptionSelectAdapter(val multiSelectEnabled: Boolean) :
208209
} else {
209210
(holder as OptionSelectViewHolder.OptionSingle).radioButton
210211
}
211-
compoundButton.text = item.option.displayString
212+
compoundButton.text = item.option.displayString.toSpanned()
212213
compoundButton.setCompoundDrawablesRelative(
213214
item.option.item.itemAnswerOptionImage(compoundButton.context),
214215
null,

datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/CheckBoxGroupViewHolderFactory.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import androidx.lifecycle.lifecycleScope
2727
import com.google.android.fhir.datacapture.R
2828
import com.google.android.fhir.datacapture.extensions.ChoiceOrientationTypes
2929
import com.google.android.fhir.datacapture.extensions.choiceOrientation
30-
import com.google.android.fhir.datacapture.extensions.displayString
30+
import com.google.android.fhir.datacapture.extensions.displayStringSpanned
3131
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
3232
import com.google.android.fhir.datacapture.extensions.optionExclusive
3333
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
@@ -104,7 +104,7 @@ internal object CheckBoxGroupViewHolderFactory :
104104
val checkbox =
105105
checkboxLayout.findViewById<CheckBox>(R.id.check_box).apply {
106106
id = viewId
107-
text = answerOption.value.displayString(header.context)
107+
text = answerOption.value.displayStringSpanned(header.context)
108108
setCompoundDrawablesRelative(
109109
answerOption.itemAnswerOptionImage(checkboxGroup.context),
110110
null,

datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/DialogSelectViewHolderFactory.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import com.google.android.fhir.datacapture.extensions.getRequiredOrOptionalText
3232
import com.google.android.fhir.datacapture.extensions.getValidationErrorMessage
3333
import com.google.android.fhir.datacapture.extensions.itemControl
3434
import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned
35+
import com.google.android.fhir.datacapture.extensions.toSpanned
3536
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
3637
import com.google.android.fhir.datacapture.validation.ValidationResult
3738
import com.google.android.fhir.datacapture.views.HeaderView
@@ -76,12 +77,12 @@ internal object QuestionnaireItemDialogSelectViewHolderFactory :
7677

7778
val questionnaireItem = questionnaireViewItem.questionnaireItem
7879
val selectedOptions = questionnaireViewItem.extractInitialOptions(holder.header.context)
79-
holder.summary.text = selectedOptions.selectedSummary
80+
holder.summary.text = selectedOptions.selectedSummary.toSpanned()
8081
selectedOptionsJob =
8182
activity.lifecycleScope.launch {
8283
// Listen for changes to selected options to update summary + FHIR data model
8384
viewModel.getSelectedOptionsFlow(questionnaireItem.linkId).collect { selectedOptions ->
84-
holder.summary.text = selectedOptions.selectedSummary
85+
holder.summary.text = selectedOptions.selectedSummary.toSpanned()
8586
updateAnswers(selectedOptions)
8687
}
8788
}

datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/DropDownViewHolderFactory.kt

+8-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.google.android.fhir.datacapture.views.factories
1818

1919
import android.content.Context
2020
import android.graphics.drawable.Drawable
21+
import android.text.Spanned
2122
import android.view.LayoutInflater
2223
import android.view.View
2324
import android.view.ViewGroup
@@ -33,6 +34,7 @@ import com.google.android.fhir.datacapture.extensions.getValidationErrorMessage
3334
import com.google.android.fhir.datacapture.extensions.identifierString
3435
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
3536
import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned
37+
import com.google.android.fhir.datacapture.extensions.toSpanned
3638
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
3739
import com.google.android.fhir.datacapture.validation.ValidationResult
3840
import com.google.android.fhir.datacapture.views.HeaderView
@@ -92,8 +94,8 @@ internal object DropDownViewHolderFactory :
9294
answerOptionList
9395
.firstOrNull { it.answerId == selectedAnswerIdentifier }
9496
?.let {
95-
autoCompleteTextView.setText(it.answerOptionString)
96-
autoCompleteTextView.setSelection(it.answerOptionString.length)
97+
autoCompleteTextView.setText(it.answerOptionStringSpanned())
98+
autoCompleteTextView.setSelection(it.answerOptionStringSpanned().length)
9799
autoCompleteTextView.setCompoundDrawablesRelative(
98100
it.answerOptionImage,
99101
null,
@@ -105,7 +107,7 @@ internal object DropDownViewHolderFactory :
105107
autoCompleteTextView.onItemClickListener =
106108
AdapterView.OnItemClickListener { _, _, position, _ ->
107109
val selectedItem = adapter.getItem(position)
108-
autoCompleteTextView.setText(selectedItem?.answerOptionString, false)
110+
autoCompleteTextView.setText(selectedItem?.answerOptionStringSpanned(), false)
109111
autoCompleteTextView.setCompoundDrawablesRelative(
110112
adapter.getItem(position)?.answerOptionImage,
111113
null,
@@ -165,7 +167,7 @@ internal class AnswerOptionDropDownArrayAdapter(
165167
val answerOption: DropDownAnswerOption? = getItem(position)
166168
val answerOptionTextView =
167169
listItemView?.findViewById<View>(R.id.answer_option_textview) as TextView
168-
answerOptionTextView.text = answerOption?.answerOptionString
170+
answerOptionTextView.text = answerOption?.answerOptionStringSpanned()
169171
answerOptionTextView.setCompoundDrawablesRelative(
170172
answerOption?.answerOptionImage,
171173
null,
@@ -187,4 +189,6 @@ internal data class DropDownAnswerOption(
187189
override fun toString(): String {
188190
return this.answerOptionString
189191
}
192+
193+
fun answerOptionStringSpanned(): Spanned = answerOptionString.toSpanned()
190194
}

datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/RadioGroupViewHolderFactory.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import androidx.lifecycle.lifecycleScope
2828
import com.google.android.fhir.datacapture.R
2929
import com.google.android.fhir.datacapture.extensions.ChoiceOrientationTypes
3030
import com.google.android.fhir.datacapture.extensions.choiceOrientation
31-
import com.google.android.fhir.datacapture.extensions.displayString
31+
import com.google.android.fhir.datacapture.extensions.displayStringSpanned
3232
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
3333
import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
3434
import com.google.android.fhir.datacapture.validation.Invalid
@@ -113,7 +113,7 @@ internal object RadioGroupViewHolderFactory :
113113
val radioButton =
114114
radioButtonItem.findViewById<RadioButton>(R.id.radio_button).apply {
115115
id = viewId
116-
text = answerOption.value.displayString(header.context)
116+
text = answerOption.value.displayStringSpanned(header.context)
117117
setCompoundDrawablesRelative(
118118
answerOption.itemAnswerOptionImage(radioGroup.context),
119119
null,

datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/ReviewViewHolderFactory.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.google.android.fhir.datacapture.extensions.getHeaderViewVisibility
2626
import com.google.android.fhir.datacapture.extensions.getLocalizedInstructionsSpanned
2727
import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned
2828
import com.google.android.fhir.datacapture.extensions.localizedPrefixSpanned
29+
import com.google.android.fhir.datacapture.extensions.toSpanned
2930
import com.google.android.fhir.datacapture.extensions.updateTextAndVisibility
3031
import com.google.android.fhir.datacapture.validation.Invalid
3132
import com.google.android.fhir.datacapture.views.QuestionnaireViewItem
@@ -90,7 +91,7 @@ internal object ReviewViewHolderFactory : QuestionnaireItemViewHolderFactory(R.l
9091
answerView.visibility = GONE
9192
}
9293
else -> {
93-
answerView.text = questionnaireViewItem.answerString(answerView.context)
94+
answerView.text = questionnaireViewItem.answerString(answerView.context).toSpanned()
9495
answerView.visibility = VISIBLE
9596
if (questionnaireViewItem.validationResult is Invalid) {
9697
errorView.findViewById<TextView>(R.id.error_text_view).text =

datacapture/src/test/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireResponsesTest.kt

+115
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,121 @@ class MoreQuestionnaireResponsesTest {
260260
assertResourceEquals(questionnaireResponse, packedQuestionnaireResponse)
261261
}
262262

263+
@Test
264+
fun `should pack repeated groups recursively`() {
265+
val questionnaire =
266+
Questionnaire().apply {
267+
addItem(
268+
QuestionnaireItemComponent().apply {
269+
linkId = "repeated-group"
270+
type = Questionnaire.QuestionnaireItemType.GROUP
271+
repeats = true
272+
addItem(
273+
QuestionnaireItemComponent().apply {
274+
linkId = "nested-repeated-group"
275+
type = Questionnaire.QuestionnaireItemType.GROUP
276+
repeats = true
277+
addItem(
278+
QuestionnaireItemComponent().apply {
279+
linkId = "nested-nested-question"
280+
type = Questionnaire.QuestionnaireItemType.BOOLEAN
281+
},
282+
)
283+
},
284+
)
285+
},
286+
)
287+
}
288+
289+
val questionnaireResponse =
290+
QuestionnaireResponse().apply {
291+
addItem(
292+
QuestionnaireResponseItemComponent().apply {
293+
linkId = "repeated-group"
294+
addItem(
295+
QuestionnaireResponseItemComponent().apply {
296+
linkId = "nested-repeated-group"
297+
addItem(
298+
QuestionnaireResponseItemComponent().apply {
299+
linkId = "nested-nested-question"
300+
addAnswer(
301+
QuestionnaireResponseItemAnswerComponent().apply {
302+
value = BooleanType(true)
303+
},
304+
)
305+
},
306+
)
307+
},
308+
)
309+
addItem(
310+
QuestionnaireResponseItemComponent().apply {
311+
linkId = "nested-repeated-group"
312+
addItem(
313+
QuestionnaireResponseItemComponent().apply {
314+
linkId = "nested-nested-question"
315+
addAnswer(
316+
QuestionnaireResponseItemAnswerComponent().apply {
317+
value = BooleanType(false)
318+
},
319+
)
320+
},
321+
)
322+
},
323+
)
324+
},
325+
)
326+
}
327+
328+
val packedQuestionnaireResponse =
329+
QuestionnaireResponse().apply {
330+
addItem(
331+
QuestionnaireResponseItemComponent().apply {
332+
linkId = "repeated-group"
333+
addAnswer(
334+
QuestionnaireResponseItemAnswerComponent().apply {
335+
addItem(
336+
QuestionnaireResponseItemComponent().apply {
337+
linkId = "nested-repeated-group"
338+
addAnswer(
339+
QuestionnaireResponseItemAnswerComponent().apply {
340+
addItem(
341+
QuestionnaireResponseItemComponent().apply {
342+
linkId = "nested-nested-question"
343+
addAnswer(
344+
QuestionnaireResponseItemAnswerComponent().apply {
345+
value = BooleanType(true)
346+
},
347+
)
348+
},
349+
)
350+
},
351+
)
352+
addAnswer(
353+
QuestionnaireResponseItemAnswerComponent().apply {
354+
addItem(
355+
QuestionnaireResponseItemComponent().apply {
356+
linkId = "nested-nested-question"
357+
addAnswer(
358+
QuestionnaireResponseItemAnswerComponent().apply {
359+
value = BooleanType(false)
360+
},
361+
)
362+
},
363+
)
364+
},
365+
)
366+
},
367+
)
368+
},
369+
)
370+
},
371+
)
372+
}
373+
374+
questionnaireResponse.packRepeatedGroups(questionnaire)
375+
assertResourceEquals(questionnaireResponse, packedQuestionnaireResponse)
376+
}
377+
263378
@Test
264379
fun `should not modify non-repeated groups while packing repeated groups`() {
265380
val questionnaire =

datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/CheckBoxGroupViewHolderFactoryTest.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ class CheckBoxGroupViewHolderFactoryTest {
124124
val checkBoxGroup = viewHolder.itemView.findViewById<ConstraintLayout>(R.id.checkbox_group)
125125
val children = checkBoxGroup.children.asIterable().filterIsInstance<CheckBox>()
126126
children.forEachIndexed { index, view ->
127-
assertThat(view.text).isEqualTo(questionnaire.answerOption[index].valueCoding.display)
127+
assertThat(view.text.toString())
128+
.isEqualTo(questionnaire.answerOption[index].valueCoding.display)
128129
assertThat(view.layoutParams.width).isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT)
129130
}
130131
}
@@ -161,7 +162,8 @@ class CheckBoxGroupViewHolderFactoryTest {
161162
val checkBoxGroup = viewHolder.itemView.findViewById<ConstraintLayout>(R.id.checkbox_group)
162163
val children = checkBoxGroup.children.asIterable().filterIsInstance<CheckBox>()
163164
children.forEachIndexed { index, view ->
164-
assertThat(view.text).isEqualTo(questionnaire.answerOption[index].valueCoding.display)
165+
assertThat(view.text.toString())
166+
.isEqualTo(questionnaire.answerOption[index].valueCoding.display)
165167
assertThat(view.layoutParams.width).isEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT)
166168
}
167169
}

datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/RadioGroupViewHolderFactoryTest.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ class RadioGroupViewHolderFactoryTest {
118118
val radioGroup = viewHolder.itemView.findViewById<ConstraintLayout>(R.id.radio_group)
119119
val children = radioGroup.children.asIterable().filterIsInstance<RadioButton>()
120120
children.forEachIndexed { index, view ->
121-
assertThat(view.text).isEqualTo(questionnaire.answerOption[index].valueCoding.display)
121+
assertThat(view.text.toString())
122+
.isEqualTo(questionnaire.answerOption[index].valueCoding.display)
122123
assertThat(view.layoutParams.width).isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT)
123124
}
124125
}
@@ -154,7 +155,8 @@ class RadioGroupViewHolderFactoryTest {
154155
val radioGroup = viewHolder.itemView.findViewById<ConstraintLayout>(R.id.radio_group)
155156
val children = radioGroup.children.asIterable().filterIsInstance<RadioButton>()
156157
children.forEachIndexed { index, view ->
157-
assertThat(view.text).isEqualTo(questionnaire.answerOption[index].valueCoding.display)
158+
assertThat(view.text.toString())
159+
.isEqualTo(questionnaire.answerOption[index].valueCoding.display)
158160
assertThat(view.layoutParams.width).isEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT)
159161
}
160162
}

datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/ReviewViewHolderFactoryTest.kt

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 Google LLC
2+
* Copyright 2023-2024 Google LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -180,7 +180,7 @@ class ReviewViewHolderFactoryTest {
180180
),
181181
)
182182

183-
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text)
183+
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text.toString())
184184
.isEqualTo(
185185
ApplicationProvider.getApplicationContext<Application>().getString(R.string.not_answered),
186186
)
@@ -206,7 +206,7 @@ class ReviewViewHolderFactoryTest {
206206
),
207207
)
208208

209-
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text)
209+
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text.toString())
210210
.isEqualTo(ApplicationProvider.getApplicationContext<Application>().getString(R.string.yes))
211211
}
212212

@@ -321,7 +321,7 @@ class ReviewViewHolderFactoryTest {
321321
),
322322
)
323323

324-
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text)
324+
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text.toString())
325325
.isEqualTo("Yes")
326326
}
327327

@@ -340,7 +340,7 @@ class ReviewViewHolderFactoryTest {
340340
),
341341
)
342342

343-
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text)
343+
assertThat(viewHolder.itemView.findViewById<TextView>(R.id.answer_text_view).text.toString())
344344
.isEqualTo("Not Answered")
345345
}
346346

0 commit comments

Comments
 (0)