Skip to content

Commit

Permalink
Move the sheetViewModel into the ComposeFormDataCollectionFragment.kt
Browse files Browse the repository at this point in the history
  • Loading branch information
michelleb-stripe committed Apr 28, 2022
1 parent 0bc4c1e commit d8fd1d1
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,50 +88,9 @@ internal abstract class BaseAddPaymentMethodFragment : Fragment() {
}
}

sheetViewModel.processing.observe(viewLifecycleOwner) { isProcessing ->
(getFragment() as? ComposeFormDataCollectionFragment)?.setProcessing(isProcessing)
}

// If the activity was destroyed and recreated then we need to re-attach the fragment,
// as attach will not be called again.
childFragmentManager.fragments.forEach { fragment ->
attachComposeFragmentViewModel(fragment)
}

childFragmentManager.addFragmentOnAttachListener { _, fragment ->
attachComposeFragmentViewModel(fragment)
}

sheetViewModel.eventReporter.onShowNewPaymentOptionForm()
}

override fun onStop() {
super.onStop()
composeFragmentFieldValues?.cancel()
}

private fun attachComposeFragmentViewModel(fragment: Fragment) {
composeFragmentFieldValues?.cancel()

(fragment as? ComposeFormDataCollectionFragment)?.let { formFragment ->
// Need to access the formViewModel so it is constructed.
val formViewModel = formFragment.formViewModel
composeFragmentFieldValues = viewLifecycleOwner.lifecycleScope.launch {
formViewModel.completeFormValues.collect { formFieldValues ->
// if the formFieldValues is a change either null or new values for the
// newLpm then we should clear it out --- but what happens if we cancel -- selection should
// have the correct value
sheetViewModel.updateSelection(
transformToPaymentSelection(
formFieldValues,
sheetViewModel.getAddFragmentSelectedLpmValue()
)
)
}
}
}
}

