package com.kickstarter.viewmodels; import android.support.annotation.NonNull; import com.kickstarter.libs.ActivityViewModel; import com.kickstarter.libs.CurrentConfigType; import com.kickstarter.libs.CurrentUserType; import com.kickstarter.libs.Environment; import com.kickstarter.libs.rx.transformers.Transformers; import com.kickstarter.libs.utils.I18nUtils; import com.kickstarter.libs.utils.StringUtils; import com.kickstarter.services.ApiClientType; import com.kickstarter.services.apiresponses.AccessTokenEnvelope; import com.kickstarter.services.apiresponses.ErrorEnvelope; import com.kickstarter.ui.activities.SignupActivity; import com.kickstarter.viewmodels.errors.SignupViewModelErrors; import com.kickstarter.viewmodels.inputs.SignupViewModelInputs; import com.kickstarter.viewmodels.outputs.SignupViewModelOutputs; import rx.Observable; import rx.subjects.BehaviorSubject; import rx.subjects.PublishSubject; public final class SignupViewModel extends ActivityViewModel<SignupActivity> implements SignupViewModelInputs, SignupViewModelOutputs, SignupViewModelErrors { private final ApiClientType client; private final CurrentUserType currentUser; private final CurrentConfigType currentConfig; protected final static class SignupData { final @NonNull String fullName; final @NonNull String email; final @NonNull String password; final boolean sendNewsletters; protected SignupData(final @NonNull String fullName, final @NonNull String email, final @NonNull String password, final boolean sendNewsletters) { this.fullName = fullName; this.email = email; this.password = password; this.sendNewsletters = sendNewsletters; } protected boolean isValid() { return fullName.length() > 0 && StringUtils.isEmail(email) && password.length() >= 6; } } // INPUTS private final PublishSubject<String> fullName = PublishSubject.create(); public void fullName(final @NonNull String s) { fullName.onNext(s); } private final PublishSubject<String> email = PublishSubject.create(); public void email(final @NonNull String s) { email.onNext(s); } private final PublishSubject<String> password = PublishSubject.create(); public void password(final @NonNull String s) { password.onNext(s); } private final PublishSubject<Boolean> sendNewslettersClick = PublishSubject.create(); public void sendNewslettersClick(final boolean b) { sendNewslettersClick.onNext(b); } private final PublishSubject<Void> signupClick = PublishSubject.create(); public void signupClick() { signupClick.onNext(null); } // OUTPUTS private final PublishSubject<Void> signupSuccess = PublishSubject.create(); public Observable<Void> signupSuccess() { return signupSuccess.asObservable(); } private final PublishSubject<Boolean> formSubmitting = PublishSubject.create(); public Observable<Boolean> formSubmitting() { return formSubmitting.asObservable(); } private final PublishSubject<Boolean> formIsValid = PublishSubject.create(); public Observable<Boolean> formIsValid() { return formIsValid.asObservable(); } private final BehaviorSubject<Boolean> sendNewslettersIsChecked = BehaviorSubject.create(); public Observable<Boolean> sendNewslettersIsChecked() { return sendNewslettersIsChecked; } // ERRORS private final PublishSubject<ErrorEnvelope> signupError = PublishSubject.create(); public Observable<String> signupError() { return signupError .takeUntil(signupSuccess) .map(ErrorEnvelope::errorMessage); } public final SignupViewModelInputs inputs = this; public final SignupViewModelOutputs outputs = this; public final SignupViewModelErrors errors = this; public SignupViewModel(final @NonNull Environment environment) { super(environment); client = environment.apiClient(); currentConfig = environment.currentConfig(); currentUser = environment.currentUser(); final Observable<SignupData> signupData = Observable.combineLatest( fullName, email, password, sendNewslettersIsChecked, SignupData::new); sendNewslettersClick .compose(bindToLifecycle()) .subscribe(sendNewslettersIsChecked::onNext); signupData .map(SignupData::isValid) .compose(bindToLifecycle()) .subscribe(formIsValid); signupData .compose(Transformers.takeWhen(signupClick)) .flatMap(this::submit) .compose(bindToLifecycle()) .subscribe(this::success); currentConfig.observable() .take(1) .map(config -> I18nUtils.isCountryUS(config.countryCode())) .compose(bindToLifecycle()) .subscribe(sendNewslettersIsChecked::onNext); signupError .compose(bindToLifecycle()) .subscribe(__ -> koala.trackRegisterError()); sendNewslettersClick .compose(bindToLifecycle()) .subscribe(koala::trackSignupNewsletterToggle); signupSuccess .compose(bindToLifecycle()) .subscribe(__ -> { koala.trackLoginSuccess(); koala.trackRegisterSuccess(); }); koala.trackRegisterFormView(); } private Observable<AccessTokenEnvelope> submit(final @NonNull SignupData data) { return client.signup(data.fullName, data.email, data.password, data.password, data.sendNewsletters) .compose(Transformers.pipeApiErrorsTo(signupError)) .compose(Transformers.neverError()) .doOnSubscribe(() -> formSubmitting.onNext(true)) .doAfterTerminate(() -> formSubmitting.onNext(false)); } private void success(final @NonNull AccessTokenEnvelope envelope) { currentUser.login(envelope.user(), envelope.accessToken()); signupSuccess.onNext(null); } }