@@ -20,12 +20,12 @@ import androidx.compose.foundation.layout.Row
2020import  androidx.compose.foundation.layout.fillMaxWidth 
2121import  androidx.compose.material3.DropdownMenuItem 
2222import  androidx.compose.material3.ExperimentalMaterial3Api 
23+ import  androidx.compose.material3.ExposedDropdownMenuAnchorType 
2324import  androidx.compose.material3.ExposedDropdownMenuBox 
2425import  androidx.compose.material3.ExposedDropdownMenuDefaults 
2526import  androidx.compose.material3.Icon 
2627import  androidx.compose.material3.IconButton 
2728import  androidx.compose.material3.MaterialTheme 
28- import  androidx.compose.material3.MenuAnchorType 
2929import  androidx.compose.material3.OutlinedTextField 
3030import  androidx.compose.material3.Text 
3131import  androidx.compose.runtime.Composable 
@@ -43,19 +43,20 @@ import androidx.compose.ui.res.painterResource
4343import  androidx.compose.ui.semantics.error 
4444import  androidx.compose.ui.semantics.semantics 
4545import  androidx.compose.ui.text.AnnotatedString 
46+ import  androidx.compose.ui.text.TextRange 
47+ import  androidx.compose.ui.text.input.TextFieldValue 
4648import  androidx.core.graphics.drawable.toBitmap 
4749import  com.google.android.fhir.datacapture.R 
4850import  com.google.android.fhir.datacapture.views.factories.DropDownAnswerOption 
4951
5052@OptIn(ExperimentalMaterial3Api ::class )
5153@Composable
52- internal  fun  ExposedDropDownMenuBoxItem (
54+ internal  fun  DropDownItem (
5355  modifier :  Modifier ,
5456  enabled :  Boolean ,
5557  labelText :  AnnotatedString ?  = null,
5658  supportingText :  String?  = null,
5759  isError :  Boolean  = false,
58-   showClearIcon :  Boolean  = false,
5960  selectedOption :  DropDownAnswerOption ?  = null,
6061  options :  List <DropDownAnswerOption >,
6162  onDropDownAnswerOptionSelected :  (DropDownAnswerOption ? ) ->  Unit ,
@@ -84,7 +85,7 @@ internal fun ExposedDropDownMenuBoxItem(
8485        Modifier .fillMaxWidth()
8586          .testTag(DROP_DOWN_TEXT_FIELD_TAG )
8687          .semantics { if  (isError) error(supportingText ? :  " " 
87-           .menuAnchor(MenuAnchorType .PrimaryNotEditable , enabled),
88+           .menuAnchor(ExposedDropdownMenuAnchorType .PrimaryNotEditable , enabled),
8889      readOnly =  true ,
8990      enabled =  enabled,
9091      minLines =  1 ,
@@ -101,6 +102,109 @@ internal fun ExposedDropDownMenuBoxItem(
101102            )
102103          }
103104        },
105+       trailingIcon =  { ExposedDropdownMenuDefaults .TrailingIcon (expanded =  expanded) },
106+     )
107+     ExposedDropdownMenu (expanded =  expanded, onDismissRequest =  { expanded =  false  }) {
108+       options.forEach { option -> 
109+         DropDownAnswerMenuItem (enabled, option) {
110+           selectedDropDownAnswerOption =  option
111+           expanded =  false 
112+         }
113+       }
114+     }
115+   }
116+ }
117+ 
118+ @OptIn(ExperimentalMaterial3Api ::class )
119+ @Composable
120+ internal  fun  DropDownAnswerMenuItem (
121+   enabled :  Boolean ,
122+   answerOption :  DropDownAnswerOption ,
123+   onSelected :  () ->  Unit ,
124+ ) {
125+   DropdownMenuItem (
126+     modifier =  Modifier .testTag(DROP_DOWN_ANSWER_MENU_ITEM_TAG ),
127+     text =  {
128+       Text (answerOption.answerOptionAnnotatedString(), style =  MaterialTheme .typography.bodyLarge)
129+     },
130+     leadingIcon = 
131+       answerOption.answerOptionImage?.let  {
132+         {
133+           Icon (
134+             it.toBitmap().asImageBitmap(),
135+             contentDescription =  answerOption.answerOptionString,
136+           )
137+         }
138+       },
139+     enabled =  enabled,
140+     onClick =  { onSelected() },
141+     contentPadding =  ExposedDropdownMenuDefaults .ItemContentPadding ,
142+   )
143+ }
144+ 
145+ @OptIn(ExperimentalMaterial3Api ::class )
146+ @Composable
147+ internal  fun  AutoCompleteDropDownItem (
148+   modifier :  Modifier ,
149+   enabled :  Boolean ,
150+   labelText :  AnnotatedString ?  = null,
151+   supportingText :  String?  = null,
152+   isError :  Boolean  = false,
153+   showClearIcon :  Boolean  = false,
154+   readOnly :  Boolean  = showClearIcon,
155+   selectedOption :  DropDownAnswerOption ?  = null,
156+   options :  List <DropDownAnswerOption >,
157+   onDropDownAnswerOptionSelected :  (DropDownAnswerOption ? ) ->  Unit ,
158+ ) {
159+   var  expanded by remember { mutableStateOf(false ) }
160+   var  selectedDropDownAnswerOption by
161+     remember(selectedOption, options) { mutableStateOf(selectedOption) }
162+   var  selectedOptionDisplay by
163+     remember(selectedDropDownAnswerOption) {
164+       val  stringValue =  selectedDropDownAnswerOption?.answerOptionString ? :  " " 
165+       mutableStateOf(TextFieldValue (stringValue, selection =  TextRange (stringValue.length)))
166+     }
167+   val  filteredOptions = 
168+     remember(options, selectedOptionDisplay) {
169+       options.filter { it.answerOptionString.contains(selectedOptionDisplay.text, true ) }
170+     }
171+ 
172+   LaunchedEffect (selectedDropDownAnswerOption) {
173+     onDropDownAnswerOptionSelected(selectedDropDownAnswerOption)
174+   }
175+ 
176+   ExposedDropdownMenuBox (
177+     modifier =  modifier,
178+     expanded =  expanded,
179+     onExpandedChange =  { expanded =  it },
180+   ) {
181+     OutlinedTextField (
182+       value =  selectedOptionDisplay,
183+       onValueChange =  {
184+         selectedOptionDisplay =  it
185+         if  (! expanded) expanded =  true 
186+       },
187+       modifier = 
188+         Modifier .fillMaxWidth()
189+           .testTag(DROP_DOWN_TEXT_FIELD_TAG )
190+           .semantics { if  (isError) error(supportingText ? :  " " 
191+           .menuAnchor(ExposedDropdownMenuAnchorType .PrimaryEditable , enabled),
192+       readOnly =  readOnly,
193+       enabled =  enabled,
194+       minLines =  1 ,
195+       isError =  isError,
196+       label =  { labelText?.let  { Text (it) } },
197+       supportingText =  { supportingText?.let  { Text (it) } },
198+       leadingIcon = 
199+         selectedDropDownAnswerOption?.answerOptionImage?.let  {
200+           {
201+             Icon (
202+               it.toBitmap().asImageBitmap(),
203+               contentDescription =  selectedDropDownAnswerOption!! .answerOptionString,
204+               modifier =  Modifier .testTag(DROP_DOWN_TEXT_FIELD_LEADING_ICON_TAG ),
205+             )
206+           }
207+         },
104208      trailingIcon =  {
105209        Row (verticalAlignment =  Alignment .CenterVertically ) {
106210          if  (showClearIcon) {
@@ -111,33 +215,26 @@ internal fun ExposedDropDownMenuBoxItem(
111215              Icon (painterResource(R .drawable.ic_clear), contentDescription =  " clear" 
112216            }
113217          }
114-           ExposedDropdownMenuDefaults .TrailingIcon (expanded =  expanded)
218+           ExposedDropdownMenuDefaults .TrailingIcon (
219+             expanded =  expanded,
220+             modifier = 
221+               Modifier .menuAnchor(
222+                 ExposedDropdownMenuAnchorType .SecondaryEditable ,
223+                 enabled,
224+               ),
225+           )
115226        }
116227      },
117228    )
118-     ExposedDropdownMenu (expanded =  expanded, onDismissRequest =  { expanded =  false  }) {
119-       options.forEach { option -> 
120-         DropdownMenuItem (
121-           modifier =  Modifier .testTag(DROP_DOWN_MENU_ITEM_TAG ),
122-           text =  {
123-             Text (option.answerOptionAnnotatedString(), style =  MaterialTheme .typography.bodyLarge)
124-           },
125-           leadingIcon = 
126-             option.answerOptionImage?.let  {
127-               {
128-                 Icon (
129-                   it.toBitmap().asImageBitmap(),
130-                   contentDescription =  option.answerOptionString,
131-                 )
132-               }
133-             },
134-           enabled =  enabled,
135-           onClick =  {
229+ 
230+     if  (filteredOptions.isNotEmpty()) {
231+       ExposedDropdownMenu (expanded =  expanded, onDismissRequest =  { expanded =  false  }) {
232+         filteredOptions.forEach { option -> 
233+           DropDownAnswerMenuItem (enabled, option) {
136234            selectedDropDownAnswerOption =  option
137235            expanded =  false 
138-           },
139-           contentPadding =  ExposedDropdownMenuDefaults .ItemContentPadding ,
140-         )
236+           }
237+         }
141238      }
142239    }
143240  }
@@ -146,4 +243,4 @@ internal fun ExposedDropDownMenuBoxItem(
146243const  val  CLEAR_TEXT_ICON_BUTTON_TAG  =  " clear_field_text" 
147244const  val  DROP_DOWN_TEXT_FIELD_TAG  =  " drop_down_text_field" 
148245const  val  DROP_DOWN_TEXT_FIELD_LEADING_ICON_TAG  =  " drop_down_text_field_leading_icon" 
149- const  val  DROP_DOWN_MENU_ITEM_TAG  =  " drop_down_list_menu_item " 
246+ const  val  DROP_DOWN_ANSWER_MENU_ITEM_TAG  =  " drop_down_answer_list_menu_item " 
0 commit comments