From 43b74f8a5d1aa4ac5cab1c9c11a2aca90a9c85e4 Mon Sep 17 00:00:00 2001 From: dilys Date: Fri, 3 Jan 2025 13:18:30 +1000 Subject: [PATCH 1/3] add custom callback for autocomplete --- .../fhir/catalog/CatalogApplication.kt | 12 ++ .../fhir/datacapture/DataCaptureConfig.kt | 8 +- .../datacapture/QuestionnaireEditAdapter.kt | 12 +- .../datacapture/QuestionnaireViewModel.kt | 7 +- .../views/QuestionnaireViewItem.kt | 5 +- .../AutoCompleteViewHolderFactory.kt | 140 ++++++++++++++---- .../AutoCompleteViewHolderFactoryTest.kt | 43 +++++- 7 files changed, 196 insertions(+), 31 deletions(-) diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt b/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt index 204651fd02..974ad5266c 100644 --- a/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt +++ b/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt @@ -21,7 +21,10 @@ import ca.uhn.fhir.context.FhirContext import com.google.android.fhir.FhirEngine import com.google.android.fhir.FhirEngineConfiguration import com.google.android.fhir.FhirEngineProvider +import com.google.android.fhir.datacapture.CustomCallback.AutoCompleteCallback +import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.DataCaptureConfig +import com.google.android.fhir.datacapture.views.factories.AutoCompleteViewAnswerOption import com.google.android.fhir.search.search import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -44,6 +47,15 @@ class CatalogApplication : Application(), DataCaptureConfig.Provider { xFhirQueryResolver = { fhirEngine.search(it).map { it.resource } }, questionnaireItemViewHolderFactoryMatchersProviderFactory = ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory, + callbacks = mapOf(Pair(CustomCallbackType.AUTO_COMPLETE, AutoCompleteCallback( + callback = { query -> + run { + listOf(AutoCompleteViewAnswerOption("a", "Type 2 Diabetes Mellitus"), + AutoCompleteViewAnswerOption("b", "Test") + ) + } + } + ))) ) CoroutineScope(Dispatchers.IO).launch { diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt index 34208ad29b..6219725a93 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Google LLC + * Copyright 2022-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,6 +56,12 @@ data class DataCaptureConfig( var questionnaireItemViewHolderFactoryMatchersProviderFactory: QuestionnaireItemViewHolderFactoryMatchersProviderFactory? = null, + + /** + * A [CustomCallback] may be set by the client to override the behaviour of an existing component + * in the sdc. Currently only supports [CustomCallbackType.AUTO_COMPLETE]. + */ + var callbacks: Map? = null, ) { /** diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt index 6fc427eae2..a9485823b8 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Google LLC + * Copyright 2022-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ 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 +import com.google.android.fhir.datacapture.views.factories.AutoCompleteViewAnswerOption import com.google.android.fhir.datacapture.views.factories.AutoCompleteViewHolderFactory import com.google.android.fhir.datacapture.views.factories.BooleanChoiceViewHolderFactory import com.google.android.fhir.datacapture.views.factories.CheckBoxGroupViewHolderFactory @@ -391,3 +392,12 @@ internal object DiffCallbacks { } } } + +sealed class CustomCallback { + data class AutoCompleteCallback(val callback: (String) -> List) : + CustomCallback() +} + +enum class CustomCallbackType { + AUTO_COMPLETE, +} diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt index ecc019b0a8..f49a46c412 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 Google LLC + * Copyright 2023-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -96,6 +96,10 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat DataCapture.getConfiguration(application).valueSetResolverExternal } + private val callbacks: Map? by lazy { + DataCapture.getConfiguration(application).callbacks + } + /** The current questionnaire as questions are being answered. */ internal val questionnaire: Questionnaire @@ -985,6 +989,7 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat ), isHelpCardOpen = isHelpCard && isHelpCardOpen, helpCardStateChangedCallback = helpCardStateChangedCallback, + callbacks = callbacks, ), ) add(question) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt index d9025fd284..7122c36101 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 Google LLC + * Copyright 2023-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ package com.google.android.fhir.datacapture.views import android.content.Context import android.text.Spanned import androidx.recyclerview.widget.RecyclerView +import com.google.android.fhir.datacapture.CustomCallback +import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.isHelpCode @@ -93,6 +95,7 @@ data class QuestionnaireViewItem( val helpCardStateChangedCallback: (Boolean, QuestionnaireResponseItemComponent) -> Unit = { _, _ -> }, + val callbacks: Map? = null, ) { fun getQuestionnaireResponseItem(): QuestionnaireResponseItemComponent = questionnaireResponseItem diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt index 149185aeb3..5b086a2d29 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Google LLC + * Copyright 2022-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,21 @@ package com.google.android.fhir.datacapture.views.factories +import android.content.Context +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.AdapterView import android.widget.ArrayAdapter +import android.widget.Filter import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children import androidx.core.view.get import androidx.core.view.isEmpty import androidx.lifecycle.lifecycleScope +import com.google.android.fhir.datacapture.CustomCallback +import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.identifierString @@ -53,9 +59,17 @@ internal object AutoCompleteViewHolderFactory : private lateinit var autoCompleteTextView: MaterialAutoCompleteTextView private lateinit var chipContainer: ChipGroup private lateinit var textInputLayout: TextInputLayout + private lateinit var adapter: ArrayAdapter + private val canHaveMultipleAnswers get() = questionnaireViewItem.questionnaireItem.repeats + private val callback: ((String) -> List)? + get() = + (questionnaireViewItem.callbacks?.get(CustomCallbackType.AUTO_COMPLETE) + as? CustomCallback.AutoCompleteCallback) + ?.callback + override lateinit var questionnaireViewItem: QuestionnaireViewItem private lateinit var errorTextView: TextView @@ -66,29 +80,13 @@ internal object AutoCompleteViewHolderFactory : chipContainer = itemView.findViewById(R.id.chipContainer) textInputLayout = itemView.findViewById(R.id.text_input_layout) errorTextView = itemView.findViewById(R.id.error) - autoCompleteTextView.onItemClickListener = - AdapterView.OnItemClickListener { _, _, position, _ -> - val answer = - QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply { - value = - questionnaireViewItem.enabledAnswerOptions - .first { - it.value.identifierString(header.context) == - (autoCompleteTextView.adapter.getItem(position) - as AutoCompleteViewAnswerOption) - .answerId - } - .valueCoding - } - - onAnswerSelected(answer) - autoCompleteTextView.setText("") - } + autoCompleteTextView.onItemClickListener = onClickListener() } override fun bind(questionnaireViewItem: QuestionnaireViewItem) { header.bind(questionnaireViewItem) header.showRequiredOrOptionalTextInHeaderView(questionnaireViewItem) + val suggestions = mutableListOf() val answerOptionValues = questionnaireViewItem.enabledAnswerOptions.map { AutoCompleteViewAnswerOption( @@ -96,12 +94,14 @@ internal object AutoCompleteViewHolderFactory : answerDisplay = it.value.displayString(header.context), ) } - val adapter = - ArrayAdapter( - header.context, - R.layout.drop_down_list_item, - R.id.answer_option_textview, - answerOptionValues, + suggestions.addAll(answerOptionValues) + adapter = + AutoCompleteArrayAdapter( + context = header.context, + resource = R.layout.drop_down_list_item, + textViewResourceId = R.id.answer_option_textview, + objects = answerOptionValues, + callback = callback, ) autoCompleteTextView.setAdapter(adapter) // Remove chips if any from the last bindView call on this VH. @@ -136,6 +136,39 @@ internal object AutoCompleteViewHolderFactory : } } + private fun onClickListener() = + AdapterView.OnItemClickListener { _, _, position, _ -> + val answer: QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent + if (questionnaireViewItem.enabledAnswerOptions.isEmpty()) { + val answerValue = + autoCompleteTextView.adapter.getItem(position) as AutoCompleteViewAnswerOption + val answerCoding = + Coding().apply { + code = answerValue.answerId + display = answerValue.answerDisplay + } + answer = + QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply { + value = answerCoding + } + } else { + answer = + QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply { + value = + questionnaireViewItem.enabledAnswerOptions + .first { + it.value.identifierString(header.context) == + (autoCompleteTextView.adapter.getItem(position) + as AutoCompleteViewAnswerOption) + .answerId + } + .valueCoding + } + } + onAnswerSelected(answer) + autoCompleteTextView.setText("") + } + /** * Adds a new chip if it not already present in [chipContainer].It returns [true] if a new * Chip is added and [false] if the Chip is already present for the selected answer. The later @@ -242,8 +275,63 @@ internal object AutoCompleteViewHolderFactory : * An answer option that would show up as a dropdown item in an [AutoCompleteViewHolderFactory] * textview */ -internal data class AutoCompleteViewAnswerOption(val answerId: String, val answerDisplay: String) { +data class AutoCompleteViewAnswerOption(val answerId: String, val answerDisplay: String) { override fun toString(): String { return this.answerDisplay } } + +internal class AutoCompleteArrayAdapter( + context: Context, + val resource: Int, + val textViewResourceId: Int, + private val objects: List, + private val callback: ((String) -> List)? = null, +) : ArrayAdapter(context, resource, textViewResourceId, objects) { + + private var items = listOf() + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = convertView ?: LayoutInflater.from(context).inflate(resource, parent, false) + val item = getItem(position) + view.findViewById(textViewResourceId).text = item.toString() + return view + } + + override fun getCount(): Int = items.size + + fun updateData(newData: List) { + items = newData + notifyDataSetChanged() + } + + override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { + return getView(position, convertView, parent) + } + + override fun getItem(position: Int): AutoCompleteViewAnswerOption? = items.getOrNull(position) + + override fun getFilter(): Filter { + return object : Filter() { + override fun performFiltering(constraint: CharSequence?): FilterResults { + val query = (constraint?.toString() ?: "").trim() + val filteredResults: List = + if (callback != null && objects.isEmpty()) { + callback.invoke(query) + } else { + objects.filter { it.answerDisplay.contains(query, ignoreCase = true) } + } + return FilterResults().apply { + values = filteredResults + count = filteredResults.size + } + } + + override fun publishResults(constraint: CharSequence?, results: FilterResults?) { + @Suppress("UNCHECKED_CAST") + val data = results?.values as? List ?: emptyList() + updateData(data) + } + } + } +} diff --git a/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt b/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt index 04d63a634b..82285abd54 100644 --- a/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt +++ b/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 Google LLC + * Copyright 2023-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,13 @@ package com.google.android.fhir.datacapture.views.factories import android.view.View +import android.widget.AutoCompleteTextView import android.widget.FrameLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.view.get +import com.google.android.fhir.datacapture.CustomCallback.AutoCompleteCallback +import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.identifierString @@ -33,6 +36,7 @@ import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup import com.google.android.material.textfield.TextInputLayout import com.google.common.truth.Truth.assertThat +import kotlin.test.assertNotNull import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Questionnaire import org.hl7.fhir.r4.model.QuestionnaireResponse @@ -465,4 +469,41 @@ class AutoCompleteViewHolderFactoryTest { assertThat(viewHolder.itemView.findViewById(R.id.required_optional_text).visibility) .isEqualTo(View.GONE) } + + @Test + fun givenCustomCallback_thenDisplayCallbackResponse() { + viewHolder.bind( + QuestionnaireViewItem( + Questionnaire.QuestionnaireItemComponent().apply { text = "Question" }, + QuestionnaireResponse.QuestionnaireResponseItemComponent(), + validationResult = NotValidated, + answersChangedCallback = { _, _, _, _ -> }, + questionViewTextConfiguration = QuestionTextConfiguration(showOptionalText = false), + callbacks = + mapOf( + Pair( + CustomCallbackType.AUTO_COMPLETE, + AutoCompleteCallback( + callback = { _ -> + run { + listOf( + AutoCompleteViewAnswerOption("a", "Answer A"), + AutoCompleteViewAnswerOption("b", "Answer B"), + ) + } + }, + ), + ), + ), + ), + ) + + val autoCompleteTextView = + viewHolder.itemView.findViewById(R.id.autoCompleteTextView) + + autoCompleteTextView.setText("t2") + val adapter = autoCompleteTextView.adapter + assertNotNull(adapter) + assertThat(adapter.count).isEqualTo(2) + } } From 2a7962f8df00ede35e147e30fa3061cfffee9d87 Mon Sep 17 00:00:00 2001 From: dilys Date: Thu, 9 Jan 2025 12:04:26 +1000 Subject: [PATCH 2/3] Incorporated review feedback --- .../fhir/datacapture/DataCaptureConfig.kt | 4 +- .../datacapture/QuestionnaireEditAdapter.kt | 10 +---- .../datacapture/QuestionnaireViewModel.kt | 6 +-- .../views/QuestionnaireViewItem.kt | 3 +- .../AutoCompleteViewHolderFactory.kt | 21 ++++++---- .../AutoCompleteViewHolderFactoryTest.kt | 41 ++++++++++--------- 6 files changed, 40 insertions(+), 45 deletions(-) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt index 6219725a93..9d33964acc 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt @@ -59,9 +59,9 @@ data class DataCaptureConfig( /** * A [CustomCallback] may be set by the client to override the behaviour of an existing component - * in the sdc. Currently only supports [CustomCallbackType.AUTO_COMPLETE]. + * in the sdc. */ - var callbacks: Map? = null, + var callback: CustomCallback<*>? = null, ) { /** diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt index a9485823b8..b366721cad 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt @@ -29,7 +29,6 @@ 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 -import com.google.android.fhir.datacapture.views.factories.AutoCompleteViewAnswerOption import com.google.android.fhir.datacapture.views.factories.AutoCompleteViewHolderFactory import com.google.android.fhir.datacapture.views.factories.BooleanChoiceViewHolderFactory import com.google.android.fhir.datacapture.views.factories.CheckBoxGroupViewHolderFactory @@ -393,11 +392,4 @@ internal object DiffCallbacks { } } -sealed class CustomCallback { - data class AutoCompleteCallback(val callback: (String) -> List) : - CustomCallback() -} - -enum class CustomCallbackType { - AUTO_COMPLETE, -} +typealias CustomCallback = (String, String) -> List diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt index f49a46c412..da837da6a4 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt @@ -96,8 +96,8 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat DataCapture.getConfiguration(application).valueSetResolverExternal } - private val callbacks: Map? by lazy { - DataCapture.getConfiguration(application).callbacks + private val callback: CustomCallback<*>? by lazy { + DataCapture.getConfiguration(application).callback } /** The current questionnaire as questions are being answered. */ @@ -989,7 +989,7 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat ), isHelpCardOpen = isHelpCard && isHelpCardOpen, helpCardStateChangedCallback = helpCardStateChangedCallback, - callbacks = callbacks, + callback = callback, ), ) add(question) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt index 7122c36101..4d7a85c3c0 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt @@ -20,7 +20,6 @@ import android.content.Context import android.text.Spanned import androidx.recyclerview.widget.RecyclerView import com.google.android.fhir.datacapture.CustomCallback -import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.isHelpCode @@ -95,7 +94,7 @@ data class QuestionnaireViewItem( val helpCardStateChangedCallback: (Boolean, QuestionnaireResponseItemComponent) -> Unit = { _, _ -> }, - val callbacks: Map? = null, + val callback: CustomCallback<*>? = null, ) { fun getQuestionnaireResponseItem(): QuestionnaireResponseItemComponent = questionnaireResponseItem diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt index 5b086a2d29..58d5c11149 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt @@ -30,7 +30,6 @@ import androidx.core.view.get import androidx.core.view.isEmpty import androidx.lifecycle.lifecycleScope import com.google.android.fhir.datacapture.CustomCallback -import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.identifierString @@ -64,11 +63,8 @@ internal object AutoCompleteViewHolderFactory : private val canHaveMultipleAnswers get() = questionnaireViewItem.questionnaireItem.repeats - private val callback: ((String) -> List)? - get() = - (questionnaireViewItem.callbacks?.get(CustomCallbackType.AUTO_COMPLETE) - as? CustomCallback.AutoCompleteCallback) - ?.callback + private val callback: CustomCallback<*>? + get() = questionnaireViewItem.callback override lateinit var questionnaireViewItem: QuestionnaireViewItem private lateinit var errorTextView: TextView @@ -102,6 +98,7 @@ internal object AutoCompleteViewHolderFactory : textViewResourceId = R.id.answer_option_textview, objects = answerOptionValues, callback = callback, + answerValueSet = questionnaireViewItem.questionnaireItem.answerValueSet, ) autoCompleteTextView.setAdapter(adapter) // Remove chips if any from the last bindView call on this VH. @@ -286,7 +283,8 @@ internal class AutoCompleteArrayAdapter( val resource: Int, val textViewResourceId: Int, private val objects: List, - private val callback: ((String) -> List)? = null, + private val callback: CustomCallback<*>? = null, + private val answerValueSet: String? = null, ) : ArrayAdapter(context, resource, textViewResourceId, objects) { private var items = listOf() @@ -311,13 +309,18 @@ internal class AutoCompleteArrayAdapter( override fun getItem(position: Int): AutoCompleteViewAnswerOption? = items.getOrNull(position) + @Suppress("UNCHECKED_CAST") override fun getFilter(): Filter { return object : Filter() { override fun performFiltering(constraint: CharSequence?): FilterResults { val query = (constraint?.toString() ?: "").trim() val filteredResults: List = - if (callback != null && objects.isEmpty()) { - callback.invoke(query) + if (callback != null && answerValueSet != null && objects.isEmpty()) { + (callback as? CustomCallback)?.invoke( + query, + answerValueSet, + ) + ?: emptyList() } else { objects.filter { it.answerDisplay.contains(query, ignoreCase = true) } } diff --git a/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt b/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt index 82285abd54..ceb64fc77b 100644 --- a/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt +++ b/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt @@ -22,8 +22,6 @@ import android.widget.FrameLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.view.get -import com.google.android.fhir.datacapture.CustomCallback.AutoCompleteCallback -import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.identifierString @@ -36,6 +34,7 @@ import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup import com.google.android.material.textfield.TextInputLayout import com.google.common.truth.Truth.assertThat +import kotlin.test.assertEquals import kotlin.test.assertNotNull import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Questionnaire @@ -472,36 +471,38 @@ class AutoCompleteViewHolderFactoryTest { @Test fun givenCustomCallback_thenDisplayCallbackResponse() { + val testAnswerVS = "testAnswerValueSet" + val testQuery = "t2" + viewHolder.bind( QuestionnaireViewItem( - Questionnaire.QuestionnaireItemComponent().apply { text = "Question" }, + Questionnaire.QuestionnaireItemComponent().apply { + text = "Question" + answerValueSet = testAnswerVS + }, QuestionnaireResponse.QuestionnaireResponseItemComponent(), validationResult = NotValidated, answersChangedCallback = { _, _, _, _ -> }, questionViewTextConfiguration = QuestionTextConfiguration(showOptionalText = false), - callbacks = - mapOf( - Pair( - CustomCallbackType.AUTO_COMPLETE, - AutoCompleteCallback( - callback = { _ -> - run { - listOf( - AutoCompleteViewAnswerOption("a", "Answer A"), - AutoCompleteViewAnswerOption("b", "Answer B"), - ) - } - }, - ), - ), - ), + callback = { query, uri -> + assertNotNull(query) + assertNotNull(uri) + assertEquals(query, testQuery) + assertEquals(uri, testAnswerVS) + run { + listOf( + AutoCompleteViewAnswerOption("a", "Answer A"), + AutoCompleteViewAnswerOption("b", "Answer B"), + ) + } + }, ), ) val autoCompleteTextView = viewHolder.itemView.findViewById(R.id.autoCompleteTextView) - autoCompleteTextView.setText("t2") + autoCompleteTextView.setText(testQuery) val adapter = autoCompleteTextView.adapter assertNotNull(adapter) assertThat(adapter.count).isEqualTo(2) From d91d0540df03048fa7322f5d081bcc6bb527a21b Mon Sep 17 00:00:00 2001 From: dilys Date: Thu, 23 Jan 2025 12:10:50 +1000 Subject: [PATCH 3/3] Incorporated review feedback - Combined functionality with the ExternalAnswerValueSetResolver - Renamed various functions and arguments for improved clarity - Moved filter handling out of the adapter and into the textChangedListener - Moved resolver to the viewmodel --- .../main/assets/component_auto_complete.json | 21 +++++++ .../fhir/catalog/CatalogApplication.kt | 31 +++++++--- .../fhir/datacapture/DataCaptureConfig.kt | 14 ++--- .../datacapture/QuestionnaireEditAdapter.kt | 2 - .../datacapture/QuestionnaireViewModel.kt | 25 ++++++-- .../EnabledAnswerOptionsEvaluator.kt | 4 +- .../views/QuestionnaireViewItem.kt | 6 +- .../AutoCompleteViewHolderFactory.kt | 61 +++++++++++-------- .../datacapture/QuestionnaireViewModelTest.kt | 4 +- .../AutoCompleteViewHolderFactoryTest.kt | 42 ------------- 10 files changed, 113 insertions(+), 97 deletions(-) diff --git a/catalog/src/main/assets/component_auto_complete.json b/catalog/src/main/assets/component_auto_complete.json index f46d1e7b3e..1955129d11 100644 --- a/catalog/src/main/assets/component_auto_complete.json +++ b/catalog/src/main/assets/component_auto_complete.json @@ -93,6 +93,27 @@ } } ] + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "autocomplete" + } + ] + } + } + ], + "linkId": "2", + "text": "Procedure", + "type": "choice", + "required": true, + "repeats": false, + "answerValueSet": "https://my.url/fhir/ValueSet/my-valueset" } ] } diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt b/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt index 974ad5266c..d52e5a591a 100644 --- a/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt +++ b/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt @@ -21,15 +21,15 @@ import ca.uhn.fhir.context.FhirContext import com.google.android.fhir.FhirEngine import com.google.android.fhir.FhirEngineConfiguration import com.google.android.fhir.FhirEngineProvider -import com.google.android.fhir.datacapture.CustomCallback.AutoCompleteCallback -import com.google.android.fhir.datacapture.CustomCallbackType import com.google.android.fhir.datacapture.DataCaptureConfig -import com.google.android.fhir.datacapture.views.factories.AutoCompleteViewAnswerOption +import com.google.android.fhir.datacapture.ExternalAnswerValueSetResolver import com.google.android.fhir.search.search import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.hl7.fhir.r4.model.Bundle +import org.hl7.fhir.r4.model.Coding class CatalogApplication : Application(), DataCaptureConfig.Provider { // Only initiate the FhirEngine when used for the first time, not when the app is created. @@ -47,15 +47,26 @@ class CatalogApplication : Application(), DataCaptureConfig.Provider { xFhirQueryResolver = { fhirEngine.search(it).map { it.resource } }, questionnaireItemViewHolderFactoryMatchersProviderFactory = ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory, - callbacks = mapOf(Pair(CustomCallbackType.AUTO_COMPLETE, AutoCompleteCallback( - callback = { query -> - run { - listOf(AutoCompleteViewAnswerOption("a", "Type 2 Diabetes Mellitus"), - AutoCompleteViewAnswerOption("b", "Test") + valueSetResolverExternal = + object : ExternalAnswerValueSetResolver { + override suspend fun resolve(uri: String, query: String?): List { + delay(1000) + // Here we can call out to our FHIR terminology server with the provided uri and query + if (uri == "https://my.url/fhir/ValueSet/my-valueset" && !query.isNullOrBlank()) { + return listOf( + Coding().apply { + code = "a" + display = "Custom response A" + }, + Coding().apply { + code = "b" + display = "Custom response B" + }, ) + } + return emptyList() } - } - ))) + }, ) CoroutineScope(Dispatchers.IO).launch { diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt index 9d33964acc..55bd788be7 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt @@ -56,12 +56,6 @@ data class DataCaptureConfig( var questionnaireItemViewHolderFactoryMatchersProviderFactory: QuestionnaireItemViewHolderFactoryMatchersProviderFactory? = null, - - /** - * A [CustomCallback] may be set by the client to override the behaviour of an existing component - * in the sdc. - */ - var callback: CustomCallback<*>? = null, ) { /** @@ -80,12 +74,18 @@ data class DataCaptureConfig( * allows the library to render answer options to `choice` and `open-choice` type questions more * dynamically. * + * Optional query parameter can be used to accept the search string from user input for server-side + * filtering. + * * NOTE: The result of the resolution may be cached to improve performance. In other words, the * resolver may be called only once after which the same answer value set may be used multiple times * in the UI to populate answer options. + * + * @param uri The uri used to identify the questionnaire item + * @param query The text input from the user */ interface ExternalAnswerValueSetResolver { - suspend fun resolve(uri: String): List + suspend fun resolve(uri: String, query: String?): List } /** diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt index b366721cad..ef6e879ea6 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireEditAdapter.kt @@ -391,5 +391,3 @@ internal object DiffCallbacks { } } } - -typealias CustomCallback = (String, String) -> List diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt index da837da6a4..f3294609c0 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireViewModel.kt @@ -76,6 +76,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.withIndex import kotlinx.coroutines.launch +import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.DateTimeType import org.hl7.fhir.r4.model.Questionnaire import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent @@ -96,10 +97,6 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat DataCapture.getConfiguration(application).valueSetResolverExternal } - private val callback: CustomCallback<*>? by lazy { - DataCapture.getConfiguration(application).callback - } - /** The current questionnaire as questions are being answered. */ internal val questionnaire: Questionnaire @@ -393,6 +390,23 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat modificationCount.update { it + 1 } } + /** + * Function to dynamically resolve answer options for the AutoComplete component using + * [ExternalAnswerValueSetResolver.resolve] + */ + private val autoCompleteAnswerOptionResolver: (String, String?, (List) -> Unit) -> Unit = + { query, answerValueSet, callback -> + viewModelScope.launch { + val response = + if (externalValueSetResolver != null && answerValueSet != null) { + externalValueSetResolver!!.resolve(query, answerValueSet) + } else { + emptyList() + } + callback(response) + } + } + private val expressionEvaluator: ExpressionEvaluator = ExpressionEvaluator( questionnaire, @@ -954,6 +968,7 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat validationResult = validationResult, answersChangedCallback = answersChangedCallback, enabledAnswerOptions = enabledQuestionnaireAnswerOptions, + autoCompleteAnswerOptionResolver = autoCompleteAnswerOptionResolver, minAnswerValue = questionnaireItem.minValueCqfCalculatedValueExpression?.let { expressionEvaluator.evaluateExpressionValue( @@ -989,7 +1004,7 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat ), isHelpCardOpen = isHelpCard && isHelpCardOpen, helpCardStateChangedCallback = helpCardStateChangedCallback, - callback = callback, + // suggestions = suggestions, ), ) add(question) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/expressions/EnabledAnswerOptionsEvaluator.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/expressions/EnabledAnswerOptionsEvaluator.kt index 94c633221e..2c1fec912f 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/expressions/EnabledAnswerOptionsEvaluator.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/expressions/EnabledAnswerOptionsEvaluator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Google LLC + * Copyright 2022-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -179,7 +179,7 @@ internal class EnabledAnswerOptionsEvaluator( } } else { // Ask the client to provide the answers from an external expanded Valueset. - externalValueSetResolver?.resolve(uri)?.map { coding -> + externalValueSetResolver?.resolve(uri, null)?.map { coding -> Questionnaire.QuestionnaireItemAnswerOptionComponent(coding.copy()) } } diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt index 4d7a85c3c0..fe5ed498b6 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/QuestionnaireViewItem.kt @@ -19,7 +19,6 @@ package com.google.android.fhir.datacapture.views import android.content.Context import android.text.Spanned import androidx.recyclerview.widget.RecyclerView -import com.google.android.fhir.datacapture.CustomCallback import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.isHelpCode @@ -31,6 +30,7 @@ import com.google.android.fhir.datacapture.validation.NotValidated import com.google.android.fhir.datacapture.validation.Valid import com.google.android.fhir.datacapture.validation.ValidationResult import com.google.android.fhir.datacapture.views.factories.QuestionnaireItemViewHolder +import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Questionnaire import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent import org.hl7.fhir.r4.model.QuestionnaireResponse @@ -94,7 +94,9 @@ data class QuestionnaireViewItem( val helpCardStateChangedCallback: (Boolean, QuestionnaireResponseItemComponent) -> Unit = { _, _ -> }, - val callback: CustomCallback<*>? = null, + internal val autoCompleteAnswerOptionResolver: (String, String?, (List) -> Unit) -> Unit = + { _, _, _ -> + }, ) { fun getQuestionnaireResponseItem(): QuestionnaireResponseItemComponent = questionnaireResponseItem diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt index 58d5c11149..8e49a7c584 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactory.kt @@ -28,8 +28,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children import androidx.core.view.get import androidx.core.view.isEmpty +import androidx.core.widget.addTextChangedListener import androidx.lifecycle.lifecycleScope -import com.google.android.fhir.datacapture.CustomCallback import com.google.android.fhir.datacapture.R import com.google.android.fhir.datacapture.extensions.displayString import com.google.android.fhir.datacapture.extensions.identifierString @@ -58,14 +58,11 @@ internal object AutoCompleteViewHolderFactory : private lateinit var autoCompleteTextView: MaterialAutoCompleteTextView private lateinit var chipContainer: ChipGroup private lateinit var textInputLayout: TextInputLayout - private lateinit var adapter: ArrayAdapter + private lateinit var adapter: AutoCompleteArrayAdapter private val canHaveMultipleAnswers get() = questionnaireViewItem.questionnaireItem.repeats - private val callback: CustomCallback<*>? - get() = questionnaireViewItem.callback - override lateinit var questionnaireViewItem: QuestionnaireViewItem private lateinit var errorTextView: TextView @@ -82,7 +79,6 @@ internal object AutoCompleteViewHolderFactory : override fun bind(questionnaireViewItem: QuestionnaireViewItem) { header.bind(questionnaireViewItem) header.showRequiredOrOptionalTextInHeaderView(questionnaireViewItem) - val suggestions = mutableListOf() val answerOptionValues = questionnaireViewItem.enabledAnswerOptions.map { AutoCompleteViewAnswerOption( @@ -90,15 +86,12 @@ internal object AutoCompleteViewHolderFactory : answerDisplay = it.value.displayString(header.context), ) } - suggestions.addAll(answerOptionValues) adapter = AutoCompleteArrayAdapter( context = header.context, resource = R.layout.drop_down_list_item, textViewResourceId = R.id.answer_option_textview, objects = answerOptionValues, - callback = callback, - answerValueSet = questionnaireViewItem.questionnaireItem.answerValueSet, ) autoCompleteTextView.setAdapter(adapter) // Remove chips if any from the last bindView call on this VH. @@ -106,6 +99,30 @@ internal object AutoCompleteViewHolderFactory : presetValuesIfAny() displayValidationResult(questionnaireViewItem.validationResult) + + val serverSideFiltering = + questionnaireViewItem.questionnaireItem.answerValueSet != null && + answerOptionValues.isEmpty() + + autoCompleteTextView.addTextChangedListener { text -> + if (serverSideFiltering) { + questionnaireViewItem.autoCompleteAnswerOptionResolver( + text.toString(), + questionnaireViewItem.questionnaireItem.answerValueSet, + ) { response -> + val items = + response.map { + AutoCompleteViewAnswerOption( + answerId = it.code, + answerDisplay = it.display, + ) + } + adapter.updateData(items) + } + } else { + adapter.clientSideFilter(text.toString()) + } + } } override fun setReadOnly(isReadOnly: Boolean) { @@ -272,7 +289,7 @@ internal object AutoCompleteViewHolderFactory : * An answer option that would show up as a dropdown item in an [AutoCompleteViewHolderFactory] * textview */ -data class AutoCompleteViewAnswerOption(val answerId: String, val answerDisplay: String) { +internal data class AutoCompleteViewAnswerOption(val answerId: String, val answerDisplay: String) { override fun toString(): String { return this.answerDisplay } @@ -283,8 +300,6 @@ internal class AutoCompleteArrayAdapter( val resource: Int, val textViewResourceId: Int, private val objects: List, - private val callback: CustomCallback<*>? = null, - private val answerValueSet: String? = null, ) : ArrayAdapter(context, resource, textViewResourceId, objects) { private var items = listOf() @@ -303,6 +318,11 @@ internal class AutoCompleteArrayAdapter( notifyDataSetChanged() } + fun clientSideFilter(query: String) { + items = objects.filter { it.answerDisplay.contains(query, ignoreCase = true) } + notifyDataSetChanged() + } + override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { return getView(position, convertView, parent) } @@ -312,21 +332,12 @@ internal class AutoCompleteArrayAdapter( @Suppress("UNCHECKED_CAST") override fun getFilter(): Filter { return object : Filter() { + override fun performFiltering(constraint: CharSequence?): FilterResults { - val query = (constraint?.toString() ?: "").trim() - val filteredResults: List = - if (callback != null && answerValueSet != null && objects.isEmpty()) { - (callback as? CustomCallback)?.invoke( - query, - answerValueSet, - ) - ?: emptyList() - } else { - objects.filter { it.answerDisplay.contains(query, ignoreCase = true) } - } + // Prevent default filtering behaviour return FilterResults().apply { - values = filteredResults - count = filteredResults.size + values = items + count = items.size } } diff --git a/datacapture/src/test/java/com/google/android/fhir/datacapture/QuestionnaireViewModelTest.kt b/datacapture/src/test/java/com/google/android/fhir/datacapture/QuestionnaireViewModelTest.kt index 659429a95a..ff73407afa 100644 --- a/datacapture/src/test/java/com/google/android/fhir/datacapture/QuestionnaireViewModelTest.kt +++ b/datacapture/src/test/java/com/google/android/fhir/datacapture/QuestionnaireViewModelTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 Google LLC + * Copyright 2023-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -5022,7 +5022,7 @@ class QuestionnaireViewModelTest { DataCaptureConfig( valueSetResolverExternal = object : ExternalAnswerValueSetResolver { - override suspend fun resolve(uri: String): List { + override suspend fun resolve(uri: String, query: String?): List { return if (uri == CODE_SYSTEM_YES_NO) { listOf( Coding().apply { diff --git a/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt b/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt index ceb64fc77b..65c59b34ce 100644 --- a/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt +++ b/datacapture/src/test/java/com/google/android/fhir/datacapture/views/factories/AutoCompleteViewHolderFactoryTest.kt @@ -17,7 +17,6 @@ package com.google.android.fhir.datacapture.views.factories import android.view.View -import android.widget.AutoCompleteTextView import android.widget.FrameLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity @@ -34,8 +33,6 @@ import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup import com.google.android.material.textfield.TextInputLayout import com.google.common.truth.Truth.assertThat -import kotlin.test.assertEquals -import kotlin.test.assertNotNull import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Questionnaire import org.hl7.fhir.r4.model.QuestionnaireResponse @@ -468,43 +465,4 @@ class AutoCompleteViewHolderFactoryTest { assertThat(viewHolder.itemView.findViewById(R.id.required_optional_text).visibility) .isEqualTo(View.GONE) } - - @Test - fun givenCustomCallback_thenDisplayCallbackResponse() { - val testAnswerVS = "testAnswerValueSet" - val testQuery = "t2" - - viewHolder.bind( - QuestionnaireViewItem( - Questionnaire.QuestionnaireItemComponent().apply { - text = "Question" - answerValueSet = testAnswerVS - }, - QuestionnaireResponse.QuestionnaireResponseItemComponent(), - validationResult = NotValidated, - answersChangedCallback = { _, _, _, _ -> }, - questionViewTextConfiguration = QuestionTextConfiguration(showOptionalText = false), - callback = { query, uri -> - assertNotNull(query) - assertNotNull(uri) - assertEquals(query, testQuery) - assertEquals(uri, testAnswerVS) - run { - listOf( - AutoCompleteViewAnswerOption("a", "Answer A"), - AutoCompleteViewAnswerOption("b", "Answer B"), - ) - } - }, - ), - ) - - val autoCompleteTextView = - viewHolder.itemView.findViewById(R.id.autoCompleteTextView) - - autoCompleteTextView.setText(testQuery) - val adapter = autoCompleteTextView.adapter - assertNotNull(adapter) - assertThat(adapter.count).isEqualTo(2) - } }