1
0
Fork 1

Slider field

This commit is contained in:
Stephen Paul Weber 2024-02-14 06:26:02 +01:00 committed by Arne
parent a4038688ce
commit 10fa0047fd
3 changed files with 122 additions and 1 deletions

View file

@ -5,6 +5,7 @@ import static eu.siacs.conversations.entities.Bookmark.printableValue;
import android.content.Intent;
import de.monocles.chat.MonoclesViewPager;
import eu.siacs.conversations.databinding.CommandSliderFieldBinding;
import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.ui.UriHandlerActivity;
import android.content.DialogInterface;
@ -55,6 +56,8 @@ import android.util.DisplayMetrics;
import com.caverock.androidsvg.SVG;
import android.util.SparseBooleanArray;
import java.text.DecimalFormat;
import java.util.Collection;
import com.google.android.material.tabs.TabLayout;
@ -2713,6 +2716,65 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public void onTextChanged(CharSequence s, int start, int count, int after) { }
}
class SliderFieldViewHolder extends ViewHolder<CommandSliderFieldBinding> {
public SliderFieldViewHolder(CommandSliderFieldBinding binding) { super(binding); }
protected Field field = null;
@Override
public void bind(Item item) {
field = (Field) item;
setTextOrHide(binding.label, field.getLabel());
setTextOrHide(binding.desc, field.getDesc());
final Element validate = field.el.findChild("validate", "http://jabber.org/protocol/xdata-validate");
final String datatype = validate == null ? null : validate.getAttribute("datatype");
final Element range = validate == null ? null : validate.findChild("range", "http://jabber.org/protocol/xdata-validate");
final boolean open = validate != null && validate.findChild("open", "http://jabber.org/protocol/xdata-validate") != null;
Float min = null;
try { min = range.getAttribute("min") == null ? null : Float.valueOf(range.getAttribute("min")); } catch (NumberFormatException e) { }
Float max = null;
try { max = range.getAttribute("max") == null ? null : Float.valueOf(range.getAttribute("max")); } catch (NumberFormatException e) { }
List<Float> options = field.getOptions().stream().map(o -> Float.valueOf(o.getValue())).collect(Collectors.toList());
Collections.sort(options);
if (!open && options.size() > 0) {
min = options.get(0);
max = options.get(options.size()-1);
}
if (field.getValues().size() > 0) binding.slider.setValue(Float.valueOf(field.getValue().getContent()));
binding.slider.setValueFrom(min == null ? Float.MIN_VALUE : min);
binding.slider.setValueTo(max == null ? Float.MAX_VALUE : max);
if ("xs:integer".equals(datatype) || "xs:int".equals(datatype) || "xs:long".equals(datatype) || "xs:short".equals(datatype) || "xs:byte".equals(datatype)) {
binding.slider.setStepSize(1);
} else {
binding.slider.setStepSize(0);
}
if (!open && options.size() > 0) {
float step = -1;
Float prev = null;
for (final Float option : options) {
if (prev != null) {
float nextStep = option - prev;
if (step > 0 && step != nextStep) {
step = -1;
break;
}
step = nextStep;
}
prev = option;
}
if (step > 0) binding.slider.setStepSize(step);
// NOTE: if step == -1 and !open then the widget will allow illegal values
}
binding.slider.addOnChangeListener((slider, value, fromUser) -> {
field.setValues(List.of(new DecimalFormat().format(value)));
});
}
}
class WebViewHolder extends ViewHolder<CommandWebviewBinding> {
public WebViewHolder(CommandWebviewBinding binding) { super(binding); }
protected String boundUrl = "";
@ -2879,6 +2941,9 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
if (formType.equals("result") || fieldType.equals("fixed")) {
viewType = TYPE_RESULT_FIELD;
} else if (formType.equals("form")) {
final Element validate = el.findChild("validate", "http://jabber.org/protocol/xdata-validate");
final String datatype = validate == null ? null : validate.getAttribute("datatype");
final Element range = validate == null ? null : validate.findChild("range", "http://jabber.org/protocol/xdata-validate");
if (fieldType.equals("boolean")) {
if (fillableFieldCount == 1 && actionsAdapter.countExceptCancel() < 1) {
viewType = TYPE_BUTTON_GRID_FIELD;
@ -2886,7 +2951,14 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
viewType = TYPE_CHECKBOX_FIELD;
}
} else if (fieldType.equals("list-single")) {
Element validate = el.findChild("validate", "http://jabber.org/protocol/xdata-validate");
} else if (
range != null && (
"xs:integer".equals(datatype) || "xs:int".equals(datatype) || "xs:long".equals(datatype) || "xs:short".equals(datatype) || "xs:byte".equals(datatype) ||
"xs:decimal".equals(datatype) || "xs:double".equals(datatype)
)
) {
// has a range and is numeric, use a slider
viewType = TYPE_SLIDER_FIELD;
if (fillableFieldCount == 1 && actionsAdapter.countExceptCancel() < 1) {
viewType = TYPE_BUTTON_GRID_FIELD;
} else if (Option.forField(el).size() > 9) {
@ -2992,6 +3064,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
final int TYPE_SEARCH_LIST_FIELD = 11;
final int TYPE_ITEM_CARD = 12;
final int TYPE_BUTTON_GRID_FIELD = 13;
final int TYPE_SLIDER_FIELD = 14;
protected boolean executing = false;
protected boolean loading = false;
@ -3380,6 +3453,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
CommandTextFieldBinding binding = DataBindingUtil.inflate(LayoutInflater.from(container.getContext()), R.layout.command_text_field, container, false);
return new TextFieldViewHolder(binding);
}
case TYPE_SLIDER_FIELD: {
CommandSliderFieldBinding binding = DataBindingUtil.inflate(LayoutInflater.from(container.getContext()), R.layout.command_slider_field, container, false);
return new SliderFieldViewHolder(binding);
}
case TYPE_PROGRESSBAR: {
CommandProgressBarBinding binding = DataBindingUtil.inflate(LayoutInflater.from(container.getContext()), R.layout.command_progress_bar, container, false);
return new ProgressBarViewHolder(binding);

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="13dp"
android:paddingRight="8dp"
android:paddingBottom="8dp"
android:textAppearance="@style/TextAppearance.Conversations.Subhead"
android:textColor="?attr/edit_text_color" />
<com.google.android.material.slider.Slider
android:id="@+id/slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingBottom="8dp"
app:trackColorInactive="?color_background_primary"
app:trackColorActive="?colorAccent" />
<TextView
android:id="@+id/desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:paddingRight="8dp"
android:textAppearance="@style/TextAppearance.Conversations.Status"
android:textColor="?android:textColorSecondary" />
</LinearLayout>
</layout>

View file

@ -41,6 +41,8 @@
<item name="colorAccentLight">@color/accent_light</item>
<item name="colorAccentLightDisabled">@color/accent_light_disabled</item>
<item name="popupOverlayStyle">@style/ThemeOverlay.Material3.Light</item>
<item name="colorOnBackground">?colorPrimaryDark</item>
<item name="colorSurface">?colorPrimaryDark</item>
<item name="colorControlNormal">?attr/text_Color_Main</item>
<item name="colorControlActivated">@color/accent</item>
<item name="text_Color_Main">@color/realblack</item>