From 8850a1fbe3d8affd734b94eb0eb650dc1dfa5bd6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 23 Jan 2016 20:32:00 +0100 Subject: [PATCH] added FormWrapper and form field validation --- .../ui/forms/FormBooleanFieldWrapper.java | 25 ++++++- .../ui/forms/FormFieldFactory.java | 2 +- .../ui/forms/FormFieldWrapper.java | 24 +++++++ .../ui/forms/FormJidSingleFieldWrapper.java | 2 + .../ui/forms/FormTextFieldWrapper.java | 29 +++++++- .../conversations/ui/forms/FormWrapper.java | 66 +++++++++++++++++++ .../siacs/conversations/xmpp/forms/Field.java | 15 +++++ src/main/res/values/strings.xml | 1 + 8 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/ui/forms/FormWrapper.java diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormBooleanFieldWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormBooleanFieldWrapper.java index e9adf15a3..eba0f12d9 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormBooleanFieldWrapper.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormBooleanFieldWrapper.java @@ -2,6 +2,7 @@ package eu.siacs.conversations.ui.forms; import android.content.Context; import android.widget.CheckBox; +import android.widget.CompoundButton; import java.util.ArrayList; import java.util.List; @@ -16,6 +17,13 @@ public class FormBooleanFieldWrapper extends FormFieldWrapper { protected FormBooleanFieldWrapper(Context context, Field field) { super(context, field); checkBox = (CheckBox) view.findViewById(R.id.field); + checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + checkBox.setError(null); + invokeOnFormFieldValuesEdited(); + } + }); } @Override @@ -33,7 +41,22 @@ public class FormBooleanFieldWrapper extends FormFieldWrapper { @Override public boolean validates() { - return checkBox.isChecked() || !field.isRequired(); + if (checkBox.isChecked() || !field.isRequired()) { + return true; + } else { + checkBox.setError(context.getString(R.string.this_field_is_required)); + checkBox.requestFocus(); + return false; + } + } + + @Override + public boolean edited() { + if (field.getValues().size() == 0) { + return checkBox.isChecked(); + } else { + return super.edited(); + } } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormFieldFactory.java b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldFactory.java index 966c0e5aa..ee3064726 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormFieldFactory.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldFactory.java @@ -20,7 +20,7 @@ public class FormFieldFactory { typeTable.put("boolean", FormBooleanFieldWrapper.class); } - public static FormFieldWrapper createFromField(Context context, Field field) { + protected static FormFieldWrapper createFromField(Context context, Field field) { Class clazz = typeTable.get(field.getType()); if (clazz == null) { clazz = FormTextFieldWrapper.class; diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java index f2560ef51..8ba62bdd8 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java @@ -4,11 +4,13 @@ import android.content.Context; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.xmpp.forms.Field; @@ -17,6 +19,7 @@ public abstract class FormFieldWrapper { protected final Context context; protected final Field field; protected final View view; + protected OnFormFieldValuesEdited onFormFieldValuesEditedListener; protected FormFieldWrapper(Context context, Field field) { this.context = context; @@ -57,6 +60,23 @@ public abstract class FormFieldWrapper { return spannableString; } + protected void invokeOnFormFieldValuesEdited() { + Log.d(Config.LOGTAG, "invoke on form field values edited"); + if (this.onFormFieldValuesEditedListener != null) { + this.onFormFieldValuesEditedListener.onFormFieldValuesEdited(); + } else { + Log.d(Config.LOGTAG,"listener is null"); + } + } + + public boolean edited() { + return !field.getValues().equals(getValues()); + } + + public void setOnFormFieldValuesEditedListener(OnFormFieldValuesEdited listener) { + this.onFormFieldValuesEditedListener = listener; + } + protected static FormFieldWrapper createFromField(Class c, Context context, Field field) { try { return c.getDeclaredConstructor(Context.class, Field.class).newInstance(context,field); @@ -65,4 +85,8 @@ public abstract class FormFieldWrapper { return null; } } + + public interface OnFormFieldValuesEdited { + void onFormFieldValuesEdited(); + } } diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java index b54940f64..3890a1a7a 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java @@ -23,6 +23,8 @@ public class FormJidSingleFieldWrapper extends FormTextFieldWrapper { try { Jid.fromString(value); } catch (InvalidJidException e) { + editText.setError(context.getString(R.string.invalid_jid)); + editText.requestFocus(); return false; } } diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormTextFieldWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormTextFieldWrapper.java index 274936e86..47b8d86cb 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormTextFieldWrapper.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormTextFieldWrapper.java @@ -1,7 +1,9 @@ package eu.siacs.conversations.ui.forms; import android.content.Context; +import android.text.Editable; import android.text.InputType; +import android.text.TextWatcher; import android.widget.EditText; import android.widget.TextView; @@ -22,6 +24,21 @@ public class FormTextFieldWrapper extends FormFieldWrapper { if ("text-private".equals(field.getType())) { editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); } + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + editText.setError(null); + invokeOnFormFieldValuesEdited(); + } + + @Override + public void afterTextChanged(Editable s) { + } + }); } @Override @@ -38,14 +55,22 @@ public class FormTextFieldWrapper extends FormFieldWrapper { public List getValues() { List values = new ArrayList<>(); for (String line : getValue().split("\\n")) { - values.add(line); + if (line.length() > 0) { + values.add(line); + } } return values; } @Override public boolean validates() { - return getValue().trim().length() > 0 || !field.isRequired(); + if (getValue().trim().length() > 0 || !field.isRequired()) { + return true; + } else { + editText.setError(context.getString(R.string.this_field_is_required)); + editText.requestFocus(); + return false; + } } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormWrapper.java new file mode 100644 index 000000000..51d15f0c2 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormWrapper.java @@ -0,0 +1,66 @@ +package eu.siacs.conversations.ui.forms; + +import android.content.Context; +import android.widget.LinearLayout; + +import java.util.ArrayList; +import java.util.List; + +import eu.siacs.conversations.xmpp.forms.Data; +import eu.siacs.conversations.xmpp.forms.Field; + +public class FormWrapper { + + private final LinearLayout layout; + + private final Data form; + + private final List fieldWrappers = new ArrayList<>(); + + private FormWrapper(Context context, LinearLayout linearLayout, Data form) { + this.form = form; + this.layout = linearLayout; + this.layout.removeAllViews(); + for(Field field : form.getFields()) { + FormFieldWrapper fieldWrapper = FormFieldFactory.createFromField(context,field); + if (fieldWrapper != null) { + layout.addView(fieldWrapper.getView()); + fieldWrappers.add(fieldWrapper); + } + } + } + + public Data submit() { + for(FormFieldWrapper fieldWrapper : fieldWrappers) { + fieldWrapper.submit(); + } + this.form.submit(); + return this.form; + } + + public boolean validates() { + boolean validates = true; + for(FormFieldWrapper fieldWrapper : fieldWrappers) { + validates &= fieldWrapper.validates(); + } + return validates; + } + + public void setOnFormFieldValuesEditedListener(FormFieldWrapper.OnFormFieldValuesEdited listener) { + for(FormFieldWrapper fieldWrapper : fieldWrappers) { + fieldWrapper.setOnFormFieldValuesEditedListener(listener); + } + } + + public boolean edited() { + boolean edited = false; + for(FormFieldWrapper fieldWrapper : fieldWrappers) { + edited |= fieldWrapper.edited(); + } + return edited; + } + + public static FormWrapper createInLayout(Context context, LinearLayout layout, Data form) { + return new FormWrapper(context, layout, form); + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java b/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java index c1fc808dc..020b34b90 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java +++ b/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java @@ -1,7 +1,9 @@ package eu.siacs.conversations.xmpp.forms; +import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; +import java.util.List; import eu.siacs.conversations.xml.Element; @@ -52,6 +54,19 @@ public class Field extends Element { return findChildContent("value"); } + public List getValues() { + List values = new ArrayList<>(); + for(Element child : getChildren()) { + if ("value".equals(child.getName())) { + String content = child.getContent(); + if (content != null) { + values.add(content); + } + } + } + return values; + } + public String getLabel() { return getAttribute("label"); } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index a354435d7..38368383b 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -581,4 +581,5 @@ Disable The selected area is too large (No activated accounts) + This field is required