Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for configuring a footer layout in payment methods screen #2895

Merged
merged 1 commit into from
Sep 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class PaymentSessionActivity : AppCompatActivity() {
return PaymentSession(
activity = this,
config = PaymentSessionConfig.Builder()
.setPaymentMethodsFooter(R.layout.add_payment_method_footer)
.setAddPaymentMethodFooter(R.layout.add_payment_method_footer)
.setPrepopulatedShippingInfo(EXAMPLE_SHIPPING_INFO)
.setHiddenShippingInfoFields()
Expand Down
11 changes: 10 additions & 1 deletion stripe/res/layout/payment_methods_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@
android:layout_below="@id/toolbar"
android:visibility="gone" />

<FrameLayout
android:id="@+id/footer_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone"/>

<com.stripe.android.view.PaymentMethodsRecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar"
android:layout_marginTop="@dimen/stripe_list_top_margin" />
android:layout_above="@+id/footer_container"
android:layout_marginTop="@dimen/stripe_list_top_margin"
android:layout_marginBottom="@dimen/stripe_list_top_margin"/>
</RelativeLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
1 change: 1 addition & 0 deletions stripe/res/values/ids.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
<item type="id" name="stripe_payment_methods_add_fpx" />
<item type="id" name="stripe_add_payment_method_form" />
<item type="id" name="stripe_add_payment_method_footer" />
<item type="id" name="stripe_payment_methods_footer" />
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ class PaymentSession @VisibleForTesting internal constructor(
.setInitialPaymentMethodId(
viewModel.getSelectedPaymentMethodId(selectedPaymentMethodId)
)
.setPaymentMethodsFooter(config.paymentMethodsFooterLayoutId)
.setAddPaymentMethodFooter(config.addPaymentMethodFooterLayoutId)
.setIsPaymentSessionActive(true)
.setPaymentConfiguration(PaymentConfiguration.getInstance(context))
Expand Down
20 changes: 20 additions & 0 deletions stripe/src/main/java/com/stripe/android/PaymentSessionConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@ data class PaymentSessionConfig internal constructor(
val prepopulatedShippingInfo: ShippingInformation? = null,
val isShippingInfoRequired: Boolean = false,
val isShippingMethodRequired: Boolean = false,

@LayoutRes
@get:LayoutRes
val paymentMethodsFooterLayoutId: Int = 0,

@LayoutRes
@get:LayoutRes
val addPaymentMethodFooterLayoutId: Int = 0,

val paymentMethodTypes: List<PaymentMethod.Type> = listOf(PaymentMethod.Type.Card),
val shouldShowGooglePay: Boolean = false,
val allowedShippingCountryCodes: Set<String> = emptySet(),
Expand Down Expand Up @@ -104,6 +110,9 @@ data class PaymentSessionConfig internal constructor(
private var shouldPrefetchCustomer: Boolean = true
private var canDeletePaymentMethods: Boolean = true

@LayoutRes
private var paymentMethodsFooterLayoutId: Int = 0

@LayoutRes
private var addPaymentMethodFooterLayoutId: Int = 0

Expand Down Expand Up @@ -164,6 +173,16 @@ data class PaymentSessionConfig internal constructor(
this.shippingMethodsRequired = shippingMethodsRequired
}

/**
* @param paymentMethodsFooterLayoutId optional layout id that will be inflated and
* displayed beneath the payment method selection list on [PaymentMethodsActivity]
*/
fun setPaymentMethodsFooter(
@LayoutRes paymentMethodsFooterLayoutId: Int
): Builder = apply {
this.paymentMethodsFooterLayoutId = paymentMethodsFooterLayoutId
}

/**
* @param addPaymentMethodFooterLayoutId optional layout id that will be inflated and
* displayed beneath the payment details collection form on [AddPaymentMethodActivity]
Expand Down Expand Up @@ -266,6 +285,7 @@ data class PaymentSessionConfig internal constructor(
prepopulatedShippingInfo = shippingInformation,
isShippingInfoRequired = shippingInfoRequired,
isShippingMethodRequired = shippingMethodsRequired,
paymentMethodsFooterLayoutId = paymentMethodsFooterLayoutId,
addPaymentMethodFooterLayoutId = addPaymentMethodFooterLayoutId,
paymentMethodTypes = paymentMethodTypes,
shouldShowGooglePay = shouldShowGooglePay,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ package com.stripe.android.view

import android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.text.util.Linkify
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.text.util.LinkifyCompat
import androidx.core.view.ViewCompat
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.snackbar.Snackbar
import com.stripe.android.CustomerSession
import com.stripe.android.R
import com.stripe.android.databinding.PaymentMethodsActivityBinding
import com.stripe.android.exception.StripeException
import com.stripe.android.model.PaymentMethod
Expand Down Expand Up @@ -114,6 +122,15 @@ class PaymentMethodsActivity : AppCompatActivity() {
setDisplayShowHomeEnabled(true)
}

createFooterView(viewBinding.footerContainer)?.let { footer ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
viewBinding.recycler.accessibilityTraversalBefore = footer.id
footer.accessibilityTraversalAfter = viewBinding.recycler.id
}
viewBinding.footerContainer.addView(footer)
viewBinding.footerContainer.visibility = View.VISIBLE
}

fetchCustomerPaymentMethods()

// This prevents the first click from being eaten by the focus.
Expand Down Expand Up @@ -260,6 +277,27 @@ class PaymentMethodsActivity : AppCompatActivity() {
finish()
}

private fun createFooterView(
contentRoot: ViewGroup
): View? {
return if (args.paymentMethodsFooterLayoutId > 0) {
val footerView = layoutInflater.inflate(
args.paymentMethodsFooterLayoutId,
contentRoot,
false
)
footerView.id = R.id.stripe_payment_methods_footer
if (footerView is TextView) {
LinkifyCompat.addLinks(footerView, Linkify.ALL)
ViewCompat.enableAccessibleClickableSpanSupport(footerView)
footerView.movementMethod = LinkMovementMethod.getInstance()
}
footerView
} else {
null
}
}

override fun onDestroy() {
viewModel.selectedPaymentMethodId = adapter.selectedPaymentMethod?.id
super.onDestroy()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class PaymentMethodsActivityStarter : ActivityStarter<PaymentMethodsActivity, Ar
@Parcelize
data class Args internal constructor(
internal val initialPaymentMethodId: String?,
@LayoutRes val paymentMethodsFooterLayoutId: Int,
@LayoutRes val addPaymentMethodFooterLayoutId: Int,
internal val isPaymentSessionActive: Boolean,
internal val paymentMethodTypes: List<PaymentMethod.Type>,
Expand All @@ -61,6 +62,9 @@ class PaymentMethodsActivityStarter : ActivityStarter<PaymentMethodsActivity, Ar
private var paymentConfiguration: PaymentConfiguration? = null
private var windowFlags: Int? = null

@LayoutRes
private var paymentMethodsFooterLayoutId: Int = 0

@LayoutRes
private var addPaymentMethodFooterLayoutId: Int = 0

Expand Down Expand Up @@ -113,6 +117,16 @@ class PaymentMethodsActivityStarter : ActivityStarter<PaymentMethodsActivity, Ar
this.shouldShowGooglePay = shouldShowGooglePay
}

/**
* @param paymentMethodsFooterLayoutId optional layout id that will be inflated and
* displayed beneath the payment method selection list on [PaymentMethodsActivity]
*/
fun setPaymentMethodsFooter(
@LayoutRes paymentMethodsFooterLayoutId: Int
): Builder = apply {
this.paymentMethodsFooterLayoutId = paymentMethodsFooterLayoutId
}

/**
* @param addPaymentMethodFooterLayoutId optional layout id that will be inflated and
* displayed beneath the payment details collection form on [AddPaymentMethodActivity]
Expand Down Expand Up @@ -148,6 +162,7 @@ class PaymentMethodsActivityStarter : ActivityStarter<PaymentMethodsActivity, Ar
shouldShowGooglePay = shouldShowGooglePay,
useGooglePay = useGooglePay,
paymentConfiguration = paymentConfiguration,
paymentMethodsFooterLayoutId = paymentMethodsFooterLayoutId,
addPaymentMethodFooterLayoutId = addPaymentMethodFooterLayoutId,
windowFlags = windowFlags,
billingAddressFields = billingAddressFields,
Expand Down