package com.kickstarter.viewmodels; import android.support.annotation.NonNull; import android.util.Pair; import com.kickstarter.libs.ActivityViewModel; import com.kickstarter.libs.CurrentUserType; import com.kickstarter.libs.Environment; import com.kickstarter.libs.rx.transformers.Transformers; import com.kickstarter.libs.utils.ListUtils; import com.kickstarter.libs.utils.UserUtils; import com.kickstarter.models.User; import com.kickstarter.services.ApiClientType; import com.kickstarter.ui.activities.SettingsActivity; import com.kickstarter.ui.data.Newsletter; import com.kickstarter.viewmodels.errors.SettingsViewModelErrors; import com.kickstarter.viewmodels.inputs.SettingsViewModelInputs; import com.kickstarter.viewmodels.outputs.SettingsViewModelOutputs; import rx.Observable; import rx.subjects.BehaviorSubject; import rx.subjects.PublishSubject; public class SettingsViewModel extends ActivityViewModel<SettingsActivity> implements SettingsViewModelInputs, SettingsViewModelErrors, SettingsViewModelOutputs { // INPUTS private final PublishSubject<Void> contactEmailClicked = PublishSubject.create(); private final PublishSubject<Pair<Boolean, Newsletter>> newsletterInput = PublishSubject.create(); private final PublishSubject<User> userInput = PublishSubject.create(); public void logoutClicked() { showConfirmLogoutPrompt.onNext(true); } public void closeLogoutConfirmationClicked() { showConfirmLogoutPrompt.onNext(false); } private final PublishSubject<Void> confirmLogoutClicked = PublishSubject.create(); @Override public void confirmLogoutClicked() { confirmLogoutClicked.onNext(null); } // OUTPUTS private final PublishSubject<Newsletter> showOptInPrompt = PublishSubject.create(); public @NonNull Observable<Newsletter> showOptInPrompt() { return showOptInPrompt; } private final PublishSubject<Void> updateSuccess = PublishSubject.create(); public @NonNull final Observable<Void> updateSuccess() { return updateSuccess; } private final BehaviorSubject<User> userOutput = BehaviorSubject.create(); public @NonNull Observable<User> user() { return userOutput; } private final BehaviorSubject<Boolean> showConfirmLogoutPrompt = BehaviorSubject.create(); public @NonNull Observable<Boolean> showConfirmLogoutPrompt() { return showConfirmLogoutPrompt; } private final BehaviorSubject<Void> logout = BehaviorSubject.create(); @Override public @NonNull Observable<Void> logout() { return logout; } // ERRORS private final PublishSubject<Throwable> unableToSavePreferenceError = PublishSubject.create(); public @NonNull final Observable<String> unableToSavePreferenceError() { return unableToSavePreferenceError .takeUntil(updateSuccess) .map(__ -> null); } public final SettingsViewModelInputs inputs = this; public final SettingsViewModelOutputs outputs = this; public final SettingsViewModelErrors errors = this; private final ApiClientType client; private final CurrentUserType currentUser; @Override public void contactEmailClicked() { this.contactEmailClicked.onNext(null); } @Override public void notifyMobileOfFollower(final boolean b) { userInput.onNext(userOutput.getValue().toBuilder().notifyMobileOfFollower(b).build()); } @Override public void notifyMobileOfFriendActivity(final boolean b) { userInput.onNext(userOutput.getValue().toBuilder().notifyMobileOfFriendActivity(b).build()); } @Override public void notifyMobileOfUpdates(final boolean b) { userInput.onNext(userOutput.getValue().toBuilder().notifyMobileOfUpdates(b).build()); } @Override public void notifyOfFollower(final boolean b) { userInput.onNext(userOutput.getValue().toBuilder().notifyOfFollower(b).build()); } @Override public void notifyOfFriendActivity(final boolean b) { userInput.onNext(userOutput.getValue().toBuilder().notifyOfFriendActivity(b).build()); } @Override public void notifyOfUpdates(final boolean b) { userInput.onNext(userOutput.getValue().toBuilder().notifyOfUpdates(b).build()); } @Override public void sendGamesNewsletter(final boolean checked) { userInput.onNext(userOutput.getValue().toBuilder().gamesNewsletter(checked).build()); newsletterInput.onNext(new Pair<>(checked, Newsletter.GAMES)); } @Override public void sendHappeningNewsletter(final boolean checked) { userInput.onNext(userOutput.getValue().toBuilder().happeningNewsletter(checked).build()); newsletterInput.onNext(new Pair<>(checked, Newsletter.HAPPENING)); } @Override public void sendPromoNewsletter(final boolean checked) { userInput.onNext(userOutput.getValue().toBuilder().promoNewsletter(checked).build()); newsletterInput.onNext(new Pair<>(checked, Newsletter.PROMO)); } @Override public void sendWeeklyNewsletter(final boolean checked) { userInput.onNext(userOutput.getValue().toBuilder().weeklyNewsletter(checked).build()); newsletterInput.onNext(new Pair<>(checked, Newsletter.WEEKLY)); } public SettingsViewModel(final @NonNull Environment environment) { super(environment); client = environment.apiClient(); currentUser = environment.currentUser(); client.fetchCurrentUser() .retry(2) .compose(Transformers.neverError()) .compose(bindToLifecycle()) .subscribe(currentUser::refresh); currentUser.observable() .take(1) .compose(bindToLifecycle()) .subscribe(userOutput::onNext); userInput .concatMap(this::updateSettings) .compose(bindToLifecycle()) .subscribe(this::success); userInput .compose(bindToLifecycle()) .subscribe(userOutput); userOutput .window(2, 1) .flatMap(Observable::toList) .map(ListUtils::first) .compose(Transformers.takeWhen(unableToSavePreferenceError)) .compose(bindToLifecycle()) .subscribe(userOutput); currentUser.observable() .compose(Transformers.takePairWhen(newsletterInput)) .filter(us -> requiresDoubleOptIn(us.first, us.second.first)) .map(us -> us.second.second) .compose(bindToLifecycle()) .subscribe(showOptInPrompt); contactEmailClicked .compose(bindToLifecycle()) .subscribe(__ -> koala.trackContactEmailClicked()); newsletterInput .map(bs -> bs.first) .compose(bindToLifecycle()) .subscribe(koala::trackNewsletterToggle); confirmLogoutClicked .compose(bindToLifecycle()) .subscribe(__ -> { koala.trackLogout(); logout.onNext(null); }); koala.trackSettingsView(); } private boolean requiresDoubleOptIn(final @NonNull User user, final boolean checked) { return UserUtils.isLocationGermany(user) && checked; } private void success(final @NonNull User user) { currentUser.refresh(user); this.updateSuccess.onNext(null); } private @NonNull Observable<User> updateSettings(final @NonNull User user) { return client.updateUserSettings(user) .compose(Transformers.pipeErrorsTo(unableToSavePreferenceError)); } }