private fun setupRecyclerView(
viewBinding: FragmentPaymentsheetAddPaymentMethodBinding,
paymentMethods: List<SupportedPaymentMethod>,
Expand Down Expand Up @@ -172,6 +131,10 @@ internal abstract class BaseAddPaymentMethodFragment : Fragment() {
sheetViewModel.setAddFragmentSelectedLPM(paymentMethod)

val args = requireArguments()
args.putBoolean(
ComposeFormDataCollectionFragment.ACTIVITY_IS_PAYMENT_OPTIONS,
activity is PaymentOptionsActivity
)
args.putParcelable(
ComposeFormDataCollectionFragment.EXTRA_CONFIG,
getFormArguments(
Expand Down Expand Up @@ -236,42 +199,6 @@ internal abstract class BaseAddPaymentMethodFragment : Fragment() {
childFragmentManager.findFragmentById(R.id.payment_method_fragment_container)

companion object {
private val transformToPaymentMethodCreateParams = TransformToPaymentMethodCreateParams()

@VisibleForTesting
internal fun transformToPaymentSelection(
formFieldValues: FormFieldValues?,
selectedPaymentMethodResources: SupportedPaymentMethod,
) = formFieldValues?.let {
transformToPaymentMethodCreateParams.transform(
formFieldValues.copy(
fieldValuePairs = it.fieldValuePairs
.filterNot { entry ->
entry.key == IdentifierSpec.SaveForFutureUse ||
entry.key == IdentifierSpec.CardBrand
}
),
selectedPaymentMethodResources.type
).run {
if (selectedPaymentMethodResources.type == PaymentMethod.Type.Card) {
PaymentSelection.New.Card(
paymentMethodCreateParams = this,
brand = CardBrand.fromCode(
formFieldValues.fieldValuePairs[IdentifierSpec.CardBrand]?.value
),
customerRequestedSave = formFieldValues.userRequestedReuse

)
} else {
PaymentSelection.New.GenericPaymentMethod(
selectedPaymentMethodResources.displayNameResource,
selectedPaymentMethodResources.iconResource,
this,
customerRequestedSave = formFieldValues.userRequestedReuse
)
}
}
}

@VisibleForTesting
internal fun getFormArguments(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,31 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.stripe.android.model.CardBrand
import com.stripe.android.model.PaymentMethod
import com.stripe.android.paymentsheet.PaymentOptionsActivity
import com.stripe.android.paymentsheet.PaymentOptionsViewModel
import com.stripe.android.paymentsheet.PaymentSheetViewModel
import com.stripe.android.paymentsheet.forms.Form
import com.stripe.android.paymentsheet.forms.FormFieldValues
import com.stripe.android.paymentsheet.forms.FormViewModel
import com.stripe.android.paymentsheet.model.PaymentSelection
import com.stripe.android.paymentsheet.model.SupportedPaymentMethod
import com.stripe.android.ui.core.PaymentsTheme
import com.stripe.android.ui.core.elements.IdentifierSpec
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.launch

/**
* Fragment that displays a form for payment data collection based on the [SupportedPaymentMethod]
Expand Down Expand Up @@ -63,15 +77,83 @@ internal class ComposeFormDataCollectionFragment : Fragment() {
}
}

/**
* Informs the fragment whether PaymentSheet is in a processing state, so the fragment knows it
* should show its UI as enabled or disabled.
*/
fun setProcessing(processing: Boolean) {
formViewModel.setEnabled(!processing)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val sheetViewModel by if (activity is PaymentOptionsActivity) {
activityViewModels<PaymentOptionsViewModel>()
} else {
activityViewModels<PaymentSheetViewModel>()
}

viewLifecycleOwner.lifecycleScope.launch {
// The block passed to repeatOnLifecycle is executed when the lifecycle
// is at least STARTED and is cancelled when the lifecycle is STOPPED.
// It automatically restarts the block when the lifecycle is STARTED again.
formViewModel.completeFormValues
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collect { formFieldValues ->
// if the formFieldValues is a change either null or new values for the
// newLpm then we should clear it out --- but what happens if we cancel -- selection should
// have the correct value
sheetViewModel.updateSelection(
transformToPaymentSelection(
formFieldValues,
sheetViewModel.getAddFragmentSelectedLpmValue()
)
)
}
}


/**
* Informs the fragment whether PaymentSheet is in a processing state, so the fragment knows it
* should show its UI as enabled or disabled.
*/
sheetViewModel.processing.observe(viewLifecycleOwner) { processing ->
formViewModel.setEnabled(!processing)
}
}

@VisibleForTesting
internal fun transformToPaymentSelection(
formFieldValues: FormFieldValues?,
selectedPaymentMethodResources: SupportedPaymentMethod,
) = formFieldValues?.let {
transformToPaymentMethodCreateParams.transform(
formFieldValues.copy(
fieldValuePairs = it.fieldValuePairs
.filterNot { entry ->
entry.key == IdentifierSpec.SaveForFutureUse ||
entry.key == IdentifierSpec.CardBrand
}
),
selectedPaymentMethodResources.type
).run {
if (selectedPaymentMethodResources.type == PaymentMethod.Type.Card) {
PaymentSelection.New.Card(
paymentMethodCreateParams = this,
brand = CardBrand.fromCode(
formFieldValues.fieldValuePairs[IdentifierSpec.CardBrand]?.value
),
customerRequestedSave = formFieldValues.userRequestedReuse

)
} else {
PaymentSelection.New.GenericPaymentMethod(
selectedPaymentMethodResources.displayNameResource,
selectedPaymentMethodResources.iconResource,
this,
customerRequestedSave = formFieldValues.userRequestedReuse
)
}
}
}

internal companion object {
val ACTIVITY_IS_PAYMENT_OPTIONS =
"com.stripe.android.paymentsheet.activity_is_payment_options"
const val EXTRA_CONFIG = "com.stripe.android.paymentsheet.extra_config"

private val transformToPaymentMethodCreateParams = TransformToPaymentMethodCreateParams()
}
}

0 comments on commit d8fd1d1

Please sign in to comment.