Skip to content

Commit

Permalink
[PaymentLauncher] Replace Stripe with PaymentLauncher in example …
Browse files Browse the repository at this point in the history
…app (#4125)

* change

* change
  • Loading branch information
ccen-stripe committed Aug 26, 2021
1 parent 4cc7dbe commit 8b77ca2
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 89 deletions.
1 change: 1 addition & 0 deletions example/AndroidManifest.xml
Expand Up @@ -65,6 +65,7 @@
<activity android:name=".activity.NetbankingPaymentActivity" />
<activity android:name=".activity.SimpleConfirmationActivity" />
<activity android:name=".activity.ConnectExampleActivity" />
<activity android:name=".activity.ComposeExampleActivity" />
</application>

</manifest>
15 changes: 15 additions & 0 deletions example/build.gradle
Expand Up @@ -57,6 +57,17 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion"


// Jetpack Compose
// Integration with activities
implementation 'androidx.activity:activity-compose:1.3.1'
// Compose Material Design
implementation "androidx.compose.material:material:$composeVersion"
// Integration with observables
implementation "androidx.compose.runtime:runtime-livedata:$composeVersion"
// end of Jetpack Compose


ktlint "com.pinterest:ktlint:$ktlintVersion"

testImplementation "androidx.test:core:$androidTestVersion"
Expand Down Expand Up @@ -158,6 +169,10 @@ android {

buildFeatures {
viewBinding true
compose true
}
composeOptions {
kotlinCompilerExtensionVersion "$composeVersion"
}
}

Expand Down
1 change: 1 addition & 0 deletions example/res/values/strings.xml
Expand Up @@ -91,6 +91,7 @@
<string name="confirm_with_netbanking">Confirm with NetBanking</string>
<string name="connect_example">Connect Example</string>
<string name="simple_payment_method_example">Simple PaymentMethod Confirmation Example</string>
<string name="compose_example">Compose Example</string>

<!-- <UPI> -->
<string name="vpa_layout_hint">Virtual Payment Address (VPA)</string>
Expand Down
@@ -0,0 +1,181 @@
package com.stripe.example.activity

import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Divider
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.stripe.android.model.Address
import com.stripe.android.model.ConfirmPaymentIntentParams
import com.stripe.android.model.PaymentMethodCreateParams
import com.stripe.android.payments.paymentlauncher.PaymentLauncher
import com.stripe.android.payments.paymentlauncher.PaymentResult
import com.stripe.example.R
import com.stripe.example.Settings
import com.stripe.example.module.StripeIntentViewModel

/**
* An Activity to demonstrate [PaymentLauncher] with Jetpack Compose.
*/
class ComposeExampleActivity : AppCompatActivity() {
private val viewModel: StripeIntentViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeScreen()
}
}

@Composable
fun ComposeScreen() {
val inProgress by viewModel.inProgress.observeAsState(false)
val status by viewModel.status.observeAsState("")

createPaymentLauncher().let { paymentLauncher ->
Column(modifier = Modifier.padding(horizontal = 10.dp)) {
if (inProgress) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
)
}
Text(
stringResource(R.string.payment_auth_intro),
modifier = Modifier.padding(vertical = 5.dp),
)
ConfirmButton(
params = confirmParams3ds1,
buttonName = R.string.confirm_with_3ds1_button,
paymentLauncher = paymentLauncher,
inProgress = inProgress
)
ConfirmButton(
params = confirmParams3ds2,
buttonName = R.string.confirm_with_3ds2_button,
paymentLauncher = paymentLauncher,
inProgress = inProgress
)
Divider(modifier = Modifier.padding(vertical = 5.dp))
Text(text = status)
}
}
}

/**
* Create [PaymentLauncher] in a [Composable]
*/
@Composable
fun createPaymentLauncher(): PaymentLauncher {
val settings = Settings(LocalContext.current)
return PaymentLauncher.createForCompose(
publishableKey = settings.publishableKey,
stripeAccountId = settings.stripeAccountId
) {
when (it) {
is PaymentResult.Completed -> {
viewModel.status.value += "\n\nPaymentIntent confirmation succeeded\n\n"
viewModel.inProgress.value = false
}
is PaymentResult.Canceled -> {
viewModel.status.value += "\n\nPaymentIntent confirmation cancelled\n\n"
viewModel.inProgress.value = false
}
is PaymentResult.Failed -> {
viewModel.status.value += "\n\nPaymentIntent confirmation failed with " +
"throwable ${it.throwable} \n\n"
viewModel.inProgress.value = false
}
}
}
}

