Skip to content

Instantly share code, notes, and snippets.

@mandybess
Last active January 7, 2019 03:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mandybess/90503fea3eace85f5c31fb1982346fc6 to your computer and use it in GitHub Desktop.
Save mandybess/90503fea3eace85f5c31fb1982346fc6 to your computer and use it in GitHub Desktop.
RxJava + MVP Sign up Form Validation Take Two
port android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import club.smartsavers.presenters.SignUpPresenter;
import club.smartsavers.presenters.SignUpPresenterImpl;
import com.jakewharton.rxbinding.widget.RxTextView;
import rx.Observable;
public class SignUpActivity extends Activity implements SignUpView {
EditText firstName;
EditText lastName;
EditText email;
EditText zipCode;
EditText password;
Button submitButton;
SignUpPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//must inflate views before presenter
presenter = new SignUpPresenterImpl(this);
}
@Override
public void showProgress() {
}
@Override
public void hideProgress() {
}
@Override
public void showFirstNameError(CharSequence error) {
firstName.setError(error);
}
@Override
public void showLastNameError(CharSequence error) {
lastName.setError(error);
}
@Override
public void showEmailError(CharSequence error) {
email.setError(error);
}
@Override
public void showZipCodeError(CharSequence error) {
zipCode.setError(error);
}
@Override
public void showPasswordError(CharSequence error) {
password.setError(error);
}
@Override
public void navigateToMainScreen() {
}
@Override
public void updateSubmitButtonViewState(boolean enabled) {
submitButton.setEnabled(enabled);
}
@Override
public Observable<CharSequence> firstName() {
return RxTextView.textChanges(firstName);
}
@Override
public Observable<CharSequence> lastName() {
return RxTextView.textChanges(lastName);
}
@Override
public Observable<CharSequence> email() {
return RxTextView.textChanges(email);
}
@Override
public Observable<CharSequence> zipCode() {
return RxTextView.textChanges(zipCode);
}
@Override
public Observable<CharSequence> password() {
return RxTextView.textChanges(password);
}
}
import android.content.Context;
import club.smartsavers.R;
import club.smartsavers.views.SignUpView;
import rx.Observable;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.functions.Func5;
public class SignUpPresenter implements Presenter<SignUpView> {
private SignUpView signUpView;
private final Context context;
public SignUpPresenter(Context context) {
this.context = context;
}
public Func1<CharSequence, Boolean> isFirstNameValid() {
return textViewAfterTextChangeEvent -> FIRST_NAME_VALIDITY_CHECK;
}
public Action1<Boolean> updateFirstNameViewState() {
return isValid -> {
if (!isValid) {
signUpView.showFirstNameError(context.getString(R.string.first_name_field_validity_error));
}
};
}
public Func1<CharSequence, Boolean> isLastNameValid() {
return textViewAfterTextChangeEvent -> LAST_NAME_VALIDITY_CHECK;
}
public Action1<Boolean> updateLastNameViewState() {
return isValid -> {
if (!isValid) {
signUpView.showLastNameError(context.getString(R.string.last_name_field_validity_error));
}
};
}
public Func1<CharSequence, Boolean> isEmailValid() {
return textViewAfterTextChangeEvent -> EMAIL_VALIDITY_CHECK;
}
public Action1<Boolean> updateEmailViewState() {
return isValid -> {
if (!isValid) {
signUpView.showEmailError(context.getString(R.string.email_field_validity_error));
}
};
}
public Func1<CharSequence, Boolean> isZipCodeValid() {
return textViewAfterTextChangeEvent -> ZIPCODE_VALIDITY_CHECK;
}
public Action1<Boolean> updateZipCodeViewState() {
return isValid -> {
if (!isValid) {
signUpView.showZipCodeError(context.getString(R.string.zipcode_field_validity_error));
}
};
}
public Func1<CharSequence, Boolean> isPasswordValid() {
return textViewAfterTextChangeEvent -> PASSWORD_VALIDITY_CHECK;
}
public Action1<Boolean> updatePasswordViewState() {
return isValid -> {
if (!isValid) {
signUpView.showPasswordError(context.getString(R.string.password_field_validity_error));
}
};
}
public Func5<Boolean, Boolean, Boolean, Boolean, Boolean, Boolean> isFormValid() {
return (isFirsNameValid, isLastNameValid, isEmailValid, isZipCodeValid, isPasswordValid) ->
isFirsNameValid
&& isLastNameValid
&& isEmailValid
&& isZipCodeValid
&& isPasswordValid;
}
@Override
public void attachView(SignUpView mvpView) {
signUpView = mvpView;
Observable<Boolean> firstNameObservable = signUpView.firstName().map(isFirstNameValid());
Observable<Boolean> lastNameObservable = signUpView.lastName().map(isLastNameValid());
Observable<Boolean> emailObservable = signUpView.email().map(isEmailValid());
Observable<Boolean> zipCodeObservable = signUpView.zipCode().map(isZipCodeValid());
Observable<Boolean> passwordObservable = signUpView.password().map(isPasswordValid());
firstNameObservable.subscribe(updateFirstNameViewState());
lastNameObservable.subscribe(updateLastNameViewState());
emailObservable.subscribe(updateEmailViewState());
zipCodeObservable.subscribe(updateZipCodeViewState());
passwordObservable.subscribe(updatePasswordViewState());
Observable.combineLatest(firstNameObservable, lastNameObservable, emailObservable,
zipCodeObservable, passwordObservable, isFormValid()).subscribe(isValid -> {
signUpView.updateSubmitButtonViewState(isValid);
});
}
@Override
public void detachView() {
}
}
import rx.Observable;
public interface SignUpView extends BaseView {
void showProgress();
void hideProgress();
Observable<CharSequence> firstName();
Observable<CharSequence> lastName();
Observable<CharSequence> email();
Observable<CharSequence> zipCode();
Observable<CharSequence> password();
void showFirstNameError(CharSequence error);
void showLastNameError(CharSequence error);
void showEmailError(CharSequence error);
void showZipCodeError(CharSequence error);
void showPasswordError(CharSequence error);
void updateSubmitButtonViewState(boolean enabled);
void navigateToMainScreen();
}
@azimgoogle
Copy link

azimgoogle commented Feb 15, 2018

Not sure you are using multiple subscriptions or not on TextView. But if so then it might cause concurrency issue whenever any subscriber faces error.

@velegip
Copy link

velegip commented Oct 15, 2018

Why don't you return the ResId of string in the presenter and u can leave the context where it belongs to.

@Badranh
Copy link

Badranh commented Dec 18, 2018

I don't think that you can pass Context to presenter , since Context is from android.* and you can't use android.* in presenter you have to decouple the presenter class from android API completely

@arifardians-gibeon
Copy link

I don't think that you can pass Context to presenter , since Context is from android.* and you can't use android.* in presenter you have to decouple the presenter class from android API completely

I agree with you, as far as I know context should not pass to the presenter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment