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.KSCurrency; import com.kickstarter.libs.utils.BackingUtils; import com.kickstarter.libs.utils.BooleanUtils; import com.kickstarter.libs.utils.DateTimeUtils; import com.kickstarter.libs.utils.NumberUtils; import com.kickstarter.libs.utils.ObjectUtils; import com.kickstarter.libs.utils.RewardUtils; import com.kickstarter.models.Avatar; import com.kickstarter.models.Backing; import com.kickstarter.models.Location; import com.kickstarter.models.Photo; import com.kickstarter.models.Project; import com.kickstarter.models.Reward; import com.kickstarter.models.RewardsItem; import com.kickstarter.models.User; import com.kickstarter.services.ApiClientType; import com.kickstarter.ui.IntentKey; import com.kickstarter.ui.activities.ViewPledgeActivity; import com.kickstarter.viewmodels.inputs.ViewPledgeViewModelInputs; import com.kickstarter.viewmodels.outputs.ViewPledgeViewModelOutputs; import java.util.ArrayList; import java.util.List; import rx.Observable; import rx.subjects.BehaviorSubject; import rx.subjects.PublishSubject; import static com.kickstarter.libs.rx.transformers.Transformers.coalesce; import static com.kickstarter.libs.rx.transformers.Transformers.combineLatestPair; import static com.kickstarter.libs.rx.transformers.Transformers.neverError; import static com.kickstarter.libs.rx.transformers.Transformers.zipPair; public final class ViewPledgeViewModel extends ActivityViewModel<ViewPledgeActivity> implements ViewPledgeViewModelInputs, ViewPledgeViewModelOutputs { public ViewPledgeViewModel(final @NonNull Environment environment) { super(environment); final ApiClientType client = environment.apiClient(); final CurrentUserType currentUser = environment.currentUser(); final KSCurrency ksCurrency = environment.ksCurrency(); final Observable<Project> project = intent() .map(i -> i.getParcelableExtra(IntentKey.PROJECT)) .ofType(Project.class); final Observable<Backing> backing = project .compose(combineLatestPair(currentUser.observable())) .filter(pu -> pu.second != null) .switchMap(pu -> client.fetchProjectBacking(pu.first, pu.second) .retry(3) .compose(neverError()) ) .share(); final Observable<User> backer = backing .map(Backing::backer); final Observable<Backing> shippableBacking = backing .filter(BackingUtils::isShippable); final Observable<Reward> reward = backing .map(Backing::reward) .filter(ObjectUtils::isNotNull); backing .map(Backing::sequence) .map(NumberUtils::format) .compose(bindToLifecycle()) .subscribe(backerNumberTextViewText); backer .map(User::name) .compose(bindToLifecycle()) .subscribe(backerNameTextViewText); project .compose(zipPair(backing)) .map(pb -> backingAmountAndDate(ksCurrency, pb.first, pb.second)) .compose(bindToLifecycle()) .subscribe(backingAmountAndDateTextViewText); backing .map(Backing::status) .compose(bindToLifecycle()) .subscribe(backingStatus); project .map(p -> p.creator().name()) .compose(bindToLifecycle()) .subscribe(creatorNameTextViewText); goBack = projectClicked; backer .map(User::avatar) .map(Avatar::medium) .compose(bindToLifecycle()) .subscribe(loadBackerAvatar); project .map(Project::photo) .filter(ObjectUtils::isNotNull) .map(Photo::full) .compose(bindToLifecycle()) .subscribe(loadProjectPhoto); project .map(Project::name) .compose(bindToLifecycle()) .subscribe(projectNameTextViewText); project .compose(zipPair(backing.map(Backing::reward))) .map(pr -> rewardMinimumAndDescription(ksCurrency, pr.first, pr.second)) .compose(bindToLifecycle()) .subscribe(rewardMinimumAndDescriptionTextViewText); reward .map(Reward::rewardsItems) .compose(coalesce(new ArrayList<RewardsItem>())) .compose(bindToLifecycle()) .subscribe(rewardsItems); reward .map(RewardUtils::isItemized) .map(BooleanUtils::negate) .compose(bindToLifecycle()) .subscribe(rewardsItemsAreHidden); project .compose(zipPair(shippableBacking)) .map(pb -> ksCurrency.format(pb.second.shippingAmount(), pb.first)) .compose(bindToLifecycle()) .subscribe(shippingAmountTextViewText); backing .map(Backing::location) .filter(ObjectUtils::isNotNull) .map(Location::displayableName) .compose(bindToLifecycle()) .subscribe(shippingLocationTextViewText); backing .map(BackingUtils::isShippable) .map(BooleanUtils::negate) .compose(bindToLifecycle()) .subscribe(shippingSectionIsHidden); } private static Pair<String, String> backingAmountAndDate(final @NonNull KSCurrency ksCurrency, final @NonNull Project project, final @NonNull Backing backing) { final String amount = ksCurrency.format(backing.amount(), project); final String date = DateTimeUtils.fullDate(backing.pledgedAt()); return Pair.create(amount, date); } private static Pair<String, String> rewardMinimumAndDescription(final @NonNull KSCurrency ksCurrency, final @NonNull Project project, final @NonNull Reward reward) { final String minimum = ksCurrency.format(reward.minimum(), project); return Pair.create(minimum, reward.description()); } private final PublishSubject<Void> projectClicked = PublishSubject.create(); private final BehaviorSubject<String> backerNameTextViewText = BehaviorSubject.create(); private final BehaviorSubject<String> backerNumberTextViewText = BehaviorSubject.create(); private final BehaviorSubject<String> backingStatus = BehaviorSubject.create(); private final BehaviorSubject<Pair<String, String>> backingAmountAndDateTextViewText = BehaviorSubject.create(); private final BehaviorSubject<String> creatorNameTextViewText = BehaviorSubject.create(); private final Observable<Void> goBack; private final BehaviorSubject<String> loadBackerAvatar = BehaviorSubject.create(); private final BehaviorSubject<String> loadProjectPhoto = BehaviorSubject.create(); private final BehaviorSubject<String> projectNameTextViewText = BehaviorSubject.create(); private final BehaviorSubject<Pair<String, String>> rewardMinimumAndDescriptionTextViewText = BehaviorSubject.create(); private final BehaviorSubject<List<RewardsItem>> rewardsItems = BehaviorSubject.create(); private final BehaviorSubject<Boolean> rewardsItemsAreHidden = BehaviorSubject.create(); private final BehaviorSubject<String> shippingAmountTextViewText = BehaviorSubject.create(); private final BehaviorSubject<String> shippingLocationTextViewText = BehaviorSubject.create(); private final BehaviorSubject<Boolean> shippingSectionIsHidden = BehaviorSubject.create(); public final ViewPledgeViewModelInputs inputs = this; public final ViewPledgeViewModelOutputs outputs = this; @Override public void projectClicked() { projectClicked.onNext(null); } @Override public @NonNull Observable<String> backerNameTextViewText() { return backerNameTextViewText; } @Override public @NonNull Observable<String> backerNumberTextViewText() { return backerNumberTextViewText; } @Override public @NonNull Observable<Pair<String, String>> backingAmountAndDateTextViewText() { return backingAmountAndDateTextViewText; } @Override public @NonNull Observable<String> backingStatus() { return backingStatus; } @Override public @NonNull Observable<String> creatorNameTextViewText() { return creatorNameTextViewText; } @Override public @NonNull Observable<Void> goBack() { return goBack; } @Override public @NonNull Observable<String> loadBackerAvatar() { return loadBackerAvatar; } @Override public @NonNull Observable<String> loadProjectPhoto() { return loadProjectPhoto; } @Override public @NonNull Observable<String> projectNameTextViewText() { return projectNameTextViewText; } @Override public @NonNull Observable<Pair<String, String>> rewardMinimumAndDescriptionTextViewText() { return rewardMinimumAndDescriptionTextViewText; } @Override public @NonNull Observable<List<RewardsItem>> rewardsItems() { return rewardsItems; } @Override public @NonNull Observable<Boolean> rewardsItemsAreHidden() { return rewardsItemsAreHidden; } @Override public @NonNull Observable<String> shippingAmountTextViewText() { return shippingAmountTextViewText; } @Override public @NonNull Observable<String> shippingLocationTextViewText() { return shippingLocationTextViewText; } @Override public @NonNull Observable<Boolean> shippingSectionIsHidden() { return shippingSectionIsHidden; } }