@Composable
fun ConfirmButton(
params: PaymentMethodCreateParams,
@StringRes buttonName: Int,
paymentLauncher: PaymentLauncher,
inProgress: Boolean
) {
Button(
onClick = { createAndConfirmPaymentIntent(params, paymentLauncher) },
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 5.dp),
enabled = !inProgress
) {
Text(stringResource(buttonName))
}
}

private fun createAndConfirmPaymentIntent(
params: PaymentMethodCreateParams,
paymentLauncher: PaymentLauncher,
) {
viewModel.createPaymentIntent("us").observe(
this
) {
it.onSuccess { responseData ->
val confirmPaymentIntentParams =
ConfirmPaymentIntentParams.createWithPaymentMethodCreateParams(
paymentMethodCreateParams = params,
clientSecret = responseData.getString("secret"),
shipping = SHIPPING
)
paymentLauncher.confirm(confirmPaymentIntentParams)
}
}
}

private companion object {
/**
* See https://stripe.com/docs/payments/3d-secure#three-ds-cards for more options.
*/
private val confirmParams3ds2 =
PaymentMethodCreateParams.create(
PaymentMethodCreateParams.Card.Builder()
.setNumber("4000000000003238")
.setExpiryMonth(1)
.setExpiryYear(2025)
.setCvc("123")
.build()
)

private val confirmParams3ds1 =
PaymentMethodCreateParams.create(
PaymentMethodCreateParams.Card.Builder()
.setNumber("4000000000003063")
.setExpiryMonth(1)
.setExpiryYear(2025)
.setCvc("123")
.build()
)

private val SHIPPING = ConfirmPaymentIntentParams.Shipping(
address = Address.Builder()
.setCity("San Francisco")
.setCountry("US")
.setLine1("123 Market St")
.setLine2("#345")
.setPostalCode("94107")
.setState("CA")
.build(),
name = "Jenny Rosen",
carrier = "Fedex",
trackingNumber = "12345"
)
}
}
Expand Up @@ -3,11 +3,11 @@ package com.stripe.example.activity
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import com.stripe.android.PaymentIntentResult
import com.stripe.android.model.Address
import com.stripe.android.model.MandateDataParams
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethodCreateParams
import com.stripe.android.payments.paymentlauncher.PaymentResult
import com.stripe.example.R
import com.stripe.example.databinding.CreateSepaDebitActivityBinding

Expand Down Expand Up @@ -54,14 +54,19 @@ class ConfirmSepaDebitActivity : StripeIntentActivity() {
viewBinding.confirmButton.isEnabled = enabled
}

override fun onConfirmSuccess(result: PaymentIntentResult) {
super.onConfirmSuccess(result)
snackbarController.show("Status after confirmation: ${result.intent.status}")
override fun onConfirmSuccess() {
super.onConfirmSuccess()
snackbarController.show("Confirmation succeeded.")
}

override fun onConfirmError(throwable: Throwable) {
super.onConfirmError(throwable)
snackbarController.show("Error during confirmation: ${throwable.message}")
override fun onConfirmCanceled() {
super.onConfirmCanceled()
snackbarController.show("Confirmation canceled.")
}

override fun onConfirmError(failedResult: PaymentResult.Failed) {
super.onConfirmError(failedResult)
snackbarController.show("Error during confirmation: ${failedResult.throwable.message}")
}

private fun createPaymentMethodParams(iban: String): PaymentMethodCreateParams {
Expand Down
Expand Up @@ -119,6 +119,10 @@ class LauncherActivity : AppCompatActivity() {
Item(
activity.getString(R.string.connect_example),
ConnectExampleActivity::class.java
),
Item(
activity.getString(R.string.compose_example),
ComposeExampleActivity::class.java
)
)

Expand Down

0 comments on commit 8b77ca2

Please sign in to comment.