riteshakya037/CustomFormViews

View on GitHub
customfieldviews/src/main/java/com/ritesh/customfieldviews/CustomTextView.java

Summary

Maintainability
A
1 hr
Test Coverage
package com.ritesh.customfieldviews;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
import android.text.InputType;
import android.text.TextUtils;
import android.text.method.PasswordTransformationMethod;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnFocusChange;
import butterknife.OnTextChanged;
import com.ritesh.customfieldviews.validators.ServerListener;
import com.ritesh.customfieldviews.validators.ValidityBase;
import com.ritesh.customfieldviews.validators.ValidityListener;
import com.wang.avi.AVLoadingIndicatorView;

/**
 * @author Ritesh Shakya
 */
public class CustomTextView extends LinearLayout implements ValidityBase, ServerListener {
    @BindView(R2.id.custom_text_view_text_hint_layout) protected ViewGroup txtHintLayout;
    @BindView(R2.id.custom_text_view_validity_icon) protected ImageView validityIcon;
    @BindView(R2.id.custom_text_view_validity_animation) protected AVLoadingIndicatorView
            validityAnimation;
    @BindView(R2.id.custom_text_view_text_hint) protected TextView txtHint;
    @BindView(R2.id.custom_text_view_error_view) protected TextView errorView;
    @BindView(R2.id.custom_text_view_text_main) protected EditText inputEditText;

    private FocusListener mListener;
    private ValidityListener mValidityListener;
    private ServerValidator mServerValidator;
    private boolean validity;
    private boolean dontCallback = false;
    private String mHint;
    private boolean checkServerContinuously = false;
    private boolean clearing = false;

