Search code examples
androidrx-javarx-binding

Create a uniform Action1 to perform checks on fields


I was trying to get familiar with RxBinding and how it could be applied on simple forms. I was wondering if there is way to create one Action1 that performs the checks and updates the model. If I am not clear enough I hope the code below will help you understand what I mean.

    Observable<CharSequence> nameObservable = RxTextView.textChanges(name).share();
    Action1<CharSequence> validateAction;
    Observable<CharSequence> surnameObservable = RxTextView.textChanges(surname).share();
    Observable<CharSequence> emailObservable = RxTextView.textChanges(mail).share();

    validateAction = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            if(state.nameState && state.surnameState && state.emailState)
                submit.setBackgroundColor(getResources().getColor(R.color.green));
            else
                submit.setBackgroundColor(getResources().getColor(R.color.blue));
        }
    };



    Subscription nameState = nameObservable
            .subscribe(new Action1<CharSequence>() {
                @Override
                public void call(CharSequence charSequence) {
                    Log.d("Length","Len : " + charSequence.length());
                    if(charSequence.length() > 5)
                        state.nameState = true;
                    else
                        state.nameState = false;
                }
            });


    Subscription surnameState = surnameObservable
            .subscribe(new Action1<CharSequence>() {
                @Override
                public void call(CharSequence charSequence) {
                    Log.d("Length","Len : " + charSequence.length());
                    if(charSequence.length() > 5)
                        state.surnameState = true;
                    else
                        state.surnameState = false;
                }
            });

    Subscription mailState = emailObservable
            .subscribe(new Action1<CharSequence>() {
                @Override
                public void call(CharSequence charSequence) {
                    Log.d("Length","Len : " + charSequence.length());
                    if(charSequence.length() > 5)
                        state.emailState = true;
                    else
                        state.emailState = false;
                }
            });

    Subscription nameValidate = nameObservable.subscribe(validateAction);
    Subscription surnameValidate = surnameObservable.subscribe(validateAction);
    Subscription mailValidate = emailObservable.subscribe(validateAction);

I have created an Action1 whose responsibility is to check the state of the model and change the color of the button, created subscriptions equal to the number of Observables and passed it as a parameter.
Something like this for example

    Action1<CharSequence> lengthCheck = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            if(field is name){
                if(charSequence.length() > 5)
                    ...                    
            }
                ...
        }
    };

So my question is , is there a way to succeed something similar to this for the Action1 that check the length ? Is it even the correct place to put a check like this? It just seems silly to me that I have the exact same code , copy and pasted three times with minimal changes.
Thanks a lot for your time.


Solution

  • For name validation

    private Observable<Boolean> getNameObservable() {
        return RxTextView.textChanges(name)
                .map(charSequence -> charSequence.toString().trim().length() > 0);
    }
    

    For surname validation

    private Observable<Boolean> getSurNameObservable() {
        return RxTextView.textChanges(email)
                .map(charSequence -> charSequence.toString().trim().length() > 0);
    }
    

    For email validation

    private Observable<Boolean> getEmailObservable() {
        return RxTextView.textChanges(email)
                .map(charSequence -> charSequence.toString().trim().length() > 0);
    }
    

    Using combineLatest to combine 3 observables as 1 stream

    Observable.combineLatest(getNameObservable(),getSurNameObservable(), getEmailObservable,
                        (nameValid, surnameValid,emailValid) -> nameValid && surnameValid && emailValid)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(isAllFieldsValid ->
                                enableButton(yourButton, isAllFieldsValid));
    

    The enable function

    private void enableButton(Button button, boolean isAvailable) {
        button.setEnabled(isAvailable);
        if (isAvailable) {
            button.setBackgroundResource(R.drawable.green);
        } else {
            button.setBackgroundResource(R.drawable.blue);
        }
    }
    

    ========================================================================= PS: You can create a function that create an Observable for 3 EditText

    private Observable<Boolean> getNameObservable(EditText et) {
        return RxTextView.textChanges(et)
                .map(charSequence -> charSequence.toString().trim().length() > 0);
    }