@@ -19,8 +19,19 @@ package com.google.android.fhir.datacapture.views.factories
1919import android.view.View
2020import android.widget.TextView
2121import androidx.appcompat.app.AppCompatActivity
22+ import androidx.compose.foundation.layout.Column
23+ import androidx.compose.foundation.layout.fillMaxWidth
24+ import androidx.compose.foundation.layout.padding
25+ import androidx.compose.runtime.Composable
26+ import androidx.compose.runtime.getValue
27+ import androidx.compose.runtime.remember
28+ import androidx.compose.runtime.rememberCoroutineScope
29+ import androidx.compose.runtime.setValue
30+ import androidx.compose.ui.Modifier
31+ import androidx.compose.ui.res.dimensionResource
2232import androidx.lifecycle.lifecycleScope
2333import com.google.android.fhir.datacapture.R
34+ import com.google.android.fhir.datacapture.extensions.itemMedia
2435import com.google.android.fhir.datacapture.extensions.sliderStepValue
2536import com.google.android.fhir.datacapture.extensions.tryUnwrapContext
2637import com.google.android.fhir.datacapture.validation.Invalid
@@ -29,31 +40,85 @@ import com.google.android.fhir.datacapture.validation.Valid
2940import com.google.android.fhir.datacapture.validation.ValidationResult
3041import com.google.android.fhir.datacapture.views.HeaderView
3142import com.google.android.fhir.datacapture.views.QuestionnaireViewItem
43+ import com.google.android.fhir.datacapture.views.compose.ErrorText
44+ import com.google.android.fhir.datacapture.views.compose.Header
45+ import com.google.android.fhir.datacapture.views.compose.MediaItem
46+ import com.google.android.fhir.datacapture.views.compose.SliderItem
3247import com.google.android.material.slider.Slider
48+ import kotlin.math.roundToInt
49+ import kotlinx.coroutines.Dispatchers
3350import kotlinx.coroutines.launch
3451import org.hl7.fhir.r4.model.IntegerType
3552import org.hl7.fhir.r4.model.QuestionnaireResponse
3653import org.hl7.fhir.r4.model.Type
3754
38- internal object SliderViewHolderFactory :
39- QuestionnaireItemAndroidViewHolderFactory (R .layout.slider_view) {
55+ internal object SliderViewHolderFactory : QuestionnaireItemComposeViewHolderFactory {
4056 override fun getQuestionnaireItemViewHolderDelegate () =
41- object : QuestionnaireItemAndroidViewHolderDelegate {
57+ object : QuestionnaireItemComposeViewHolderDelegate {
4258 private lateinit var appContext: AppCompatActivity
4359 private lateinit var header: HeaderView
4460 private lateinit var slider: Slider
4561 private lateinit var error: TextView
46- override lateinit var questionnaireViewItem: QuestionnaireViewItem
4762
48- override fun init (itemView : View ) {
63+ @Composable
64+ override fun Content (questionnaireViewItem : QuestionnaireViewItem ) {
65+ val validationMessage =
66+ remember(questionnaireViewItem) {
67+ displayValidationResult(questionnaireViewItem.validationResult)
68+ }
69+ val readOnly =
70+ remember(questionnaireViewItem) { questionnaireViewItem.questionnaireItem.readOnly }
71+ val answer =
72+ remember(questionnaireViewItem) { questionnaireViewItem.answers.singleOrNull() }
73+ val minValue = remember(answer) { getMinValue(questionnaireViewItem.minAnswerValue) }
74+ val maxValue = remember(answer) { getMaxValue(questionnaireViewItem.maxAnswerValue) }
75+
76+ check(minValue < maxValue) { " minValue $minValue must be smaller than maxValue $maxValue " }
77+ val stepSize =
78+ remember(questionnaireViewItem) {
79+ questionnaireViewItem.questionnaireItem.sliderStepValue ? : SLIDER_DEFAULT_STEP_SIZE
80+ }
81+ val steps =
82+ remember(stepSize, minValue, maxValue) { (maxValue - minValue).div(stepSize).toInt() }
83+ val questionnaireViewItemAnswerValue =
84+ remember(answer) { answer?.valueIntegerType?.value?.toFloat() ? : minValue }
85+ val coroutineScope = rememberCoroutineScope { Dispatchers .Main }
86+
87+ Column (
88+ modifier =
89+ Modifier .fillMaxWidth()
90+ .padding(
91+ horizontal = dimensionResource(R .dimen.item_margin_horizontal),
92+ vertical = dimensionResource(R .dimen.item_margin_vertical),
93+ ),
94+ ) {
95+ Header (questionnaireViewItem, showRequiredOrOptionalText = true )
96+ questionnaireViewItem.questionnaireItem.itemMedia?.let { MediaItem (it) }
97+ SliderItem (
98+ startPosition = questionnaireViewItemAnswerValue,
99+ steps = steps,
100+ valueRange = minValue.. maxValue,
101+ enabled = ! readOnly,
102+ ) {
103+ coroutineScope.launch {
104+ questionnaireViewItem.setAnswer(
105+ QuestionnaireResponse .QuestionnaireResponseItemAnswerComponent ()
106+ .setValue(IntegerType (it.roundToInt())),
107+ )
108+ }
109+ }
110+ validationMessage?.let { ErrorText (it) }
111+ }
112+ }
113+
114+ fun init (itemView : View ) {
49115 appContext = itemView.context.tryUnwrapContext()!!
50116 header = itemView.findViewById(R .id.header)
51117 slider = itemView.findViewById(R .id.slider)
52118 error = itemView.findViewById(R .id.error)
53119 }
54120
55- override fun bind (questionnaireViewItem : QuestionnaireViewItem ) {
56- this .questionnaireViewItem = questionnaireViewItem
121+ fun bind (questionnaireViewItem : QuestionnaireViewItem ) {
57122 header.bind(questionnaireViewItem, showRequiredOrOptionalText = true )
58123 val answer = questionnaireViewItem.answers.singleOrNull()
59124 val minValue = getMinValue(questionnaireViewItem.minAnswerValue)
@@ -82,19 +147,17 @@ internal object SliderViewHolderFactory :
82147 }
83148 }
84149
85- displayValidationResult(questionnaireViewItem.validationResult)
150+ error.text = displayValidationResult(questionnaireViewItem.validationResult)
86151 }
87152
88- private fun displayValidationResult (validationResult : ValidationResult ) {
89- error.text =
90- when (validationResult) {
91- is NotValidated ,
92- Valid , -> null
93- is Invalid -> validationResult.getSingleStringValidationMessage()
94- }
95- }
153+ private fun displayValidationResult (validationResult : ValidationResult ) =
154+ when (validationResult) {
155+ is NotValidated ,
156+ Valid , -> null
157+ is Invalid -> validationResult.getSingleStringValidationMessage()
158+ }
96159
97- override fun setReadOnly (isReadOnly : Boolean ) {
160+ fun setReadOnly (isReadOnly : Boolean ) {
98161 slider.isEnabled = ! isReadOnly
99162 }
100163 }
0 commit comments