Skip to content

Commit

Permalink
MBL-1403 Stripe Link (#2038)
Browse files Browse the repository at this point in the history
* Upgrade Stripe SDK to 20.42.0

* Pass in userEmail and add feature flag

* Fix feature gating logic

* Revert Link on Payment Methods Settings to match iOS and web behavior.

* Fix tests

* Lint

* Remove hardcoded flag value

* Comments
  • Loading branch information
ycheng-kickstarter authored May 16, 2024
1 parent 4ce4997 commit d407dc2
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 24 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ dependencies {
implementation "com.jakewharton.rxbinding:rxbinding-recyclerview-v7:$rx_binding_version"
implementation "com.jakewharton.rxbinding:rxbinding-support-v4:$rx_binding_version"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation 'com.stripe:stripe-android:20.16.1'
implementation 'com.stripe:stripe-android:20.42.0'
final okhttp_version = '4.10.+'
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttp_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ enum class FlagKey(val key: String) {
ANDROID_DARK_MODE_ENABLED("android_dark_mode_enabled"),
ANDROID_POST_CAMPAIGN_PLEDGES("android_post_campaign_pledges"),
ANDROID_OAUTH("android_oauth"),
ANDROID_ENCRYPT("android_encrypt_token")
ANDROID_ENCRYPT("android_encrypt_token"),
ANDROID_STRIPE_LINK("android_stripe_link")
}

fun FeatureFlagClient.getFetchInterval(): Long =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,25 @@ fun Context.showAlertDialog(
* Provides the configuration for the PaymentSheet, following the specs
* @see [link](https://stripe.com/docs/payments/accept-a-payment?platform=android&ui=elements#android-flowcontroller)
*/
fun Context.getPaymentSheetConfiguration(): PaymentSheet.Configuration {
fun Context.getPaymentSheetConfiguration(userEmail: String, alwaysHideLink: Boolean): PaymentSheet.Configuration {
val stripeLinkEnabled = this.getEnvironment()?.featureFlagClient()?.getBoolean(FlagKey.ANDROID_STRIPE_LINK) ?: false
val billingDetailsCollectionConfiguration =
if (alwaysHideLink || !stripeLinkEnabled) {
PaymentSheet.BillingDetailsCollectionConfiguration(
email = PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always // Turn off Link
)
} else {
PaymentSheet.BillingDetailsCollectionConfiguration(
email = PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Automatic
)
}

return PaymentSheet.Configuration(
merchantDisplayName = getString(R.string.app_name),
allowsDelayedPaymentMethods = true,
appearance = this.getPaymentSheetAppearance()
appearance = this.getPaymentSheetAppearance(),
defaultBillingDetails = PaymentSheet.BillingDetails(email = userEmail),
billingDetailsCollectionConfiguration = billingDetailsCollectionConfiguration
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class PaymentMethodsSettingsActivity : AppCompatActivity() {
private fun flowControllerPresentPaymentOption(clientSecret: String) {
flowController.configureWithSetupIntent(
setupIntentClientSecret = clientSecret,
configuration = this.getPaymentSheetConfiguration(),
configuration = this.getPaymentSheetConfiguration("", true), // Always hide Link on settings page
callback = ::onConfigured
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ class ProjectPageActivity :

LaunchedEffect(Unit) {
latePledgeCheckoutViewModel.clientSecretForNewPaymentMethod.collect {
flowControllerPresentPaymentOption(it)
flowControllerPresentPaymentOption(it, latePledgeCheckoutUIState.userEmail)
}
}

Expand Down Expand Up @@ -1262,10 +1262,10 @@ class ProjectPageActivity :
}
}

private fun flowControllerPresentPaymentOption(clientSecret: String) {
private fun flowControllerPresentPaymentOption(clientSecret: String, userEmail: String) {
flowController.configureWithSetupIntent(
setupIntentClientSecret = clientSecret,
configuration = getPaymentSheetConfiguration(),
configuration = getPaymentSheetConfiguration(userEmail, false),
callback = ::onConfigured
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ fun FormularyScreen(
value = outputs.email().subscribeAsState(initial = "").value,
onValueChange = {},
readOnly = true,
label = { Text(stringResource(id = R.string.email)) },
label = { Text(stringResource(id = R.string.Email)) },
colors = TextFieldDefaults.textFieldColors(
backgroundColor = colors.kds_support_200,
errorLabelColor = colors.kds_alert,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ fun ResetPasswordScreen(
)
)
.testTag(ResetPasswordTestTag.EMAIL.name),
label = stringResource(id = R.string.email),
label = stringResource(id = R.string.Email),
initialValue = initialEmail,
onValueChanged = { value ->
emailInput = value
Expand Down
10 changes: 5 additions & 5 deletions app/src/main/java/com/kickstarter/ui/fragments/PledgeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -583,9 +583,9 @@ class PledgeFragment :

this.viewModel.outputs.presentPaymentSheet()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
setupClientId = it
flowControllerPresentPaymentOption(it)
.subscribe { clientSecretAndUserEmail: Pair<String, String> ->
setupClientId = clientSecretAndUserEmail.first
flowControllerPresentPaymentOption(clientSecretAndUserEmail.first, clientSecretAndUserEmail.second)
}
.addToDisposable(disposables)

Expand Down Expand Up @@ -697,11 +697,11 @@ class PledgeFragment :
}
}

private fun flowControllerPresentPaymentOption(clientSecret: String) {
private fun flowControllerPresentPaymentOption(clientSecret: String, userEmail: String) {
context?.let {
flowController.configureWithSetupIntent(
setupIntentClientSecret = clientSecret,
configuration = it.getPaymentSheetConfiguration(),
configuration = it.getPaymentSheetConfiguration(userEmail, false),
callback = ::onConfigured
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fun TopToolBar(
) {
Icon(
imageVector = leftIcon,
contentDescription = stringResource(id = R.string.back),
contentDescription = stringResource(id = R.string.Back),
tint = leftIconColor ?: colors.kds_black
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fun SearchTopBar(
) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = stringResource(id = R.string.back),
contentDescription = stringResource(id = R.string.Back),
tint = colors.kds_black
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ interface PledgeFragmentViewModel {
fun localPickUpName(): Observable<String>

/** Emits the String with the SetupIntent ClientID to present the PaymentSheet **/
fun presentPaymentSheet(): Observable<String>
fun presentPaymentSheet(): Observable<Pair<String, String>>

fun showError(): Observable<String>

Expand Down Expand Up @@ -464,7 +464,7 @@ interface PledgeFragmentViewModel {
private val localPickUpIsGone = BehaviorSubject.create<Boolean>()
private val localPickUpName = BehaviorSubject.create<String>()

private val presentPaymentSheet = PublishSubject.create<String>()
private val presentPaymentSheet = PublishSubject.create<Pair<String, String>>()
private val paymentSheetResult = PublishSubject.create<PaymentSheetResult>()
private val paySheetPresented = PublishSubject.create<Boolean>()
private val showError = PublishSubject.create<String>()
Expand Down Expand Up @@ -1253,6 +1253,7 @@ interface PledgeFragmentViewModel {

shouldPresentPaymentSheet
.compose(valuesV2())
.compose(combineLatestPair(userEmail()))
.subscribe {
this.presentPaymentSheet.onNext(it)
}
Expand Down Expand Up @@ -1847,6 +1848,12 @@ interface PledgeFragmentViewModel {
.compose(neverErrorV2())
}

private fun userEmail(): Observable<String> {
return this.apolloClient.userPrivacy()
.compose(neverErrorV2())
.map { it.email }
}

override fun onCleared() {
disposables.clear()
super.onCleared()
Expand Down Expand Up @@ -2035,7 +2042,7 @@ interface PledgeFragmentViewModel {
override fun localPickUpName(): Observable<String> =
localPickUpName

override fun presentPaymentSheet(): Observable<String> =
override fun presentPaymentSheet(): Observable<Pair<String, String>> =
this.presentPaymentSheet

override fun showError(): Observable<String> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class PledgeFragmentViewModelTest : KSRobolectricTestCase() {
private val shippingSummaryAmount = TestSubscriber<CharSequence>()
private val shippingSummaryIsGone = TestSubscriber<Boolean>()
private val shippingSummaryLocation = TestSubscriber<String>()
private val presentPaymentSheet = TestSubscriber<String>()
private val presentPaymentSheet = TestSubscriber<Pair<String, String>>()
private val showPledgeError = TestSubscriber<Unit>()
private val showPledgeSuccess = TestSubscriber<Pair<CheckoutData, PledgeData>>()
private val showSelectedCard = TestSubscriber<Pair<Int, CardState>>()
Expand Down Expand Up @@ -1966,7 +1966,7 @@ class PledgeFragmentViewModelTest : KSRobolectricTestCase() {

// - Configure PaymentSheet
this.vm.inputs.newCardButtonClicked()
this.presentPaymentSheet.assertValue(clientSecretID)
this.presentPaymentSheet.assertValue(Pair(clientSecretID, "[email protected]"))
this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName)
this.pledgeButtonIsEnabled.assertValues(true, false)
this.loadingState.assertValues(State.LOADING)
Expand Down Expand Up @@ -2021,7 +2021,7 @@ class PledgeFragmentViewModelTest : KSRobolectricTestCase() {
setUpEnvironment(environment, RewardFactory.noReward(), backedProject, PledgeReason.FIX_PLEDGE)

this.vm.inputs.newCardButtonClicked()
this.presentPaymentSheet.assertValue("")
this.presentPaymentSheet.assertValue(Pair("", "[email protected]"))
this.segmentTrack.assertNoValues()
this.pledgeButtonIsEnabled.assertValues(false, false)
this.loadingState.assertValues(State.LOADING)
Expand All @@ -2042,7 +2042,7 @@ class PledgeFragmentViewModelTest : KSRobolectricTestCase() {
setUpEnvironment(environment, RewardFactory.noReward(), backedProject, PledgeReason.UPDATE_PAYMENT)

this.vm.inputs.newCardButtonClicked()
this.presentPaymentSheet.assertValue("")
this.presentPaymentSheet.assertValue(Pair("", "[email protected]"))
this.segmentTrack.assertValue(EventName.PAGE_VIEWED.eventName)
this.pledgeButtonIsEnabled.assertValues(true, false)
this.loadingState.assertValues(State.LOADING)
Expand Down

0 comments on commit d407dc2

Please sign in to comment.