    public CustomTextView(Context context) {
        super(context);
        init(context, "", "", InputType.TYPE_CLASS_TEXT, true, false);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.custom_view);
        init(context, typedArray.getString(R.styleable.custom_view_hint),
                typedArray.getString(R.styleable.custom_view_text),
                typedArray.getInt(R.styleable.custom_view_android_inputType, 0),
                typedArray.getBoolean(R.styleable.custom_view_editable, true),
                typedArray.getBoolean(R.styleable.custom_view_password, false));
        typedArray.recycle();
    }

    @OnTextChanged(value = R2.id.custom_text_view_text_main, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
    protected void nameChanged(CharSequence text) {
        if (mListener != null && !dontCallback && !clearing) {
            validity = mListener.getTextValidity(CustomTextView.this, text.toString());
            validityIcon.setImageDrawable(ContextCompat.getDrawable(getContext(),
                    validity ? R.drawable.ic_check_green : R.drawable.ic_error));
        }
        if (mValidityListener != null) {
            mValidityListener.checkValidity();
        }
        if (checkServerContinuously && mServerValidator != null) {
            checkValidityWithServer();
        } else {
            validityIcon.setVisibility(text.length() == 0 ? GONE : VISIBLE);
        }
        clearing = false;
    }

    @OnFocusChange(R2.id.custom_text_view_text_main)
    protected void inputFocusChanged(boolean hasFocus) {
        boolean condition = hasFocus || !TextUtils.isEmpty(inputEditText.getText());
        txtHintLayout.setVisibility(condition ? VISIBLE : GONE);
        validityIcon.setVisibility(
                !TextUtils.isEmpty(inputEditText.getText().toString()) && !checkServerContinuously
                        ? VISIBLE : GONE);
        inputEditText.setHint(condition ? "" : txtHint.getText());
        if (!hasFocus && TextUtils.isEmpty(inputEditText.getText().toString())) {
            clearing = true;
            reset();
        }
    }

    public void checkValidityWithServer() {
        mServerValidator.checkValidateFromServer(CustomTextView.this,
                inputEditText.getText().toString(), this);
        validityIcon.setVisibility(GONE);
        validityAnimation.setVisibility(VISIBLE);
        checkServerContinuously = true;
    }

    private void showValidityResponse() {
        Properties properties = mServerValidator.getTextErrorProperties(CustomTextView.this);
        if (!validity) {
            errorView.setVisibility(VISIBLE);
            errorView.setTextColor(Color.parseColor("#e03d46"));
            errorView.setText(properties.getErrorMessage());
        } else {
            if (properties.getNonErrorMessage() == null) {
                errorView.setVisibility(GONE);
            } else {
                errorView.setTextColor(Color.parseColor("#8e86a2"));
                errorView.setText(properties.getNonErrorMessage());
            }
        }
        validityIcon.setImageDrawable(ContextCompat.getDrawable(getContext(),
                validity ? R.drawable.ic_check_green : R.drawable.ic_error));
    }

    private void init(Context context, String hint, String text, int inputType, boolean editable,
            boolean password) {
        mHint = hint;
        View rootView = getView(context);
        ButterKnife.bind(this, rootView);
        txtHint.setText(hint);
        txtHintLayout.setVisibility(GONE);
        inputEditText.setHint(hint);
        inputEditText.setEnabled(editable);
        inputEditText.setText(text);
        if (password) {
            inputEditText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
            inputEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());
        } else {
            inputEditText.setInputType(inputType);
        }
    }

    private View getView(Context context) {
        return inflate(context, R.layout.custom_text_view, this);
    }

    public void addFocusValidator(FocusListener listener, ValidityListener validityListener) {
        addFocusValidator(listener, validityListener, null);
    }

    public void addFocusValidator(FocusListener listener, ValidityListener validityListener,
            ServerValidator serverValidator) {
        mListener = listener;
        mValidityListener = validityListener;
        mServerValidator = serverValidator;
    }

    public String getText() {
        return inputEditText.getText().toString();
    }

    public void setText(String text) {
        setText(text, false);
    }

    public void setText(String text, boolean dontCallback) {
        this.dontCallback = dontCallback;
        if (!TextUtils.isEmpty(text) || dontCallback) {
            inputEditText.setText(text);
            txtHintLayout.setVisibility(VISIBLE);
            validityIcon.setVisibility(VISIBLE);
        }
        this.dontCallback = false;
    }

    @Override public boolean getValidity() {
        return validity;
    }

    @Override public void setValidity(boolean validity) {
        this.validity = validity;
        validityIcon.setImageDrawable(ContextCompat.getDrawable(getContext(),
                validity ? R.drawable.ic_check_green : R.drawable.ic_error));
        if (mValidityListener != null) mValidityListener.checkValidity();
    }

    @Override public void reset() {
        inputEditText.setText("");
        inputEditText.setHint(mHint);
        txtHintLayout.setVisibility(GONE);
        validityIcon.setVisibility(GONE);
    }

    @Override public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        inputEditText.setEnabled(enabled);
    }

    public void setCheckServerContinuously(boolean checkServerContinuously) {
        this.checkServerContinuously = checkServerContinuously;
    }

    @Override public void serverTaskComplete(boolean success) {
        validityIcon.setVisibility(VISIBLE);
        checkServerContinuously = false;
        validityAnimation.setVisibility(GONE);
        validity = success;
        if (mValidityListener != null) {
            mValidityListener.checkValidity();
        }
        showValidityResponse();
    }

    public interface FocusListener {
        boolean getTextValidity(CustomTextView view, String text);
    }

    public interface ServerValidator {
        void checkValidateFromServer(View view, String text, ServerListener listener);

        CustomTextView.Properties getTextErrorProperties(CustomTextView view);
    }

    public static class Properties {
        private String errorMessage;
        private String nonErrorMessage;

        public Properties(String errorMessage, String nonErrorMessage) {
            this.errorMessage = errorMessage;
            this.nonErrorMessage = nonErrorMessage;
        }

        private String getNonErrorMessage() {
            return nonErrorMessage;
        }

        private String getErrorMessage() {
            return errorMessage;
        }
    }
}