package com.kickstarter.viewmodels;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Pair;
import com.google.android.gms.wallet.FullWallet;
import com.google.android.gms.wallet.MaskedWallet;
import com.google.android.gms.wallet.WalletConstants;
import com.google.gson.Gson;
import com.kickstarter.libs.ActivityViewModel;
import com.kickstarter.libs.AndroidPayCapability;
import com.kickstarter.libs.Environment;
import com.kickstarter.libs.models.AndroidPayPayload;
import com.kickstarter.libs.rx.transformers.Transformers;
import com.kickstarter.libs.utils.AndroidPayUtils;
import com.kickstarter.libs.utils.BooleanUtils;
import com.kickstarter.libs.utils.ObjectUtils;
import com.kickstarter.models.Project;
import com.kickstarter.ui.IntentKey;
import com.kickstarter.ui.activities.CheckoutActivity;
import com.kickstarter.ui.data.ActivityResult;
import com.kickstarter.viewmodels.errors.CheckoutViewModelErrors;
import com.kickstarter.viewmodels.inputs.CheckoutViewModelInputs;
import com.kickstarter.viewmodels.outputs.CheckoutViewModelOutputs;
import rx.Observable;
import rx.subjects.BehaviorSubject;
import rx.subjects.PublishSubject;
public final class CheckoutViewModel extends ActivityViewModel<CheckoutActivity> implements CheckoutViewModelInputs,
CheckoutViewModelOutputs, CheckoutViewModelErrors {
private AndroidPayCapability androidPayCapability;
private Gson gson;
// INPUTS
private PublishSubject<String> pageIntercepted = PublishSubject.create();
@Override
public void pageIntercepted(final @NonNull String str) {
pageIntercepted.onNext(str);
}
private PublishSubject<Void> backButtonClicked = PublishSubject.create();
public void backButtonClicked() {
backButtonClicked.onNext(null);
}
private PublishSubject<String> payloadString = PublishSubject.create();
public void takePayloadString(final @Nullable String payloadString) {
this.payloadString.onNext(payloadString);
}
private PublishSubject<Void> confirmAndroidPayClicked = PublishSubject.create();
public void confirmAndroidPayClicked() {
confirmAndroidPayClicked.onNext(null);
}
// OUTPUTS
private BehaviorSubject<Project> project = BehaviorSubject.create();
@Override
public @NonNull Observable<Project> project() {
return project;
}
private BehaviorSubject<String> title = BehaviorSubject.create();
@Override
public @NonNull Observable<String> title() {
return title;
}
private BehaviorSubject<String> url = BehaviorSubject.create();
@Override
public @NonNull Observable<String> url() {
return url;
}
private BehaviorSubject<Boolean> displayAndroidPayConfirmation = BehaviorSubject.create();
public Observable<Boolean> displayAndroidPayConfirmation() {
return displayAndroidPayConfirmation;
}
private BehaviorSubject<Pair<MaskedWallet, AndroidPayPayload>> updateAndroidPayConfirmation = BehaviorSubject.create();
public Observable<Pair<MaskedWallet, AndroidPayPayload>> updateAndroidPayConfirmation() {
return updateAndroidPayConfirmation;
}
private BehaviorSubject<AndroidPayPayload> showAndroidPaySheet = BehaviorSubject.create();
public Observable<AndroidPayPayload> showAndroidPaySheet() {
return showAndroidPaySheet;
}
public Observable<Boolean> isAndroidPayAvailable() {
return Observable.just(androidPayCapability.isCapable());
}
private BehaviorSubject<Void> popActivityOffStack = BehaviorSubject.create();
public Observable<Void> popActivityOffStack() {
return popActivityOffStack;
}
private BehaviorSubject<Pair<MaskedWallet, AndroidPayPayload>> attemptAndroidPayConfirmation = BehaviorSubject.create();
public Observable<Pair<MaskedWallet, AndroidPayPayload>> attemptAndroidPayConfirmation() {
return attemptAndroidPayConfirmation;
}
private BehaviorSubject<FullWallet> completeAndroidPay = BehaviorSubject.create();
public Observable<FullWallet> completeAndroidPay() {
return completeAndroidPay;
}
// ERRORS
final private Observable<Integer> androidPayError;
public Observable<Integer> androidPayError() {
return this.androidPayError;
}
public final CheckoutViewModelInputs inputs = this;
public final CheckoutViewModelOutputs outputs = this;
public final CheckoutViewModelErrors errors = this;
public CheckoutViewModel(final @NonNull Environment environment) {
super(environment);
androidPayCapability = environment.androidPayCapability();
gson = environment.gson();
intent()
.map(i -> i.getParcelableExtra(IntentKey.PROJECT))
.ofType(Project.class)
.compose(bindToLifecycle())
.subscribe(project::onNext);
intent()
.map(i -> i.getStringExtra(IntentKey.TOOLBAR_TITLE))
.ofType(String.class)
.compose(bindToLifecycle())
.subscribe(title::onNext);
intent()
.map(i -> i.getStringExtra(IntentKey.URL))
.ofType(String.class)
.take(1)
.mergeWith(pageIntercepted)
.compose(bindToLifecycle())
.subscribe(url::onNext);
final Observable<MaskedWallet> maskedWallet = activityResult()
.filter(AndroidPayUtils::isMaskedWalletRequest)
.map(ActivityResult::intent)
.map(i -> i.getParcelableExtra(WalletConstants.EXTRA_MASKED_WALLET))
.ofType(MaskedWallet.class);
final Observable<FullWallet> fullWallet = activityResult()
.filter(AndroidPayUtils::isFullWalletRequest)
.map(ActivityResult::intent)
.map(i -> i.getParcelableExtra(WalletConstants.EXTRA_FULL_WALLET))
.ofType(FullWallet.class);
this.androidPayError = activityResult()
.map(AndroidPayUtils::walletRequestError)
.filter(ObjectUtils::isNotNull);
final Observable<AndroidPayPayload> payload = payloadString
.map(str -> AndroidPayUtils.payloadFromString(str, gson))
.ofType(AndroidPayPayload.class);
final Observable<Boolean> confirmationVisibilityOnBack = displayAndroidPayConfirmation
.compose(Transformers.takeWhen(backButtonClicked));
payload
.compose(bindToLifecycle())
.subscribe(showAndroidPaySheet::onNext);
confirmationVisibilityOnBack
.filter(BooleanUtils::isFalse)
.compose(bindToLifecycle())
.subscribe(__ -> popActivityOffStack.onNext(null));
confirmationVisibilityOnBack
.filter(BooleanUtils::isTrue)
.map(__ -> false)
.mergeWith(maskedWallet.map(__ -> true))
.compose(bindToLifecycle())
.subscribe(displayAndroidPayConfirmation::onNext);
maskedWallet
.compose(Transformers.combineLatestPair(payload))
.filter(wp -> wp.first != null && wp.second != null)
.compose(bindToLifecycle())
.subscribe(updateAndroidPayConfirmation::onNext);
maskedWallet
.compose(Transformers.combineLatestPair(payload))
.compose(Transformers.takeWhen(confirmAndroidPayClicked))
.filter(wp -> wp.second != null)
.compose(bindToLifecycle())
.subscribe(attemptAndroidPayConfirmation::onNext);
fullWallet
.compose(bindToLifecycle())
.subscribe(completeAndroidPay::onNext);
showAndroidPaySheet
.compose(bindToLifecycle())
.subscribe(__ -> koala.trackShowAndroidPaySheet());
completeAndroidPay
.compose(bindToLifecycle())
.subscribe(__ -> koala.trackAndroidPayFinished());
// Start by not showing the confirmation page.
displayAndroidPayConfirmation.onNext(false);
}
}