Skip to content

Instantly share code, notes, and snippets.

@mandybess
Last active January 7, 2019 03:27
Show Gist options
  • 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();
}
@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