package com.kickstarter.viewmodels; import android.support.annotation.NonNull; import android.util.Pair; import com.kickstarter.libs.ActivityViewModel; import com.kickstarter.libs.ApiPaginator; import com.kickstarter.libs.CurrentConfigType; import com.kickstarter.libs.CurrentUserType; import com.kickstarter.libs.Environment; import com.kickstarter.libs.FeatureKey; import com.kickstarter.libs.utils.IntegerUtils; import com.kickstarter.libs.utils.NumberUtils; import com.kickstarter.models.Project; import com.kickstarter.models.User; import com.kickstarter.services.ApiClientType; import com.kickstarter.services.DiscoveryParams; import com.kickstarter.services.apiresponses.DiscoverEnvelope; import com.kickstarter.ui.activities.ProfileActivity; import com.kickstarter.ui.adapters.ProfileAdapter; import com.kickstarter.ui.viewholders.EmptyProfileViewHolder; import com.kickstarter.ui.viewholders.ProfileCardViewHolder; import java.util.List; import rx.Observable; import rx.subjects.PublishSubject; import static com.kickstarter.libs.rx.transformers.Transformers.neverError; import static com.kickstarter.libs.utils.ObjectUtils.coalesce; public interface ProfileViewModel { interface Inputs { /** Call when the Explore Projects button in the empty state has been clicked. */ void exploreProjectsButtonClicked(); /** Call when the messages button has been clicked. */ void messsagesButtonClicked(); /** Call when the next page has been invoked. */ void nextPage(); /** Call when a project card has been clicked. */ void projectCardClicked(Project project); } interface Outputs { /** Emits the user avatar image to be displayed. */ Observable<String> avatarImageViewUrl(); /** Emits when the backed projects count should be hidden. */ Observable<Boolean> backedCountTextViewHidden(); /** Emits the backed projects count to be displayed. */ Observable<String> backedCountTextViewText(); /** Emits when the backed projects text view should be hidden. */ Observable<Boolean> backedTextViewHidden(); /** Emits when the created projects count should be hidden. */ Observable<Boolean> createdCountTextViewHidden(); /** Emits the created projects count to be displayed. */ Observable<String> createdCountTextViewText(); /** Emits when the created projects text view should be hidden. */ Observable<Boolean> createdTextViewHidden(); /** Emits when the divider view should be hidden. */ Observable<Boolean> dividerViewHidden(); /** Emits when the messages button should be hidden. */ Observable<Boolean> messagesButtonHidden(); /** Emits a list of projects to display in the profile. */ Observable<List<Project>> projects(); /** Emits when we should resume the {@link com.kickstarter.ui.activities.DiscoveryActivity}. */ Observable<Void> resumeDiscoveryActivity(); /** Emits when we should start the {@link com.kickstarter.ui.activities.MessageThreadsActivity}. */ Observable<Void> startMessageThreadsActivity(); /** Emits when we should start the {@link com.kickstarter.ui.activities.ProjectActivity}. */ Observable<Project> startProjectActivity(); /** Emits the user name to be displayed. */ Observable<String> userNameTextViewText(); } final class ViewModel extends ActivityViewModel<ProfileActivity> implements ProfileAdapter.Delegate, Inputs, Outputs { private final ApiClientType client; private final CurrentConfigType currentConfig; private final CurrentUserType currentUser; public ViewModel(final @NonNull Environment environment) { super(environment); this.client = environment.apiClient(); this.currentConfig = environment.currentConfig(); this.currentUser = environment.currentUser(); final Observable<User> freshUser = this.client.fetchCurrentUser() .retry(2) .compose(neverError()); freshUser.subscribe(this.currentUser::refresh); final DiscoveryParams params = DiscoveryParams.builder() .backed(1) .perPage(18) .sort(DiscoveryParams.Sort.ENDING_SOON) .build(); final ApiPaginator<Project, DiscoverEnvelope, DiscoveryParams> paginator = ApiPaginator.<Project, DiscoverEnvelope, DiscoveryParams>builder() .nextPage(this.nextPage) .envelopeToListOfData(DiscoverEnvelope::projects) .envelopeToMoreUrl(env -> env.urls().api().moreProjects()) .loadWithParams(__ -> this.client.fetchProjects(params)) .loadWithPaginationPath(this.client::fetchProjects) .build(); final Observable<User> loggedInUser = this.currentUser.loggedInUser(); this.avatarImageViewUrl = loggedInUser.map(u -> u.avatar().medium()); this.backedCountTextViewHidden = loggedInUser .map(u -> IntegerUtils.isZero(u.backedProjectsCount())); this.backedTextViewHidden = this.backedCountTextViewHidden; this.backedCountTextViewText = loggedInUser .map(User::backedProjectsCount) .filter(IntegerUtils::isNonZero) .map(NumberUtils::format); this.createdCountTextViewHidden = loggedInUser .map(u -> IntegerUtils.isZero(u.createdProjectsCount())); this.createdTextViewHidden = this.createdCountTextViewHidden; this.createdCountTextViewText = loggedInUser .map(User::createdProjectsCount) .filter(IntegerUtils::isNonZero) .map(NumberUtils::format); this.dividerViewHidden = Observable.combineLatest( this.backedTextViewHidden, this.createdTextViewHidden, Pair::create ) .map(p -> p.first || p.second); this.messagesButtonHidden = this.currentConfig.observable() .map(config -> !coalesce(config.features().get(FeatureKey.ANDROID_MESSAGES), false)); this.projects = paginator.paginatedData(); this.resumeDiscoveryActivity = this.exploreProjectsButtonClicked; this.startProjectActivity = this.projectCardClicked; this.startMessageThreadsActivity = this.messsagesButtonClicked; this.userNameTextViewText = loggedInUser.map(User::name); this.koala.trackProfileView(); } private final PublishSubject<Void> exploreProjectsButtonClicked = PublishSubject.create(); private final PublishSubject<Void> messsagesButtonClicked = PublishSubject.create(); private final PublishSubject<Void> nextPage = PublishSubject.create(); private final PublishSubject<Project> projectCardClicked = PublishSubject.create(); private final Observable<String> avatarImageViewUrl; private final Observable<Boolean> backedCountTextViewHidden; private final Observable<String> backedCountTextViewText; private final Observable<Boolean> backedTextViewHidden; private final Observable<Boolean> createdCountTextViewHidden; private final Observable<String> createdCountTextViewText; private final Observable<Boolean> createdTextViewHidden; private final Observable<Boolean> dividerViewHidden; private final Observable<Boolean> messagesButtonHidden; private final Observable<List<Project>> projects; private final Observable<Void> resumeDiscoveryActivity; private final Observable<Project> startProjectActivity; private final Observable<Void> startMessageThreadsActivity; private final Observable<String> userNameTextViewText; public final ProfileViewModel.Inputs inputs = this; public final ProfileViewModel.Outputs outputs = this; @Override public void emptyProfileViewHolderExploreProjectsClicked(final @NonNull EmptyProfileViewHolder viewHolder) { this.exploreProjectsButtonClicked(); } @Override public void exploreProjectsButtonClicked() { this.exploreProjectsButtonClicked.onNext(null); } @Override public void messsagesButtonClicked() { this.messsagesButtonClicked.onNext(null); } @Override public void nextPage() { this.nextPage.onNext(null); } @Override public void profileCardViewHolderClicked(final @NonNull ProfileCardViewHolder viewHolder, final @NonNull Project project) { this.projectCardClicked(project); } @Override public void projectCardClicked(final @NonNull Project project) { this.projectCardClicked.onNext(project); } @Override public @NonNull Observable<String> avatarImageViewUrl() { return this.avatarImageViewUrl; } @Override public @NonNull Observable<String> backedCountTextViewText() { return this.backedCountTextViewText; } @Override public @NonNull Observable<Boolean> backedCountTextViewHidden() { return this.backedCountTextViewHidden; } @Override public @NonNull Observable<Boolean> backedTextViewHidden() { return this.backedTextViewHidden; } @Override public @NonNull Observable<Boolean> createdCountTextViewHidden() { return this.createdCountTextViewHidden; } @Override public @NonNull Observable<String> createdCountTextViewText() { return this.createdCountTextViewText; } @Override public @NonNull Observable<Boolean> createdTextViewHidden() { return this.createdTextViewHidden; } @Override public @NonNull Observable<Boolean> dividerViewHidden() { return this.dividerViewHidden; } @Override public @NonNull Observable<Boolean> messagesButtonHidden() { return this.messagesButtonHidden; } @Override public @NonNull Observable<List<Project>> projects() { return this.projects; } @Override public @NonNull Observable<Void> resumeDiscoveryActivity() { return this.resumeDiscoveryActivity; } @Override public @NonNull Observable<Project> startProjectActivity() { return this.startProjectActivity; } @Override public @NonNull Observable<Void> startMessageThreadsActivity() { return this.startMessageThreadsActivity; } @Override public @NonNull Observable<String> userNameTextViewText() { return this.userNameTextViewText; } } }