diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/CustomQuestionnaireFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/CustomQuestionnaireFragment.kt index 281f728b13..92aa9181f3 100644 --- a/catalog/src/main/java/com/google/android/fhir/catalog/CustomQuestionnaireFragment.kt +++ b/catalog/src/main/java/com/google/android/fhir/catalog/CustomQuestionnaireFragment.kt @@ -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. @@ -16,11 +16,12 @@ package com.google.android.fhir.catalog -import com.google.android.fhir.datacapture.QuestionnaireFragment +import com.google.android.fhir.datacapture.QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatcher import com.google.android.fhir.datacapture.contrib.views.barcode.QuestionnaireItemBarCodeReaderViewHolderFactory -class CustomQuestionnaireFragment : QuestionnaireFragment() { - override fun getCustomQuestionnaireItemViewHolderFactoryMatchers(): +// TODO Remove this file and move this code to maybe a custom view in catalog app? +class CustomQuestionnaireFragment /*: QuestionnaireFragment()*/ { + /*override*/ fun getCustomQuestionnaireItemViewHolderFactoryMatchers(): List { return listOf( QuestionnaireItemViewHolderFactoryMatcher(CustomNumberPickerFactory) { questionnaireItem -> @@ -30,9 +31,8 @@ class CustomQuestionnaireFragment : QuestionnaireFragment() { }, QuestionnaireItemViewHolderFactoryMatcher(QuestionnaireItemBarCodeReaderViewHolderFactory) { questionnaireItem -> - questionnaireItem.getExtensionByUrl( - QuestionnaireItemBarCodeReaderViewHolderFactory.WIDGET_EXTENSION - ) + questionnaireItem + .getExtensionByUrl(QuestionnaireItemBarCodeReaderViewHolderFactory.WIDGET_EXTENSION) .let { if (it == null) false else it.value.toString() == QuestionnaireItemBarCodeReaderViewHolderFactory.WIDGET_TYPE diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt index 0cb1bcb7e7..37174916d0 100644 --- a/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt +++ b/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt @@ -26,11 +26,8 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.appcompat.app.AppCompatActivity -import androidx.core.os.bundleOf import androidx.fragment.app.Fragment -import androidx.fragment.app.add import androidx.fragment.app.commit -import androidx.fragment.app.replace import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope @@ -146,14 +143,12 @@ class DemoQuestionnaireFragment : Fragment() { if (childFragmentManager.findFragmentByTag(QUESTIONNAIRE_FRAGMENT_TAG) == null) { childFragmentManager.commit { setReorderingAllowed(true) - add( + add( R.id.container, - tag = QUESTIONNAIRE_FRAGMENT_TAG, - args = - bundleOf( - QuestionnaireFragment.EXTRA_QUESTIONNAIRE_JSON_STRING to - viewModel.getQuestionnaireJson() - ) + QuestionnaireFragment.builder() + .setQuestionnaire(viewModel.getQuestionnaireJson()) + .build(), + QUESTIONNAIRE_FRAGMENT_TAG ) } } @@ -179,13 +174,10 @@ class DemoQuestionnaireFragment : Fragment() { } childFragmentManager.commit { setReorderingAllowed(true) - replace( + replace( R.id.container, - tag = QUESTIONNAIRE_FRAGMENT_TAG, - args = - bundleOf( - QuestionnaireFragment.EXTRA_QUESTIONNAIRE_JSON_STRING to questionnaireJsonString - ) + QuestionnaireFragment.builder().setQuestionnaire(questionnaireJsonString).build(), + QUESTIONNAIRE_FRAGMENT_TAG ) } } 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 14e590b697..fb9418c8b3 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 @@ -18,6 +18,8 @@ package com.google.android.fhir.datacapture import android.app.Application import com.google.android.fhir.datacapture.DataCaptureConfig.Provider +import com.google.android.fhir.datacapture.QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatcher +import com.google.android.fhir.datacapture.QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatchersProvider import org.hl7.fhir.r4.context.SimpleWorkerContext import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Resource @@ -53,6 +55,15 @@ data class DataCaptureConfig( * https://build.fhir.org/ig/HL7/sdc/expressions.html#fhirquery for more details. */ var xFhirQueryResolver: XFhirQueryResolver? = null, + + /** + * A [QuestionnaireItemViewHolderFactoryMatchersProviderFactory] may be set by the client to + * provide [QuestionnaireItemViewHolderFactoryMatcher]s to add custom questionnaire components or + * override the behaviour of existing components in the sdc. + */ + var questionnaireItemViewHolderFactoryMatchersProviderFactory: + QuestionnaireItemViewHolderFactoryMatchersProviderFactory? = + null ) { internal val simpleWorkerContext: SimpleWorkerContext by lazy { @@ -93,3 +104,17 @@ interface ExternalAnswerValueSetResolver { fun interface XFhirQueryResolver { suspend fun resolve(xFhirQuery: String): List } + +/** + * Factory to create [QuestionnaireItemViewHolderFactoryMatchersProvider] for the + * [QuestionnaireFragment] to provide [List] of [QuestionnaireItemViewHolderFactoryMatcher]. The + * developers may provide the factory to the library via [DataCaptureConfig] to add custom + * questionnaire components or override the behaviour of existing components in the sdc. + * + * See the + * [developer guide](https://github.com/google/android-fhir/wiki/SDCL:-Customize-how-a-Questionnaire-is-displayed#custom-questionnaire-components) + * for more information. + */ +fun interface QuestionnaireItemViewHolderFactoryMatchersProviderFactory { + fun get(provider: String): QuestionnaireItemViewHolderFactoryMatchersProvider +} diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireFragment.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireFragment.kt index 3712317ec5..5a5845ef2e 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireFragment.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireFragment.kt @@ -16,13 +16,16 @@ package com.google.android.fhir.datacapture +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button +import androidx.annotation.VisibleForTesting import androidx.appcompat.view.ContextThemeWrapper import androidx.core.content.res.use +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.setFragmentResult @@ -44,9 +47,25 @@ import timber.log.Timber * [QuestionnaireFragment](https://github.com/google/android-fhir/wiki/SDCL%3A-Use-QuestionnaireFragment) * developer guide. */ -open class QuestionnaireFragment : Fragment() { +class QuestionnaireFragment : Fragment() { private val viewModel: QuestionnaireViewModel by viewModels() + /** + * Provides a [QuestionnaireItemViewHolderFactoryMatcher]s which are used to evaluate whether a + * custom [QuestionnaireItemViewHolderFactory] should be used to render a given questionnaire + * item. The provider may be provided by the application developer via [DataCaptureConfig], + * otherwise default no-op implementation is used. + */ + @VisibleForTesting + val questionnaireItemViewHolderFactoryMatchersProvider: + QuestionnaireItemViewHolderFactoryMatchersProvider by lazy { + requireArguments().getString(EXTRA_MATCHERS_FACTORY)?.let { + DataCapture.getConfiguration(requireContext()) + .questionnaireItemViewHolderFactoryMatchersProviderFactory?.get(it) + } + ?: EmptyQuestionnaireItemViewHolderFactoryMatchersProviderImpl + } + /** @suppress */ override fun onCreateView( inflater: LayoutInflater, @@ -95,7 +114,7 @@ open class QuestionnaireFragment : Fragment() { val questionnaireProgressIndicator: LinearProgressIndicator = view.findViewById(R.id.questionnaire_progress_indicator) val questionnaireItemEditAdapter = - QuestionnaireItemEditAdapter(getCustomQuestionnaireItemViewHolderFactoryMatchers()) + QuestionnaireItemEditAdapter(questionnaireItemViewHolderFactoryMatchersProvider.get()) val questionnaireItemReviewAdapter = QuestionnaireItemReviewAdapter() val submitButton = requireView().findViewById