diff --git a/app/src/main/java/com/kickstarter/libs/featureflag/FeatureFlagClient.kt b/app/src/main/java/com/kickstarter/libs/featureflag/FeatureFlagClient.kt index f668bec587..bc48356e8c 100644 --- a/app/src/main/java/com/kickstarter/libs/featureflag/FeatureFlagClient.kt +++ b/app/src/main/java/com/kickstarter/libs/featureflag/FeatureFlagClient.kt @@ -78,7 +78,6 @@ enum class FlagKey(val key: String) { ANDROID_STRIPE_LINK("android_stripe_link"), ANDROID_PLEDGED_PROJECTS_OVERVIEW("android_pledged_projects_overview"), ANDROID_PLEDGE_REDEMPTION("android_pledge_redemption"), - ANDROID_FIX_PLEDGE_REFACTOR("android_fix_pledge_refactor"), ANDROID_PLEDGE_OVER_TIME("android_pledge_over_time") } diff --git a/app/src/main/java/com/kickstarter/libs/utils/extensions/FragmentExt.kt b/app/src/main/java/com/kickstarter/libs/utils/extensions/FragmentExt.kt index ace3159bac..f92e39fa7d 100644 --- a/app/src/main/java/com/kickstarter/libs/utils/extensions/FragmentExt.kt +++ b/app/src/main/java/com/kickstarter/libs/utils/extensions/FragmentExt.kt @@ -6,20 +6,12 @@ import com.kickstarter.ui.ArgumentsKey import com.kickstarter.ui.data.PledgeData import com.kickstarter.ui.data.PledgeReason import com.kickstarter.ui.fragments.CrowdfundCheckoutFragment -import com.kickstarter.ui.fragments.PledgeFragment fun Fragment.selectPledgeFragment( pledgeData: PledgeData, - pledgeReason: PledgeReason, - ffEnabled: Boolean = false + pledgeReason: PledgeReason ): Fragment { - val fragment = when (pledgeReason) { - PledgeReason.FIX_PLEDGE -> - if (ffEnabled) CrowdfundCheckoutFragment() - else PledgeFragment() - else -> CrowdfundCheckoutFragment() - } - + val fragment = CrowdfundCheckoutFragment() return fragment.withData(pledgeData, pledgeReason) } diff --git a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt index 0cad22c71a..d466666f74 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt @@ -50,8 +50,6 @@ import com.kickstarter.libs.Environment import com.kickstarter.libs.KSString import com.kickstarter.libs.MessagePreviousScreenType import com.kickstarter.libs.ProjectPagerTabs -import com.kickstarter.libs.featureflag.FeatureFlagClientType -import com.kickstarter.libs.featureflag.FlagKey import com.kickstarter.libs.utils.ApplicationUtils import com.kickstarter.libs.utils.UrlUtils import com.kickstarter.libs.utils.ViewUtils @@ -87,7 +85,6 @@ import com.kickstarter.ui.extensions.startUpdatesActivity import com.kickstarter.ui.extensions.startVideoActivity import com.kickstarter.ui.fragments.BackingFragment import com.kickstarter.ui.fragments.CancelPledgeFragment -import com.kickstarter.ui.fragments.PledgeFragment import com.kickstarter.ui.fragments.RewardsFragment import com.kickstarter.utils.WindowInsetsUtil import com.kickstarter.viewmodels.projectpage.AddOnsViewModel @@ -111,10 +108,16 @@ import kotlinx.coroutines.launch const val REFRESH = "refresh" +interface PledgeDelegate { + fun pledgePaymentSuccessfullyUpdated() + fun pledgeSuccessfullyCreated(checkoutDataAndPledgeData: Pair) + fun pledgeSuccessfullyUpdated() +} + class ProjectPageActivity : AppCompatActivity(), CancelPledgeFragment.CancelPledgeDelegate, - PledgeFragment.PledgeDelegate, + PledgeDelegate, BackingFragment.BackingDelegate { private lateinit var ksString: KSString @@ -398,7 +401,7 @@ class ProjectPageActivity : this.viewModel.outputs.showUpdatePledge() .observeOn(AndroidSchedulers.mainThread()) - .subscribe { showPledgeFragment(it, ffClient) } + .subscribe { showPledgeFragment(it) } .addToDisposable(disposables) this.viewModel.outputs.startRootCommentsActivity() @@ -1154,11 +1157,9 @@ class ProjectPageActivity : .show() } private fun showPledgeFragment( - pledgeDataAndPledgeReason: Pair, - ffClient: FeatureFlagClientType + pledgeDataAndPledgeReason: Pair ) { - val ffEnabled = ffClient.getBoolean(FlagKey.ANDROID_FIX_PLEDGE_REFACTOR) - val pledgeFragment = this.selectPledgeFragment(pledgeDataAndPledgeReason.first, pledgeDataAndPledgeReason.second, ffEnabled) + val pledgeFragment = this.selectPledgeFragment(pledgeDataAndPledgeReason.first, pledgeDataAndPledgeReason.second) val tag = pledgeFragment::class.java.simpleName supportFragmentManager .beginTransaction() diff --git a/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt b/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt index 9efaea3f67..584214c5df 100644 --- a/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt +++ b/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt @@ -45,7 +45,6 @@ import com.kickstarter.ui.data.PledgeData import com.kickstarter.ui.data.PledgeReason import com.kickstarter.ui.data.ProjectData import com.kickstarter.ui.fragments.CrowdfundCheckoutFragment -import com.kickstarter.ui.fragments.PledgeFragment import timber.log.Timber fun Activity.startActivityWithTransition( @@ -78,15 +77,9 @@ fun Activity.hideKeyboard() { fun Activity.selectPledgeFragment( pledgeData: PledgeData, - pledgeReason: PledgeReason, - ffEnabled: Boolean = false + pledgeReason: PledgeReason ): Fragment { - val fragment = when (pledgeReason) { - PledgeReason.FIX_PLEDGE -> - if (ffEnabled) CrowdfundCheckoutFragment() - else PledgeFragment() - else -> CrowdfundCheckoutFragment() - } + val fragment = CrowdfundCheckoutFragment() return fragment.withData(pledgeData, pledgeReason) } diff --git a/app/src/main/java/com/kickstarter/ui/fragments/BackingAddOnsFragment.kt b/app/src/main/java/com/kickstarter/ui/fragments/BackingAddOnsFragment.kt index ec56e046f0..ef1c0c4f4b 100644 --- a/app/src/main/java/com/kickstarter/ui/fragments/BackingAddOnsFragment.kt +++ b/app/src/main/java/com/kickstarter/ui/fragments/BackingAddOnsFragment.kt @@ -15,8 +15,6 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import com.kickstarter.R import com.kickstarter.databinding.FragmentBackingAddonsBinding -import com.kickstarter.libs.featureflag.FeatureFlagClientType -import com.kickstarter.libs.featureflag.FlagKey import com.kickstarter.libs.utils.extensions.getEnvironment import com.kickstarter.libs.utils.extensions.selectPledgeFragment import com.kickstarter.ui.ArgumentsKey @@ -99,8 +97,7 @@ class BackingAddOnsFragment : Fragment() { viewModelC.getPledgeDataAndReason()?.let { pDataAndReason -> showPledgeFragment( pledgeData = pDataAndReason.first, - pledgeReason = pDataAndReason.second, - ffClient = ffClient + pledgeReason = pDataAndReason.second ) } } else { @@ -123,11 +120,9 @@ class BackingAddOnsFragment : Fragment() { private fun showPledgeFragment( pledgeData: PledgeData, - pledgeReason: PledgeReason, - ffClient: FeatureFlagClientType + pledgeReason: PledgeReason ) { - val ffEnabled = ffClient.getBoolean(FlagKey.ANDROID_FIX_PLEDGE_REFACTOR) - val fragment = this.selectPledgeFragment(pledgeData, pledgeReason, ffEnabled) + val fragment = this.selectPledgeFragment(pledgeData, pledgeReason) parentFragmentManager .beginTransaction() .setCustomAnimations(R.anim.slide_up, 0, 0, R.anim.slide_down) diff --git a/app/src/main/java/com/kickstarter/ui/fragments/CrowdfundCheckoutFragment.kt b/app/src/main/java/com/kickstarter/ui/fragments/CrowdfundCheckoutFragment.kt index eeb0097a45..b10c933a57 100644 --- a/app/src/main/java/com/kickstarter/ui/fragments/CrowdfundCheckoutFragment.kt +++ b/app/src/main/java/com/kickstarter/ui/fragments/CrowdfundCheckoutFragment.kt @@ -23,6 +23,7 @@ import com.kickstarter.models.Reward import com.kickstarter.models.StoredCard import com.kickstarter.models.chrome.ChromeTabsHelperActivity import com.kickstarter.ui.activities.DisclaimerItems +import com.kickstarter.ui.activities.PledgeDelegate import com.kickstarter.ui.activities.compose.projectpage.CheckoutScreen import com.kickstarter.ui.activities.compose.projectpage.getRewardListAndPrices import com.kickstarter.ui.compose.designsystem.KSTheme @@ -30,7 +31,6 @@ import com.kickstarter.ui.compose.designsystem.KickstarterApp import com.kickstarter.ui.data.PledgeReason import com.kickstarter.ui.extensions.showErrorToast import com.kickstarter.ui.extensions.startDisclaimerChromeTab -import com.kickstarter.ui.fragments.PledgeFragment.PledgeDelegate import com.kickstarter.viewmodels.projectpage.CheckoutUIState import com.kickstarter.viewmodels.projectpage.CrowdfundCheckoutViewModel import com.kickstarter.viewmodels.projectpage.CrowdfundCheckoutViewModel.Factory diff --git a/app/src/main/java/com/kickstarter/ui/fragments/PledgeFragment.kt b/app/src/main/java/com/kickstarter/ui/fragments/PledgeFragment.kt deleted file mode 100644 index b63d393ada..0000000000 --- a/app/src/main/java/com/kickstarter/ui/fragments/PledgeFragment.kt +++ /dev/null @@ -1,790 +0,0 @@ -package com.kickstarter.ui.fragments - -import android.annotation.SuppressLint -import android.content.Intent -import android.graphics.Rect -import android.net.Uri -import android.os.Bundle -import android.text.SpannableString -import android.text.SpannableStringBuilder -import android.text.TextPaint -import android.text.method.LinkMovementMethod -import android.text.style.ClickableSpan -import android.text.style.URLSpan -import android.util.Pair -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.constraintlayout.widget.ConstraintSet -import androidx.core.content.ContextCompat -import androidx.core.view.isGone -import androidx.core.view.isInvisible -import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.transition.ChangeBounds -import androidx.transition.TransitionManager -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.kickstarter.KSApplication -import com.kickstarter.R -import com.kickstarter.databinding.FragmentPledgeBinding -import com.kickstarter.libs.KSString -import com.kickstarter.libs.utils.UrlUtils -import com.kickstarter.libs.utils.ViewUtils -import com.kickstarter.libs.utils.extensions.addToDisposable -import com.kickstarter.libs.utils.extensions.getEnvironment -import com.kickstarter.libs.utils.extensions.getPaymentSheetConfiguration -import com.kickstarter.libs.utils.extensions.isNotNull -import com.kickstarter.models.Project -import com.kickstarter.models.Reward -import com.kickstarter.models.ShippingRule -import com.kickstarter.models.StoredCard -import com.kickstarter.models.chrome.ChromeTabsHelperActivity -import com.kickstarter.ui.activities.HelpActivity -import com.kickstarter.ui.activities.LoginToutActivity -import com.kickstarter.ui.adapters.ExpandableHeaderAdapter -import com.kickstarter.ui.adapters.RewardCardAdapter -import com.kickstarter.ui.adapters.ShippingRulesAdapter -import com.kickstarter.ui.data.CardState -import com.kickstarter.ui.data.CheckoutData -import com.kickstarter.ui.data.PledgeData -import com.kickstarter.ui.extensions.hideKeyboard -import com.kickstarter.ui.extensions.showErrorToast -import com.kickstarter.ui.itemdecorations.RewardCardItemDecoration -import com.kickstarter.viewmodels.PledgeFragmentViewModel -import com.stripe.android.ApiResultCallback -import com.stripe.android.SetupIntentResult -import com.stripe.android.Stripe -import com.stripe.android.paymentsheet.PaymentSheet -import com.stripe.android.paymentsheet.PaymentSheetResult -import com.stripe.android.paymentsheet.model.PaymentOption -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import timber.log.Timber - -class PledgeFragment : - Fragment(), - RewardCardAdapter - .Delegate, - ShippingRulesAdapter.Delegate { - - interface PledgeDelegate { - fun pledgePaymentSuccessfullyUpdated() - fun pledgeSuccessfullyCreated(checkoutDataAndPledgeData: Pair) - fun pledgeSuccessfullyUpdated() - } - - private lateinit var adapter: ShippingRulesAdapter - private var headerAdapter = ExpandableHeaderAdapter() - private var isExpanded = false - private var setupClientId: String = "" - private lateinit var flowController: PaymentSheet.FlowController - - private var binding: FragmentPledgeBinding? = null - - private lateinit var viewModelFactory: PledgeFragmentViewModel.Factory - private val viewModel: PledgeFragmentViewModel.PledgeFragmentViewModel by viewModels { viewModelFactory } - - private var disposables = CompositeDisposable() - - private lateinit var stripe: Stripe - private lateinit var ksString: KSString - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - super.onCreateView(inflater, container, savedInstanceState) - binding = FragmentPledgeBinding.inflate(inflater, container, false) - return binding?.root - } - - @SuppressLint("ClickableViewAccessibility") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val env = this.context?.getEnvironment()?.let { env -> - viewModelFactory = PledgeFragmentViewModel.Factory(env, bundle = arguments) - env - } - - stripe = requireNotNull(env?.stripe()) - ksString = requireNotNull(env?.ksString()) - - setUpCardsAdapter() - setUpShippingAdapter() - setupRewardRecyclerView() - - flowController = PaymentSheet.FlowController.create( - fragment = this, - paymentOptionCallback = ::onPaymentOption, - paymentResultCallback = ::onPaymentSheetResult - ) - - this.viewModel.outputs.headerSectionIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderContainer?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.estimatedDelivery() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderEstimatedDeliveryLabel ?.text = String.format("%1$2s / %2$2s", binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderEstimatedDeliveryLabel ?.text, it) - } - .addToDisposable(disposables) - - this.viewModel.outputs.estimatedDeliveryInfoIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderEstimatedDeliveryLabel ?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.continueButtonIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionFooter?.pledgeFooterContinueButton?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.conversionTextViewIsGone() - .subscribe { - binding?.pledgeSectionTotal?.totalAmountConversion?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.conversionText() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { setConversionTextView(it) } - .addToDisposable(disposables) - - this.viewModel.outputs.paymentContainerIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionPayment?.paymentContainer?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.showSelectedCard() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { updatePledgeCardState(it) } - .addToDisposable(disposables) - - this.viewModel.outputs.pledgeAmountHeader() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderSummaryAmount?.text = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.cardsAndProject() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { (binding?.pledgeSectionPayment?.cardsRecycler?.adapter as? RewardCardAdapter)?.takeCards(it.first, it.second) } - .addToDisposable(disposables) - - this.viewModel.outputs.addedCard() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - val position = (binding?.pledgeSectionPayment?.cardsRecycler?.adapter as? RewardCardAdapter)?.insertCard(it) - position?.let { position -> this.viewModel.inputs.addedCardPosition(position) } - } - .addToDisposable(disposables) - - this.viewModel.outputs.startLoginToutActivity() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { startActivity(Intent(this.context, LoginToutActivity::class.java)) } - .addToDisposable(disposables) - - this.viewModel.outputs.selectedShippingRule() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionShipping?.shippingRulesStatic ?.text = it.toString() - } - .addToDisposable(disposables) - - this.viewModel.outputs.shippingAmount() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionShipping?. shippingAmountStatic?.let { shippingAmountStatic -> - setPlusTextView( - shippingAmountStatic, it - ) - } - } - .addToDisposable(disposables) - - this.viewModel.outputs.shippingSummaryAmount() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionSummaryShipping?.shippingSummaryAmount?.let { shippingSummaryAmount -> - setPlusTextView(shippingSummaryAmount, it) - } - } - .addToDisposable(disposables) - - this.viewModel.outputs.shippingSummaryLocation() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionSummaryShipping?.shippingLabel?.text = String.format("%s: %s", getString(R.string.Shipping), it) - } - .addToDisposable(disposables) - - this.viewModel.outputs.shippingRulesAndProject() - .observeOn(AndroidSchedulers.mainThread()) - .filter { context.isNotNull() } - .subscribe { - displayShippingRules(it.first, it.second) - } - .addToDisposable(disposables) - - this.viewModel.outputs.shippingRuleStaticIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionShipping?.staticShippingCl?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.shippingSummaryIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionSummaryShipping?.shippingSummary?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.pledgeSummaryAmount() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { binding?.pledgeSectionSummaryPledge?.pledgeSummaryAmount?.text = it } - .addToDisposable(disposables) - - this.viewModel.outputs.bonusSummaryIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionSummaryBonus?.bonusSummary?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.bonusSummaryAmount() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { binding?.pledgeSectionSummaryBonus?.bonusSummaryAmount?.text = it } - .addToDisposable(disposables) - - this.viewModel.outputs.pledgeSummaryIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionSummaryPledge?.pledgeSummary?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.totalDividerIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.dividerTotal?.root?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.totalAmount() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionTotal?.totalAmountLoadingView?.isGone = true - binding?.pledgeSectionTotal?.totalAmount ?.text = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.totalAndDeadline() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { setDeadlineWarning(it) } - .addToDisposable(disposables) - - this.viewModel.outputs.totalAndDeadlineIsVisible() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.deadlineWarning?.isInvisible = false - } - .addToDisposable(disposables) - - this.viewModel.outputs.showPledgeSuccess() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { (activity as PledgeDelegate?)?.pledgeSuccessfullyCreated(it) } - .addToDisposable(disposables) - - this.viewModel.outputs.showSCAFlow() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - stripeNextAction(it) - } - .addToDisposable(disposables) - - this.viewModel.outputs.showPledgeError() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - activity?.applicationContext?.let { - binding?.pledgeContent?.let { pledgeContent -> - showErrorToast(it, pledgeContent, getString(R.string.general_error_something_wrong)) - } - } - } - .addToDisposable(disposables) - - this.viewModel.outputs.startChromeTab() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - activity?.let { activity -> - ChromeTabsHelperActivity.openCustomTab(activity, UrlUtils.baseCustomTabsIntent(activity), Uri.parse(it), null) - } - } - .addToDisposable(disposables) - - this.viewModel.outputs.baseUrlForTerms() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { setHtmlStrings(it) } - .addToDisposable(disposables) - - this.viewModel.outputs.showUpdatePledgeError() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - activity?.applicationContext?.let { - binding?.pledgeContent?.let { pledgeContent -> - showErrorToast( - it, - pledgeContent, - getString(R.string.general_error_something_wrong) - ) - } - } - } - .addToDisposable(disposables) - - this.viewModel.outputs.showUpdatePledgeSuccess() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { (activity as PledgeDelegate?)?.pledgeSuccessfullyUpdated() } - .addToDisposable(disposables) - - this.viewModel.outputs.showUpdatePaymentError() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - activity?.applicationContext?.let { - binding?.pledgeContent?.let { pledgeContent -> - showErrorToast(it, pledgeContent, getString(R.string.general_error_something_wrong)) - } - } - } - .addToDisposable(disposables) - - this.viewModel.outputs.showUpdatePaymentSuccess() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { (activity as PledgeDelegate?)?.pledgePaymentSuccessfullyUpdated() } - .addToDisposable(disposables) - - this.viewModel.outputs.pledgeButtonCTA() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { binding?.pledgeSectionFooter?.pledgeFooterPledgeButton?.setText(it) } - .addToDisposable(disposables) - - this.viewModel.outputs.pledgeButtonIsEnabled() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { binding?.pledgeSectionFooter?.pledgeFooterPledgeButton?.isEnabled = it } - .addToDisposable(disposables) - - this.viewModel.outputs.pledgeButtonIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionFooter?.pledgeFooterPledgeButton?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.pledgeProgressIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionFooter?.pledgeFooterPledgeButtonProgress?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.continueButtonIsEnabled() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { binding?.pledgeSectionFooter?.pledgeFooterContinueButton?.isEnabled = it } - .addToDisposable(disposables) - - this.viewModel.outputs.headerSelectedItems() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - populateHeaderItems(it) - } - .addToDisposable(disposables) - - this.viewModel.outputs.isNoReward() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderContainer?.isGone = it - binding?.pledgeSectionRewardSummary?.pledgeHeaderContainerNoReward ?.visibility = View.VISIBLE - } - .addToDisposable(disposables) - - this.viewModel.outputs.projectTitle() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeSectionRewardSummary?.pledgeHeaderTitleNoReward ?.text = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.localPickUpIsGone() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - this.binding?.pledgeSectionPickupLocation?.localPickupContainer?.isGone = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.localPickUpName() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - this.binding?.pledgeSectionPickupLocation?.localPickupLocationName?.text = it - } - .addToDisposable(disposables) - - this.viewModel.outputs.presentPaymentSheet() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { clientSecretAndUserEmail: Pair -> - setupClientId = clientSecretAndUserEmail.first - flowControllerPresentPaymentOption(clientSecretAndUserEmail.first, clientSecretAndUserEmail.second) - } - .addToDisposable(disposables) - - this.viewModel.outputs.showError() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - binding?.pledgeContent?.let { pledgeContent -> - context?.let { - showErrorToast(it, pledgeContent, getString(R.string.general_error_something_wrong)) - } - } - } - .addToDisposable(disposables) - - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderContainer?.setOnClickListener { - toggleAnimation(isExpanded) - } - - binding?.pledgeSectionFooter?.pledgeFooterPledgeButton?.setOnClickListener { - this.viewModel.inputs.pledgeButtonClicked() - } - - binding?.pledgeSectionFooter?.pledgeFooterContinueButton?.setOnClickListener { - this.viewModel.inputs.continueButtonClicked() - } - - this.viewModel.outputs.setState() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - (binding?.pledgeSectionPayment?.cardsRecycler?.adapter as? RewardCardAdapter)?.updateState(it) - } - .addToDisposable(disposables) - } - - private fun stripeNextAction(it: String) { - try { - // - PaymentIntent format - if (it.contains("pi_")) { - stripe.handleNextActionForPayment(this, it) - } else { - // - SetupIntent format - stripe.handleNextActionForSetupIntent(this, it) - } - } catch (exception: Exception) { - FirebaseCrashlytics.getInstance().recordException(exception) - } - } - - // Update the UI with the returned PaymentOption - private fun onPaymentOption(paymentOption: PaymentOption?) { - paymentOption?.let { - val storedCard = StoredCard.Builder( - lastFourDigits = paymentOption.label.takeLast(4), - resourceId = paymentOption.drawableResourceId, - clientSetupId = setupClientId - ).build() - this.viewModel.inputs.cardSaved(storedCard) - Timber.d(" ${this.javaClass.canonicalName} onPaymentOption with ${storedCard.lastFourDigits()} and ${storedCard.clientSetupId()}") - flowController.confirm() - } - } - - private fun flowControllerPresentPaymentOption(clientSecret: String, userEmail: String) { - context?.let { - flowController.configureWithSetupIntent( - setupIntentClientSecret = clientSecret, - configuration = it.getPaymentSheetConfiguration(userEmail), - callback = ::onConfigured - ) - } - } - - private fun onConfigured(success: Boolean, error: Throwable?) { - if (success) { - flowController.presentPaymentOptions() - } else { - binding?.pledgeContent?.let { pledgeContent -> - context?.let { - showErrorToast(it, pledgeContent, getString(R.string.general_error_something_wrong)) - } - } - } - this.viewModel.inputs.paymentSheetPresented(success) - } - - fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { - this.viewModel.inputs.paymentSheetResult(paymentSheetResult) - when (paymentSheetResult) { - is PaymentSheetResult.Canceled -> { - binding?.pledgeContent?.let { pledgeContent -> - context?.let { - showErrorToast(it, pledgeContent, getString(R.string.general_error_oops)) - } - } - } - is PaymentSheetResult.Failed -> { - binding?.pledgeContent?.let { pledgeContent -> - context?.let { - val errorMessage = paymentSheetResult.error.localizedMessage ?: getString(R.string.general_error_something_wrong) - showErrorToast(it, pledgeContent, errorMessage) - } - } - } - is PaymentSheetResult.Completed -> { - } - } - } - - private fun populateHeaderItems(selectedItems: List>) { - headerAdapter.populateData(selectedItems) - } - - private fun toggleAnimation(isExpanded: Boolean) { - if (isExpanded) - collapseAnimation() - else - expandAnimation() - - this.isExpanded = !isExpanded - } - - private fun expandAnimation() { - binding?.pledgeSectionHeaderRewardSummary?.headerArrowButton?.animate()?.rotation(180f)?.start() - - val constraintSet = ConstraintSet() - constraintSet.clone(binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderContainer) - constraintSet.clear(R.id.header_summary_list, ConstraintSet.BOTTOM) - - val transition = ChangeBounds() - transition.duration = 100 - - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderContainer?.let { - TransitionManager.beginDelayedTransition(it, transition) - constraintSet.applyTo(it) - } - } - - private fun collapseAnimation() { - binding?.pledgeSectionHeaderRewardSummary?.headerArrowButton?.animate()?.rotation(0f)?.start() - - val constraintSet = ConstraintSet() - constraintSet.clone(binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderContainer) - constraintSet.connect(R.id.header_summary_list, ConstraintSet.BOTTOM, R.id.header_animation_guideline, ConstraintSet.BOTTOM) - - val transition = ChangeBounds() - transition.duration = 100 - - binding?.pledgeSectionHeaderRewardSummary?.pledgeHeaderContainer?.let { - TransitionManager.beginDelayedTransition(it, transition) - constraintSet.applyTo(it) - } - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - stripe.onSetupResult( - requestCode, data, - object : ApiResultCallback { - override fun onSuccess(result: SetupIntentResult) { - this@PledgeFragment.viewModel.inputs.stripeSetupResultSuccessful(result.outcome) - } - - override fun onError(e: Exception) { - this@PledgeFragment.viewModel.inputs.stripeSetupResultUnsuccessful(e) - } - } - ) - } - - override fun onDestroyView() { - disposables.clear() - binding?.pledgeSectionPayment?.cardsRecycler?.adapter = null - binding?.pledgeSectionHeaderRewardSummary?.headerSummaryList?.adapter = null - super.onDestroyView() - } - - override fun addNewCardButtonClicked() { - this.viewModel.inputs.newCardButtonClicked() - } - - fun cardAdded(storedCard: StoredCard) { - this.viewModel.inputs.cardSaved(storedCard) - } - - override fun cardSelected(storedCard: StoredCard, position: Int) { - this.viewModel.inputs.cardSelected(storedCard, position) - } - - override fun ruleSelected(rule: ShippingRule) { - this.viewModel.inputs.shippingRuleSelected(rule) - activity?.hideKeyboard() - - if (binding?.pledgeSectionFooter?.pledgeFooterPledgeButton?.isEnabled == false) { - binding?.pledgeSectionFooter?.pledgeFooterPledgeButton?.isEnabled = true - } - } - - private fun displayShippingRules(shippingRules: List, project: Project) { - adapter.populateShippingRules(shippingRules, project) - } - - private fun relativeTop(view: View, parent: ViewGroup): Int { - val offsetViewBounds = Rect() - view.getDrawingRect(offsetViewBounds) - parent.offsetDescendantRectToMyCoords(view, offsetViewBounds) - - return offsetViewBounds.top - parent.paddingTop - } - - private fun setDeadlineWarning(totalAndDeadline: Pair) { - val total = totalAndDeadline.first - val deadline = totalAndDeadline.second - val warning = ksString.format( - getString(R.string.If_the_project_reaches_its_funding_goal_you_will_be_charged_total_on_project_deadline_and_receive_proof_of_pledge), - "total", total, - "project_deadline", deadline - ) - - val spannableWarning = SpannableString(warning) - - ViewUtils.addBoldSpan(spannableWarning, total) - ViewUtils.addBoldSpan(spannableWarning, deadline) - - binding?.deadlineWarning?.text = spannableWarning - } - - private fun setPlusTextView(textView: TextView, localizedAmount: CharSequence) { - textView.contentDescription = ksString.format(getString(R.string.plus_shipping_cost), "shipping_cost", localizedAmount.toString()) - textView.text = localizedAmount - } - - private fun setTextColor(colorResId: Int, vararg textViews: TextView) { - context?.let { - val color = ContextCompat.getColor(it, colorResId) - for (textView in textViews) { - textView.setTextColor(color) - } - } - } - - private fun setUpCardsAdapter() { - binding?.pledgeSectionPayment?.cardsRecycler?.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) - binding?.pledgeSectionPayment?.cardsRecycler?.adapter = RewardCardAdapter(this) - binding?.pledgeSectionPayment?.cardsRecycler?.addItemDecoration(RewardCardItemDecoration(resources.getDimensionPixelSize(R.dimen.grid_1))) - } - - private fun setUpShippingAdapter() { - context?.let { - adapter = ShippingRulesAdapter(it, R.layout.item_shipping_rule, arrayListOf(), this) - } - } - - private fun setupRewardRecyclerView() { - binding?.pledgeSectionHeaderRewardSummary?.headerSummaryList?.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) - binding?.pledgeSectionHeaderRewardSummary?.headerSummaryList?.adapter = headerAdapter - } - - private fun setClickableHtml(string: String, textView: TextView) { - val spannableBuilder = SpannableStringBuilder(ViewUtils.html(string)) - // https://stackoverflow.com/a/19989677 - val urlSpans = spannableBuilder.getSpans(0, string.length, URLSpan::class.java) - for (urlSpan in urlSpans) { - val clickableSpan = object : ClickableSpan() { - override fun onClick(widget: View) { - this@PledgeFragment.viewModel.inputs.linkClicked(urlSpan.url) - } - - override fun updateDrawState(ds: TextPaint) { - ds.color = ContextCompat.getColor(textView.context, R.color.accent) - } - } - val spanStart = spannableBuilder.getSpanStart(urlSpan) - val spanEnd = spannableBuilder.getSpanEnd(urlSpan) - val spanFlags = spannableBuilder.getSpanFlags(urlSpan) - spannableBuilder.setSpan(clickableSpan, spanStart, spanEnd, spanFlags) - spannableBuilder.removeSpan(urlSpan) - } - - textView.text = spannableBuilder - textView.movementMethod = LinkMovementMethod.getInstance() - } - - private fun setConversionTextView(amount: String) { - val currencyConversionString = context?.getString(R.string.About_reward_amount) - binding?.pledgeSectionTotal?.totalAmountConversion ?.text = ( - currencyConversionString?.let { - ksString.format(it, "reward_amount", amount) - } - ) - } - - @SuppressLint("SetTextI18n") - private fun setHtmlStrings(baseUrl: String) { - val termsOfUseUrl = UrlUtils.appendPath(baseUrl, HelpActivity.TERMS_OF_USE) - val cookiePolicyUrl = UrlUtils.appendPath(baseUrl, HelpActivity.COOKIES) - val privacyPolicyUrl = UrlUtils.appendPath(baseUrl, HelpActivity.PRIVACY) - - val ksString = requireNotNull((activity?.applicationContext as? KSApplication)?.component()?.environment()?.ksString()) - val byPledgingYouAgree = getString(R.string.By_pledging_you_agree_to_Kickstarters_Terms_of_Use_Privacy_Policy_and_Cookie_Policy) - - val agreementWithUrls = ksString.format( - byPledgingYouAgree, "terms_of_use_link", termsOfUseUrl, - "privacy_policy_link", privacyPolicyUrl, "cookie_policy_link", cookiePolicyUrl - ) - - binding?.pledgeSectionFooter?.pledgeFooterPledgeAgreement?.let { - setClickableHtml( - agreementWithUrls, - it - ) - } - - val trustUrl = UrlUtils.appendPath(baseUrl, "trust") - val accountabilityWithUrl = ksString.format( - getString(R.string.Its_a_way_to_bring_creative_projects_to_life_Learn_more_about_accountability), - "trust_link", - trustUrl - ) - - binding?.pledgeSectionAccountability?. accountability?.let { - setClickableHtml( - accountabilityWithUrl, - it - ) - } - binding?.pledgeSectionAccountability?. accountabilityContainer?.setOnClickListener { - this.viewModel.inputs.linkClicked(trustUrl) - } - } - - private fun updatePledgeCardState(positionAndCardState: Pair) { - val position = positionAndCardState.first - val cardState = positionAndCardState.second - val rewardCardAdapter = binding?.pledgeSectionPayment?.cardsRecycler?.adapter as? RewardCardAdapter - - if (cardState == CardState.SELECTED) { - rewardCardAdapter?.setSelectedPosition(position) - } else { - rewardCardAdapter?.resetSelectedPosition() - } - } -} diff --git a/app/src/main/java/com/kickstarter/viewmodels/PledgeFragmentViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/PledgeFragmentViewModel.kt deleted file mode 100644 index c284de18e9..0000000000 --- a/app/src/main/java/com/kickstarter/viewmodels/PledgeFragmentViewModel.kt +++ /dev/null @@ -1,2085 +0,0 @@ -package com.kickstarter.viewmodels - -import android.os.Bundle -import android.text.SpannableString -import android.util.Pair -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.kickstarter.R -import com.kickstarter.libs.Config -import com.kickstarter.libs.Environment -import com.kickstarter.libs.RefTag -import com.kickstarter.libs.models.Country -import com.kickstarter.libs.rx.transformers.Transformers.combineLatestPair -import com.kickstarter.libs.rx.transformers.Transformers.errorsV2 -import com.kickstarter.libs.rx.transformers.Transformers.ignoreValuesV2 -import com.kickstarter.libs.rx.transformers.Transformers.neverErrorV2 -import com.kickstarter.libs.rx.transformers.Transformers.takeWhenV2 -import com.kickstarter.libs.rx.transformers.Transformers.valuesV2 -import com.kickstarter.libs.rx.transformers.Transformers.zipPairV2 -import com.kickstarter.libs.utils.DateTimeUtils -import com.kickstarter.libs.utils.NumberUtils -import com.kickstarter.libs.utils.ProjectViewUtils -import com.kickstarter.libs.utils.RefTagUtils -import com.kickstarter.libs.utils.RewardUtils -import com.kickstarter.libs.utils.ThirdPartyEventValues -import com.kickstarter.libs.utils.extensions.acceptedCardType -import com.kickstarter.libs.utils.extensions.addToDisposable -import com.kickstarter.libs.utils.extensions.isFalse -import com.kickstarter.libs.utils.extensions.isNotNull -import com.kickstarter.libs.utils.extensions.isNull -import com.kickstarter.libs.utils.extensions.isTrue -import com.kickstarter.libs.utils.extensions.negate -import com.kickstarter.libs.utils.extensions.parseToDouble -import com.kickstarter.mock.factories.ShippingRuleFactory -import com.kickstarter.models.Backing -import com.kickstarter.models.Checkout -import com.kickstarter.models.Project -import com.kickstarter.models.Reward -import com.kickstarter.models.ShippingRule -import com.kickstarter.models.StoredCard -import com.kickstarter.models.extensions.getBackingData -import com.kickstarter.models.extensions.isFromPaymentSheet -import com.kickstarter.services.mutations.CreateBackingData -import com.kickstarter.services.mutations.UpdateBackingData -import com.kickstarter.type.CreditCardPaymentType -import com.kickstarter.ui.ArgumentsKey -import com.kickstarter.ui.data.CardState -import com.kickstarter.ui.data.CheckoutData -import com.kickstarter.ui.data.PledgeData -import com.kickstarter.ui.data.PledgeFlowContext -import com.kickstarter.ui.data.PledgeReason -import com.kickstarter.ui.data.ProjectData -import com.kickstarter.ui.viewholders.State -import com.kickstarter.viewmodels.usecases.SendThirdPartyEventUseCaseV2 -import com.stripe.android.StripeIntentResult -import com.stripe.android.paymentsheet.PaymentSheetResult -import io.reactivex.Notification -import io.reactivex.Observable -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.subjects.BehaviorSubject -import io.reactivex.subjects.PublishSubject -import java.math.RoundingMode -import java.text.NumberFormat -import kotlin.math.max - -interface PledgeFragmentViewModel { - interface Inputs { - /** Call when a card has been inserted into the stored cards list. */ - fun addedCardPosition(position: Int) - - /** Call when a card has successfully saved. */ - fun cardSaved(storedCard: StoredCard) - - /** Call when user selects a card they want to pledge with. */ - fun cardSelected(storedCard: StoredCard, position: Int) - - /** Call when logged out user clicks the continue button. */ - fun continueButtonClicked() - - /** Call when user clicks the decrease pledge button. */ - fun decreasePledgeButtonClicked() - - /** Call when user clicks the increase pledge button. */ - fun increasePledgeButtonClicked() - - /** Call when user clicks the decrease bonus button. */ - fun decreaseBonusButtonClicked() - - /** Call when user clicks the increase bonus button. */ - fun increaseBonusButtonClicked() - - /** Call when user clicks a url. */ - fun linkClicked(url: String) - - /** Call when user clicks the mini reward. */ - fun miniRewardClicked() - - /** Call when the new card button is clicked. */ - fun newCardButtonClicked() - - /** Call when the user updates the pledge amount. */ - fun pledgeInput(amount: String) - - /** Call when user clicks the pledge button. */ - fun pledgeButtonClicked() - - /** Call when user selects a shipping location. */ - fun shippingRuleSelected(shippingRule: ShippingRule) - - /** Call when Stripe SCA is successful. */ - fun stripeSetupResultSuccessful(outcome: Int) - - /** Call when Stripe SCA is unsuccessful. */ - fun stripeSetupResultUnsuccessful(exception: Exception) - - fun onRiskMessageDismissed() - - fun paymentSheetResult(paymentSheetResult: PaymentSheetResult) - - fun paymentSheetPresented(isSuccesfullyPresented: Boolean) - } - - interface Outputs { - /** Emits a newly added stored card and the project. */ - fun addedCard(): Observable> - - /** Emits the additional pledge amount string. */ - fun additionalPledgeAmount(): Observable - - /** Emits when the additional pledge amount should be hidden. */ - fun additionalPledgeAmountIsGone(): Observable - - /** Emits the base URL to build terms URLs. */ - fun baseUrlForTerms(): Observable - - /** Emits a list of stored cards for a user. */ - fun cardsAndProject(): Observable, Project>> - - /** Emits a boolean determining if the continue button should be enabled. */ - fun continueButtonIsEnabled(): Observable - - /** Emits a boolean determining if the continue button should be hidden. */ - fun continueButtonIsGone(): Observable - - /** Emits a string representing the total pledge amount in the user's preferred currency. */ - fun conversionText(): Observable - - /** Returns `true` if the conversion should be hidden, `false` otherwise. */ - fun conversionTextViewIsGone(): Observable - - /** Emits a boolean determining if the decrease pledge button should be enabled. */ - fun decreasePledgeButtonIsEnabled(): Observable - - /** Emits the estimated delivery date string of the reward. */ - fun estimatedDelivery(): Observable - - /** Emits a boolean determining if the estimated delivery info should be hidden. */ - fun estimatedDeliveryInfoIsGone(): Observable - - /** Emits a boolean determining if the increase pledge button should be enabled.*/ - fun increasePledgeButtonIsEnabled(): Observable - - /** Emits a boolean determining if the payment container should be hidden. */ - fun paymentContainerIsGone(): Observable - - /** Emits the pledge amount string of the reward or backing. */ - fun pledgeAmount(): Observable - - /** Emits the string resource ID of the pledge button. */ - fun pledgeButtonCTA(): Observable - - /** Emits a boolean determining if the pledge button should be enabled. */ - fun pledgeButtonIsEnabled(): Observable - - /** Emits a boolean determining if the pledge button should be hidden. */ - fun pledgeButtonIsGone(): Observable - - /** Emits a boolean determining if the pledge progress bar should be hidden. */ - fun pledgeProgressIsGone(): Observable - - /** Emits the hint text for the pledge amount. */ - fun pledgeHint(): Observable - - /** Emits the maximum pledge amount in the project's currency. */ - fun pledgeMaximum(): Observable - - /** Emits a boolean determining if the pledge maximum should be hidden. */ - fun pledgeMaximumIsGone(): Observable - - /** Emits the minimum pledge amount in the project's currency. */ - fun pledgeMinimum(): Observable - - /** Emits a boolean determining if the pledge section should be hidden. */ - fun pledgeSectionIsGone(): Observable - - /** Emits the pledge amount string of the backing. */ - fun pledgeSummaryAmount(): Observable - - /** Emits a boolean determining if the pledge summary section should be hidden. */ - fun pledgeSummaryIsGone(): Observable - - /** Emits the color resource ID of the pledge amount. */ - fun pledgeTextColor(): Observable - - /** Emits the currency symbol string of the project. */ - fun projectCurrencySymbol(): Observable> - - /** Emits a boolean determining if the delivery section should be hidden. */ - fun rewardSummaryIsGone(): Observable - - /** Emits the title of the current reward. */ - fun rewardTitle(): Observable - - /** Emits the currently selected shipping rule. */ - fun selectedShippingRule(): Observable - - /** Emits the shipping amount of the selected shipping rule. */ - fun shippingAmount(): Observable - - /** Emits the shipping rule. */ - fun shippingRule(): Observable - - /** Emits a pair of list of shipping rules to be selected and the project. */ - fun shippingRulesAndProject(): Observable, Project>> - - /** Emits when the shipping rules section should be hidden. */ - fun shippingRulesSectionIsGone(): Observable - - /** Emits the shipping amount of the selected shipping rule. */ - fun shippingSummaryAmount(): Observable - - /** Emits a boolean determining if the shipping summary should be hidden. */ - fun shippingSummaryIsGone(): Observable - - /** Emits the displayable name of the backing's location. */ - fun shippingSummaryLocation(): Observable - - /** Emits when the pledge call was unsuccessful. */ - fun showPledgeError(): Observable - - /** Emits when the creating backing mutation was successful. */ - fun showPledgeSuccess(): Observable> - - /** Emits when the cards adapter should update the selected position. */ - fun showSelectedCard(): Observable> - - /** Emits when we should show the SCA flow with the client secret. */ - fun showSCAFlow(): Observable - - /** Emits when the update payment source mutation was unsuccessful. */ - fun showUpdatePaymentError(): Observable - - /** Emits when the update payment source mutation was successful. */ - fun showUpdatePaymentSuccess(): Observable - - /** Emits when the update pledge call was unsuccessful. */ - fun showUpdatePledgeError(): Observable - - /** Emits when the update pledge call was successful. */ - fun showUpdatePledgeSuccess(): Observable - - /** Emits when we should start a Chrome tab. */ - fun startChromeTab(): Observable - - /** Emits when we should start the [com.kickstarter.ui.activities.LoginToutActivity]. */ - fun startLoginToutActivity(): Observable - - /** Emits the total amount string of the pledge. */ - fun totalAmount(): Observable - - /** Emits the total pledge amount in the project's currency and the project's deadline. */ - fun totalAndDeadline(): Observable> - - /** Emits when the total and deadline warning should be shown. */ - fun totalAndDeadlineIsVisible(): Observable - - /** Emits a boolean determining if the divider above the total should be hidden. */ - fun totalDividerIsGone(): Observable - - /** Emits a boolean determining if the header whould be hidden */ - fun headerSectionIsGone(): Observable - - /** Emits a Pair containing reward/add-on title and the amount */ - fun headerSelectedItems(): Observable>> - - /** Emits a boolean determining if the minimum pledge amount subtitle should be shown */ - fun isPledgeMinimumSubtitleGone(): Observable - - /** Emits a boolean determining if the bonus support section is visible */ - fun isBonusSupportSectionGone(): Observable - - /** Emits a boolean determining if the decrease bonus button should be enabled. */ - fun decreaseBonusButtonIsEnabled(): Observable - - /** Emits a boolean determining if the increase bonus button should be enabled.*/ - fun increaseBonusButtonIsEnabled(): Observable - - /** Emits the bonus amount string of the reward or backing. */ - fun bonusAmount(): Observable - - /** Emits the hint text for the bonus amount. */ - fun bonusHint(): Observable - - /** Emits if a reward is a No Reward. */ - fun isNoReward(): Observable - - /** Emits the title of the project for `No Reward` use case */ - fun projectTitle(): Observable - - /** Emits the selected reward + addOns list*/ - fun rewardAndAddOns(): Observable> - - /** Emits if the static shipping selection area should be gone */ - fun shippingRuleStaticIsGone(): Observable - - /** Emits if the bonus summary section area should be gone */ - fun bonusSummaryIsGone(): Observable - - /** Emits the bonus summary amount */ - fun bonusSummaryAmount(): Observable - - /** Emits the total pledgeAmount for Rewards + AddOns **/ - fun pledgeAmountHeader(): Observable - - /** Emits a boolean that determines if the local PickUp section should be hidden **/ - fun localPickUpIsGone(): Observable - - /** Emits the String with the Local Pickup Displayable name **/ - fun localPickUpName(): Observable - - /** Emits the String with the SetupIntent ClientID to present the PaymentSheet **/ - fun presentPaymentSheet(): Observable> - - fun showError(): Observable - - /** Emits the state LOADONG | DEFAULT when createSetupIntent mutation is called **/ - fun setState(): Observable - - /** Emits with the third party analytic event mutation response **/ - fun eventSent(): Observable - } - - class PledgeFragmentViewModel( - private val environment: Environment, - private val bundle: Bundle? = null - ) : ViewModel(), Inputs, Outputs { - - private val addedCardPosition = BehaviorSubject.create() - private val cardSaved = BehaviorSubject.create() - private val cardSelected = BehaviorSubject.create>() - private val continueButtonClicked = BehaviorSubject.create() - private val decreasePledgeButtonClicked = BehaviorSubject.create() - private val increasePledgeButtonClicked = BehaviorSubject.create() - private val linkClicked = BehaviorSubject.create() - private val miniRewardClicked = BehaviorSubject.create() - private val newCardButtonClicked = BehaviorSubject.create() - private val pledgeButtonClicked = BehaviorSubject.create() - private val pledgeInput = BehaviorSubject.create() - private val shippingRule = BehaviorSubject.create() - private val stripeSetupResultSuccessful = BehaviorSubject.create() - private val stripeSetupResultUnsuccessful = BehaviorSubject.create() - private val decreaseBonusButtonClicked = BehaviorSubject.create() - private val increaseBonusButtonClicked = BehaviorSubject.create() - private val onRiskMessageDismissed = BehaviorSubject.create() - - private val addedCard = BehaviorSubject.create>() - private val additionalPledgeAmount = BehaviorSubject.create() - private val additionalPledgeAmountIsGone = BehaviorSubject.create() - private val baseUrlForTerms = BehaviorSubject.create() - private val cardsAndProject = BehaviorSubject.create, Project>>() - private val continueButtonIsEnabled = BehaviorSubject.create() - private val continueButtonIsGone = BehaviorSubject.create() - private val conversionText = BehaviorSubject.create() - private val conversionTextViewIsGone = BehaviorSubject.create() - private val decreasePledgeButtonIsEnabled = BehaviorSubject.create() - private val rewardSummaryIsGone = BehaviorSubject.create() - private val estimatedDelivery = BehaviorSubject.create() - private val estimatedDeliveryInfoIsGone = BehaviorSubject.create() - private val increasePledgeButtonIsEnabled = BehaviorSubject.create() - private val paymentContainerIsGone = BehaviorSubject.create() - private val pledgeAmount = BehaviorSubject.create() - private val pledgeButtonCTA = BehaviorSubject.create() - private val pledgeButtonIsGone = BehaviorSubject.create() - private val pledgeButtonIsEnabled = BehaviorSubject.create() - private val pledgeHint = BehaviorSubject.create() - private val pledgeMaximum = BehaviorSubject.create() - private val pledgeMaximumIsGone = BehaviorSubject.create() - private val pledgeMinimum = BehaviorSubject.create() - private val pledgeProgressIsGone = BehaviorSubject.create() - private val pledgeSectionIsGone = BehaviorSubject.create() - private val pledgeSummaryAmount = BehaviorSubject.create() - private val pledgeSummaryIsGone = BehaviorSubject.create() - private val pledgeTextColor = BehaviorSubject.create() - private val projectCurrencySymbol = BehaviorSubject.create>() - private val rewardTitle = BehaviorSubject.create() - private val shippingAmount = BehaviorSubject.create() - private val shippingRulesAndProject = BehaviorSubject.create, Project>>() - private val shippingRulesSectionIsGone = BehaviorSubject.create() - - // - when having add-ons the shipping location is an static field, no changes allowed in there - private val shippingRuleStaticIsGone = BehaviorSubject.create() - private val shippingSummaryAmount = BehaviorSubject.create() - private val shippingSummaryIsGone = BehaviorSubject.create() - private val shippingSummaryLocation = BehaviorSubject.create() - private val showPledgeError = PublishSubject.create() - private val showPledgeSuccess = PublishSubject.create>() - private val showSelectedCard = BehaviorSubject.create>() - private val showSCAFlow = PublishSubject.create() - private val showUpdatePaymentError = PublishSubject.create() - private val showUpdatePaymentSuccess = PublishSubject.create() - private val showUpdatePledgeError = PublishSubject.create() - private val showUpdatePledgeSuccess = PublishSubject.create() - private val startChromeTab = PublishSubject.create() - private val startLoginToutActivity = PublishSubject.create() - private val totalAmount = BehaviorSubject.create() - private val totalAndDeadline = BehaviorSubject.create>() - private val totalAndDeadlineIsVisible = BehaviorSubject.create() - private val totalDividerIsGone = BehaviorSubject.create() - - private val headerSectionIsGone = BehaviorSubject.create() - private val headerSelectedItems = BehaviorSubject.create>>() - private val isPledgeMinimumSubtitleGone = BehaviorSubject.create() - private val isBonusSupportSectionGone = BehaviorSubject.create() - private val bonusAmount = BehaviorSubject.create() - private val decreaseBonusButtonIsEnabled = BehaviorSubject.create() - private val increaseBonusButtonIsEnabled = BehaviorSubject.create() - private val bonusHint = BehaviorSubject.create() - - // - Keep track if the bonus stepper increase/decrease has being pressed at some point - private val bonusAmountHasChanged = BehaviorSubject.createDefault(false) - private val isNoReward = BehaviorSubject.create() - private val projectTitle = BehaviorSubject.create() - - private val apolloClient = requireNotNull(environment.apolloClientV2()) - private val ffClient = requireNotNull(environment.featureFlagClient()) - private val cookieManager = requireNotNull(environment.cookieManager()) - private val currentConfig = requireNotNull(environment.currentConfigV2()) - private val currentUser = requireNotNull(environment.currentUserV2()) - private val ksCurrency = requireNotNull(environment.ksCurrency()) - private val sharedPreferences = requireNotNull(environment.sharedPreferences()) - private val analyticEvents = requireNotNull(environment.analytics()) - private val minPledgeByCountry = BehaviorSubject.create() - private val shippingRuleUpdated = BehaviorSubject.createDefault(false) - private val selectedReward = BehaviorSubject.create() - private val rewardAndAddOns = BehaviorSubject.create>() - private val shippingAmountSelectedRw = BehaviorSubject.createDefault(0.0) - - private val bonusSummaryIsGone = BehaviorSubject.create() - private val bonusSummaryAmount = BehaviorSubject.create() - - private val thirdpartyEventIsSuccessful = BehaviorSubject.create() - - // - Flag to know if the shipping location should be the default one, - // - meaning we don't have shipping location selected yet - // - Use case: (Reward shippable without addOns in new pledge or updating pledge with restricted location) - private val shouldLoadDefaultLocation = BehaviorSubject.create() - private val pledgeAmountHeader = BehaviorSubject.create() - private val stepperAmount = 1 - - private val localPickUpIsGone = BehaviorSubject.create() - private val localPickUpName = BehaviorSubject.create() - - private val presentPaymentSheet = PublishSubject.create>() - private val paymentSheetResult = PublishSubject.create() - private val paySheetPresented = PublishSubject.create() - private val showError = PublishSubject.create() - - private val loadingState = BehaviorSubject.create() - - private val disposables = CompositeDisposable() - - val inputs: Inputs = this - val outputs: Outputs = this - - private fun arguments() = bundle?.let { Observable.just(it) } ?: Observable.empty() - init { - val userIsLoggedIn = this.currentUser.isLoggedIn - .distinctUntilChanged() - - val pledgeData = arguments() - .map { it.getParcelable(ArgumentsKey.PLEDGE_PLEDGE_DATA) as PledgeData? } - .ofType(PledgeData::class.java) - - pledgeData - .map { it.reward() } - .subscribe { this.selectedReward.onNext(it) } - .addToDisposable(disposables) - - val projectData = pledgeData - .map { it.projectData() } - - val project = projectData - .map { it.project() } - - pledgeData - .map { - it.bonusAmount() - } - .subscribe { - this.bonusAmount.onNext(it.toString()) - }.addToDisposable(disposables) - - pledgeData - .filter { it.shippingRule().isNotNull() && it.shippingRule()?.location().isNotNull() } - .map { - requireNotNull(it.shippingRule()) - } - .subscribe { - this.shippingRule.onNext(it) - }.addToDisposable(disposables) - - // Shipping rules section - val shippingRules = BehaviorSubject.create>() - this.selectedReward - .distinctUntilChanged() - .filter { RewardUtils.isShippable(it) } - .switchMap { - this.apolloClient.getShippingRules(it).compose(neverErrorV2()) - } - .map { it.shippingRules() } - .subscribe { - shippingRules.onNext(it) - } - .addToDisposable(disposables) - - val pledgeReason = arguments() - .map { it.getSerializable(ArgumentsKey.PLEDGE_PLEDGE_REASON) as PledgeReason } - .distinctUntilChanged() - - val updatingPayment = pledgeReason - .map { it == PledgeReason.UPDATE_PAYMENT || it == PledgeReason.FIX_PLEDGE } - .distinctUntilChanged() - - val updatingPaymentOrUpdatingPledge = pledgeReason - .map { it == PledgeReason.UPDATE_PAYMENT || it == PledgeReason.UPDATE_PLEDGE || it == PledgeReason.FIX_PLEDGE } - .distinctUntilChanged() - - val addOns = pledgeData - .map { if (it.addOns().isNullOrEmpty()) emptyList() else it.addOns() as List } - - val backing = projectData - .compose>(combineLatestPair(pledgeReason)) - .filter { it.second != PledgeReason.PLEDGE } - .map { it.first.backing() ?: it.first.project().backing() } - .filter { it.isNotNull() } - .map { requireNotNull(it) } - - backing - .map { it.locationId() == null } - .subscribe { - this.shouldLoadDefaultLocation.onNext(it) - } - .addToDisposable(disposables) - - val backingShippingRule = backing - .compose>(combineLatestPair(pledgeData)) - .filter { - shouldLoadShippingRuleFromBacking(it) - } - .filter { it.first.locationId().isNotNull() } - .map { requireNotNull(it.first.locationId()) } - .compose>>(combineLatestPair(shippingRules)) - .map { shippingInfo -> - selectedShippingRule(shippingInfo) - } - - val backingWhenPledgeReasonUpdate = backing - .compose>(combineLatestPair(pledgeReason)) - .filter { PledgeReason.UPDATE_PAYMENT == it.second || PledgeReason.UPDATE_PLEDGE == it.second } - .map { it.first } - - val backingShippingRuleUpdate = backingWhenPledgeReasonUpdate - .filter { it.reward()?.let { reward -> !RewardUtils.isNoReward(reward) } ?: false } - .compose>(combineLatestPair(pledgeData)) - .filter { it.first.locationId().isNotNull() } - .map { requireNotNull(it.first.locationId()) } - .compose>>(combineLatestPair(shippingRules)) - .map { shippingInfo -> - selectedShippingRule(shippingInfo) - } - - val initShippingRule = pledgeData - .distinctUntilChanged() - .filter { it.shippingRule().isNotNull() } - .map { requireNotNull(it.shippingRule()) } - - pledgeData - .map { it.shippingRule() == null && RewardUtils.isShippable(it.reward()) } - .subscribe { this.shouldLoadDefaultLocation.onNext(it) } - .addToDisposable(disposables) - - val preSelectedShippingRule = Observable.merge(initShippingRule, backingShippingRule, backingShippingRuleUpdate) - .distinctUntilChanged() - - preSelectedShippingRule - .filter { it.isNotNull() } - .map { requireNotNull(it) } - .subscribe { - this.shippingRule.onNext(it) - } - .addToDisposable(disposables) - - backing - .map { if (it.addOns().isNullOrEmpty()) emptyList() else requireNotNull(it.addOns()) } - .compose, Reward>>(combineLatestPair(this.selectedReward)) - .subscribe { - val updatedList = it.first.toMutableList() - updatedList.add(0, it.second) - this.rewardAndAddOns.onNext(updatedList.toList()) - } - .addToDisposable(disposables) - - this.selectedReward - .compose>(combineLatestPair(pledgeReason)) - .filter { it.second == PledgeReason.PLEDGE || it.second == PledgeReason.UPDATE_REWARD } - .map { it.first } - .compose>>(combineLatestPair(addOns)) - .map { - joinRewardAndAddOns(it.first, it.second) - } - .subscribe { this.rewardAndAddOns.onNext(it) } - .addToDisposable(disposables) - - val pledgeAmountHeader = this.rewardAndAddOns - .filter { !RewardUtils.isNoReward(it.first()) } - .map { getPledgeAmount(it, backing.blockingLast(Backing.builder().build()).isPostCampaign()) } - - pledgeAmountHeader - .compose>(combineLatestPair(project)) - .map { ProjectViewUtils.styleCurrency(it.first, it.second, this.ksCurrency) } - .subscribe { this.pledgeAmountHeader.onNext(it) } - .addToDisposable(disposables) - - val projectAndReward = project - .compose>(combineLatestPair(this.selectedReward)) - - val country = project - .map { Country.findByCurrencyCode(it.currency()) } - .filter { it != null } - .distinctUntilChanged() - .ofType(Country::class.java) - - country - .map { it.minPledge.toDouble() } - .compose>(combineLatestPair(this.selectedReward)) - .filter { RewardUtils.isNoReward(it.second) } - .map { it.first } - .distinctUntilChanged() - .subscribe { - minPledgeByCountry.onNext(it) - } - .addToDisposable(disposables) - - projectAndReward - .map { rewardTitle(it.first, it.second) } - .distinctUntilChanged() - .subscribe { this.rewardTitle.onNext(it) } - .addToDisposable(disposables) - - this.selectedReward - .filter { !RewardUtils.isShippable(it) } - .map { - RewardUtils.isLocalPickup(it) - } - .subscribe { - this.localPickUpIsGone.onNext(!it) - } - .addToDisposable(disposables) - - this.selectedReward - .filter { !RewardUtils.isShippable(it) } - .filter { RewardUtils.isLocalPickup(it) } - .map { it.localReceiptLocation()?.displayableName() } - .filter { it.isNotNull() } - .map { requireNotNull(it) } - .subscribe { this.localPickUpName.onNext(it) } - .addToDisposable(disposables) - - this.selectedReward - .filter { it.estimatedDeliveryOn().isNotNull() } - .map { requireNotNull(it.estimatedDeliveryOn()) } - .map { dateTime -> dateTime.let { DateTimeUtils.estimatedDeliveryOn(it) } } - .distinctUntilChanged() - .subscribe { this.estimatedDelivery.onNext(it) } - .addToDisposable(disposables) - - this.selectedReward - .map { it.estimatedDeliveryOn().isNull() || RewardUtils.isNoReward(it) } - .subscribe { this.estimatedDeliveryInfoIsGone.onNext(it) } - .addToDisposable(disposables) - - val minRw = this.selectedReward - .filter { !RewardUtils.isNoReward(it) } - .map { it.minimum() } - .distinctUntilChanged() - - val rewardMinimum = Observable.merge(minRw, minPledgeByCountry) - - rewardMinimum - .map { NumberUtils.format(it.toInt()) } - .subscribe { this.pledgeHint.onNext(it) } - .addToDisposable(disposables) - - Observable.combineLatest(rewardMinimum, project) { amount, project -> - return@combineLatest this.ksCurrency.format(amount, project) - } - .distinctUntilChanged() - .subscribe { this.pledgeMinimum.onNext(it) } - .addToDisposable(disposables) - - this.rewardAndAddOns - .compose, Project>>(combineLatestPair(project)) - .map { joinProject(it) } - .subscribe { this.headerSelectedItems.onNext(it) } - .addToDisposable(disposables) - - project - .map { ProjectViewUtils.currencySymbolAndPosition(it, this.ksCurrency) } - .subscribe { this.projectCurrencySymbol.onNext(it) } - .addToDisposable(disposables) - - project - .map { it.name() } - .subscribe { this.projectTitle.onNext(it) } - .addToDisposable(disposables) - - // Pledge stepper section - val additionalPledgeAmount = BehaviorSubject.createDefault(0.0) - - val additionalAmountOrZero = additionalPledgeAmount - .map { max(0.0, it) } - - val stepAmount = country - .map { it.minPledge } - - additionalAmountOrZero - .compose>(combineLatestPair(project)) - .map { this.ksCurrency.format(it.first, it.second, RoundingMode.HALF_UP) } - .distinctUntilChanged() - .subscribe { this.additionalPledgeAmount.onNext(it) } - .addToDisposable(disposables) - - additionalAmountOrZero - .map { it <= 0.0 } - .distinctUntilChanged() - .subscribe { this.additionalPledgeAmountIsGone.onNext(it) } - .addToDisposable(disposables) - - val initialAmount = rewardMinimum - .compose>(combineLatestPair(updatingPaymentOrUpdatingPledge)) - .filter { it.second.isFalse() } - .map { it.first } - - // - For no Reward the amount of the RW and the bonus amount are the same value - val backingAmountNR = backing - .filter { it.reward() == null } - .map { it.bonusAmount() } - .distinctUntilChanged() - - val backingAmountRW = backing - .filter { it.reward()?.let { rw -> !RewardUtils.isNoReward(rw) } ?: false } - .map { it.amount() - it.shippingAmount() - it.bonusAmount() } - .distinctUntilChanged() - - val backingAmount = Observable.merge(backingAmountNR, backingAmountRW) - - val pledgeInput = Observable.merge(initialAmount, this.pledgeInput.map { it.parseToDouble() }, backingAmount) - .map { it } - .distinctUntilChanged() - - pledgeInput - .compose(takeWhenV2(this.increasePledgeButtonClicked)) - .map { it + this.stepperAmount } - .map { it.toString() } - .subscribe { this.pledgeInput.onNext(it) } - .addToDisposable(disposables) - - pledgeInput - .compose(takeWhenV2(this.decreasePledgeButtonClicked)) - .map { it - this.stepperAmount } - .map { it.toString() } - .subscribe { this.pledgeInput.onNext(it) } - .addToDisposable(disposables) - - pledgeInput - .compose>(combineLatestPair(minPledgeByCountry)) - .map { it.first - it.second } - .subscribe { additionalPledgeAmount.onNext(it) } - .addToDisposable(disposables) - - pledgeInput - .compose>(combineLatestPair(minPledgeByCountry)) - .map { max(it.first, it.second) > it.second } - .distinctUntilChanged() - .subscribe { this.decreasePledgeButtonIsEnabled.onNext(it) } - .addToDisposable(disposables) - - pledgeInput - .map { - val formatter = NumberFormat.getNumberInstance() - formatter.maximumFractionDigits = 2 - formatter.format(it) - } - .subscribe { this.pledgeAmount.onNext(it) } - .addToDisposable(disposables) - - Observable.merge(this.decreaseBonusButtonClicked, this.decreasePledgeButtonClicked, this.increaseBonusButtonClicked, this.increasePledgeButtonClicked) - .distinctUntilChanged() - .subscribe { - this.bonusAmountHasChanged.onNext(true) - } - .addToDisposable(disposables) - - val rulesAndProject = shippingRules - .compose, Project>>(combineLatestPair(project)) - - rulesAndProject - .subscribe { this.shippingRulesAndProject.onNext(it) } - .addToDisposable(disposables) - - Observable.combineLatest( - shippingRules, this.currentConfig.observable(), shouldLoadDefaultLocation - ) { rules, config, isDefault -> - if (isDefault && rules.isNotEmpty()) defaultConfigShippingRule( - rules.toMutableList(), - config - ) else ShippingRuleFactory.emptyShippingRule() - } - .filter { it.location()?.id()?.let { it > 0 } ?: false } - .compose>(combineLatestPair(pledgeReason)) - .filter { it.second == PledgeReason.PLEDGE || it.second == PledgeReason.UPDATE_REWARD || it.second == PledgeReason.FIX_PLEDGE } - .map { it.first } - .compose>(combineLatestPair(project)) - .subscribe { - this.shippingRule.onNext(it.first) - } - .addToDisposable(disposables) - - val backingShippingAmount = backing - .map { it.shippingAmount() } - - val shippingAmountWhenBacking = Observable.combineLatest(this.shippingRule, pledgeReason, backingShippingAmount, rewardAndAddOns) { rule, reason, bShippingAmount, listRw -> - return@combineLatest getShippingAmount(rule, reason, bShippingAmount, listRw) - } - .distinctUntilChanged() - - val newPledge = pledgeReason - .filter { it == PledgeReason.PLEDGE || it == PledgeReason.UPDATE_REWARD } - .map { it } - - // - Shipping amount when no backing - val shippingAmountNewPledge = Observable.combineLatest(this.shippingRule, newPledge, rewardAndAddOns) { rule, reason, listRw -> - return@combineLatest getShippingAmount(rule, reason, listRw = listRw) - } - .distinctUntilChanged() - - val shippingAmount = Observable.merge(shippingAmountNewPledge, shippingAmountWhenBacking) - - shippingAmount - .compose>(combineLatestPair(project)) - .distinctUntilChanged() - .subscribe { - shippingAmountSelectedRw.onNext(it.first) - this.shippingAmount.onNext(ProjectViewUtils.styleCurrency(it.first, it.second, this.ksCurrency)) - } - .addToDisposable(disposables) - - // - When updating payment, shipping location area should always be gone - updatingPayment - .compose>(combineLatestPair(this.selectedReward)) - .filter { it.first == true && RewardUtils.isShippable(it.second) } - .subscribe { - this.shippingRulesSectionIsGone.onNext(true) - } - .addToDisposable(disposables) - - val isRewardWithShipping = this.selectedReward - .filter { RewardUtils.isShippable(it) } - .distinctUntilChanged() - - val isDigitalRw = this.selectedReward - .filter { RewardUtils.isDigital(it) || RewardUtils.isLocalPickup(it) } - .distinctUntilChanged() - - // - Calculate total for Reward || Rewards + AddOns with Shipping location - val totalWShipping = Observable.combineLatest(isRewardWithShipping, pledgeAmountHeader, shippingAmount, this.bonusAmount, pledgeReason) { - _, pAmount, shippingAmount, bAmount, pReason -> - return@combineLatest getAmount(pAmount, shippingAmount, bAmount, pReason) - } - .distinctUntilChanged() - - // - Calculate total for NoReward - val totalNR = this.selectedReward - .filter { RewardUtils.isNoReward(it) } - .compose>(combineLatestPair(this.pledgeInput.startWith(""))) - .map { if (it.second.isNotEmpty()) it.second.parseToDouble() else it.first.minimum() } - - // - Calculate total for DigitalRewards || DigitalReward + DigitalAddOns || LocalPickup - val totalNoShipping = Observable.combineLatest(isDigitalRw, pledgeAmountHeader, this.bonusAmount, pledgeReason) { _, pledgeAmount, bonusAmount, pReason -> - return@combineLatest getAmountDigital(pledgeAmount, bonusAmount.parseToDouble(), pReason) - } - .distinctUntilChanged() - - val total = Observable.merge(totalWShipping, totalNR, totalNoShipping) - .distinctUntilChanged() - - total - .compose>(combineLatestPair(project)) - .map { ProjectViewUtils.styleCurrency(it.first, it.second, this.ksCurrency) } - .subscribe { - this.totalAmount.onNext(it) - } - .addToDisposable(disposables) - - total - .compose>(combineLatestPair(project)) - .map { Pair(this.ksCurrency.format(it.first, it.second, RoundingMode.HALF_UP), it.second) } - .filter { it.second.deadline().isNotNull() } - .map { totalAndProject -> totalAndProject.second.deadline()?.let { Pair(totalAndProject.first, DateTimeUtils.longDate(it)) } } - .map { requireNotNull(it) } - .distinctUntilChanged() - .subscribe { this.totalAndDeadline.onNext(it) } - .addToDisposable(disposables) - - this.totalAndDeadline - .compose(ignoreValuesV2()) - .subscribe { this.totalAndDeadlineIsVisible.onNext(it) } - .addToDisposable(disposables) - - total - .compose>(combineLatestPair(project)) - .filter { it.second.currency() != it.second.currentCurrency() } - .map { this.ksCurrency.formatWithUserPreference(it.first, it.second, RoundingMode.UP, 2) } - .subscribe { this.conversionText.onNext(it) } - .addToDisposable(disposables) - - projectAndReward - .map { it.first.currency() != it.first.currentCurrency() } - .map { it.negate() } - .distinctUntilChanged() - .subscribe { this.conversionTextViewIsGone.onNext(it) } - .addToDisposable(disposables) - - val currencyMaximum = country - .map { it.maxPledge.toDouble() } - .distinctUntilChanged() - - val threshold = pledgeAmountHeader - .compose>(combineLatestPair(shippingAmount)) - .map { it.first + it.second } - .distinctUntilChanged() - - val selectedPledgeAmount = Observable.merge(pledgeAmountHeader, threshold, minPledgeByCountry) - - val bonusSupportMaximum = currencyMaximum - .compose>(combineLatestPair(selectedPledgeAmount)) - .compose, Reward>>(combineLatestPair(this.selectedReward)) - .map { if (RewardUtils.isNoReward(it.second)) it.first.first else it.first.first - it.first.second } - - val pledgeMaximumIsGone = currencyMaximum - .compose>(combineLatestPair(total)) - .map { it.first >= it.second } - .distinctUntilChanged() - - pledgeMaximumIsGone - .distinctUntilChanged() - .subscribe { - this.pledgeMaximumIsGone.onNext(it) - } - .addToDisposable(disposables) - - bonusSupportMaximum - .distinctUntilChanged() - .compose>(combineLatestPair(project)) - .map { this.ksCurrency.format(it.first, it.second, RoundingMode.HALF_UP) } - .subscribe { - this.pledgeMaximum.onNext(it) - } - .addToDisposable(disposables) - - val minAndMaxPledge = rewardMinimum - .compose>(combineLatestPair(currencyMaximum)) - - pledgeInput - .compose>>(combineLatestPair(minAndMaxPledge)) - .map { it.first in it.second.first..it.second.second } - .map { if (it) R.color.kds_create_700 else R.color.kds_alert } - .distinctUntilChanged() - .subscribe { this.pledgeTextColor.onNext(it) } - .addToDisposable(disposables) - - val stepAndMaxPledge = stepAmount - .map { it.toDouble() } - .compose>(combineLatestPair(currencyMaximum)) - - pledgeInput - .compose>>(combineLatestPair(stepAndMaxPledge)) - .map { it.second.second - it.first >= it.second.first } - .distinctUntilChanged() - .subscribe { this.increasePledgeButtonIsEnabled.onNext(it) } - .addToDisposable(disposables) - - // Manage pledge section - backingAmount - .compose>(combineLatestPair(project)) - .map { ProjectViewUtils.styleCurrency(it.first, it.second, this.ksCurrency) } - .distinctUntilChanged() - .subscribe { this.pledgeSummaryAmount.onNext(it) } - .addToDisposable(disposables) - - updatingPayment - .subscribe { this.totalDividerIsGone.onNext(it) } - .addToDisposable(disposables) - - backing - .map { it.shippingAmount().toDouble() } - .compose>(combineLatestPair(project)) - .map { ProjectViewUtils.styleCurrency(it.first, it.second, this.ksCurrency) } - .subscribe { this.shippingSummaryAmount.onNext(it) } - .addToDisposable(disposables) - - backing - .map { it.bonusAmount() } - .compose>(combineLatestPair(pledgeReason)) - .filter { it.second == PledgeReason.UPDATE_PAYMENT } - .map { it.first } - .compose>(combineLatestPair(project)) - .map { ProjectViewUtils.styleCurrency(it.first, it.second, this.ksCurrency) } - .subscribe { - this.bonusSummaryAmount.onNext(it) - } - .addToDisposable(disposables) - - val summary: Observable = this.shippingRule - .map { it.location()?.displayableName() } - .filter { it.isNotNull() } - .map { requireNotNull(it) } - .distinctUntilChanged() - - summary - .subscribe { this.shippingSummaryLocation.onNext(it) } - .addToDisposable(disposables) - - val updatingPledge = pledgeReason - .map { it == PledgeReason.UPDATE_PLEDGE } - - val rewardAmountUpdated = total - .compose>(combineLatestPair(this.selectedReward)) - .filter { !RewardUtils.isNoReward(it.second) } - .map { it.first } - .compose>(combineLatestPair(updatingPledge)) - .filter { it.second } - .map { it.first } - .compose>(combineLatestPair(backing)) - .map { it.first != it.second.amount() } - .startWith(false) - - val noRewardAmountUpdated = pledgeInput - .compose>(combineLatestPair(this.selectedReward)) - .filter { RewardUtils.isNoReward(it.second) } - .map { it.first } - .compose>(combineLatestPair(updatingPledge)) - .filter { it.second } - .map { it.first } - .compose>(combineLatestPair(backingAmount)) - .map { it.first != it.second } - .startWith(false) - - val amountUpdated = Observable.combineLatest(this.selectedReward, rewardAmountUpdated, noRewardAmountUpdated) { rw, rAmount, noRAmount -> - if (RewardUtils.isNoReward(rw)) return@combineLatest noRAmount - else return@combineLatest rAmount - } - .distinctUntilChanged() - - Observable.combineLatest(this.shippingRule, backingShippingRule) { rule, dfRule -> - return@combineLatest rule.id() != dfRule.id() - } - .distinctUntilChanged() - .subscribe { this.shippingRuleUpdated.onNext(it) } - .addToDisposable(disposables) - - val shippingOrAmountChanged = Observable.combineLatest(shippingRuleUpdated, this.bonusAmountHasChanged, amountUpdated, pledgeReason) { shippingUpdated, bHasChanged, aUpdated, pReason -> - return@combineLatest hasBeenUpdated(shippingUpdated, pReason, bHasChanged, aUpdated) - } - .distinctUntilChanged() - - val totalIsValid = total - .compose>>(combineLatestPair(minAndMaxPledge)) - .map { it.first in it.second.first..it.second.second } - .distinctUntilChanged() - - val validChange = shippingOrAmountChanged - .compose>(combineLatestPair(totalIsValid)) - .map { it.first && it.second } - - val changeDuringUpdatingPledge = validChange - .compose>(combineLatestPair(updatingPledge)) - .filter { it.second.isTrue() } - .map { it.first } - - // Payment section - pledgeReason - .map { it == PledgeReason.UPDATE_PLEDGE || it == PledgeReason.UPDATE_REWARD } - .compose>(combineLatestPair(userIsLoggedIn)) - .map { it.first || !it.second } - .distinctUntilChanged() - .subscribe { this.paymentContainerIsGone.onNext(it) } - .addToDisposable(disposables) - - userIsLoggedIn - .subscribe { this.continueButtonIsGone.onNext(it) } - .addToDisposable(disposables) - - userIsLoggedIn - .map { it.negate() } - .subscribe { this.pledgeButtonIsGone.onNext(it) } - .addToDisposable(disposables) - - val storedCards = BehaviorSubject.create>() - - userIsLoggedIn - .filter { it.isTrue() } - .compose>(combineLatestPair(pledgeReason)) - .take(1) - .switchMap { storedCards() } - .subscribe { - storedCards.onNext(it) - } - .addToDisposable(disposables) - - val cardsAndProject = storedCards - .compose, Project>>(combineLatestPair(project)) - - cardsAndProject - .subscribe { this.cardsAndProject.onNext(it) } - .addToDisposable(disposables) - - val initialCardSelection = cardsAndProject - .take(1) - .map { initialCardSelection(it.first, it.second) } - - // - When setupIntent finishes with error reload the payment methods - this.paymentSheetResult - .filter { - it != PaymentSheetResult.Completed - } - .withLatestFrom(cardsAndProject) { _, cardsAndProject -> - return@withLatestFrom cardsAndProject - } - .subscribe { this.cardsAndProject.onNext(it) } - .addToDisposable(disposables) - - this.cardSaved - .compose>(combineLatestPair(project)) - .subscribe { this.addedCard.onNext(it) } - .addToDisposable(disposables) - - val selectedCardAndPosition = Observable.merge( - initialCardSelection, - this.cardSelected, - this.cardSaved.compose>(zipPairV2(this.addedCardPosition)) - ) - - selectedCardAndPosition - .map { it.second } - .filter { it >= 0 } - .subscribe { this.showSelectedCard.onNext(Pair(it, CardState.SELECTED)) } - .addToDisposable(disposables) - - val userHasCards = selectedCardAndPosition - .map { it.second >= 0 } - - Observable.combineLatest(changeDuringUpdatingPledge.startWith(false), userHasCards, pledgeReason) { - changedValues, hasCards, pReason -> - return@combineLatest shouldBeEnabled(changedValues, hasCards, pReason) - } - .distinctUntilChanged() - .subscribe { - this.pledgeButtonIsEnabled.onNext(it) - } - .addToDisposable(disposables) - - val changeCard = Observable.merge( - this.cardSelected, - this.cardSaved.compose>(zipPairV2(this.addedCardPosition)) - ).map { - it.second >= 0 - } - - tPAddPaymentMethodEvent(project, changeCard, pledgeData, shippingAmount, total) - - // - Present PaymentSheet if user logged in, and add card button pressed - val shouldPresentPaymentSheet = PublishSubject.create>() - this.newCardButtonClicked - .withLatestFrom(project) { _, latestProject -> latestProject } - .switchMap { - this.apolloClient.createSetupIntent(it) - .doOnSubscribe { - this.loadingState.onNext(State.LOADING) - this.pledgeButtonIsEnabled.onNext(false) - } - .doOnError { - this.loadingState.onNext(State.DEFAULT) - this.pledgeButtonIsEnabled.onNext(true) - } - .materialize() - } - .subscribe { - shouldPresentPaymentSheet.onNext(it) - } - .addToDisposable(disposables) - - shouldPresentPaymentSheet - .compose(valuesV2()) - .compose(combineLatestPair(userEmail())) - .subscribe { - this.presentPaymentSheet.onNext(it) - } - .addToDisposable(disposables) - - shouldPresentPaymentSheet - .compose(errorsV2()) - .subscribe { - // - Display error snackbar in case the SetupIntent was not successfully created - this.showError.onNext(it?.message ?: "") - } - .addToDisposable(disposables) - - this.paySheetPresented - .subscribe { - this.pledgeButtonIsEnabled.onNext(true) - this.loadingState.onNext(State.DEFAULT) - } - .addToDisposable(disposables) - - this.continueButtonClicked - .subscribe { this.startLoginToutActivity.onNext(it) } - .addToDisposable(disposables) - - userIsLoggedIn - .filter { it.isFalse() } - .compose>(combineLatestPair(pledgeReason)) - .filter { it.second == PledgeReason.PLEDGE } - .compose, Boolean>>(combineLatestPair(totalIsValid)) - .map { it.second } - .subscribe { this.continueButtonIsEnabled.onNext(it) } - .addToDisposable(disposables) - - // An observable of the ref tag stored in the cookie for the project - val cookieRefTag = project - .take(1) - .map { p -> - RefTagUtils.storedCookieRefTagForProject(p, cookieManager, sharedPreferences) - ?: RefTag.Builder().build() - } - - val locationId: Observable = shippingRule - .filter { it.location() != null } - .map { it.location() } - .map { it.id() ?: -1L } - .map { it.toString() } - .startWith("") - - val backingToUpdate = project - .filter { it.isBacking() } - .map { it.backing() } - .ofType(Backing::class.java) - .distinctUntilChanged() - - val paymentMethod: Observable = selectedCardAndPosition.map { it.first } - - val extendedListForCheckOut = rewardAndAddOns - .map { extendAddOns(it) } - - val pledgeButtonClicked = pledgeReason - .compose(takeWhenV2(this.pledgeButtonClicked)) - .filter { it == PledgeReason.PLEDGE } - .compose(ignoreValuesV2()) - - val createBackingNotification = Observable.combineLatest( - project, - total.map { it.toString() }, - paymentMethod, - locationId, - extendedListForCheckOut, - cookieRefTag - ) { proj, amount, paymentMethod, locationId, rewards, cookieRefTag -> - paymentMethod.getBackingData(proj, amount, locationId, rewards, cookieRefTag) - } - .compose(takeWhenV2(pledgeButtonClicked)) - .switchMap { - this.apolloClient.createBacking(it) - .doOnSubscribe { - this.pledgeProgressIsGone.onNext(false) - this.pledgeButtonIsEnabled.onNext(false) - } - .materialize() - } - .share() - - val totalString: Observable = total - .map { it.toString() } - .startWith("") - - val updatePaymentClick = pledgeReason - .compose(takeWhenV2(this.pledgeButtonClicked)) - .filter { it == PledgeReason.UPDATE_PAYMENT } - .compose(ignoreValuesV2()) - - val fixPaymentClick = pledgeReason - .compose(takeWhenV2(this.pledgeButtonClicked)) - .filter { it == PledgeReason.FIX_PLEDGE } - .compose(ignoreValuesV2()) - - val updatePledgeClick = pledgeReason - .compose(takeWhenV2(this.pledgeButtonClicked)) - .filter { it == PledgeReason.UPDATE_PLEDGE || it == PledgeReason.UPDATE_REWARD } - .compose(ignoreValuesV2()) - - val updateBackingNotification = Observable.combineLatest( - backingToUpdate, - totalString, - locationId, - extendedListForCheckOut, - paymentMethod, - project - ) { b, a, l, r, pMethod, pro -> - if (pro.isBacking() && pro.backing()?.amount().toString() == a) { - Pair(this.getUpdateBackingData(b, null, l, r, pMethod), pro) - } else { - Pair(this.getUpdateBackingData(b, a, l, r, pMethod), pro) - } - } - .compose>(takeWhenV2(Observable.merge(updatePledgeClick, updatePaymentClick, fixPaymentClick))) - .switchMap { - this.apolloClient.updateBacking(it.first) - .doOnSubscribe { - this.pledgeProgressIsGone.onNext(false) - this.pledgeButtonIsEnabled.onNext(false) - } - .materialize() - } - .share() - - val checkoutResult = Observable.merge(createBackingNotification, updateBackingNotification) - .compose(valuesV2()) - - val successfulSCACheckout = checkoutResult - .compose(takeWhenV2(this.stripeSetupResultSuccessful.filter { it == StripeIntentResult.Outcome.SUCCEEDED })) - - val successfulCheckout = checkoutResult - .filter { it.backing().requiresAction().isFalse() } - - val successfulBacking = successfulCheckout - .filter { it.backing().isNotNull() } - .map { it.backing() } - - val successAndPledgeReason = Observable.merge( - successfulBacking, - this.stripeSetupResultSuccessful.filter { it == StripeIntentResult.Outcome.SUCCEEDED } - ) - .compose>(combineLatestPair(pledgeReason)) - - Observable.combineLatest(shippingAmountSelectedRw, total, this.bonusAmount, Observable.merge(successfulCheckout, successfulSCACheckout)) { s, t, b, c -> - checkoutData(s, t, b.parseToDouble(), c) - } - .compose>(combineLatestPair(pledgeData)) - .filter { it.second.pledgeFlowContext() == PledgeFlowContext.NEW_PLEDGE } - .subscribe { this.showPledgeSuccess.onNext(it) } - .addToDisposable(disposables) - - successAndPledgeReason - .filter { it.second == PledgeReason.UPDATE_PLEDGE || it.second == PledgeReason.UPDATE_REWARD } - .compose(ignoreValuesV2()) - .subscribe { this.showUpdatePledgeSuccess.onNext(it) } - .addToDisposable(disposables) - - successAndPledgeReason - .filter { it.second == PledgeReason.UPDATE_PAYMENT || it.second == PledgeReason.FIX_PLEDGE } - .compose(ignoreValuesV2()) - .subscribe { this.showUpdatePaymentSuccess.onNext(it) } - .addToDisposable(disposables) - - Observable.merge(createBackingNotification, updateBackingNotification) - .compose(valuesV2()) - .map { it.backing() } - .filter { it.requiresAction().isTrue() } - .map { it.clientSecret() } - .filter { it.isNotNull() } - .map { requireNotNull(it) } - .subscribe { this.showSCAFlow.onNext(it) } - .addToDisposable(disposables) - - val createOrUpdateError = Observable.merge( - createBackingNotification.compose(errorsV2()), - updateBackingNotification.compose(errorsV2()) - ) - - val stripeSetupError = Observable.merge( - this.stripeSetupResultUnsuccessful, - this.stripeSetupResultSuccessful.filter { it != StripeIntentResult.Outcome.SUCCEEDED } - ) - - val errorAndPledgeReason = Observable.merge(createOrUpdateError, stripeSetupError) - .compose(ignoreValuesV2()) - .compose>(combineLatestPair(pledgeReason)) - - errorAndPledgeReason - .filter { it.second == PledgeReason.PLEDGE } - .compose(ignoreValuesV2()) - .subscribe { - this.pledgeProgressIsGone.onNext(true) - this.pledgeButtonIsEnabled.onNext(true) - this.showPledgeError.onNext(Unit) - } - .addToDisposable(disposables) - - errorAndPledgeReason - .filter { it.second == PledgeReason.UPDATE_PLEDGE || it.second == PledgeReason.UPDATE_REWARD } - .compose(ignoreValuesV2()) - .subscribe { - this.pledgeProgressIsGone.onNext(true) - this.pledgeButtonIsEnabled.onNext(true) - this.showUpdatePledgeError.onNext(Unit) - } - .addToDisposable(disposables) - - errorAndPledgeReason - .filter { it.second == PledgeReason.UPDATE_PAYMENT || it.second == PledgeReason.FIX_PLEDGE } - .compose(ignoreValuesV2()) - .subscribe { - this.pledgeProgressIsGone.onNext(true) - this.pledgeButtonIsEnabled.onNext(true) - this.showUpdatePaymentError.onNext(Unit) - } - .addToDisposable(disposables) - - this.baseUrlForTerms.onNext(this.environment.webEndpoint()) - - this.linkClicked - .withLatestFrom(this.loadingState.startWith(State.DEFAULT)) { link, state -> Pair(link, state) } - .filter { it.second == State.DEFAULT } - .map { it.first } - .subscribe { this.startChromeTab.onNext(it) } - .addToDisposable(disposables) - - pledgeReason - .map { if (it == PledgeReason.PLEDGE) R.string.Pledge else R.string.Confirm } - .subscribe { this.pledgeButtonCTA.onNext(it) } - .addToDisposable(disposables) - - val checkoutAndPledgeData = - Observable.combineLatest( - shippingAmountSelectedRw, - total, - this.bonusAmount - ) { s, t, b -> - checkoutData(s, t, b.parseToDouble(), null) - } - .compose>(combineLatestPair(pledgeData)) - - checkoutAndPledgeData - .take(1) - .filter { it.second.pledgeFlowContext() == PledgeFlowContext.NEW_PLEDGE } - .subscribe { - this.analyticEvents.trackCheckoutScreenViewed(it.first, it.second) - } - .addToDisposable(disposables) - - checkoutAndPledgeData - .take(1) - .filter { it.second.pledgeFlowContext() == PledgeFlowContext.MANAGE_REWARD } - .subscribe { - this.analyticEvents.trackUpdatePledgePageViewed(it.first, it.second) - } - .addToDisposable(disposables) - - checkoutAndPledgeData - .filter { shouldTrackPledgeSubmitButtonClicked(it.second.pledgeFlowContext()) } - .compose>(takeWhenV2(this.pledgeButtonClicked)) - .subscribe { - this.analyticEvents.trackPledgeSubmitCTA(it.first, it.second) - } - .addToDisposable(disposables) - - // - Screen configuration Logic (Different configurations depending on: PledgeReason, Reward type, Shipping, AddOns) - this.selectedReward - .compose>(combineLatestPair(pledgeReason)) - .subscribe { - when (it.second) { - PledgeReason.PLEDGE, - PledgeReason.UPDATE_REWARD -> { - this.pledgeSummaryIsGone.onNext(true) - if (!RewardUtils.isNoReward(it.first)) { - this.headerSectionIsGone.onNext(false) - this.isBonusSupportSectionGone.onNext(false) - this.pledgeSectionIsGone.onNext(true) - } else { - this.pledgeSectionIsGone.onNext(false) - this.isPledgeMinimumSubtitleGone.onNext(true) - this.headerSectionIsGone.onNext(true) - this.isNoReward.onNext(true) - this.isBonusSupportSectionGone.onNext(true) - } - } - PledgeReason.UPDATE_PAYMENT, - PledgeReason.FIX_PLEDGE -> { - this.headerSectionIsGone.onNext(true) - - if (RewardUtils.isNoReward(it.first)) { - this.pledgeSummaryIsGone.onNext(true) - this.shippingSummaryIsGone.onNext(true) - this.bonusSummaryIsGone.onNext(true) - } else { - this.shippingSummaryIsGone.onNext(!RewardUtils.isShippable(it.first)) - this.pledgeSummaryIsGone.onNext(false) - } - } - else -> {} - } - } - .addToDisposable(disposables) - - // - Update visibility for shippingRules sections - val shouldHideShippingSections = Observable.combineLatest(this.rewardAndAddOns, pledgeReason) { rwAndAddOns, reason -> - return@combineLatest shippingRulesSectionShouldHide(rwAndAddOns, reason) - } - - shouldHideShippingSections - .subscribe { - this.shippingRulesSectionIsGone.onNext(it.first) - this.shippingRuleStaticIsGone.onNext(it.second) - } - .addToDisposable(disposables) - - pledgeReason - .compose>(combineLatestPair(backing)) - .subscribe { - val hasBonus = it.second.bonusAmount() > 0 - val isNoReward = it.second.reward() == null && hasBonus - - when (it.first) { - PledgeReason.UPDATE_PLEDGE -> { - this.isBonusSupportSectionGone.onNext(isNoReward) // has bonus, sections is not gone - this.pledgeSectionIsGone.onNext(!isNoReward) - this.headerSectionIsGone.onNext(true) - this.pledgeSummaryIsGone.onNext(isNoReward) // Gone if No reward, Show if regular reward - } - PledgeReason.UPDATE_PAYMENT, - PledgeReason.FIX_PLEDGE -> { - if (!isNoReward) { - this.bonusSummaryIsGone.onNext(!hasBonus) - } - } - else -> {} - } - } - .addToDisposable(disposables) - } - - /** - * ThirdParty Analytic event sent when there is a change with the selected payment method - * it does require pledgeAmount and shipping amount information plus the selected rewards/addOns - * - * @param project observable with the current project, should always emit - * @param changeCard observable that will emit if the selected payment changes - * @param pledgeData current user selection to make a pledge, should always emit - * @param shippingAmount observable with shipping amount, will emit when reward or addon are shippable - * @param total observable with the total amount of the plede, will always emit - */ - private fun tPAddPaymentMethodEvent( - project: Observable, - changeCard: Observable, - pledgeData: Observable, - shippingAmount: Observable, - total: Observable - ) { - project - .compose(takeWhenV2(changeCard)) - .withLatestFrom(pledgeData) { _, pData -> - pData - } - // - Start with 0 in case of digital reward/addon without shipping - .withLatestFrom(shippingAmount.startWith(0.0)) { pData, shipAmount -> - Pair(pData, shipAmount) - } - .withLatestFrom(total) { data, totAmount -> - val pledData = data.first - val shipAmt = data.second - val pledgAmount = totAmount - shipAmt - val prject = pledData.projectData().project() - Triple(pledData, prject, Pair(pledgAmount, shipAmt)) - } - .switchMap { - SendThirdPartyEventUseCaseV2(sharedPreferences, ffClient) - .sendThirdPartyEvent( - project = Observable.just(it.second), - currentUser = currentUser, - apolloClient = apolloClient, - draftPledge = it.third, - checkoutAndPledgeData = Observable.just(Pair(null, it.first)), - eventName = ThirdPartyEventValues.EventName.ADD_PAYMENT_INFO - ) - } - .compose(neverErrorV2()) - .subscribe { - thirdpartyEventIsSuccessful.onNext(it.first) - } - .addToDisposable(disposables) - } - - private fun shouldBeEnabled(changedValues: Boolean, hasCards: Boolean, pReason: PledgeReason): Boolean { - val isEnabled = when (pReason) { - PledgeReason.UPDATE_REWARD, - PledgeReason.PLEDGE, - PledgeReason.UPDATE_PAYMENT, - PledgeReason.LATE_PLEDGE, - PledgeReason.FIX_PLEDGE -> hasCards - PledgeReason.UPDATE_PLEDGE -> changedValues && hasCards - } - - return isEnabled - } - - /** - * The shipping rule from the backing object should be load on the next scenarios: - * - Shippable Reward without available addOns - * - Shippable Reward with available addOns but not backedAddOns - * - * Note: If pledgeData object contains shipping rule it comes from selecting addOns that's - * the prioritary shippingRule ignore anything on the backingObject - * - * Note: If skipping addOns, pledgeData.shippingRule will be null but we will display - * the shippingSelector for the user, so loading the backing shippingRule it's correct as - * it can be edited. - */ - private fun shouldLoadShippingRuleFromBacking(it: Pair) = - RewardUtils.isShippable(it.second.reward()) && it.first.locationId().isNotNull() && - !hasBackedAddOns(Pair(it.first, it.second.reward())) && !hasSelectedAddOns(it.second.addOns()) && - it.second.shippingRule() == null - - /** - * If a user has selected addOns, we will know by checking field addOns from pledgeData input - */ - private fun hasSelectedAddOns(addOns: List?): Boolean = addOns?.isNotEmpty() ?: false - - /** - * Determine if the user has backed addOns - */ - private fun hasBackedAddOns(it: Pair) = - it.second.hasAddons() && it.first.addOns()?.isNotEmpty() ?: false - - private fun getAmountDigital(pledgeAmount: Double, bAmount: Double, pReason: PledgeReason) = pledgeAmount + bAmount - - /** - * Calculate the pledge amount for the selected reward + addOns - */ - private fun getPledgeAmount(rewards: List, isLatePledge: Boolean): Double { - var totalPledgeAmount = 0.0 - rewards.forEach { - totalPledgeAmount += if (isLatePledge) { - if (it.latePledgeAmount() > 0) { - if (RewardUtils.isNoReward(it) && !it.isAddOn()) it.latePledgeAmount() // - Cost of the selected Reward - else it.quantity()?.let { q -> (q * it.latePledgeAmount()) } ?: it.latePledgeAmount() // - Cost of each addOn - } else { - // We don't have a late pledge amount to work with, use the default minimum - if (RewardUtils.isNoReward(it) && !it.isAddOn()) it.minimum() // - Default cost of the selected Reward - else it.quantity()?.let { q -> (q * it.minimum()) } ?: it.minimum() // - Default cost of each addOn - } - } else { - // We have a pledge amount to work with, use it - if (it.pledgeAmount() > 0.0) { - if (RewardUtils.isNoReward(it) && !it.isAddOn()) it.pledgeAmount() // - Cost of the selected Reward during the campaign - else it.quantity()?.let { q -> (q * it.pledgeAmount()) } ?: it.pledgeAmount() // - Cost of each addOn during the campaign - } else { - // We don't have a pledge amount to work with, use the default minimum - if (RewardUtils.isNoReward(it) && !it.isAddOn()) it.minimum() // - Default cost of the selected Reward - else it.quantity()?.let { q -> (q * it.minimum()) } ?: it.minimum() // - Default cost of each addOn - } - } - } - return totalPledgeAmount - } - - /** - * Logic to hide/show the shipping location sections - * @return Pair.first ShippingRulesSection -> This section shows/Hide the shippingSelector for shippable rewards without addOns - * @return Pair.second ShippingRulesStaticSection -> this section shows/hides the textview showing the current shipping location - */ - private fun shippingRulesSectionShouldHide(rewardAndAddOns: List, reason: PledgeReason): Pair { - var hideFlags = Pair(true, true) - val rw = rewardAndAddOns.first() - - if (reason == PledgeReason.PLEDGE || reason == PledgeReason.UPDATE_REWARD || reason == PledgeReason.UPDATE_PLEDGE) { - val showSelector = !hasSelectedAddons(rewardAndAddOns) && RewardUtils.isShippable(rw) - val showStaticInfo = hasSelectedAddons(rewardAndAddOns) && RewardUtils.isShippable(rw) - hideFlags = Pair(!showSelector, !showStaticInfo) - } - - return hideFlags - } - - /** - * Choose the correct shipping location in case of a just Reward Selected - * - If any location available for a reward matches our default configuration select that - * - In case no matching between our default and the locations available for a reward - * just select the fist one available. - */ - private fun defaultConfigShippingRule(rules: MutableList, config: Config) = - rules.firstOrNull { it.location()?.country() == config.countryCode() }?.let { it } ?: rules.first() - - /** - * Calculate the shipping amount in case of shippable reward and reward + AddOns - */ - private fun getShippingAmount(rule: ShippingRule, reason: PledgeReason, bShippingAmount: Float? = null, listRw: List): Double { - val rw = listRw.first() - - return when (reason) { - PledgeReason.UPDATE_REWARD, - PledgeReason.PLEDGE -> if (rw.hasAddons()) shippingCostForAddOns(listRw, rule) + rule.cost() else rule.cost() - PledgeReason.FIX_PLEDGE, - PledgeReason.UPDATE_PAYMENT, - PledgeReason.LATE_PLEDGE, - PledgeReason.UPDATE_PLEDGE -> bShippingAmount?.toDouble() ?: rule.cost() - } - } - - private fun shippingCostForAddOns(listRw: List, selectedRule: ShippingRule): Double { - var shippingCost = 0.0 - listRw.filter { - it.isAddOn() - }.map { rw -> - rw.shippingRules()?.filter { rule -> - rule.location()?.id() == selectedRule.location()?.id() - }?.map { rule -> - shippingCost += rule.cost() * (rw.quantity() ?: 1) - } - } - - return shippingCost - } - - /** - * When retrieving the backing shipping information we do have available the LocationId on the backingObject - * and the list of shippingRules available for the selected reward, the backing shippingRule will be - * the one matching the backingObject field locationId - */ - private fun selectedShippingRule(shippingInfo: Pair>): ShippingRule = - requireNotNull(shippingInfo.second.first { it.location()?.id() == shippingInfo.first }) - - /** For the checkout we need to send a list repeating as much addOns items - * as the user has selected: - * User selection [R, 2xa, 3xb] - * Checkout data [R, a, a, b, b, b] - */ - private fun extendAddOns(flattenedList: List): List { - val mutableList = mutableListOf() - - flattenedList.map { - if (!it.isAddOn()) mutableList.add(it) - else { - val q = it.quantity() ?: 1 - for (i in 1..q) { - mutableList.add(it) - } - } - } - - return mutableList.toList() - } - - private fun hasBeenUpdated(shippingUpdated: Boolean, pReason: PledgeReason?, bHasChanged: Boolean, aUpdated: Boolean): Boolean { - var updated = false - - if (pReason == PledgeReason.PLEDGE) updated = true - else if (pReason == PledgeReason.UPDATE_PLEDGE) { - updated = (bHasChanged || aUpdated) || shippingUpdated - } - - return updated - } - - private fun hasSelectedAddons(itemsList: List) = itemsList.size > 1 - - private fun joinProject(items: Pair, Project>?): List> { - return items?.first?.map { - Pair(items.second, it) - } ?: emptyList() - } - private fun joinRewardAndAddOns(rw: Reward, addOns: List): List { - val joinedList = addOns.toMutableList() - joinedList.add(0, rw) - return joinedList.toList() - } - - private fun getAmount(pAmount: Double, shippingAmount: Double, bAmount: String, pReason: PledgeReason) = pAmount + shippingAmount + bAmount.parseToDouble() - - private fun checkoutData(shippingAmount: Double, total: Double, bonusAmount: Double?, checkout: Checkout?): CheckoutData { - return CheckoutData.builder() - .amount(total) - .id(checkout?.id()) - .paymentType(CreditCardPaymentType.CREDIT_CARD) - .bonusAmount(bonusAmount) - .shippingAmount(shippingAmount) - .build() - } - - private fun initialCardSelection(storedCards: List, project: Project): Pair { - val defaultIndex = storedCards.indexOfFirst { project.acceptedCardType(it.type()) } - val backingPaymentSourceIndex = storedCards.indexOfFirst { it.id() == project.backing()?.paymentSource()?.id() } - return when { - backingPaymentSourceIndex != -1 -> Pair(storedCards[backingPaymentSourceIndex], backingPaymentSourceIndex) - storedCards.isNotEmpty() && defaultIndex != -1 -> Pair(storedCards[defaultIndex], defaultIndex) - else -> Pair(StoredCard.builder().build(), -1) - } - } - - private fun rewardTitle(project: Project, reward: Reward): String { - val projectName = project.name() - return when { - RewardUtils.isNoReward(reward) -> projectName - else -> reward.title() ?: projectName - } - } - - private fun shouldTrackPledgeSubmitButtonClicked(pledgeFlowContext: PledgeFlowContext) = - pledgeFlowContext == PledgeFlowContext.NEW_PLEDGE || - pledgeFlowContext == PledgeFlowContext.FIX_ERRORED_PLEDGE - - private fun storedCards(): Observable> { - return this.apolloClient.getStoredCards() - .compose(neverErrorV2()) - } - - private fun userEmail(): Observable { - return this.apolloClient.userPrivacy() - .compose(neverErrorV2()) - .map { it.email } - } - - override fun onCleared() { - disposables.clear() - super.onCleared() - } - - // - Inputs - override fun addedCardPosition(position: Int) = this.addedCardPosition.onNext(position) - - override fun cardSaved(storedCard: StoredCard) = this.cardSaved.onNext(storedCard) - - override fun cardSelected(storedCard: StoredCard, position: Int) = this.cardSelected.onNext(Pair(storedCard, position)) - - override fun continueButtonClicked() = this.continueButtonClicked.onNext(Unit) - - override fun decreasePledgeButtonClicked() = this.decreasePledgeButtonClicked.onNext(Unit) - - override fun increasePledgeButtonClicked() = this.increasePledgeButtonClicked.onNext(Unit) - - override fun decreaseBonusButtonClicked() = this.decreaseBonusButtonClicked.onNext(Unit) - - override fun increaseBonusButtonClicked() = this.increaseBonusButtonClicked.onNext(Unit) - - override fun onRiskMessageDismissed() = this.onRiskMessageDismissed.onNext(Unit) - - override fun linkClicked(url: String) = this.linkClicked.onNext(url) - - override fun miniRewardClicked() = this.miniRewardClicked.onNext(Unit) - - override fun newCardButtonClicked() = this.newCardButtonClicked.onNext(Unit) - - override fun pledgeInput(amount: String) = this.pledgeInput.onNext(amount) - - override fun pledgeButtonClicked() = this.pledgeButtonClicked.onNext(Unit) - - override fun shippingRuleSelected(shippingRule: ShippingRule) = this.shippingRule.onNext(shippingRule) - - override fun stripeSetupResultSuccessful(@StripeIntentResult.Outcome outcome: Int) = this.stripeSetupResultSuccessful.onNext(outcome) - - override fun stripeSetupResultUnsuccessful(exception: Exception) = this.stripeSetupResultUnsuccessful.onNext(exception) - - override fun paymentSheetResult(paymentResult: PaymentSheetResult) = this.paymentSheetResult.onNext( - paymentResult - ) - - override fun paymentSheetPresented(isSuccesfullyPresented: Boolean) = this.paySheetPresented.onNext(isSuccesfullyPresented) - - // - Outputs - override fun addedCard(): Observable> = this.addedCard - - override fun additionalPledgeAmount(): Observable = this.additionalPledgeAmount - - override fun additionalPledgeAmountIsGone(): Observable = this.additionalPledgeAmountIsGone - - override fun baseUrlForTerms(): Observable = this.baseUrlForTerms - - override fun cardsAndProject(): Observable, Project>> = this.cardsAndProject - - override fun continueButtonIsEnabled(): Observable = this.continueButtonIsEnabled - - override fun continueButtonIsGone(): Observable = this.continueButtonIsGone - - override fun conversionTextViewIsGone(): Observable = this.conversionTextViewIsGone - - override fun conversionText(): Observable = this.conversionText - - override fun decreasePledgeButtonIsEnabled(): Observable = this.decreasePledgeButtonIsEnabled - - override fun estimatedDelivery(): Observable = this.estimatedDelivery - - override fun estimatedDeliveryInfoIsGone(): Observable = this.estimatedDeliveryInfoIsGone - - override fun increasePledgeButtonIsEnabled(): Observable = this.increasePledgeButtonIsEnabled - - override fun paymentContainerIsGone(): Observable = this.paymentContainerIsGone - - override fun pledgeAmount(): Observable = this.pledgeAmount - - override fun pledgeButtonCTA(): Observable = this.pledgeButtonCTA - - override fun pledgeButtonIsEnabled(): Observable = this.pledgeButtonIsEnabled - - override fun pledgeButtonIsGone(): Observable = this.pledgeButtonIsGone - - override fun pledgeHint(): Observable = this.pledgeHint - - override fun pledgeMaximum(): Observable = this.pledgeMaximum - - override fun pledgeMaximumIsGone(): Observable = this.pledgeMaximumIsGone - - override fun pledgeMinimum(): Observable = this.pledgeMinimum - - override fun pledgeProgressIsGone(): Observable = this.pledgeProgressIsGone - - override fun pledgeSectionIsGone(): Observable = this.pledgeSectionIsGone - - override fun pledgeSummaryAmount(): Observable = this.pledgeSummaryAmount - - override fun pledgeSummaryIsGone(): Observable = this.pledgeSummaryIsGone - - override fun pledgeTextColor(): Observable = this.pledgeTextColor - - override fun projectCurrencySymbol(): Observable> = this.projectCurrencySymbol - - override fun rewardSummaryIsGone(): Observable = this.rewardSummaryIsGone - - override fun rewardTitle(): Observable = this.rewardTitle - - override fun selectedShippingRule(): Observable = this.shippingRule - - override fun shippingAmount(): Observable = this.shippingAmount - - override fun shippingRulesAndProject(): Observable, Project>> = this.shippingRulesAndProject - - override fun shippingRulesSectionIsGone(): BehaviorSubject = this.shippingRulesSectionIsGone - - override fun shippingSummaryAmount(): Observable = this.shippingSummaryAmount - - override fun shippingSummaryLocation(): Observable = this.shippingSummaryLocation - - override fun shippingSummaryIsGone(): Observable = this.shippingSummaryIsGone - - override fun showPledgeError(): Observable = this.showPledgeError - - override fun showPledgeSuccess(): Observable> = this.showPledgeSuccess - - override fun showSelectedCard(): Observable> = this.showSelectedCard - - override fun showSCAFlow(): Observable = this.showSCAFlow - - override fun showUpdatePaymentError(): Observable = this.showUpdatePaymentError - - override fun showUpdatePaymentSuccess(): Observable = this.showUpdatePaymentSuccess - - override fun showUpdatePledgeError(): Observable = this.showUpdatePledgeError - - override fun showUpdatePledgeSuccess(): Observable = this.showUpdatePledgeSuccess - - override fun startChromeTab(): Observable = this.startChromeTab - - override fun startLoginToutActivity(): Observable = this.startLoginToutActivity - - override fun totalAmount(): Observable = this.totalAmount - - override fun totalAndDeadline(): Observable> = this.totalAndDeadline - - override fun totalAndDeadlineIsVisible(): Observable = this.totalAndDeadlineIsVisible - - override fun totalDividerIsGone(): Observable = this.totalDividerIsGone - - override fun headerSectionIsGone(): Observable = this.headerSectionIsGone - - override fun headerSelectedItems(): Observable>> = this.headerSelectedItems - - override fun isPledgeMinimumSubtitleGone(): Observable = this.isPledgeMinimumSubtitleGone - - override fun isBonusSupportSectionGone(): Observable = this.isBonusSupportSectionGone - - override fun bonusAmount(): Observable = this.bonusAmount - - override fun decreaseBonusButtonIsEnabled(): Observable = this.decreaseBonusButtonIsEnabled - - override fun increaseBonusButtonIsEnabled(): Observable = this.increaseBonusButtonIsEnabled - - override fun bonusHint(): Observable = this.bonusHint - - override fun isNoReward(): Observable = this.isNoReward - - override fun projectTitle(): Observable = this.projectTitle - - override fun rewardAndAddOns(): Observable> = this.rewardAndAddOns - - override fun shippingRuleStaticIsGone(): Observable = this.shippingRuleStaticIsGone - override fun bonusSummaryAmount(): Observable = this.bonusSummaryAmount - - override fun bonusSummaryIsGone(): Observable = this.bonusSummaryIsGone - - override fun pledgeAmountHeader(): Observable = this.pledgeAmountHeader - - override fun shippingRule(): Observable = this.shippingRule - - override fun localPickUpIsGone(): Observable = - localPickUpIsGone - - override fun localPickUpName(): Observable = - localPickUpName - - override fun presentPaymentSheet(): Observable> = - this.presentPaymentSheet - - override fun showError(): Observable = - this.showError - - override fun setState(): Observable = this.loadingState - - override fun eventSent(): Observable = this.thirdpartyEventIsSuccessful - } - - @Suppress("UNCHECKED_CAST") - class Factory(private val environment: Environment, private val bundle: Bundle? = null) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - return PledgeFragmentViewModel( - environment, - bundle = bundle - ) as T - } - } -} - -/** - * Obtain the data model input that will be send to UpdateBacking mutation - * - When updating payment method with a new payment method using payment sheet - * - When updating payment method with a previously existing payment source - * - Updating any other parameter like location, amount or rewards - */ -fun PledgeFragmentViewModel.PledgeFragmentViewModel.getUpdateBackingData( - backing: Backing, - amount: String? = null, - locationId: String? = null, - rewardsList: List = listOf(), - pMethod: StoredCard? = null -): UpdateBackingData { - return pMethod?.let { card -> - // - Updating the payment method, a new one from PaymentSheet or already existing one - if (card.isFromPaymentSheet()) UpdateBackingData( - backing, - amount, - locationId, - rewardsList, - intentClientSecret = card.clientSetupId() - ) - else UpdateBackingData( - backing, - amount, - locationId, - rewardsList, - paymentSourceId = card.id() - ) - // - Updating amount, location or rewards - } ?: UpdateBackingData( - backing, - amount, - locationId, - rewardsList - ) -} diff --git a/app/src/test/java/com/kickstarter/libs/utils/extensions/FragmentExtTest.kt b/app/src/test/java/com/kickstarter/libs/utils/extensions/FragmentExtTest.kt index 36a9edac48..d496c4f71c 100644 --- a/app/src/test/java/com/kickstarter/libs/utils/extensions/FragmentExtTest.kt +++ b/app/src/test/java/com/kickstarter/libs/utils/extensions/FragmentExtTest.kt @@ -11,26 +11,12 @@ import com.kickstarter.ui.data.PledgeData import com.kickstarter.ui.data.PledgeFlowContext import com.kickstarter.ui.data.PledgeReason import com.kickstarter.ui.fragments.CrowdfundCheckoutFragment -import com.kickstarter.ui.fragments.PledgeFragment import org.junit.Test class FragmentExtTest : KSRobolectricTestCase() { - fun `test fragment is PledgeFragment when fix_pledge and ff disabled`() { - val project = ProjectFactory.project() - val projectData = ProjectDataFactory.project(project) - - val pledgeData = PledgeData.builder() - .pledgeFlowContext(PledgeFlowContext.FIX_ERRORED_PLEDGE) - .projectData(projectData) - .build() - - val fragment = Fragment().selectPledgeFragment(pledgeData, PledgeReason.FIX_PLEDGE, false) - assertTrue(fragment is PledgeFragment) - } - @Test - fun `test fragment is CrowdfundCheckoutFragment when fix_pledge and ff enabled`() { + fun `test fragment is CrowdfundCheckoutFragment when fix_pledge`() { val project = ProjectFactory.project() val projectData = ProjectDataFactory.project(project) @@ -39,7 +25,7 @@ class FragmentExtTest : KSRobolectricTestCase() { .projectData(projectData) .build() - val fragment = Fragment().selectPledgeFragment(pledgeData, PledgeReason.FIX_PLEDGE, true) + val fragment = Fragment().selectPledgeFragment(pledgeData, PledgeReason.FIX_PLEDGE) assertTrue(fragment is CrowdfundCheckoutFragment) } @@ -116,7 +102,7 @@ class FragmentExtTest : KSRobolectricTestCase() { val fragment = Fragment().selectPledgeFragment(pledgeData, PledgeReason.FIX_PLEDGE) - assertTrue(fragment is PledgeFragment) + assertTrue(fragment is CrowdfundCheckoutFragment) val arg1 = fragment.arguments?.get(ArgumentsKey.PLEDGE_PLEDGE_DATA) as? PledgeData val arg2 = fragment.arguments?.get(ArgumentsKey.PLEDGE_PLEDGE_REASON) diff --git a/app/src/test/java/com/kickstarter/viewmodels/PledgeFragmentViewModelTest.kt b/app/src/test/java/com/kickstarter/viewmodels/PledgeFragmentViewModelTest.kt deleted file mode 100644 index 541de5daa1..0000000000 --- a/app/src/test/java/com/kickstarter/viewmodels/PledgeFragmentViewModelTest.kt +++ /dev/null @@ -1,3741 +0,0 @@ -package com.kickstarter.viewmodels - -import android.content.SharedPreferences -import android.os.Bundle -import android.util.Pair -import com.kickstarter.KSRobolectricTestCase -import com.kickstarter.R -import com.kickstarter.libs.Environment -import com.kickstarter.libs.MockCurrentUserV2 -import com.kickstarter.libs.MockSharedPreferences -import com.kickstarter.libs.RefTag -import com.kickstarter.libs.featureflag.FlagKey -import com.kickstarter.libs.models.Country -import com.kickstarter.libs.utils.DateTimeUtils -import com.kickstarter.libs.utils.EventName -import com.kickstarter.libs.utils.RefTagUtils -import com.kickstarter.libs.utils.extensions.addToDisposable -import com.kickstarter.libs.utils.extensions.trimAllWhitespace -import com.kickstarter.mock.MockCurrentConfigV2 -import com.kickstarter.mock.MockFeatureFlagClient -import com.kickstarter.mock.factories.BackingFactory -import com.kickstarter.mock.factories.CheckoutFactory -import com.kickstarter.mock.factories.ConfigFactory -import com.kickstarter.mock.factories.LocationFactory -import com.kickstarter.mock.factories.PaymentSourceFactory -import com.kickstarter.mock.factories.ProjectDataFactory -import com.kickstarter.mock.factories.ProjectFactory -import com.kickstarter.mock.factories.RewardFactory -import com.kickstarter.mock.factories.ShippingRuleFactory -import com.kickstarter.mock.factories.ShippingRulesEnvelopeFactory -import com.kickstarter.mock.factories.StoredCardFactory -import com.kickstarter.mock.factories.UserFactory -import com.kickstarter.mock.services.MockApolloClientV2 -import com.kickstarter.models.Backing -import com.kickstarter.models.Checkout -import com.kickstarter.models.Project -import com.kickstarter.models.Reward -import com.kickstarter.models.ShippingRule -import com.kickstarter.models.StoredCard -import com.kickstarter.services.apiresponses.ShippingRulesEnvelope -import com.kickstarter.services.mutations.CreateBackingData -import com.kickstarter.services.mutations.UpdateBackingData -import com.kickstarter.type.CreditCardTypes -import com.kickstarter.ui.ArgumentsKey -import com.kickstarter.ui.SharedPreferenceKey -import com.kickstarter.ui.data.CardState -import com.kickstarter.ui.data.CheckoutData -import com.kickstarter.ui.data.PledgeData -import com.kickstarter.ui.data.PledgeFlowContext -import com.kickstarter.ui.data.PledgeReason -import com.kickstarter.ui.data.ProjectData -import com.kickstarter.ui.viewholders.State -import com.kickstarter.viewmodels.PledgeFragmentViewModel.PledgeFragmentViewModel -import com.kickstarter.viewmodels.usecases.TPEventInputData -import com.stripe.android.StripeIntentResult -import io.reactivex.Observable -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.subscribers.TestSubscriber -import junit.framework.TestCase -import org.joda.time.DateTime -import org.junit.After -import org.junit.Test -import org.mockito.Mockito -import java.math.RoundingMode -import java.net.CookieManager -import java.util.Collections - -class PledgeFragmentViewModelTest : KSRobolectricTestCase() { - - private lateinit var vm: PledgeFragmentViewModel - private val deadline = DateTime.parse("2020-10-23T18:13:09Z") - - private val addedCard = TestSubscriber>() - private val additionalPledgeAmount = TestSubscriber() - private val additionalPledgeAmountIsGone = TestSubscriber() - private val baseUrlForTerms = TestSubscriber() - private val cardsAndProject = TestSubscriber, Project>>() - private val continueButtonIsEnabled = TestSubscriber() - private val continueButtonIsGone = TestSubscriber() - private val conversionText = TestSubscriber() - private val conversionTextViewIsGone = TestSubscriber() - private val decreasePledgeButtonIsEnabled = TestSubscriber() - private val estimatedDelivery = TestSubscriber() - private val estimatedDeliveryInfoIsGone = TestSubscriber() - private val increasePledgeButtonIsEnabled = TestSubscriber() - private val paymentContainerIsGone = TestSubscriber() - private val pledgeAmount = TestSubscriber() - private val pledgeButtonCTA = TestSubscriber() - private val pledgeButtonIsEnabled = TestSubscriber() - private val pledgeButtonIsGone = TestSubscriber() - private val pledgeHint = TestSubscriber() - private val pledgeMaximum = TestSubscriber() - private val pledgeMaximumIsGone = TestSubscriber() - private val pledgeMinimum = TestSubscriber() - private val pledgeProgressIsGone = TestSubscriber() - private val pledgeSectionIsGone = TestSubscriber() - private val pledgeSummaryAmount = TestSubscriber() - private val pledgeSummaryIsGone = TestSubscriber() - private val pledgeTextColor = TestSubscriber() - private val projectCurrencySymbol = TestSubscriber() - private val rewardTitle = TestSubscriber() - private val selectedShippingRule = TestSubscriber() - private val shippingAmount = TestSubscriber() - private val shippingRuleAndProject = TestSubscriber, Project>>() - private val shippingRulesSectionIsGone = TestSubscriber() - private val shippingSummaryAmount = TestSubscriber() - private val shippingSummaryIsGone = TestSubscriber() - private val shippingSummaryLocation = TestSubscriber() - private val presentPaymentSheet = TestSubscriber>() - private val showPledgeError = TestSubscriber() - private val showPledgeSuccess = TestSubscriber>() - private val showSelectedCard = TestSubscriber>() - private val showSCAFlow = TestSubscriber() - private val showUpdatePaymentError = TestSubscriber() - private val showUpdatePaymentSuccess = TestSubscriber() - private val showUpdatePledgeError = TestSubscriber() - private val showUpdatePledgeSuccess = TestSubscriber() - private val startChromeTab = TestSubscriber() - private val startLoginToutActivity = TestSubscriber() - private val totalAmount = TestSubscriber() - private val totalAndDeadline = TestSubscriber>() - private val totalAndDeadlineIsVisible = TestSubscriber() - private val totalDividerIsGone = TestSubscriber() - private val headerSectionIsGone = TestSubscriber() - private val bonusAmount = TestSubscriber() - private val decreaseBonusButtonIsEnabled = TestSubscriber() - private val isNoReward = TestSubscriber() - private val projectTitle = TestSubscriber() - private val rewardAndAddOns = TestSubscriber>() - private val headerSelectedItems = TestSubscriber>>() - private val shippingRuleStaticIsGone = TestSubscriber() - private val bonusSectionIsGone = TestSubscriber() - private val bonusSummaryIsGone = TestSubscriber() - private val shippingRule = TestSubscriber() - private val localPickUpIsGone = TestSubscriber() - private val localPickupName = TestSubscriber() - private val showError = TestSubscriber() - private val loadingState = TestSubscriber() - private val thirdPartyEvent = TestSubscriber() - private val pledgeAmountHeader = TestSubscriber() - private val disposables = CompositeDisposable() - - @After - fun cleanUp() { - disposables.clear() - } - private fun setUpEnvironment( - environment: Environment, - reward: Reward = RewardFactory.rewardWithShipping(), - project: Project = ProjectFactory.project(), - pledgeReason: PledgeReason = PledgeReason.PLEDGE, - addOns: List? = null - ) { - - val projectData = project.backing()?.let { - return@let ProjectData.builder() - .project(project) - .backing(it) - .build() - } ?: ProjectDataFactory.project( - project.toBuilder() - .deadline(this.deadline) - .build() - ) - - val bundle = Bundle() - bundle.putParcelable( - ArgumentsKey.PLEDGE_PLEDGE_DATA, - PledgeData.with( - PledgeFlowContext.forPledgeReason(pledgeReason), - projectData, - reward, - addOns, - ShippingRuleFactory.usShippingRule() - ) - ) - - bundle.putSerializable(ArgumentsKey.PLEDGE_PLEDGE_REASON, pledgeReason) - - this.vm = PledgeFragmentViewModel(environment, bundle) - - this.vm.outputs.addedCard().subscribe { this.addedCard.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.additionalPledgeAmount().subscribe { this.additionalPledgeAmount.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.additionalPledgeAmountIsGone().subscribe { this.additionalPledgeAmountIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.baseUrlForTerms().subscribe { this.baseUrlForTerms.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.cardsAndProject().subscribe { this.cardsAndProject.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.continueButtonIsEnabled().subscribe { this.continueButtonIsEnabled.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.continueButtonIsGone().subscribe { this.continueButtonIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.conversionText().subscribe { this.conversionText.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.conversionTextViewIsGone().subscribe { this.conversionTextViewIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.decreasePledgeButtonIsEnabled().subscribe { this.decreasePledgeButtonIsEnabled.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.estimatedDelivery().subscribe { this.estimatedDelivery.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.estimatedDeliveryInfoIsGone().subscribe { this.estimatedDeliveryInfoIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.increasePledgeButtonIsEnabled().subscribe { this.increasePledgeButtonIsEnabled.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.paymentContainerIsGone().subscribe { this.paymentContainerIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeAmount().subscribe { this.pledgeAmount.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeButtonCTA().subscribe { this.pledgeButtonCTA.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeButtonIsEnabled().subscribe { this.pledgeButtonIsEnabled.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeButtonIsGone().subscribe { this.pledgeButtonIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeHint().subscribe { this.pledgeHint.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeMaximum().subscribe { this.pledgeMaximum.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeMaximumIsGone().subscribe { this.pledgeMaximumIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeMinimum().subscribe { this.pledgeMinimum.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeProgressIsGone().subscribe { this.pledgeProgressIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeSectionIsGone().subscribe { this.pledgeSectionIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeSummaryAmount().map { normalizeCurrency(it) }.subscribe { this.pledgeSummaryAmount.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeSummaryIsGone().subscribe { this.pledgeSummaryIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeTextColor().subscribe { this.pledgeTextColor.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.projectCurrencySymbol().map { it.first.toString().trimAllWhitespace() }.subscribe { this.projectCurrencySymbol.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.rewardTitle().subscribe { this.rewardTitle.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.selectedShippingRule().subscribe { this.selectedShippingRule.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingAmount().map { normalizeCurrency(it) }.subscribe { this.shippingAmount.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingRulesAndProject().subscribe { this.shippingRuleAndProject.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingRulesSectionIsGone().subscribe { this.shippingRulesSectionIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingSummaryAmount().map { normalizeCurrency(it) }.subscribe { this.shippingSummaryAmount.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingSummaryIsGone().subscribe { this.shippingSummaryIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingSummaryLocation().subscribe { this.shippingSummaryLocation.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.presentPaymentSheet().subscribe { this.presentPaymentSheet.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showPledgeError().subscribe { this.showPledgeError.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showPledgeSuccess().subscribe { this.showPledgeSuccess.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showSelectedCard().subscribe { this.showSelectedCard.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showSCAFlow().subscribe { this.showSCAFlow.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showUpdatePaymentError().subscribe { this.showUpdatePaymentError.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showUpdatePaymentSuccess().subscribe { this.showUpdatePaymentSuccess.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showUpdatePledgeError().subscribe { this.showUpdatePledgeError.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showUpdatePledgeSuccess().subscribe { this.showUpdatePledgeSuccess.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.startChromeTab().subscribe { this.startChromeTab.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.startLoginToutActivity().subscribe { this.startLoginToutActivity.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.totalAmount().map { normalizeCurrency(it) }.subscribe { this.totalAmount.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.totalAndDeadline().subscribe { this.totalAndDeadline.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.totalAndDeadlineIsVisible().subscribe { this.totalAndDeadlineIsVisible.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.totalDividerIsGone().subscribe { this.totalDividerIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.headerSectionIsGone().subscribe { this.headerSectionIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.bonusAmount().subscribe { this.bonusAmount.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.decreaseBonusButtonIsEnabled().subscribe { this.decreaseBonusButtonIsEnabled.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.isNoReward().subscribe { this.isNoReward.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.projectTitle().subscribe { this.projectTitle.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.rewardAndAddOns().subscribe { this.rewardAndAddOns.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.headerSelectedItems().subscribe { this.headerSelectedItems.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingRuleStaticIsGone().subscribe { this.shippingRuleStaticIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.isBonusSupportSectionGone().subscribe { this.bonusSectionIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.bonusSummaryIsGone().subscribe { this.bonusSummaryIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.shippingRule().subscribe { this.shippingRule.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.localPickUpIsGone().subscribe { this.localPickUpIsGone.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.localPickUpName().subscribe { this.localPickupName.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.showError().subscribe { this.showError.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.setState().subscribe { this.loadingState.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.eventSent().subscribe { this.thirdPartyEvent.onNext(it) }.addToDisposable(disposables) - this.vm.outputs.pledgeAmountHeader().subscribe { this.pledgeAmountHeader.onNext(it.toString()) }.addToDisposable(disposables) - } - - @Test - fun testBaseUrlForTerms() { - setUpEnvironment( - environment().toBuilder() - .webEndpoint("www.test.dev") - .build() - ) - - this.baseUrlForTerms.assertValue("www.test.dev") - } - - @Test - fun testThirdPartyEventAddPaymentMethodSent_withFeatureFlagsOn_ConsentManagement_On() { - var sharedPreferences: SharedPreferences = Mockito.mock(SharedPreferences::class.java) - Mockito.`when`(sharedPreferences.getBoolean(SharedPreferenceKey.CONSENT_MANAGEMENT_PREFERENCE, false)).thenReturn(true) - - val card = StoredCardFactory.discoverCard() - val mockCurrentUser = MockCurrentUserV2(UserFactory.user()) - val project = ProjectFactory.project().toBuilder() - .deadline(this.deadline) - .build() - - val mockFeatureFlagClient: MockFeatureFlagClient = - object : MockFeatureFlagClient() { - override fun getBoolean(FlagKey: FlagKey): Boolean { - return true - } - } - - val environment = environment() - .toBuilder() - .sharedPreferences(sharedPreferences) - .currentUserV2(mockCurrentUser) - .featureFlagClient(mockFeatureFlagClient) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(card)) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - - override fun triggerThirdPartyEvent(eventInput: TPEventInputData): Observable> { - return Observable.just(Pair(true, "")) - } - }).build() - - setUpEnvironment(environment, project = project) - - this.cardsAndProject.assertValue(Pair(listOf(card), project)) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - val visa = StoredCardFactory.visa() - this.vm.inputs.cardSaved(visa) - this.vm.inputs.addedCardPosition(0) - - this.cardsAndProject.assertValue(Pair(Collections.singletonList(card), project)) - this.addedCard.assertValue(Pair(visa, project)) - this.showSelectedCard.assertValues(Pair(0, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - thirdPartyEvent.assertValue(true) - } - @Test - fun testCards_whenLoggedIn_userHasCards() { - val card = StoredCardFactory.discoverCard() - val mockCurrentUser = MockCurrentUserV2(UserFactory.user()) - val project = ProjectFactory.project().toBuilder() - .deadline(this.deadline) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(mockCurrentUser) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(card)) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }).build() - - setUpEnvironment(environment, project = project) - - this.cardsAndProject.assertValue(Pair(Collections.singletonList(card), project)) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - val visa = StoredCardFactory.visa() - this.vm.inputs.cardSaved(visa) - this.vm.inputs.addedCardPosition(0) - - this.cardsAndProject.assertValue(Pair(Collections.singletonList(card), project)) - this.addedCard.assertValue(Pair(visa, project)) - this.showSelectedCard.assertValues(Pair(0, CardState.SELECTED), Pair(0, CardState.SELECTED)) - } - - @Test - fun testCards_whenLoggedIn_userHasCards_firstCardIsNotAllowed() { - val allowedCard = StoredCardFactory.visa() - val storedCards = listOf(StoredCardFactory.discoverCard(), allowedCard, StoredCardFactory.visa()) - val mockCurrentUser = MockCurrentUserV2(UserFactory.user()) - val project = ProjectFactory.mxProject().toBuilder() - .deadline(this.deadline) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(mockCurrentUser) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .build() - - setUpEnvironment(environment, project = project) - - this.cardsAndProject.assertValue(Pair(storedCards, project)) - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - val visa = StoredCardFactory.visa() - this.vm.inputs.cardSaved(visa) - this.vm.inputs.addedCardPosition(0) - - this.cardsAndProject.assertValue(Pair(storedCards, project)) - this.addedCard.assertValue(Pair(visa, project)) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - } - - @Test - fun testCards_whenLoggedIn_userHasCards_noAllowedCards() { - val storedCards = listOf(StoredCardFactory.discoverCard()) - val mockCurrentUser = MockCurrentUserV2(UserFactory.user()) - val project = ProjectFactory.mxProject().toBuilder() - .deadline(this.deadline) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(mockCurrentUser) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .build() - - setUpEnvironment(environment, project = project) - - this.cardsAndProject.assertValue(Pair(storedCards, project)) - this.showSelectedCard.assertNoValues() - - val visa = StoredCardFactory.visa() - this.vm.inputs.cardSaved(visa) - this.vm.inputs.addedCardPosition(0) - - this.cardsAndProject.assertValue(Pair(storedCards, project)) - this.addedCard.assertValue(Pair(visa, project)) - this.showSelectedCard.assertValues(Pair(0, CardState.SELECTED)) - } - - @Test - fun testCards_whenLoggedIn_userHasNoCards() { - val mockCurrentUser = MockCurrentUserV2(UserFactory.user()) - val project = ProjectFactory.project().toBuilder() - .deadline(this.deadline) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(mockCurrentUser) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(emptyList()) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .build() - - setUpEnvironment(environment, project = project) - - this.cardsAndProject.assertValue(Pair(Collections.emptyList(), project)) - this.showSelectedCard.assertNoValues() - this.pledgeButtonIsEnabled.assertValue(false) - - val visa = StoredCardFactory.visa() - this.vm.inputs.cardSaved(visa) - this.vm.inputs.addedCardPosition(0) - - this.cardsAndProject.assertValue(Pair(Collections.emptyList(), project)) - this.addedCard.assertValue(Pair(visa, project)) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - } - - @Test - fun testCards_whenLoggedIn_userBackedProject() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - val storedCards = testData.storedCards - val shippingRulesEnvelope = testData.shippingRulesEnvelope as ShippingRulesEnvelope - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.cardsAndProject.assertValue(Pair(storedCards, backedProject)) - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - val visa = StoredCardFactory.visa() - this.vm.inputs.cardSaved(visa) - this.vm.inputs.addedCardPosition(0) - - this.cardsAndProject.assertValue(Pair(storedCards, backedProject)) - this.addedCard.assertValue(Pair(visa, backedProject)) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - } - - @Test - fun testCards_whenLoggedOut() { - setUpEnvironment(environment()) - - this.cardsAndProject.assertNoValues() - this.showSelectedCard.assertNoValues() - } - - @Test - fun testPaymentLoggingInUser_whenPhysicalReward() { - val mockCurrentUser = MockCurrentUserV2() - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(Collections.emptyList()) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(mockCurrentUser) - .build() - setUpEnvironment(environment) - - this.cardsAndProject.assertNoValues() - this.continueButtonIsGone.assertValue(false) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonIsGone.assertValue(true) - - mockCurrentUser.refresh(UserFactory.user()) - - this.cardsAndProject.assertValueCount(1) - this.continueButtonIsGone.assertValues(false, true) - this.paymentContainerIsGone.assertValues(true, false) - this.pledgeButtonIsGone.assertValues(true, false) - } - - @Test - fun testPaymentLoggingInUser_whenDigitalReward() { - val mockCurrentUser = MockCurrentUserV2() - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(Collections.emptyList()) - } - }) - .currentUserV2(mockCurrentUser) - .build() - - setUpEnvironment(environment, RewardFactory.reward()) - - this.cardsAndProject.assertNoValues() - this.continueButtonIsGone.assertValue(false) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonIsGone.assertValue(true) - - mockCurrentUser.refresh(UserFactory.user()) - - this.cardsAndProject.assertValueCount(1) - this.continueButtonIsGone.assertValues(false, true) - this.paymentContainerIsGone.assertValues(true, false) - this.pledgeButtonIsGone.assertValues(true, false) - } - - @Test - fun testPaymentLoggingInUser_whenLocalPickupReward() { - val mockCurrentUser = MockCurrentUserV2() - val environment = environment().toBuilder() - .currentUserV2(mockCurrentUser) - .build() - - setUpEnvironment(environment, RewardFactory.localReceiptLocation()) - - this.cardsAndProject.assertNoValues() - this.continueButtonIsGone.assertValue(false) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonIsGone.assertValue(true) - this.localPickupName.assertValue(RewardFactory.localReceiptLocation().localReceiptLocation()?.displayableName()) - this.localPickUpIsGone.assertValue(false) - - mockCurrentUser.refresh(UserFactory.user()) - - this.cardsAndProject.assertValueCount(1) - this.continueButtonIsGone.assertValues(false, true) - this.paymentContainerIsGone.assertValues(true, false) - this.pledgeButtonIsGone.assertValues(true, false) - this.localPickUpIsGone.assertValue(false) - this.localPickupName.assertValue(RewardFactory.localReceiptLocation().localReceiptLocation()?.displayableName()) - } - - @Test - fun testPledgeAmount_whenUpdatingPledge() { - val reward = RewardFactory.rewardWithShipping() - val backing = BackingFactory.backing() - .toBuilder() - .amount(40.0) - .shippingAmount(10f) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - setUpEnvironment(environment(), reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.pledgeAmount.assertValue("30") - } - - @Test - fun testPledgeScreenConfiguration_whenPledgingShippableRewardAndNotLoggedIn() { - - val mockCurrentUser = MockCurrentUserV2() - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(Collections.emptyList()) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(mockCurrentUser) - .build() - - setUpEnvironment(environment) - - this.continueButtonIsEnabled.assertValue(true) - this.continueButtonIsGone.assertValue(false) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonCTA.assertValue(R.string.Pledge) - this.pledgeButtonIsEnabled.assertNoValues() - this.pledgeButtonIsGone.assertValue(true) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(false) - this.pledgeSummaryIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(false) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertNoValues() - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenPledgingDigitalRewardAndNotLoggedIn() { - setUpEnvironment(environment(), reward = RewardFactory.noReward()) - - this.continueButtonIsEnabled.assertValue(true) - this.continueButtonIsGone.assertValue(false) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonCTA.assertValue(R.string.Pledge) - this.pledgeButtonIsEnabled.assertNoValues() - this.pledgeButtonIsGone.assertValue(true) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(false) - this.pledgeSummaryIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertValue(true) - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenPledgingShippableRewardAndLoggedIn() { - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonCTA.assertValue(R.string.Pledge) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(false) - this.shippingRulesSectionIsGone.assertValue(false) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertNoValues() - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenPledgingDigitalRewardAndLoggedIn() { - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, RewardFactory.noReward()) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonCTA.assertValue(R.string.Pledge) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(false) - this.pledgeSummaryIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(true) - this.headerSectionIsGone.assertValue(true) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertValue(true) - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenPledgingLocalPickupRewardAndLoggedIn() { - val reward = RewardFactory.localReceiptLocation() - val locationName = reward.localReceiptLocation()?.displayableName() - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, reward) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonCTA.assertValue(R.string.Pledge) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(true) - this.pledgeSummaryIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(false) - this.headerSectionIsGone.assertValue(false) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - this.localPickUpIsGone.assertValue(false) - this.localPickupName.assertValue(locationName) - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingPledgeOfShippableReward() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsEnabled.assertValue(false) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(true) - this.pledgeSummaryIsGone.assertValue(false) - this.bonusSectionIsGone.assertValue(false) - this.shippingRulesSectionIsGone.assertValues(false) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertNoValues() - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingPledgeOfDigitalReward() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsEnabled.assertValue(false) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(false) - this.pledgeSummaryIsGone.assertValue(false) - this.headerSectionIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertValue(true) - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingPledgeOfLocalReceiptReward() { - val testData = setUpBackedLocalPickUpTestData() - val backedProject = testData.project - val reward = testData.reward - val pickupName = reward.localReceiptLocation()?.displayableName() - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsEnabled.assertValue(false) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(false) - this.pledgeSummaryIsGone.assertValue(false) - this.headerSectionIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - this.localPickUpIsGone.assertValue(false) - this.localPickupName.assertValue(pickupName) - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingPaymentOfShippableReward() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - val shippingRulesEnvelope = testData.shippingRulesEnvelope as ShippingRulesEnvelope - - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertNoValues() - this.pledgeSummaryIsGone.assertValue(false) - this.shippingRulesSectionIsGone.assertValues(true) - this.totalDividerIsGone.assertValue(true) - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertNoValues() - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingPaymentOfDigitalReward() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertNoValues() - this.pledgeSummaryIsGone.assertValue(true) - this.headerSectionIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.selectedShippingRule.assertValueCount(1) - this.shippingSummaryIsGone.assertValues(true) - this.totalDividerIsGone.assertValue(true) - this.pledgeButtonIsEnabled.assertValue(true) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertValue(true) - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingPaymentOfLocalReceiptReward() { - val testData = setUpBackedLocalPickUpTestData() - val backedProject = testData.project - val reward = testData.reward - val pickupName = reward.localReceiptLocation()?.displayableName() - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertNoValues() - this.bonusSectionIsGone.assertNoValues() - this.pledgeSummaryIsGone.assertValue(false) - this.headerSectionIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.selectedShippingRule.assertValueCount(1) - this.shippingSummaryIsGone.assertValues(true) - this.totalDividerIsGone.assertValue(true) - this.pledgeButtonIsEnabled.assertValue(true) - this.localPickupName.assertValue(pickupName) - this.localPickUpIsGone.assertValue(false) - - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - } - - @Test - fun testPledgeScreenConfiguration_whenFixingPaymentOfShippableReward() { - val shippableReward = RewardFactory.rewardWithShipping() - val unitedStates = LocationFactory.unitedStates() - val shippingRule = ShippingRuleFactory.usShippingRule().toBuilder().location(unitedStates).build() - val backing = BackingFactory.backing() - .toBuilder() - .amount(50.0) - .location(unitedStates) - .locationId(unitedStates.id()) - .reward(shippableReward) - .rewardId(shippableReward.id()) - .shippingAmount(shippingRule.cost().toFloat()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val shippingRulesEnvelope = ShippingRulesEnvelopeFactory.shippingRules() - .toBuilder() - .shippingRules(listOf(ShippingRuleFactory.germanyShippingRule(), shippingRule)) - .build() - - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.FIX_PLEDGE) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeSectionIsGone.assertNoValues() - this.bonusSectionIsGone.assertNoValues() - this.pledgeSummaryIsGone.assertValue(false) - this.shippingRulesSectionIsGone.assertValues(true) - this.shippingSummaryIsGone.assertValue(false) - this.totalDividerIsGone.assertValue(true) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertNoValues() - - this.segmentTrack.assertNoValues() - } - - @Test - fun testPledgeScreenConfiguration_whenFixingPaymentOfDigitalReward() { - val noReward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .reward(noReward) - .rewardId(noReward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.FIX_PLEDGE) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(false) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeSectionIsGone.assertNoValues() - this.bonusSectionIsGone.assertNoValues() - this.pledgeSummaryIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.selectedShippingRule.assertValueCount(1) - this.shippingSummaryIsGone.assertValues(true) - this.bonusSummaryIsGone.assertValues(true) - this.totalDividerIsGone.assertValue(true) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertValue(true) - - this.segmentTrack.assertNoValues() - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingRewardToShippableReward() { - val shippableReward = RewardFactory.rewardWithShipping() - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, shippableReward, ProjectFactory.backedProject(), PledgeReason.UPDATE_REWARD) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(true) - this.bonusSectionIsGone.assertValue(false) - this.pledgeSummaryIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(false) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertNoValues() - - this.segmentTrack.assertNoValues() - } - - @Test - fun testPledgeScreenConfiguration_whenUpdatingRewardToDigitalReward() { - val noReward = RewardFactory.noReward() - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, noReward, ProjectFactory.backedProject(), PledgeReason.UPDATE_REWARD) - - this.continueButtonIsEnabled.assertNoValues() - this.continueButtonIsGone.assertValue(true) - this.paymentContainerIsGone.assertValue(true) - this.pledgeButtonCTA.assertValue(R.string.Confirm) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeButtonIsGone.assertValue(false) - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeProgressIsGone.assertNoValues() - this.pledgeSectionIsGone.assertValue(false) - this.pledgeSummaryIsGone.assertValue(true) - this.headerSectionIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.shippingSummaryIsGone.assertNoValues() - this.totalDividerIsGone.assertValue(false) - - this.localPickupName.assertNoValues() - this.localPickUpIsGone.assertValue(true) - - this.segmentTrack.assertNoValues() - } - - @Test - fun testPledgeSummaryAmount_whenUpatingPaymentMethod() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - - val environment = environment() - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.totalAmount.assertValue(expectedCurrency(environment, backedProject, 1.0)) - } - - @Test - fun testPledgeSummaryAmount_whenFixingPaymentMethod() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - - val environment = environment() - setUpEnvironment(environment, noReward, backedProject, PledgeReason.FIX_PLEDGE) - - this.totalAmount.assertValue(expectedCurrency(environment, backedProject, 1.0)) - } - - @Test - fun testPledgeSummaryAmount_whenFixingPaymentMethod_whenRewardAddOnShipping() { - val testData = setUpBackedRewardWithAddOnsAndShippingTestData() - val backedProject = testData.project - val reward = testData.reward - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .build() - setUpEnvironment(environment, reward, backedProject, PledgeReason.FIX_PLEDGE) - - this.totalAmount.assertValue(expectedCurrency(environment, backedProject, 40.0)) - } - - @Test - fun testTotalAmount_whenUpdatingPledge() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - val shippingRulesEnvelope = testData.shippingRulesEnvelope as ShippingRulesEnvelope - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .build() - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.totalAmount.assertValue(expectedCurrency(environment, backedProject, 50.0)) - } - - @Test - fun testTotalAmount_whenUpdatingPayment() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - val shippingRulesEnvelope = testData.shippingRulesEnvelope as ShippingRulesEnvelope - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .build() - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.totalAmount.assertValue(expectedCurrency(environment, backedProject, 50.0)) - } - - @Test - fun testTotalAmount_whenFixingPaymentMethod() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - val shippingRulesEnvelope = testData.shippingRulesEnvelope as ShippingRulesEnvelope - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.FIX_PLEDGE) - - this.totalAmount.assertValue(expectedCurrency(environment, backedProject, 50.0)) - } - - @Test - fun testTotalAmount_whenUpdatingReward() { - val reward = RewardFactory.rewardWithShipping() - val backedProject = ProjectFactory.backedProject() - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_REWARD) - - this.totalAmount.assertValue(expectedCurrency(environment, backedProject, 50.0)) - } - - @Test - fun testEstimatedDelivery_whenPhysicalReward() { - setUpEnvironment(environment()) - this.estimatedDelivery.assertValue(DateTimeUtils.estimatedDeliveryOn(RewardFactory.ESTIMATED_DELIVERY)) - this.estimatedDeliveryInfoIsGone.assertValue(false) - } - - @Test - fun testEstimatedDelivery_whenDigitalReward() { - setUpEnvironment(environment(), reward = RewardFactory.reward()) - - this.estimatedDelivery.assertValue(DateTimeUtils.estimatedDeliveryOn(RewardFactory.ESTIMATED_DELIVERY)) - this.estimatedDeliveryInfoIsGone.assertValue(false) - } - - @Test - fun testEstimatedDelivery_whenNoReward() { - setUpEnvironment(environment(), RewardFactory.noReward()) - - this.estimatedDelivery.assertNoValues() - this.estimatedDeliveryInfoIsGone.assertValue(true) - } - -// @Test TODO: Test for bonus input compose component -// fun testShowMaxPledge_USProject_USDPref() { -// val environment = environment() -// .toBuilder() -// .apolloClientV2(object : MockApolloClientV2() { -// override fun getStoredCards(): Observable> { -// return Observable.just(listOf(StoredCardFactory.visa())) -// } -// override fun getShippingRules(reward: Reward): Observable { -// return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) -// } -// }) -// .currentUserV2(MockCurrentUserV2(UserFactory.user())) -// .build() -// val project = ProjectFactory.project() -// val rw = RewardFactory.reward() -// setUpEnvironment(environment, rw, project) -// -// this.vm.inputs.bonusInput("999999") -// -// this.pledgeMaximumIsGone.assertValues(true, false) -// this.pledgeMaximum.assertValues("$9,950") // 10.000 - 20 : MAXUSD - REWARD.minimum -// } - - @Test - fun testUpdatingPledgeAmount_WithShippingChange_USProject_USDPref() { - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - val project = ProjectFactory.project() - setUpEnvironment(environment, project = project) - - val defaultRule = ShippingRuleFactory.usShippingRule() - this.selectedShippingRule.assertValues(defaultRule) - - assertInitialPledgeState_WithShipping() - assertInitialPledgeCurrencyStates_WithShipping_USProject(environment, project) - - val selectedRule = ShippingRuleFactory.germanyShippingRule() - this.vm.inputs.shippingRuleSelected(selectedRule) - - this.additionalPledgeAmountIsGone.assertValues(true) - this.additionalPledgeAmount.assertValues(expectedCurrency(environment, project, 0.0)) - this.continueButtonIsEnabled.assertNoValues() - this.conversionText.assertNoValues() - this.conversionTextViewIsGone.assertValues(true) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeHint.assertValue("20") - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeMinimum.assertValue(expectedCurrency(environment, project, 20.0)) - this.pledgeTextColor.assertValues(R.color.kds_create_700) - this.projectCurrencySymbol.assertValue("$") - this.selectedShippingRule.assertValues(defaultRule, selectedRule) - this.shippingAmount.assertValues( - expectedCurrency(environment, project, 30.0), - expectedCurrency(environment, project, 40.0) - ) - this.totalAmount.assertValues( - expectedCurrency(environment, project, 50.0), - expectedCurrency(environment, project, 60.0) - ) - this.totalAndDeadlineIsVisible.assertValueCount(2) - } - - @Test - fun testUpdatingPledgeAmount_WithStepper_MXProject_USDPref() { - val project = ProjectFactory.mxProject().toBuilder().currentCurrency("USD").build() - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, project = project) - - assertInitialPledgeState_WithShipping() - assertInitialPledgeCurrencyStates_WithShipping_MXProject(environment, project) - - this.continueButtonIsEnabled.assertNoValues() - this.conversionText.assertValues(expectedConvertedCurrency(environment, project, 50.0)) - this.conversionTextViewIsGone.assertValues(false) - - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeMinimum.assertValue(expectedCurrency(environment, project, 20.0)) - this.pledgeTextColor.assertValue(R.color.kds_create_700) - this.projectCurrencySymbol.assertValue("MX$") - this.shippingAmount.assertValue(expectedCurrency(environment, project, 30.0)) - this.totalAmount.assertValues(expectedCurrency(environment, project, 50.0)) - this.totalAndDeadline.assertValues(Pair(expectedCurrency(environment, project, 50.0), DateTimeUtils.longDate(this.deadline))) - this.totalAndDeadlineIsVisible.assertValueCount(1) - - this.continueButtonIsEnabled.assertNoValues() - this.conversionText.assertValues(expectedConvertedCurrency(environment, project, 50.0)) - this.conversionTextViewIsGone.assertValues(false) - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeHint.assertValue("20") - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeMinimum.assertValue(expectedCurrency(environment, project, 20.0)) - this.pledgeTextColor.assertValue(R.color.kds_create_700) - this.projectCurrencySymbol.assertValue("MX$") - this.shippingAmount.assertValue(expectedCurrency(environment, project, 30.0)) - this.totalAmount.assertValues(expectedCurrency(environment, project, 50.0)) - this.totalAndDeadline.assertValues(Pair(expectedCurrency(environment, project, 50.0), DateTimeUtils.longDate(this.deadline))) - this.totalAndDeadlineIsVisible.assertValueCount(1) - } - - @Test - fun testUpdatingPledgeAmount_WithShippingChange_MXProject_USDPref() { - val project = ProjectFactory.mxProject().toBuilder().currentCurrency("USD").build() - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, project = project) - - assertInitialPledgeState_WithShipping() - assertInitialPledgeCurrencyStates_WithShipping_MXProject(environment, project) - val initialRule = ShippingRuleFactory.usShippingRule() - this.selectedShippingRule.assertValues(initialRule) - - val selectedRule = ShippingRuleFactory.germanyShippingRule() - this.vm.inputs.shippingRuleSelected(selectedRule) - - this.additionalPledgeAmount.assertValue(expectedCurrency(environment, project, 0.0)) - this.additionalPledgeAmountIsGone.assertValues(true) - this.continueButtonIsEnabled.assertNoValues() - this.conversionText.assertValues( - expectedConvertedCurrency(environment, project, 50.0), - expectedConvertedCurrency(environment, project, 60.0) - ) - this.conversionTextViewIsGone.assertValues(false) - - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeHint.assertValue("20") - this.pledgeMaximumIsGone.assertValue(true) - this.pledgeMinimum.assertValue(expectedCurrency(environment, project, 20.0)) - this.pledgeTextColor.assertValue(R.color.kds_create_700) - this.projectCurrencySymbol.assertValue("MX$") - this.selectedShippingRule.assertValues(initialRule, selectedRule) - this.shippingAmount.assertValues( - expectedCurrency(environment, project, 30.0), - expectedCurrency(environment, project, 40.0) - ) - this.totalAmount.assertValues( - expectedCurrency(environment, project, 50.0), - expectedCurrency(environment, project, 60.00) - ) - this.totalAndDeadline.assertValues( - Pair(expectedCurrency(environment, project, 50.0), DateTimeUtils.longDate(this.deadline)), - Pair(expectedCurrency(environment, project, 60.00), DateTimeUtils.longDate(this.deadline)) - ) - this.totalAndDeadlineIsVisible.assertValueCount(2) - } - - @Test - fun testPledgeStepping_maxReward_USProject() { - val environment = environment() - val project = ProjectFactory.project() - setUpEnvironment(environment, RewardFactory.maxReward(Country.US), project) - -// this.additionalPledgeAmountIsGone.assertValuesAndClear(true) -// this.additionalPledgeAmount.assertValuesAndClear(expectedCurrency(environment, project, 0.0)) -// this.decreaseBonusButtonIsEnabled.assertValuesAndClear(false) -// this.increasePledgeButtonIsEnabled.assertValuesAndClear(false) - } - -// @Test TODO: Test form compose bonus amount component -// fun testPledgeStepping_maxReward_MXProject() { -// val environment = environment() -// val mxProject = ProjectFactory.mxProject() -// setUpEnvironment(environment, RewardFactory.maxReward(Country.MX), mxProject) -// -// this.additionalPledgeAmountIsGone.assertValue(true) -// this.additionalPledgeAmount.assertValue(expectedCurrency(environment, mxProject, 0.0)) -// this.decreaseBonusButtonIsEnabled.assertValue(false) -// this.increasePledgeButtonIsEnabled.assertValue(false) -// } - - @Test - fun testRefTagIsSent() { - val project = ProjectFactory.project() - val sharedPreferences: SharedPreferences = MockSharedPreferences() - val cookieManager = CookieManager() - - val environment = environment() - .toBuilder() - .cookieManager(cookieManager) - .sharedPreferences(sharedPreferences) - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - // Assert that stored cookie is passed in - TestCase.assertEquals(createBackingData.refTag, RefTag.discovery()) - return super.createBacking(createBackingData) - } - }) - .build() - - // Store discovery ref tag for project - RefTagUtils.storeCookie(RefTag.discovery(), project, cookieManager, sharedPreferences) - - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.vm.inputs.cardSelected(StoredCardFactory.visa(), 0) - this.pledgeButtonIsEnabled.assertValue(true) - this.vm.inputs.pledgeButtonClicked() - - this.segmentTrack.assertValues(EventName.PAGE_VIEWED.eventName, EventName.CTA_CLICKED.eventName) - } - - @Test - fun testRewardTitle_forRewardWithTitle() { - val reward = RewardFactory.reward() - .toBuilder() - .title("Coolest reward") - .build() - val backing = BackingFactory.backing() - .toBuilder() - .amount(20.0) - .shippingAmount(0f) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - setUpEnvironment(environment(), reward, backedProject, PledgeReason.PLEDGE) - - this.rewardTitle.assertValue("Coolest reward") - } - - @Test - fun testRewardTitle_forRewardWithNullTitle() { - val reward = RewardFactory.reward() - .toBuilder() - .title(null) - .build() - val backing = BackingFactory.backing() - .toBuilder() - .amount(20.0) - .shippingAmount(0f) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .name("Restart Your Computer") - .build() - - setUpEnvironment(environment(), reward, backedProject, PledgeReason.PLEDGE) - - this.rewardTitle.assertValue("Restart Your Computer") - } - - @Test - fun testRewardTitle_forNoReward() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .amount(20.0) - .shippingAmount(0f) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .name("Restart Your Computer") - .build() - - setUpEnvironment(environment(), reward, backedProject, PledgeReason.PLEDGE) - - this.rewardTitle.assertValue("Restart Your Computer") - } - - @Test - fun testShippingSummaryAmount_whenFixingPaymentMethod() { - val reward = RewardFactory.rewardWithShipping() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .shippingAmount(10f) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val environment = environment() - setUpEnvironment(environment, reward, backedProject, PledgeReason.FIX_PLEDGE) - - this.shippingSummaryAmount.assertValue(expectedCurrency(environment, backedProject, 10.0)) - } - - @Test - fun testShippingSummaryAmount_whenUpdatingPaymentMethod() { - val reward = RewardFactory.rewardWithShipping() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .locationId(ShippingRuleFactory.usShippingRule().location()?.id()) - .shippingAmount(10f) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val environment = environment() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.shippingSummaryAmount.assertValue(expectedCurrency(environment, backedProject, 10.0)) - } - - @Test - fun testUpdatePayment_whenAddonsWithRewardAndShipping_shouldEmitShippingRule() { - val reward = RewardFactory.rewardWithShipping() - val backing = BackingFactory.backing() - .toBuilder() - .addOns(listOf(RewardFactory.addOnMultiple())) - .amount(30.0) - .locationId(ShippingRuleFactory.usShippingRule().location()?.id()) - .shippingAmount(10f) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.shippingRule.assertValue(ShippingRuleFactory.usShippingRule()) - } - - @Test - fun testUpdatePayment_whenNoReward_shouldNotEmitShippingRule() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .locationId(ShippingRuleFactory.usShippingRule().location()?.id()) - .shippingAmount(10f) - .reward(RewardFactory.noReward()) - .rewardId(0) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val environment = environment() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.shippingRule.assertValueCount(1) - } - - @Test - fun testShippingSummaryLocation_whenUpdatingPaymentMethod() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - val shippingRulesEnvelope = testData.shippingRulesEnvelope as ShippingRulesEnvelope - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.shippingSummaryLocation.assertValue("Brooklyn, NY") - } - - @Test - fun testShippingSummaryLocation_whenFixingPaymentMethod() { - val testData = setUpBackedShippableRewardTestData() - val backedProject = testData.project - val shippableReward = testData.reward - val shippingRulesEnvelope = testData.shippingRulesEnvelope as ShippingRulesEnvelope - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, shippableReward, backedProject, PledgeReason.FIX_PLEDGE) - - this.shippingSummaryLocation.assertValue("Brooklyn, NY") - } - - @Test - fun testShippingRulesAndProject_whenPhysicalReward() { - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - val project = ProjectFactory.project().toBuilder() - .deadline(this.deadline) - .build() - setUpEnvironment(environment, project = project) - - val shippingRules = ShippingRulesEnvelopeFactory.shippingRules().shippingRules() - this.shippingRuleAndProject.assertValues(Pair.create(shippingRules, project)) - } - - @Test - fun testShippingRulesAndProject_whenNoReward() { - setUpEnvironment(environment(), RewardFactory.noReward()) - - this.shippingRuleAndProject.assertNoValues() - } - - @Test - fun testShippingRulesAndProject_whenDigitalReward() { - setUpEnvironment(environment(), RewardFactory.reward()) - - this.shippingRuleAndProject.assertNoValues() - } - - @Test - fun testShippingRulesAndProject_error() { - val environment = environment().toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.error(Throwable("error")) - } - }) - .build() - val project = ProjectFactory.project() - setUpEnvironment(environment, project = project) - - this.shippingRuleAndProject.assertNoValues() - this.totalAmount.assertValueCount(1) - } - - @Test - fun testPresentPaymentSheet_ForLoggedInUser() { - val project = ProjectFactory - .project().toBuilder() - .deadline(this.deadline) - .build() - - val clientSecretID = "clientSecretId" - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun createSetupIntent(project: Project?): Observable { - return Observable.just(clientSecretID) - } - }) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.loadingState.assertNoValues() - - // - Configure PaymentSheet - this.vm.inputs.newCardButtonClicked() - this.presentPaymentSheet.assertValue(Pair(clientSecretID, "some@email.com")) - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - this.pledgeButtonIsEnabled.assertValues(true, false) - this.loadingState.assertValues(State.LOADING) - - // - PaymentSheet presented - this.vm.inputs.paymentSheetPresented(true) - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.loadingState.assertValues(State.LOADING, State.DEFAULT) - } - - @Test - fun testPresentPaymentSheet_Error() { - val project = ProjectFactory - .project().toBuilder() - .deadline(this.deadline) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun createSetupIntent(project: Project?): Observable { - return Observable.error(Exception("Error Message")) - } - }) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.vm.inputs.newCardButtonClicked() - this.presentPaymentSheet.assertNoValues() - this.showError.assertValue("Error Message") - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.loadingState.assertValues(State.LOADING, State.DEFAULT) - - // - User hit button for second time - this.vm.inputs.newCardButtonClicked() - this.presentPaymentSheet.assertNoValues() - this.showError.assertValues("Error Message", "Error Message") - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - this.pledgeButtonIsEnabled.assertValues(true, false, true, false, true) - this.loadingState.assertValues(State.LOADING, State.DEFAULT, State.LOADING, State.DEFAULT) - } - - @Test - fun testPresentPaymentSheet_whenFixingPaymentMethod() { - val backedProject = ProjectFactory.backedProject() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), backedProject, PledgeReason.FIX_PLEDGE) - - this.vm.inputs.newCardButtonClicked() - this.presentPaymentSheet.assertValue(Pair("", "some@email.com")) - this.segmentTrack.assertNoValues() - this.pledgeButtonIsEnabled.assertValues(false, false) - this.loadingState.assertValues(State.LOADING) - - // - PaymentSheet presented - this.vm.inputs.paymentSheetPresented(true) - this.pledgeButtonIsEnabled.assertValues(false, false, true) - this.loadingState.assertValues(State.LOADING, State.DEFAULT) - } - - @Test - fun testPresentPaymentSheet_whenUpdatingPaymentMethod() { - val backedProject = ProjectFactory.backedProjectWithNoReward() - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), backedProject, PledgeReason.UPDATE_PAYMENT) - - this.vm.inputs.newCardButtonClicked() - this.presentPaymentSheet.assertValue(Pair("", "some@email.com")) - this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName) - this.pledgeButtonIsEnabled.assertValues(true, false) - this.loadingState.assertValues(State.LOADING) - - // - PaymentSheet presented - this.vm.inputs.paymentSheetPresented(true) - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.loadingState.assertValues(State.LOADING, State.DEFAULT) - } - - @Test - fun testShowUpdatePaymentError_whenUpdatingPaymentMethod() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - val storedCards = testData.storedCards - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.error(Exception("womp")) - } - }).build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - this.vm.inputs.cardSelected(storedCards[0], 0) - - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showUpdatePaymentError.assertValueCount(1) - } - - @Test - fun testShowUpdatePaymentError_whenFixingPaymentMethod() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - val storedCards = testData.storedCards - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.error(Exception("womp")) - } - }).build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.FIX_PLEDGE) - - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - this.vm.inputs.cardSelected(storedCards[0], 0) - - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showUpdatePaymentError.assertValueCount(1) - - this.segmentTrack.assertValue(EventName.CTA_CLICKED.eventName) - } - - @Test - fun testShowUpdatePaymentSuccess_whenUpdatingPaymentMethod() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - val storedCards = testData.storedCards - - val checkout = Checkout.builder().backing(Checkout.Backing.builder().requiresAction(false).clientSecret("client").build()).build() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(checkout) - } - }) - .build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - this.vm.inputs.cardSelected(storedCards[0], 0) - - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showUpdatePaymentSuccess.assertValueCount(1) - } - - @Test - fun testShowUpdatePaymentSuccess_whenFixingPaymentMethod() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - val storedCards = testData.storedCards - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(Checkout.Builder().backing(Checkout.Backing.builder().clientSecret("").requiresAction(false).build()).build()) - } - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.FIX_PLEDGE) - - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - this.vm.inputs.cardSelected(storedCards[0], 0) - - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showUpdatePaymentSuccess.assertValueCount(1) - - this.segmentTrack.assertValue(EventName.CTA_CLICKED.eventName) - } - - @Test - fun testShowUpdatePaymentSuccess_whenRequiresAction_isSuccessful_successOutcome() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - val storedCards = testData.storedCards - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }).build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - this.vm.inputs.cardSelected(storedCards[0], 0) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePaymentError.assertNoValues() - this.showUpdatePaymentSuccess.assertNoValues() - - this.vm.inputs.stripeSetupResultSuccessful(StripeIntentResult.Outcome.SUCCEEDED) - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePaymentError.assertNoValues() - this.showUpdatePaymentSuccess.assertValueCount(1) - } - - @Test - fun testShowUpdatePaymentSuccess_whenRequiresAction_isSuccessful_unsuccessfulOutcome() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - val storedCards = testData.storedCards - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }).build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - this.vm.inputs.cardSelected(storedCards[0], 0) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePaymentError.assertNoValues() - this.showUpdatePaymentSuccess.assertNoValues() - - this.vm.inputs.stripeSetupResultSuccessful(StripeIntentResult.Outcome.FAILED) - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePaymentError.assertValueCount(1) - this.showUpdatePaymentSuccess.assertNoValues() - } - - @Test - fun testShowUpdatePaymentSuccess_whenRequiresAction_isUnsuccessful() { - val testData = setUpBackedNoRewardTestData() - val backedProject = testData.project - val noReward = testData.reward - val storedCards = testData.storedCards - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }).build() - - setUpEnvironment(environment, noReward, backedProject, PledgeReason.UPDATE_PAYMENT) - - this.showSelectedCard.assertValue(Pair(1, CardState.SELECTED)) - - this.vm.inputs.cardSelected(storedCards[0], 0) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePaymentError.assertNoValues() - this.showUpdatePaymentSuccess.assertNoValues() - - this.vm.inputs.stripeSetupResultUnsuccessful(Exception("eek")) - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showSelectedCard.assertValues(Pair(1, CardState.SELECTED), Pair(0, CardState.SELECTED)) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePaymentError.assertValueCount(1) - this.showUpdatePaymentSuccess.assertNoValues() - } - - @Test - fun testShowUpdatePledgeError_whenUpdatingPledgeWithShipping() { - val reward = RewardFactory.rewardWithShipping() - val unitedStates = LocationFactory.unitedStates() - val backingShippingRule = ShippingRuleFactory.usShippingRule().toBuilder().location(unitedStates).build() - val backing = BackingFactory.backing() - .toBuilder() - .amount(40.0) - .location(unitedStates) - .locationId(unitedStates.id()) - .reward(reward) - .rewardId(reward.id()) - .shippingAmount(backingShippingRule.cost().toFloat()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val germanyShippingRule = ShippingRuleFactory.germanyShippingRule() - val shippingRulesEnvelope = ShippingRulesEnvelopeFactory.shippingRules() - .toBuilder() - .shippingRules(listOf(germanyShippingRule, backingShippingRule)) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.error(Exception("womp")) - } - }) - .build() - - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.vm.inputs.shippingRuleSelected(germanyShippingRule) - this.vm.inputs.pledgeButtonClicked() - - this.showUpdatePledgeError.assertValueCount(1) - } - - @Test - fun testShowUpdatePledgeError_whenUpdatingPledgeWithNoShipping() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.error(Exception("womp")) - } - }) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.vm.inputs.pledgeInput("31") - this.vm.inputs.increasePledgeButtonClicked() - this.vm.inputs.pledgeButtonClicked() - - this.showUpdatePledgeError.assertValueCount(1) - this.pledgeButtonIsEnabled.assertValues(false, true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - } - - @Test - fun testShowUpdatePledgeError_whenUpdatingRewardWithShipping() { - val envelope = ShippingRulesEnvelopeFactory.shippingRules() - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.error(Exception("womp")) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(envelope) - } - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, project = ProjectFactory.backedProject(), pledgeReason = PledgeReason.UPDATE_REWARD) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showUpdatePledgeError.assertValueCount(1) - } - - @Test - fun testShowUpdatePledgeError_whenUpdatingRewardWithNoShipping() { - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.error(Exception("womp")) - } - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - - setUpEnvironment(environment, RewardFactory.noReward(), ProjectFactory.backedProject(), PledgeReason.UPDATE_REWARD) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showUpdatePledgeError.assertValueCount(1) - } - - @Test - fun testShowUpdatePledgeSuccess_whenUpdatingPledgeWithShipping() { - val reward = RewardFactory.rewardWithShipping() - val unitedStates = LocationFactory.unitedStates() - val backingShippingRule = ShippingRuleFactory.usShippingRule().toBuilder().location(unitedStates).build() - val backing = BackingFactory.backing() - .toBuilder() - .amount(40.0) - .location(unitedStates) - .locationId(unitedStates.id()) - .reward(reward) - .rewardId(reward.id()) - .shippingAmount(backingShippingRule.cost().toFloat()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val germanyShippingRule = ShippingRuleFactory.germanyShippingRule() - val shippingRulesEnvelope = ShippingRulesEnvelopeFactory.shippingRules() - .toBuilder() - .shippingRules(listOf(germanyShippingRule, backingShippingRule)) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .build() - - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.vm.inputs.shippingRuleSelected(germanyShippingRule) - this.vm.inputs.pledgeButtonClicked() - - this.pledgeProgressIsGone.assertValues(false) - } - - @Test - fun testShowUpdatePledgeSuccess_whenUpdatingPledgeWithNoShipping() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .availableCardTypes(listOf(CreditCardTypes.VISA.rawValue)) - .backing(backing) - .build() - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just( - Checkout.builder() - .backing(Checkout.Backing.builder().clientSecret("secret").requiresAction(false).build()) - .id(3) - .build() - ) - } - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .build() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.vm.inputs.pledgeInput("32.0") - this.vm.inputs.increasePledgeButtonClicked() - this.vm.inputs.increasePledgeButtonClicked() - this.vm.inputs.pledgeButtonClicked() - - this.totalAmount.assertValues("$1", "$32", "$33", "$34") - this.pledgeButtonIsEnabled.assertValues(false, true, false) - this.pledgeProgressIsGone.assertValue(false) - } - - @Test - fun testShowUpdatePledgeSuccess_whenUpdatingRewardWithShipping() { - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(Checkout.builder().backing(Checkout.Backing.builder().requiresAction(false).clientSecret("secret").build()).build()) - } - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - setUpEnvironment(environment, project = ProjectFactory.backedProject(), pledgeReason = PledgeReason.UPDATE_REWARD) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showUpdatePledgeSuccess.assertValueCount(1) - } - - @Test - fun testShowUpdatePledgeSuccess_whenUpdatingRewardWithNoShipping() { - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(Checkout.builder().backing(Checkout.Backing.builder().requiresAction(false).clientSecret("secret").build()).build()) - } - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, RewardFactory.noReward(), ProjectFactory.backedProject(), PledgeReason.UPDATE_REWARD) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showUpdatePledgeSuccess.assertValueCount(1) - } - - /* FIX TODO in https://kickstarter.atlassian.net/browse/NT-1462 - @Test - fun testShowUpdatePledgeSuccess_whenRequiresAction_isSuccessful_successOutcome() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val environment = environmentForLoggedInUser(UserFactory.user()) - .toBuilder() - .apolloClient(object : MockApolloClient() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }) - .build() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.vm.inputs.bonusInput("31") - this.vm.inputs.increaseBonusButtonClicked() - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(false) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePledgeError.assertNoValues() - this.showUpdatePledgeSuccess.assertNoValues() - - this.vm.inputs.stripeSetupResultSuccessful(StripeIntentResult.Outcome.SUCCEEDED) - - this.pledgeButtonIsEnabled.assertValues(false, false) - this.pledgeProgressIsGone.assertValues(false) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePledgeError.assertNoValues() - this.showUpdatePledgeSuccess.assertValueCount(1) - this.koalaTest.assertValues("Update Pledge Button Clicked") - } - - @Test - fun testShowUpdatePledgeSuccess_whenRequiresAction_isSuccessful_unsuccessfulOutcome() { - val testData = setUpBackedShippableRewardTestData() - - val environment = environmentForLoggedInUser(UserFactory.user()) - .toBuilder() - .apolloClient(object : MockApolloClient() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }) - .build() - setUpEnvironment(environment, testData.reward, testData.project, PledgeReason.UPDATE_PLEDGE) - - this.vm.inputs.bonusInput("31") - this.vm.inputs.increaseBonusButtonClicked() - - this.pledgeProgressIsGone.assertNoValues() - this.showSCAFlow.assertValueCount(1) - this.showUpdatePledgeError.assertNoValues() - this.showUpdatePledgeSuccess.assertNoValues() - this.pledgeButtonIsEnabled.assertValues(false) - - this.vm.inputs.stripeSetupResultSuccessful(StripeIntentResult.Outcome.FAILED) - - this.pledgeButtonIsEnabled.assertValues(false, true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePledgeError.assertValueCount(1) - this.showUpdatePledgeSuccess.assertNoValues() - this.koalaTest.assertValues("Update Pledge Button Clicked") - } - - @Test - fun testShowUpdatePledgeSuccess_whenRequiresAction_isUnsuccessful() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val environment = environmentForLoggedInUser(UserFactory.user()) - .toBuilder() - .apolloClient(object : MockApolloClient() { - override fun updateBacking(updateBackingData: UpdateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }) - .build() - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.vm.inputs.bonusInput("31") - this.vm.inputs.increaseBonusButtonClicked() - this.pledgeButtonIsEnabled.assertValues(false) - this.pledgeProgressIsGone.assertNoValues() - this.showSCAFlow.assertValueCount(1) - this.showUpdatePledgeError.assertNoValues() - this.showUpdatePledgeSuccess.assertNoValues() - - this.vm.inputs.stripeSetupResultUnsuccessful(Exception("woops")) - - this.pledgeButtonIsEnabled.assertValues(false, true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showSCAFlow.assertValueCount(1) - this.showUpdatePledgeError.assertValueCount(1) - this.showUpdatePledgeSuccess.assertNoValues() - this.koalaTest.assertValues("Update Pledge Button Clicked") - }*/ - - @Test - fun testStartChromeTab() { - setUpEnvironment( - environment().toBuilder() - .webEndpoint("www.test.dev") - .build() - ) - -// this.vm.inputs.linkClicked("www.test.dev/trust") -// this.startChromeTab.assertValuesAndClear("www.test.dev/trust") -// -// -// this.vm.inputs.linkClicked("www.test.dev/cookies") -// this.startChromeTab.assertValuesAndClear("www.test.dev/cookies") -// -// this.vm.inputs.linkClicked("www.test.dev/privacy") -// this.startChromeTab.assertValuesAndClear("www.test.dev/privacy") -// -// this.vm.inputs.linkClicked("www.test.dev/terms") -// this.startChromeTab.assertValuesAndClear("www.test.dev/terms") - } - - @Test - fun testStartLoginToutActivity() { - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .build() - setUpEnvironment(environment) - this.continueButtonIsEnabled.assertValue(true) - - this.vm.inputs.pledgeInput("1") - this.vm.inputs.increasePledgeButtonClicked() - this.continueButtonIsEnabled.assertValues(true) - - this.vm.inputs.pledgeInput("20") - this.vm.inputs.increasePledgeButtonClicked() - this.continueButtonIsEnabled.assertValues(true) - - this.vm.inputs.continueButtonClicked() - - this.startLoginToutActivity.assertValueCount(1) - } - - @Test - fun testShowPledgeSuccess_whenNoReward() { - val project = ProjectFactory.project() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - return Observable.just( - Checkout.builder() - .backing(Checkout.Backing.builder().clientSecret("secret").requiresAction(false).build()) - .id(3) - .build() - ) - } - }) - .build() - - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - this.pledgeButtonIsEnabled.assertValues(true) - this.vm.inputs.pledgeButtonClicked() - - // Successfully pledging with a valid amount should show the thanks page - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertValueCount(1) - this.showPledgeError.assertNoValues() - - this.segmentTrack.assertValues(EventName.PAGE_VIEWED.eventName, EventName.CTA_CLICKED.eventName) - } - - @Test - fun testShowPledgeSuccess_whenDigitalReward() { - val project = ProjectFactory.project() - val reward = RewardFactory.reward() - - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - return Observable.just(Checkout.builder().backing(Checkout.Backing.builder().requiresAction(false).clientSecret("secret").build()).build()) - } - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - - setUpEnvironment(environment, reward, project) - - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - this.pledgeButtonIsEnabled.assertValues(true) - this.vm.inputs.pledgeButtonClicked() - - // Successfully pledging with a valid amount should show the thanks page - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertValueCount(1) - this.showPledgeError.assertNoValues() - - this.segmentTrack.assertValues(EventName.PAGE_VIEWED.eventName, EventName.CTA_CLICKED.eventName) - } - - @Test - fun testShowPledgeSuccess_whenPhysicalReward() { - val project = ProjectFactory.project() - val reward = RewardFactory.rewardWithShipping() - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - return Observable.just(Checkout.builder().backing(Checkout.Backing.builder().requiresAction(false).clientSecret("secret").build()).build()) - } - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - setUpEnvironment(environment, reward, project) - - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - // Successfully pledging with a valid amount should show the thanks page - this.vm.inputs.pledgeButtonClicked() - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertValueCount(1) - this.showPledgeError.assertNoValues() - - this.pledgeButtonIsEnabled.assertValues(true, false) - - this.segmentTrack.assertValues(EventName.PAGE_VIEWED.eventName, EventName.CTA_CLICKED.eventName) - } - - @Test - fun testShowPledgeSuccess_error() { - val project = ProjectFactory.project() - - val storedCards = listOf(StoredCardFactory.visa()) - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val user = MockCurrentUserV2(UserFactory.user()) - - val environment = environment() - .toBuilder() - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - return Observable.error(Throwable("error")) - } - override fun getStoredCards(): Observable> { - return Observable.just(storedCards) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .currentConfig2(currentConfig) - .currentUserV2(user) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValueCount(2) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertValueCount(1) - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertValueCount(1) - this.showSCAFlow.assertNoValues() - - this.segmentTrack.assertValues( - EventName.PAGE_VIEWED.eventName, - EventName.CTA_CLICKED.eventName - ) - } - - @Test - fun testShowPledgeSuccess_whenRequiresAction_isSuccessful_successOutcome() { - val project = ProjectFactory.project() - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - this.pledgeButtonIsEnabled.assertValues(true) - this.vm.inputs.pledgeButtonClicked() - - this.pledgeProgressIsGone.assertValue(false) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertNoValues() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValue(false) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertNoValues() - this.showSCAFlow.assertValueCount(1) - - this.segmentTrack.assertValues(EventName.PAGE_VIEWED.eventName, EventName.CTA_CLICKED.eventName) - - this.vm.inputs.stripeSetupResultSuccessful(StripeIntentResult.Outcome.SUCCEEDED) - - this.showPledgeSuccess.assertValueCount(1) - this.showPledgeError.assertNoValues() - } - - @Test - fun testShowPledgeSuccess_whenRequiresAction_isSuccessful_unsuccessfulOutcome() { - val project = ProjectFactory.project() - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.pledgeButtonIsEnabled.assertValues(true) - - this.vm.inputs.pledgeButtonClicked() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValue(false) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertNoValues() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValue(false) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertNoValues() - this.showSCAFlow.assertValueCount(1) - - this.vm.inputs.stripeSetupResultSuccessful(StripeIntentResult.Outcome.FAILED) - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertValueCount(1) - - this.segmentTrack.assertValues(EventName.PAGE_VIEWED.eventName, EventName.CTA_CLICKED.eventName) - } - - @Test - fun testShowPledgeSuccess_whenRequiresAction_isUnsuccessful() { - val project = ProjectFactory.project() - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun createBacking(createBackingData: CreateBackingData): Observable { - return Observable.just(CheckoutFactory.requiresAction(true)) - } - }) - .build() - setUpEnvironment(environment, RewardFactory.noReward(), project) - - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - - this.pledgeButtonIsEnabled.assertValues(true) - this.vm.inputs.pledgeButtonClicked() - - this.pledgeProgressIsGone.assertValue(false) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertNoValues() - - this.pledgeButtonIsEnabled.assertValues(true, false) - this.pledgeProgressIsGone.assertValues(false) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertNoValues() - this.showSCAFlow.assertValueCount(1) - - this.vm.inputs.stripeSetupResultUnsuccessful(Exception("yikes")) - - this.pledgeButtonIsEnabled.assertValues(true, false, true) - this.pledgeProgressIsGone.assertValues(false, true) - this.showSelectedCard.assertValue(Pair(0, CardState.SELECTED)) - this.showPledgeSuccess.assertNoValues() - this.showPledgeError.assertValueCount(1) - - this.segmentTrack.assertValues(EventName.PAGE_VIEWED.eventName, EventName.CTA_CLICKED.eventName) - } - - @Test - fun testUpdatePledgeButtonIsEnabled_UpdatingPledge_whenShippingChanged() { - val reward = RewardFactory.rewardWithShipping() - val unitedStates = LocationFactory.unitedStates() - val backingShippingRule = ShippingRuleFactory.usShippingRule().toBuilder().location(unitedStates).build() - val backing = BackingFactory.backing() - .toBuilder() - .amount(50.0) - .location(unitedStates) - .locationId(unitedStates.id()) - .reward(reward) - .rewardId(reward.id()) - .shippingAmount(backingShippingRule.cost().toFloat()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val config = ConfigFactory.configForUSUser() - val currentConfig = MockCurrentConfigV2() - currentConfig.config(config) - - val germanyShippingRule = ShippingRuleFactory.germanyShippingRule() - val shippingRulesEnvelope = ShippingRulesEnvelopeFactory.shippingRules() - .toBuilder() - .shippingRules(listOf(germanyShippingRule, backingShippingRule)) - .build() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getStoredCards(): Observable> { - return Observable.just(listOf(StoredCardFactory.visa())) - } - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(shippingRulesEnvelope) - } - }) - .build() - - setUpEnvironment(environment, reward, backedProject, PledgeReason.UPDATE_PLEDGE) - - this.selectedShippingRule.assertValues(backingShippingRule) - this.pledgeButtonIsEnabled.assertValues(false) - - this.vm.inputs.shippingRuleSelected(germanyShippingRule) - this.selectedShippingRule.assertValues(backingShippingRule, germanyShippingRule) - this.pledgeButtonIsEnabled.assertValues(false) - - this.vm.inputs.shippingRuleSelected(backingShippingRule) - this.selectedShippingRule.assertValues(backingShippingRule, germanyShippingRule, backingShippingRule) - this.pledgeButtonIsEnabled.assertValues(false) - - this.vm.inputs.increaseBonusButtonClicked() - this.pledgeButtonIsEnabled.assertValues(false, true) - } - - @Test - fun testExpandableHeaderIsVisible() { - val reward = RewardFactory.reward() - val backing = BackingFactory.backing() - .toBuilder() - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - setUpEnvironment(environment(), reward, backedProject) - - this.headerSectionIsGone.assertValue(false) - this.isNoReward.assertNoValues() - } - - @Test - fun testNoRewardHeaderIsVisible() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - setUpEnvironment(environment(), reward, backedProject) - - this.headerSectionIsGone.assertValue(true) - this.shippingRulesSectionIsGone.assertValue(true) - this.shippingRuleStaticIsGone.assertValue(true) - this.isNoReward.assertValue(true) - this.projectTitle.assertValue(backedProject.name()) - } - - @Test - fun testExpandableHeaderIsNoVisible() { - val reward = RewardFactory.noReward() - val backing = BackingFactory.backing() - .toBuilder() - .reward(reward) - .rewardId(reward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - setUpEnvironment(environment(), reward, backedProject) - - this.headerSectionIsGone.assertValues(true) - } - - @Test - fun testTotalAmountUpdates_whenBonusIsAdded() { - val testData = setUpBackedShippableRewardTestData() - - val environment = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2(UserFactory.user())) - .apolloClientV2(object : MockApolloClientV2() { - override fun getShippingRules(reward: Reward): Observable { - return Observable.just(ShippingRulesEnvelopeFactory.shippingRules()) - } - }) - .build() - setUpEnvironment(environment, testData.reward, testData.project, PledgeReason.UPDATE_PLEDGE) - - this.totalAmount.assertValues("$50") - this.bonusAmount.assertValues("0.0") - } - - @Test - fun testRewardPlusAddons_inHeader() { - val reward = RewardFactory.rewardWithShipping().toBuilder() - .hasAddons(true) - .build() - val project = ProjectFactory.project() - .toBuilder() - .rewards(listOf(reward)) - .deadline(this.deadline) - .build() - - val addOn = RewardFactory.itemizedAddOn().toBuilder().quantity(2).build() - val listAddOns = listOf(addOn, addOn, addOn) - - setUpEnvironment(environment(), reward, project, addOns = listAddOns) - - this.shippingRuleStaticIsGone.assertValue(false) - this.shippingRulesSectionIsGone.assertValue(true) - this.rewardAndAddOns.assertValue(listOf(reward, addOn, addOn, addOn)) - this.headerSelectedItems.assertValue( - listOf( - Pair(project, reward), - Pair(project, addOn), - Pair(project, addOn), - Pair(project, addOn) - ) - ) - } - - @Test - fun total_whenShippableAddOns() { - val shipRule = ShippingRuleFactory.usShippingRule() - val reward = RewardFactory.rewardWithShipping().toBuilder() - .hasAddons(true) - .build() - val project = ProjectFactory.project() - .toBuilder() - .rewards(listOf(reward)) - .build() - - val addOn = RewardFactory.itemizedAddOn().toBuilder().quantity(2) - .shippingRules(listOf(ShippingRuleFactory.usShippingRule())) - .build() - val listAddOns = listOf(addOn, addOn, addOn) - - val environment = environment() - setUpEnvironment(environment, reward, project, addOns = listAddOns) - - this.vm.inputs.shippingRuleSelected(shipRule) - - this.totalAmount.assertValue("$290") - } - - @Test - fun total_whenShippableAddOns_differentShippingCost() { - val shipRule = ShippingRuleFactory.usShippingRule() - val reward = RewardFactory.rewardWithShipping().toBuilder() - .hasAddons(true) - .minimum(50.0) - .pledgeAmount(50.0) - .latePledgeAmount(60.0) - .build() - val project = ProjectFactory.project() - .toBuilder() - .rewards(listOf(reward)) - .build() - // - total rw = 50 + 30 = 80 - - val addOn = RewardFactory.itemizedAddOn().toBuilder().quantity(2) - .minimum(9.0) - .pledgeAmount(9.0) - .latePledgeAmount(10.0) - .shippingRules( - listOf( - ShippingRuleFactory.usShippingRule() - .toBuilder() - .cost(5.0) - .build() - ) - ) - .build() - // - total a1 = (9 + 5) * 2 = 28 - - val addOn2 = RewardFactory.itemizedAddOn().toBuilder().quantity(4) - .minimum(11.0) - .pledgeAmount(11.0) - .latePledgeAmount(15.0) - .shippingRules( - listOf( - ShippingRuleFactory.usShippingRule() - .toBuilder() - .cost(3.0) - .build() - ) - ) - .build() - // total a2 = (11 + 3) * 4 = 56 - - val addOn3 = RewardFactory.itemizedAddOn().toBuilder().quantity(10) - .minimum(15.0) - .pledgeAmount(15.0) - .latePledgeAmount(20.0) - .shippingRules( - listOf( - ShippingRuleFactory.usShippingRule() - .toBuilder() - .cost(10.0) - .build() - ) - ) - .build() - // total a3 = (15 + 10) * 10 = 250 - - val listAddOns = listOf(addOn, addOn2, addOn3) - - val environment = environment() - setUpEnvironment(environment, reward, project, addOns = listAddOns) - - this.vm.inputs.shippingRuleSelected(shipRule) - - this.totalAmount.assertValues("$414") - } - - @Test - fun total_whenShippableAddOns_differentShippingCost_AndBonus() { - val shipRule = ShippingRuleFactory.usShippingRule() - val reward = RewardFactory.rewardWithShipping().toBuilder() - .hasAddons(true) - .minimum(50.0) - .pledgeAmount(50.0) - .latePledgeAmount(60.0) - .build() - val project = ProjectFactory.project() - .toBuilder() - .rewards(listOf(reward)) - .build() - // - total rw = 50 + 30 = 80 - - val addOn = RewardFactory.itemizedAddOn().toBuilder().quantity(2) - .minimum(9.0) - .pledgeAmount(9.0) - .latePledgeAmount(10.0) - .shippingRules( - listOf( - ShippingRuleFactory.usShippingRule() - .toBuilder() - .cost(5.0) - .build() - ) - ) - .build() - // - total a1 = (9 + 5) * 2 = 28 - - val addOn2 = RewardFactory.itemizedAddOn().toBuilder().quantity(4) - .minimum(11.0) - .pledgeAmount(11.0) - .latePledgeAmount(12.0) - .shippingRules( - listOf( - ShippingRuleFactory.usShippingRule() - .toBuilder() - .cost(3.0) - .build() - ) - ) - .build() - // total a2 = (11 + 3) * 4 = 56 - - val addOn3 = RewardFactory.itemizedAddOn().toBuilder().quantity(10) - .minimum(15.0) - .pledgeAmount(15.0) - .latePledgeAmount(20.0) - .shippingRules( - listOf( - ShippingRuleFactory.usShippingRule() - .toBuilder() - .cost(10.0) - .build() - ) - ) - .build() - // total a3 = (15 + 10) * 10 = 250 - - val listAddOns = listOf(addOn, addOn2, addOn3) - - val environment = environment() - setUpEnvironment(environment, reward, project, addOns = listAddOns) - - this.totalAmount.assertValues( - "$414" - ) - } - - @Test - fun updateBackingDataFromPaymentSheet() { - setUpEnvironment(environment(), pledgeReason = PledgeReason.UPDATE_PAYMENT) - - val card = StoredCardFactory.fromPaymentSheetCard() - val backing = BackingFactory.backing() - val rewards = listOf(RewardFactory.reward(), RewardFactory.addOn()) - val updateBackingData = this.vm.getUpdateBackingData(backing, rewardsList = rewards, pMethod = card) - - assertTrue(updateBackingData.paymentSourceId == null) - assertTrue(updateBackingData.intentClientSecret == card.clientSetupId()) - } - - @Test - fun updateBackingDataFromPaymentSource() { - setUpEnvironment(environment(), pledgeReason = PledgeReason.UPDATE_PAYMENT) - - val card = StoredCardFactory.visa() - val backing = BackingFactory.backing() - val rewards = listOf(RewardFactory.reward(), RewardFactory.addOn()) - val updateBackingData = this.vm.getUpdateBackingData(backing, rewardsList = rewards, pMethod = card) - - assertTrue(updateBackingData.paymentSourceId == card.id()) - assertTrue(updateBackingData.intentClientSecret == card.clientSetupId()) - } - - @Test - fun updateBackingData_When_UpdatePledge() { - setUpEnvironment(environment(), pledgeReason = PledgeReason.UPDATE_PLEDGE) - - val backing = BackingFactory.backing() - val locationId = LocationFactory.germany().id() - val rewards = listOf(RewardFactory.reward(), RewardFactory.addOn()) - val updateBackingData = this.vm.getUpdateBackingData(backing, locationId = locationId.toString(), rewardsList = rewards) - - assertTrue(updateBackingData.paymentSourceId == null) - assertTrue(updateBackingData.intentClientSecret == null) - assertNotNull(updateBackingData.backing) - } - - @Test - fun `test_when_backing_is_not_late_pledge_then_pledge_amount_header_is_correct`() { - val shipRule = ShippingRuleFactory.usShippingRule() - val reward = RewardFactory.rewardWithShipping() - val backing = BackingFactory.backing() - .toBuilder() - .amount(20.0) - .shippingAmount(0f) - .reward(reward) - .rewardId(reward.id()) - .isPostCampaign(false) // original price from campaign should be used ($20) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - setUpEnvironment(environment(), reward, backedProject, PledgeReason.UPDATE_PAYMENT) - - vm.shippingRuleSelected(shipRule) - - // Reward amount is 20 with no shipping - this.pledgeAmountHeader.assertValues("$20") - } - - @Test - fun `test_when_backing_is_late_pledge_then_pledge_amount_header_is_correct`() { - val shipRule = ShippingRuleFactory.usShippingRule() - val reward = RewardFactory.rewardWithShipping() - val backing = BackingFactory.backing() - .toBuilder() - .amount(30.0) - .shippingAmount(0f) - .reward(reward) - .rewardId(reward.id()) - .isPostCampaign(true) // new price from late pledges should be used ($30) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - setUpEnvironment(environment(), reward, backedProject, PledgeReason.UPDATE_PAYMENT) - - vm.shippingRuleSelected(shipRule) - - // Reward amount for late pledge is 30 with no shipping - this.pledgeAmountHeader.assertValues("$30") - } - - private fun assertInitialPledgeCurrencyStates_NoShipping_USProject(environment: Environment, project: Project) { - this.additionalPledgeAmount.assertValue(expectedCurrency(environment, project, 0.0)) - this.conversionText.assertNoValues() - this.conversionTextViewIsGone.assertValues(true) - this.pledgeMaximumIsGone.assertValue(true) - this.projectCurrencySymbol.assertValue("$") - } - - private fun assertInitialPledgeCurrencyStates_WithShipping_MXProject(environment: Environment, project: Project) { - this.additionalPledgeAmount.assertValue(expectedCurrency(environment, project, 0.0)) - this.conversionText.assertValue(expectedConvertedCurrency(environment, project, 50.0)) - this.conversionTextViewIsGone.assertValues(false) - this.pledgeMaximumIsGone.assertValue(true) - this.projectCurrencySymbol.assertValue("MX$") - this.shippingAmount.assertValue(expectedCurrency(environment, project, 30.0)) - this.totalAmount.assertValues(expectedCurrency(environment, project, 50.0)) - this.totalAndDeadline.assertValue(Pair(expectedCurrency(environment, project, 50.0), DateTimeUtils.longDate(this.deadline))) - this.totalAndDeadlineIsVisible.assertValueCount(1) - } - - private fun assertInitialPledgeCurrencyStates_WithShipping_USProject(environment: Environment, project: Project) { - this.additionalPledgeAmount.assertValue(expectedCurrency(environment, project, 0.0)) - this.conversionText.assertNoValues() - this.conversionTextViewIsGone.assertValues(true) - this.pledgeMaximumIsGone.assertValue(true) - this.projectCurrencySymbol.assertValue("$") - this.shippingAmount.assertValue(expectedCurrency(environment, project, 30.0)) - this.totalAmount.assertValues(expectedCurrency(environment, project, 50.0)) - this.totalAndDeadline.assertValue(Pair(expectedCurrency(environment, project, 50.0), DateTimeUtils.longDate(this.deadline))) - this.totalAndDeadlineIsVisible.assertValueCount(1) - } - - private fun assertInitialPledgeState_NoShipping(environment: Environment, project: Project) { - this.additionalPledgeAmountIsGone.assertValue(true) - this.continueButtonIsEnabled.assertNoValues() - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeHint.assertValue("20") - this.pledgeTextColor.assertValue(R.color.kds_create_700) - this.shippingAmount.assertNoValues() - this.totalAmount.assertValues(expectedCurrency(environment, project, 20.0)) - this.totalAndDeadline.assertValue(Pair(expectedCurrency(environment, project, 20.0), DateTimeUtils.longDate(this.deadline))) - this.totalAndDeadlineIsVisible.assertValueCount(1) - } - - private fun assertInitialPledgeState_WithShipping() { - this.additionalPledgeAmountIsGone.assertValue(true) - this.continueButtonIsEnabled.assertNoValues() - this.pledgeButtonIsEnabled.assertValue(true) - this.pledgeTextColor.assertValue(R.color.kds_create_700) - } - - data class TestData( - val reward: Reward, - val project: Project, - val backing: Backing?, - val shippingRulesEnvelope: ShippingRulesEnvelope?, - val storedCards: List - ) - - private fun setUpBackedShippableRewardTestData(): TestData { - val backingCard = StoredCardFactory.visa() - val shippableReward = RewardFactory.rewardWithShipping() - val unitedStates = LocationFactory.unitedStates() - val shippingRule = ShippingRuleFactory.usShippingRule().toBuilder().location(unitedStates).build() - val storedCards = listOf(StoredCardFactory.discoverCard(), backingCard, StoredCardFactory.visa()) - val backing = BackingFactory.backing() - .toBuilder() - .amount(50.0) - .location(unitedStates) - .locationId(unitedStates.id()) - .paymentSource( - PaymentSourceFactory.visa() - .toBuilder() - .id(backingCard.id()) - .build() - ) - .reward(shippableReward) - .rewardId(shippableReward.id()) - .shippingAmount(shippingRule.cost().toFloat()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val shippingRulesEnvelope = ShippingRulesEnvelopeFactory.shippingRules() - .toBuilder() - .shippingRules(listOf(ShippingRuleFactory.germanyShippingRule(), shippingRule)) - .build() - - return TestData(shippableReward, backedProject, backing, shippingRulesEnvelope, storedCards) - } - - private fun setUpBackedRewardWithAddOnsAndShippingAndBonusAmountTestData(): TestData { - val backingCard = StoredCardFactory.visa() - val reward = RewardFactory.rewardWithShipping() - val addOns = RewardFactory.rewardWithShipping() - val bAmount = 2.0 - val storedCards = listOf(StoredCardFactory.discoverCard(), backingCard, StoredCardFactory.visa()) - val backing = BackingFactory.backing() - .toBuilder() - .paymentSource( - PaymentSourceFactory.visa() - .toBuilder() - .id(backingCard.id()) - .build() - ) - .bonusAmount(bAmount) - .reward(reward) - .rewardId(reward.id()) - .addOns(listOf(addOns)) - .build() - - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val shippingRulesEnvelope = ShippingRulesEnvelopeFactory.shippingRules() - .toBuilder() - .shippingRules(listOf(ShippingRuleFactory.usShippingRule(), ShippingRuleFactory.germanyShippingRule(), ShippingRuleFactory.mexicoShippingRule())) - .build() - - return TestData(reward, backedProject, backing, shippingRulesEnvelope, storedCards) - } - - private fun setUpBackedRewardWithAddOnsAndShippingTestData(): TestData { - val backingCard = StoredCardFactory.visa() - val reward = RewardFactory.rewardWithShipping() - val addOns = RewardFactory.rewardWithShipping() - val storedCards = listOf(StoredCardFactory.discoverCard(), backingCard, StoredCardFactory.visa()) - val backing = BackingFactory.backing() - .toBuilder() - .paymentSource( - PaymentSourceFactory.visa() - .toBuilder() - .id(backingCard.id()) - .build() - ) - .reward(reward) - .rewardId(reward.id()) - .addOns(listOf(addOns)) - .build() - - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - val shippingRulesEnvelope = ShippingRulesEnvelopeFactory.shippingRules() - .toBuilder() - .shippingRules(listOf(ShippingRuleFactory.usShippingRule(), ShippingRuleFactory.germanyShippingRule(), ShippingRuleFactory.mexicoShippingRule())) - .build() - - return TestData(reward, backedProject, backing, shippingRulesEnvelope, storedCards) - } - - private fun setUpBackedNoRewardTestData(): TestData { - val backingCard = StoredCardFactory.visa() - val noReward = RewardFactory.noReward() - val storedCards = listOf(StoredCardFactory.discoverCard(), backingCard, StoredCardFactory.visa()) - val backing = BackingFactory.backing() - .toBuilder() - .paymentSource( - PaymentSourceFactory.visa() - .toBuilder() - .id(backingCard.id()) - .build() - ) - .reward(noReward) - .rewardId(noReward.id()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - return TestData(noReward, backedProject, backing, null, storedCards) - } - - private fun setUpBackedLocalPickUpTestData(): TestData { - val backingCard = StoredCardFactory.visa() - val reward = RewardFactory.localReceiptLocation() - val storedCards = listOf(StoredCardFactory.discoverCard(), backingCard, StoredCardFactory.visa()) - val backing = BackingFactory.backing() - .toBuilder() - .paymentSource( - PaymentSourceFactory.visa() - .toBuilder() - .id(backingCard.id()) - .build() - ) - .reward(reward) - .rewardId(reward.id()) - .amount(reward.convertedMinimum()) - .build() - val backedProject = ProjectFactory.backedProject() - .toBuilder() - .backing(backing) - .build() - - return TestData(reward, backedProject, backing, null, storedCards) - } - - private fun expectedConvertedCurrency(environment: Environment, project: Project, amount: Double): String = - requireNotNull(environment.ksCurrency()).formatWithUserPreference(amount, project, RoundingMode.HALF_UP, 2) - - private fun expectedCurrency(environment: Environment, project: Project, amount: Double): String = - requireNotNull(environment.ksCurrency()).format(amount, project, RoundingMode.HALF_UP) - - private fun normalizeCurrency(spannedCurrencyString: CharSequence) = - spannedCurrencyString.toString().replace("\u00A0", " ") -}