22// Licensed under the MIT License.
33package io .adaptivecards .renderer .input ;
44
5+ import static androidx .appcompat .content .res .AppCompatResources .getDrawable ;
6+
7+ import android .app .Activity ;
58import android .content .Context ;
9+ import android .content .Intent ;
610import android .content .res .Resources ;
11+
12+ import androidx .activity .result .ActivityResultLauncher ;
13+ import androidx .activity .result .ActivityResultRegistry ;
14+ import androidx .activity .result .contract .ActivityResultContracts ;
715import androidx .annotation .NonNull ;
816import androidx .annotation .Nullable ;
917import androidx .fragment .app .FragmentManager ;
1018
19+ import android .graphics .drawable .Drawable ;
1120import android .os .Build ;
1221import android .text .TextUtils ;
22+ import android .util .Log ;
1323import android .util .TypedValue ;
1424import android .view .KeyEvent ;
1525import android .view .MotionEvent ;
4454import io .adaptivecards .renderer .input .customcontrols .ValidatedRadioGroup ;
4555import io .adaptivecards .renderer .input .customcontrols .ValidatedSpinner ;
4656import io .adaptivecards .renderer .input .customcontrols .ValidatedSpinnerLayout ;
57+ import io .adaptivecards .renderer .input .customcontrols .ValidatedTextView ;
4758import io .adaptivecards .renderer .inputhandler .AutoCompleteTextViewHandler ;
4859import io .adaptivecards .renderer .inputhandler .CheckBoxSetInputHandler ;
4960import io .adaptivecards .renderer .inputhandler .ComboBoxInputHandler ;
5263import io .adaptivecards .objectmodel .HostConfig ;
5364import io .adaptivecards .renderer .BaseCardElementRenderer ;
5465import io .adaptivecards .renderer .inputhandler .RadioGroupInputHandler ;
66+ import io .adaptivecards .renderer .inputhandler .TypeAheadTextViewHandler ;
5567import io .adaptivecards .renderer .registration .CardRendererRegistration ;
68+ import io .adaptivecards .renderer .typeaheadsearch .DynamicTypeAheadService ;
69+ import io .adaptivecards .renderer .typeaheadsearch .IChoicesResolver ;
70+ import io .adaptivecards .renderer .typeaheadsearch .TypeAheadSearchActivity ;
71+ import io .adaptivecards .renderer .typeaheadsearch .TypeAheadSearchLaunchParams ;
5672
5773import java .util .ArrayList ;
5874import java .util .Arrays ;
@@ -611,6 +627,123 @@ public void onNothingSelected(AdapterView<?> parent)
611627 }
612628 }
613629
630+ public View renderTypeAheadControl (
631+ RenderedAdaptiveCard renderedCard ,
632+ Context context ,
633+ ChoiceSetInput choiceSetInput ,
634+ IChoicesResolver choicesResolver ,
635+ HostConfig hostConfig ,
636+ RenderArgs renderArgs )
637+ {
638+ final List <String > titleList = new ArrayList ();
639+ ChoiceInputVector choiceInputVector = choiceSetInput .GetChoices ();
640+ long size = choiceInputVector .size ();
641+ int valueIndex = -1 ;
642+ String value = choiceSetInput .GetValue ();
643+ final List <String > valueList = new ArrayList ();
644+ for (int i = 0 ; i < size ; i ++)
645+ {
646+ ChoiceInput choiceInput = choiceInputVector .get (i );
647+ titleList .add (choiceInput .GetTitle ());
648+ valueList .add (choiceInput .GetTitle ());
649+
650+ if (choiceInput .GetValue ().equals (value ))
651+ {
652+ valueIndex = i ;
653+ }
654+ }
655+
656+ boolean usingCustomInputs = isUsingCustomInputs (context );
657+
658+ ValidatedTextView validatedTypeAheadTextView = new ValidatedTextView (context , usingCustomInputs );
659+
660+ Drawable chevronDrawable = getDrawable (context , R .drawable .adaptive_card_ic_chevron_right );
661+ chevronDrawable .setTint (getColor (hostConfig .GetForegroundColor (ContainerStyle .Default , ForegroundColor .Default , false )));
662+ validatedTypeAheadTextView .setCompoundDrawablesWithIntrinsicBounds (null , null , chevronDrawable , null );
663+ validatedTypeAheadTextView .setPaddingRelative (0 , 10 , 20 , 10 );
664+ validatedTypeAheadTextView .setEllipsize (TextUtils .TruncateAt .END );
665+
666+ final TypeAheadTextViewHandler typeAheadTextInputHandler = new TypeAheadTextViewHandler (choiceSetInput );
667+
668+ ValidatedInputLayout inputLayout = null ;
669+
670+ // if using custom inputs, we don't have to create the surrounding linear layout
671+ boolean needsOuterLayout = (!usingCustomInputs );
672+ if (needsOuterLayout )
673+ {
674+ inputLayout = new ValidatedSpinnerLayout (context ,
675+ getColor (hostConfig .GetForegroundColor (ContainerStyle .Default , ForegroundColor .Attention , false )));
676+ inputLayout .setTag (new TagContent (choiceSetInput , typeAheadTextInputHandler ));
677+ typeAheadTextInputHandler .setView (inputLayout );
678+ }
679+ else
680+ {
681+ validatedTypeAheadTextView .setTag (new TagContent (choiceSetInput , typeAheadTextInputHandler ));
682+ typeAheadTextInputHandler .setView (validatedTypeAheadTextView );
683+ }
684+ renderedCard .registerInputHandler (typeAheadTextInputHandler , renderArgs .getContainerCardId ());
685+
686+ validatedTypeAheadTextView .setFocusable (true );
687+ if (valueIndex != -1 )
688+ {
689+ validatedTypeAheadTextView .setText (titleList .get (valueIndex ));
690+ typeAheadTextInputHandler .setInput (titleList .get (valueIndex ), valueList .get (valueIndex ));
691+ }
692+
693+ validatedTypeAheadTextView .setOnClickListener (view -> {
694+ ActivityResultRegistry registry = CardRendererRegistration .getInstance ().getActivityResultRegistry ();
695+ if (registry != null ) {
696+ ActivityResultLauncher <Intent > launcher = registry .register ("adaptive-card-dynamic-type-ahead" ,
697+ new ActivityResultContracts .StartActivityForResult (),
698+ result -> {
699+ if (result .getResultCode () == Activity .RESULT_OK
700+ && result .getData () != null
701+ && result .getData ().getExtras () != null
702+ && result .getData ().getExtras ().getString ("typeAheadSearchSelectedKey" ) != null ) {
703+ String selectedTitle = result .getData ().getExtras ().getString ("typeAheadSearchSelectedKey" );
704+ String selectedValue = result .getData ().getExtras ().getString ("typeAheadSearchSelectedValue" );
705+
706+ validatedTypeAheadTextView .setText (selectedTitle );
707+ typeAheadTextInputHandler .setInput (selectedTitle , selectedValue );
708+ CardRendererRegistration .getInstance ().notifyInputChange (typeAheadTextInputHandler .getId (), typeAheadTextInputHandler .getInput ());
709+ Log .d ("SelectedChoice" , selectedTitle );
710+ }
711+ DynamicTypeAheadService .INSTANCE .removeIChoicesResolver ();
712+ }
713+ );
714+
715+ Intent intent = new Intent (context , TypeAheadSearchActivity .class );
716+ TypeAheadSearchLaunchParams launchParams = new TypeAheadSearchLaunchParams (
717+ typeAheadTextInputHandler .getInputTitle (),
718+ choiceSetInput .GetChoicesData ().GetChoicesDataType (),
719+ choiceSetInput .GetChoicesData ().GetDataset (),
720+ titleList ,
721+ valueList ,
722+ getColor (hostConfig .GetBackgroundColor (ContainerStyle .Default )),
723+ getColor (hostConfig .GetForegroundColor (ContainerStyle .Default , ForegroundColor .Default , false )));
724+ intent .putExtra ("launchParams" , launchParams );
725+
726+ DynamicTypeAheadService .INSTANCE .setIChoicesResolver (choicesResolver );
727+ launcher .launch (intent );
728+ }
729+ else {
730+ renderedCard .addWarning (
731+ new AdaptiveWarning (AdaptiveWarning .INTERACTIVITY_DISALLOWED ,
732+ "Interactivity is not allowed. ActivityResultRegistry is null." )
733+ );
734+ }
735+ });
736+
737+ if (needsOuterLayout )
738+ {
739+ inputLayout .addView (validatedTypeAheadTextView );
740+ return inputLayout ;
741+ }
742+ else
743+ {
744+ return validatedTypeAheadTextView ;
745+ }
746+ }
614747
615748 @ Override
616749 public View render (
@@ -632,7 +765,11 @@ public View render(
632765 ChoiceSetInput choiceSetInput = Util .castTo (baseCardElement , ChoiceSetInput .class );
633766
634767 View inputView = null ;
635- if (choiceSetInput .GetIsMultiSelect ())
768+ if (choiceSetInput .GetChoicesData () != null && !choiceSetInput .GetChoicesData ().GetChoicesDataType ().isEmpty ()) {
769+ // Create dynamic type ahead control
770+ inputView = renderTypeAheadControl (renderedCard , context , choiceSetInput , channelAdaptor .getChoicesResolver (), hostConfig , renderArgs );
771+ }
772+ else if (choiceSetInput .GetIsMultiSelect ())
636773 {
637774 // Create multi-select checkbox
638775 inputView = renderCheckBoxSet (renderedCard , context , choiceSetInput , hostConfig , renderArgs );
0 commit comments