@@ -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