package com.basgeekball.awesomevalidation.validators; import android.content.Context; import android.content.res.ColorStateList; import android.support.constraint.ConstraintLayout; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewCompat; import android.text.Editable; import android.text.TextWatcher; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; import com.basgeekball.awesomevalidation.AwesomeValidation; import com.basgeekball.awesomevalidation.ValidationHolder; import com.basgeekball.awesomevalidation.exception.MissingContextException; import com.basgeekball.awesomevalidation.exception.UnsupportedLayoutException; import com.basgeekball.awesomevalidation.utility.ValidationCallback; import com.basgeekball.awesomevalidation.utility.ViewsInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; public class UnderlabelValidator extends Validator { private Context mContext; private ArrayList<ViewsInfo> mViewsInfos = new ArrayList<>(); private int mColor; private boolean mHasFailed = false; private ValidationCallback mValidationCallback; private HashMap<EditText, TextWatcher> mTextWatcherForEditText = new HashMap<EditText, TextWatcher>(); private void init() { mValidationCallback = new ValidationCallback() { @Override public void execute(ValidationHolder validationHolder, Matcher matcher) { TextView textView = replaceView(validationHolder); if (AwesomeValidation.isAutoFocusOnFirstFailureEnabled() && !mHasFailed) { textView.setFocusable(true); textView.setFocusableInTouchMode(true); textView.setClickable(true); textView.requestFocus(); mHasFailed = true; } ViewCompat.setBackgroundTintList(validationHolder.getEditText(), ColorStateList.valueOf(mColor)); } }; } public void setContext(Context context) { mContext = context; setColorByResource(android.R.color.holo_red_light); init(); } public void setColor(int colorValue) { mColor = colorValue; } public void setColorByResource(int colorResId) { if (mContext == null) { throw new MissingContextException("Context should be set before setting color for Underlabel style."); } else { mColor = ContextCompat.getColor(mContext, colorResId); } } @Override public boolean trigger() { halt(); return checkFields(mValidationCallback); } @Override public void halt() { for (ViewsInfo viewsInfo : mViewsInfos) { viewsInfo.restoreViews(); } for (ValidationHolder validationHolder : mValidationHolderList) { if (validationHolder.isSomeSortOfView()) { validationHolder.resetCustomError(); } } if (AwesomeValidation.isAutoFocusOnFirstFailureEnabled() && mValidationHolderList.size() > 0) { ValidationHolder validationHolder = mValidationHolderList.get(0); if (!validationHolder.isSomeSortOfView()) { validationHolder.getEditText().requestFocus(); } } mViewsInfos.clear(); mHasFailed = false; for (Map.Entry<EditText, TextWatcher> entry : mTextWatcherForEditText.entrySet()) { entry.getKey().removeTextChangedListener(entry.getValue()); } } private TextView replaceView(ValidationHolder validationHolder) { final EditText editText = validationHolder.getEditText(); ViewGroup parent = (ViewGroup) editText.getParent(); if (parent instanceof ConstraintLayout) { throw new UnsupportedLayoutException("UnderlabelValidator doesn't support ConstraintLayout, please use TextInputLayoutValidator or other any other validator."); } int index = parent.indexOfChild(editText); LinearLayout newContainer = new LinearLayout(mContext); newContainer.setLayoutParams(editText.getLayoutParams()); newContainer.setOrientation(LinearLayout.VERTICAL); TextView textView = new TextView(mContext); textView.setText(validationHolder.getErrMsg()); textView.setTextColor(mColor); textView.setPadding(editText.getPaddingLeft(), 0, editText.getPaddingRight(), 0); textView.startAnimation(AnimationUtils.loadAnimation(mContext, android.R.anim.fade_in)); parent.removeView(editText); newContainer.addView(editText); newContainer.addView(textView); parent.addView(newContainer, index); final ViewsInfo viewsInfo = new ViewsInfo(index, parent, newContainer, editText); mViewsInfos.add(viewsInfo); TextWatcher textWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { // do nothing } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { editText.removeTextChangedListener(this); viewsInfo.restoreViews(); editText.requestFocus(); } @Override public void afterTextChanged(Editable editable) { // do nothing } }; editText.addTextChangedListener(textWatcher); mTextWatcherForEditText.put(editText, textWatcher); return textView; } }