Created
August 16, 2014 17:52
-
-
Save juliomarcos/948344a2b3390a48e0d8 to your computer and use it in GitHub Desktop.
Android form validator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package /* YOUR PACKAGE HERE */; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
import android.app.Activity; | |
import android.app.AlertDialog; | |
import android.text.Html; | |
import android.text.TextUtils; | |
import android.view.View; | |
import android.widget.EditText; | |
import android.widget.Spinner; | |
public class FormValidator { | |
private class LabelFieldSimpleRuleTriplet { | |
public String fieldSimpleRule; | |
public String fieldLabel; | |
public View fieldView; | |
} | |
public interface OnLegalListener { | |
public void onLegal(); | |
} | |
@SuppressWarnings("serial") | |
public class ListenerNotSetException extends RuntimeException { | |
public ListenerNotSetException(String message) { | |
super(message); | |
} | |
} | |
private static final String EQ = "equal"; | |
private final static String NOT_EMPTY = "not_empty"; | |
private static final String IGNORE_NOT_EMPTY_IF_ALL_EMPTY = "ignore_not_empty_if_all_empty"; | |
private class RuleContainer { | |
public String rule; | |
public Integer msgResId; | |
public View[] views; | |
public RuleContainer(String rule, Integer msgResId, View[] views) { | |
this.rule = rule; | |
this.msgResId = msgResId; | |
this.views = views; | |
} | |
} | |
@SuppressWarnings("serial") | |
private class RuleContainers extends ArrayList<RuleContainer> { | |
public RuleContainer findRule(String rule) { | |
for (RuleContainer ruleContainer : this) { | |
if (ruleContainer.rule.equals(rule)) return ruleContainer; | |
} | |
return null; | |
} | |
public List<View> findViews(String rule) { | |
List<View> acc = new ArrayList<View>(); | |
for (RuleContainer ruleContainer : this) { | |
if (ruleContainer.rule.equals(rule)) { | |
for (int i = 0; i < ruleContainer.views.length; i++) { | |
acc.add(ruleContainer.views[i]); | |
} | |
} | |
} | |
return acc; | |
} | |
} | |
private List<LabelFieldSimpleRuleTriplet> labelFieldSimpleRuleTripletList; | |
private List<String> criticas; | |
private RuleContainers ruleContainers; | |
private OnLegalListener onLegalListener; | |
public void setOnLegalListener(OnLegalListener onLegalListener) { | |
this.onLegalListener = onLegalListener; | |
} | |
public FormValidator(OnLegalListener onLegalListener) { | |
labelFieldSimpleRuleTripletList = new ArrayList<FormValidator.LabelFieldSimpleRuleTriplet>(); | |
criticas = new ArrayList<String>(); | |
ruleContainers = new RuleContainers(); | |
criticasComRegras = new ArrayList<Integer>(); | |
this.onLegalListener = onLegalListener; | |
} | |
public void notEmpty(final String label, final View field) { | |
labelFieldSimpleRuleTripletList.add(new LabelFieldSimpleRuleTriplet() {{ | |
fieldSimpleRule = NOT_EMPTY; | |
fieldLabel = label; | |
fieldView = field; | |
}}); | |
} | |
public void mirror(int msgResId, View... views) { | |
rule(EQ, msgResId, views); | |
} | |
public static class RandomDataOptions { | |
public final static int ALL_RANDOM = 0; | |
public final static int ALL_SAME = 1; | |
static String randomString(int length) { | |
StringBuilder sb = new StringBuilder(); | |
for (int i = 0; i < length; i++) { | |
char randomCharacter = (char) (65 + Math.random() * 57); | |
sb.append(randomCharacter); | |
} | |
return sb.toString(); | |
} | |
} | |
public void fillViewsWithRandomDataForTesting() { | |
fillViewsWithRandomDataForTesting(RandomDataOptions.ALL_RANDOM); | |
} | |
public void fillViewsWithRandomDataForTesting(int options) { | |
if (options == RandomDataOptions.ALL_RANDOM) { | |
for (LabelFieldSimpleRuleTriplet pair : labelFieldSimpleRuleTripletList) { | |
setViewValue(pair.fieldView, RandomDataOptions.randomString(7)); | |
} | |
} else if (options == RandomDataOptions.ALL_SAME) { | |
String randomValue = RandomDataOptions.randomString(7); | |
for (LabelFieldSimpleRuleTriplet pair : labelFieldSimpleRuleTripletList) { | |
setViewValue(pair.fieldView, randomValue); | |
} | |
} | |
} | |
public void validate(Activity activity) { | |
if (onLegalListener == null) throw new ListenerNotSetException("validate() can't be called without setting an onLegalListener"); | |
for (LabelFieldSimpleRuleTriplet labelFieldRuleTriplet : labelFieldSimpleRuleTripletList) { | |
String simpleRule = labelFieldRuleTriplet.fieldSimpleRule; | |
String label = labelFieldRuleTriplet.fieldLabel; | |
View view = labelFieldRuleTriplet.fieldView; | |
String viewValue = getViewValue(view); | |
mayAccumulateCritique(simpleRule, viewValue, label); | |
} | |
for (RuleContainer ruleContainer : ruleContainers) { | |
mayAccumulateRuledCritique(ruleContainer); | |
} | |
if (criticas.size() > 0 || criticasComRegras.size() > 0) { | |
buildErrorDialog(activity); | |
} | |
else { | |
onLegalListener.onLegal(); | |
} | |
} | |
private void mayAccumulateCritique(String rule, String fieldValue, String fieldName) { | |
RuleContainer matchedRule = ruleContainers.findRule(IGNORE_NOT_EMPTY_IF_ALL_EMPTY); | |
if (rule.equals(NOT_EMPTY) && matchedRule != null) { | |
// do special comparison | |
// TODO: cada regra especial tinha que ter sua classe, e todas as | |
// regras deveriam ficar em uma RuleContainer. Ter dois tipos, | |
// simple rule e rule normal é muito ruim. | |
List<View> ruleViews = new ArrayList<View>(Arrays.asList(matchedRule.views)); | |
List<View> matchedViews = findSimpleRuledViews(rule); | |
final List<String> viewValuesThatMatters = new ArrayList<String>(); | |
for (View v : matchedViews) { | |
if (ruleViews.contains(v)) { | |
viewValuesThatMatters.add(getViewValue(v)); | |
} | |
} | |
// Quero tanto java 8, esse tipo de loop... | |
boolean allEmpty = true; | |
for (String value : viewValuesThatMatters) { | |
if (!TextUtils.isEmpty(value)) { | |
allEmpty = false; | |
break; | |
} | |
} | |
if (!allEmpty) { // adicionar views das matched rules | |
if (rule.equals(NOT_EMPTY)){ | |
if (TextUtils.isEmpty(fieldValue)) { | |
criticas.add(fieldName); | |
} | |
} | |
} | |
} else if (rule.equals(NOT_EMPTY)){ | |
if (TextUtils.isEmpty(fieldValue)) { | |
criticas.add(fieldName); | |
} | |
} | |
} | |
private List<View> findSimpleRuledViews(String rule) { | |
List<View> acc = new ArrayList<View>(); | |
for (LabelFieldSimpleRuleTriplet triplet : labelFieldSimpleRuleTripletList) { | |
if (triplet.fieldSimpleRule.equals(rule)) acc.add(triplet.fieldView); | |
} | |
return acc; | |
} | |
private String getViewValue(View view) { | |
if (view instanceof Spinner) { | |
Spinner spinner = (Spinner) view; | |
return spinner.getSelectedItem().toString(); | |
} else if (view instanceof EditText) { | |
EditText editText = (EditText) view; | |
return editText.getText().toString(); | |
} | |
// TODO: Talvez seja necessário tratar checkboxes | |
return null; | |
} | |
private void mayAccumulateRuledCritique(RuleContainer ruleContainer) { | |
String rule = ruleContainer.rule; | |
View[] views = ruleContainer.views; | |
Integer msgResId = ruleContainer.msgResId; | |
if (rule.equals(EQ)) { | |
String value = getViewValue(views[0]); | |
for (int i = 1; i < views.length; i++) { | |
String thatValue = getViewValue(views[i]); | |
if (!thatValue.equals(value)) { | |
criticasComRegras.add(msgResId); | |
return; | |
} | |
value = thatValue; | |
} | |
} | |
} | |
private void buildErrorDialog(Activity activity) { | |
StringBuilder sb = new StringBuilder(); | |
if (criticas.size() > 0) { | |
sb.append(activity.getString(R.string.os_seguintes_campos_branco)); | |
sb.append("<br/><br/>"); | |
for (String critica : criticas) { | |
sb.append("•"); sb.append(critica); sb.append("<br/>"); | |
} | |
} | |
if (criticasComRegras.size() > 0) { | |
if (criticas.size() > 0) sb.append("<br/>"); | |
for (Integer msgResId : criticasComRegras) { | |
sb.append(activity.getString(msgResId)); | |
} | |
} | |
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity); | |
alertDialogBuilder | |
.setIconAttribute(android.R.attr.alertDialogIcon) | |
.setTitle(R.string.campos_em_branco) | |
.setMessage(Html.fromHtml(sb.toString())) | |
.setNeutralButton("OK", null) | |
.create() | |
.show(); | |
criticas.clear(); | |
criticasComRegras.clear(); | |
} | |
private List<Integer> criticasComRegras; | |
private void rule(String rule, int msgResId, View... views) { | |
ruleContainers.add(new RuleContainer(rule, msgResId, views)); | |
} | |
private void setViewValue(View view, String value) { | |
if (view instanceof Spinner) { | |
Spinner spinner = (Spinner) view; | |
if (spinner.getCount() > 0) spinner.setSelection(1); | |
} else if (view instanceof EditText) { | |
EditText editText = (EditText) view; | |
editText.setText(value); | |
} | |
} | |
public void ignoreNotEmptyIfAllEmpty(View... views) { | |
ruleContainers.add(new RuleContainer(IGNORE_NOT_EMPTY_IF_ALL_EMPTY, null, views)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment