From e1f6767fd53b5732b2700f38476341906683bd37 Mon Sep 17 00:00:00 2001 From: Michael Shafrir Date: Tue, 22 Oct 2019 14:17:29 -0400 Subject: [PATCH] Update sample store app - Update stripe-android to v12.2.0 - Update backend API to reflect backend changes - Update store product list and pricing to match backend - Simplify models and use data class/@Parcelize --- app/build.gradle | 4 +- .../com/stripe/samplestore/PaymentActivity.kt | 160 ++++++++++-------- .../java/com/stripe/samplestore/Settings.kt | 7 +- .../com/stripe/samplestore/StoreActivity.kt | 4 +- .../com/stripe/samplestore/StoreAdapter.kt | 55 +++--- .../java/com/stripe/samplestore/StoreCart.kt | 80 ++------- .../com/stripe/samplestore/StoreLineItem.kt | 43 +---- .../java/com/stripe/samplestore/StoreUtils.kt | 4 - .../stripe/samplestore/service/BackendApi.kt | 8 +- app/src/main/res/layout/activity_payment.xml | 2 +- 10 files changed, 150 insertions(+), 217 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c3aea98..e628269 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,7 +46,7 @@ android { } dependencies { - implementation 'com.stripe:stripe-android:11.2.0' + implementation 'com.stripe:stripe-android:12.2.0' implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.0.0' @@ -81,7 +81,7 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion" - ktlint 'com.pinterest:ktlint:0.34.2' + ktlint 'com.pinterest:ktlint:0.35.0' } repositories { diff --git a/app/src/main/java/com/stripe/samplestore/PaymentActivity.kt b/app/src/main/java/com/stripe/samplestore/PaymentActivity.kt index 90fe736..4a6d203 100644 --- a/app/src/main/java/com/stripe/samplestore/PaymentActivity.kt +++ b/app/src/main/java/com/stripe/samplestore/PaymentActivity.kt @@ -42,7 +42,6 @@ import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers -import okhttp3.ResponseBody import org.json.JSONException import org.json.JSONObject import java.io.IOException @@ -102,12 +101,11 @@ class PaymentActivity : AppCompatActivity() { .build()) .build()) - stripe = if (Settings.STRIPE_ACCOUNT_ID != null) { - Stripe(this, PaymentConfiguration.getInstance(this).publishableKey, - Settings.STRIPE_ACCOUNT_ID) - } else { - Stripe(this, PaymentConfiguration.getInstance(this).publishableKey) - } + stripe = Stripe( + this, + PaymentConfiguration.getInstance(this).publishableKey, + Settings.STRIPE_ACCOUNT_ID + ) service = RetrofitFactory.instance.create(BackendApi::class.java) @@ -125,7 +123,7 @@ class PaymentActivity : AppCompatActivity() { updateConfirmPaymentButton() enterShippingInfo = findViewById(R.id.shipping_info) - enterPaymentInfo = findViewById(R.id.payment_source) + enterPaymentInfo = findViewById(R.id.payment_method) compositeDisposable.add(RxView.clicks(enterShippingInfo) .subscribe { paymentSession.presentShippingFlow() }) compositeDisposable.add(RxView.clicks(enterPaymentInfo) @@ -223,7 +221,7 @@ class PaymentActivity : AppCompatActivity() { } private fun updateConfirmPaymentButton() { - val price = paymentSession.paymentSessionData?.cartTotal ?: 0 + val price = paymentSession.paymentSessionData.cartTotal confirmPaymentButton.text = getString(R.string.pay_label, StoreUtils.getPriceString(price, null)) } @@ -232,7 +230,7 @@ class PaymentActivity : AppCompatActivity() { cartItemLayout.removeAllViewsInLayout() val currencySymbol = storeCart.currency.getSymbol(Locale.US) - addLineItems(currencySymbol, storeCart.lineItems) + addLineItems(currencySymbol, storeCart.storeLineItems.toList()) addLineItems(currencySymbol, listOf(StoreLineItem(getString(R.string.checkout_shipping_cost_label), 1, shippingCosts))) @@ -244,17 +242,17 @@ class PaymentActivity : AppCompatActivity() { } private fun addLineItems(currencySymbol: String, items: List) { - for (item in items) { + items.forEach { val view = layoutInflater.inflate( R.layout.cart_item, cartItemLayout, false) - fillOutCartItemView(item, view, currencySymbol) + fillOutCartItemView(it, view, currencySymbol) cartItemLayout.addView(view) } } private fun setupTotalPriceView(view: View, currencySymbol: String) { val itemViews = getItemViews(view) - val totalPrice = paymentSession.paymentSessionData?.cartTotal ?: 0 + val totalPrice = paymentSession.paymentSessionData.cartTotal itemViews[0].text = getString(R.string.checkout_total_cost_label) val price = PayWithGoogleUtils.getPriceString(totalPrice, storeCart.currency) @@ -297,17 +295,19 @@ class PaymentActivity : AppCompatActivity() { ): HashMap { val params = HashMap() params["amount"] = data.cartTotal.toString() - params["payment_method"] = data.paymentMethod!!.id!! + params["payment_method_id"] = data.paymentMethod!!.id!! params["payment_method_types"] = Settings.ALLOWED_PAYMENT_METHOD_TYPES.map { it.code } - params["currency"] = Settings.CURRENCY + params["country"] = Settings.COUNTRY params["customer_id"] = customerId - if (data.shippingInformation != null) { - params["shipping"] = data.shippingInformation!!.toParamMap() + data.shippingInformation?.let { + params["shipping"] = it.toParamMap() } params["return_url"] = "stripe://payment-auth-return" - if (stripeAccountId != null) { - params["stripe_account"] = stripeAccountId + stripeAccountId?.let { + params["stripe_account"] = it } + + params["products"] = storeCart.products return params } @@ -317,11 +317,12 @@ class PaymentActivity : AppCompatActivity() { stripeAccountId: String? ): HashMap { val params = HashMap() - params["payment_method"] = data.paymentMethod!!.id!! + params["payment_method"] = data.paymentMethod?.id!! params["payment_method_types"] = Settings.ALLOWED_PAYMENT_METHOD_TYPES.map { it.code } params["customer_id"] = customerId params["return_url"] = "stripe://payment-auth-return" params["currency"] = Settings.CURRENCY + params["country"] = Settings.COUNTRY if (stripeAccountId != null) { params["stripe_account"] = stripeAccountId } @@ -330,12 +331,12 @@ class PaymentActivity : AppCompatActivity() { private fun capturePayment(customerId: String) { val paymentSessionData = paymentSession.paymentSessionData - if (paymentSessionData?.paymentMethod == null) { + if (paymentSessionData.paymentMethod == null) { displayError("No payment method selected") return } - val stripeResponse = service.capturePayment( + val stripeResponse = service.confirmPaymentIntent( createCapturePaymentParams(paymentSessionData, customerId, Settings.STRIPE_ACCOUNT_ID)) compositeDisposable.add(stripeResponse @@ -344,14 +345,14 @@ class PaymentActivity : AppCompatActivity() { .doOnSubscribe { startLoading() } .doFinally { stopLoading() } .subscribe( - { onStripeIntentClientSecretResponse(it) }, + { onStripeIntentClientSecretResponse(it.string()) }, { throwable -> displayError(throwable.localizedMessage) } )) } private fun createSetupIntent(customerId: String) { val paymentSessionData = paymentSession.paymentSessionData - if (paymentSessionData?.paymentMethod == null) { + if (paymentSessionData.paymentMethod == null) { displayError("No payment method selected") return } @@ -365,19 +366,20 @@ class PaymentActivity : AppCompatActivity() { .doOnSubscribe { startLoading() } .doFinally { stopLoading() } .subscribe( - { onStripeIntentClientSecretResponse(it) }, + { onStripeIntentClientSecretResponse(it.string()) }, { throwable -> displayError(throwable.localizedMessage) } )) } private fun displayError(errorMessage: String?) { - val alertDialog = AlertDialog.Builder(this).create() - alertDialog.setTitle("Error") - alertDialog.setMessage(errorMessage) - alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK") { - dialog, _ -> dialog.dismiss() - } - alertDialog.show() + AlertDialog.Builder(this) + .setTitle("Error") + .setMessage(errorMessage) + .setNeutralButton("OK") { + dialog, _ -> dialog.dismiss() + } + .create() + .show() } private fun processStripeIntent(stripeIntent: StripeIntent) { @@ -403,35 +405,50 @@ class PaymentActivity : AppCompatActivity() { } private fun confirmStripeIntent(stripeIntentId: String, stripeAccountId: String?) { - val params = HashMap() - params["payment_intent_id"] = stripeIntentId + val params: HashMap = hashMapOf( + "payment_intent_id" to stripeIntentId + ) if (stripeAccountId != null) { params["stripe_account"] = stripeAccountId } - compositeDisposable.add(service.confirmPayment(params) + compositeDisposable.add(service.confirmPaymentIntent(params) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe { startLoading() } .doFinally { stopLoading() } .subscribe( - { onStripeIntentClientSecretResponse(it) }, + { onStripeIntentClientSecretResponse(it.string()) }, { throwable -> displayError(throwable.localizedMessage) } )) } @Throws(IOException::class, JSONException::class) - private fun onStripeIntentClientSecretResponse(responseBody: ResponseBody) { - val clientSecret = JSONObject(responseBody.string()).getString("secret") - compositeDisposable.add( - Observable - .fromCallable { retrieveStripeIntent(clientSecret) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe { startLoading() } - .doFinally { stopLoading() } - .subscribe { processStripeIntent(it) } - ) + private fun onStripeIntentClientSecretResponse(responseContents: String) { + val response = JSONObject(responseContents) + + if (response.has("success")) { + val success = response.getBoolean("success") + if (success) { + finishPayment() + } else { + displayError("Payment failed") + } + } else { + val clientSecret = response.getString("secret") + compositeDisposable.add( + Observable + .fromCallable { retrieveStripeIntent(clientSecret) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnSubscribe { startLoading() } + .doFinally { stopLoading() } + .subscribe( + { processStripeIntent(it) }, + { throwable -> displayError(throwable.localizedMessage) } + ) + ) + } } private fun retrieveStripeIntent(clientSecret: String): StripeIntent { @@ -462,11 +479,14 @@ class PaymentActivity : AppCompatActivity() { val paymentSession = PaymentSession(this) paymentSession.init(PaymentSessionListenerImpl(this), PaymentSessionConfig.Builder() - .setPrepopulatedShippingInfo(exampleShippingInfo).build()) + .setShippingMethodsRequired(false) + .setShippingInfoRequired(false) + .setPrepopulatedShippingInfo(exampleShippingInfo) + .setPaymentMethodTypes(Settings.ALLOWED_PAYMENT_METHOD_TYPES) + .build()) paymentSession.setCartTotal(storeCart.totalPrice) - val isPaymentReadyToCharge = - paymentSession.paymentSessionData?.isPaymentReadyToCharge == true + val isPaymentReadyToCharge = paymentSession.paymentSessionData.isPaymentReadyToCharge confirmPaymentButton.isEnabled = isPaymentReadyToCharge setupPaymentCredentialsButton.isEnabled = isPaymentReadyToCharge @@ -519,34 +539,33 @@ class PaymentActivity : AppCompatActivity() { private fun getValidShippingMethods( shippingInformation: ShippingInformation ): List { - val isCourierSupported = shippingInformation.address != null && - "94110" == shippingInformation.address!!.postalCode + val isCourierSupported = "94110" == shippingInformation.address?.postalCode val courierMethod = if (isCourierSupported) { ShippingMethod("1 Hour Courier", "courier", - "Arrives in the next hour", 1099, Settings.CURRENCY) + 1099, Settings.CURRENCY, "Arrives in the next hour") } else { null } return listOfNotNull( ShippingMethod("UPS Ground", "ups-ground", - "Arrives in 3-5 days", 0, Settings.CURRENCY), + 0, Settings.CURRENCY, "Arrives in 3-5 days"), ShippingMethod("FedEx", "fedex", - "Arrives tomorrow", 599, Settings.CURRENCY), + 599, Settings.CURRENCY, "Arrives tomorrow"), courierMethod ) } private fun onPaymentSessionDataChanged(data: PaymentSessionData) { - if (data.shippingMethod != null) { - enterShippingInfo.text = data.shippingMethod!!.label - shippingCosts = data.shippingMethod!!.amount + data.shippingMethod?.let { shippingMethod -> + enterShippingInfo.text = shippingMethod.label + shippingCosts = shippingMethod.amount paymentSession.setCartTotal(storeCart.totalPrice + shippingCosts) addCartItems() updateConfirmPaymentButton() } - if (data.paymentMethod != null) { - enterPaymentInfo.text = getPaymentMethodDescription(data.paymentMethod!!) + data.paymentMethod?.let { + enterPaymentInfo.text = getPaymentMethodDescription(it) } if (data.isPaymentReadyToCharge) { @@ -562,14 +581,11 @@ class PaymentActivity : AppCompatActivity() { override fun onCommunicatingStateChanged(isCommunicating: Boolean) {} override fun onError(errorCode: Int, errorMessage: String) { - val activity = listenerActivity ?: return - - activity.displayError(errorMessage) + listenerActivity?.displayError(errorMessage) } override fun onPaymentSessionDataChanged(data: PaymentSessionData) { - val activity = listenerActivity ?: return - activity.onPaymentSessionDataChanged(data) + listenerActivity?.onPaymentSessionDataChanged(data) } } @@ -578,15 +594,11 @@ class PaymentActivity : AppCompatActivity() { ) : CustomerSession.ActivityCustomerRetrievalListener(activity) { override fun onCustomerRetrieved(customer: Customer) { - val activity = activity ?: return - - customer.id?.let { activity.capturePayment(it) } + customer.id?.let { activity?.capturePayment(it) } } override fun onError(httpCode: Int, errorMessage: String, stripeError: StripeError?) { - val activity = activity ?: return - - activity.displayError("Error getting payment method:. $errorMessage") + activity?.displayError("Error getting payment method:. $errorMessage") } } @@ -595,13 +607,11 @@ class PaymentActivity : AppCompatActivity() { ) : CustomerSession.ActivityCustomerRetrievalListener(activity) { override fun onCustomerRetrieved(customer: Customer) { - val activity = activity ?: return - customer.id?.let { activity.createSetupIntent(it) } + customer.id?.let { activity?.createSetupIntent(it) } } override fun onError(httpCode: Int, errorMessage: String, stripeError: StripeError?) { - val activity = activity ?: return - activity.displayError("Error getting payment method:. $errorMessage") + activity?.displayError("Error getting payment method:. $errorMessage") } } diff --git a/app/src/main/java/com/stripe/samplestore/Settings.kt b/app/src/main/java/com/stripe/samplestore/Settings.kt index d260798..df6f6df 100644 --- a/app/src/main/java/com/stripe/samplestore/Settings.kt +++ b/app/src/main/java/com/stripe/samplestore/Settings.kt @@ -30,7 +30,12 @@ internal object Settings { * Three-letter ISO [currency code](https://stripe.com/docs/api/payment_intents/object#payment_intent_object-currency), * in lowercase. Must be a [supported currency](https://stripe.com/docs/currencies). */ - const val CURRENCY = "usd" + const val CURRENCY = "USD" + + /** + * Two-letter country code. + */ + const val COUNTRY = "us" /** * The list of [payment method types](https://stripe.com/docs/api/payment_intents/object#payment_intent_object-payment_method_types) diff --git a/app/src/main/java/com/stripe/samplestore/StoreActivity.kt b/app/src/main/java/com/stripe/samplestore/StoreActivity.kt index 2ae5ce9..7f1ac5a 100644 --- a/app/src/main/java/com/stripe/samplestore/StoreActivity.kt +++ b/app/src/main/java/com/stripe/samplestore/StoreActivity.kt @@ -90,7 +90,7 @@ class StoreActivity : AppCompatActivity(), StoreAdapter.TotalItemsChangedListene val emojiView = dialogView.findViewById(R.id.dlg_emoji_display) // Show a smiley face! - emojiView.text = StoreUtils.getEmojiByUnicode(0x1F642) + emojiView.text = "🙂" val priceView = dialogView.findViewById(R.id.dlg_price_display) priceView.text = StoreUtils.getPriceString(price, null) @@ -107,7 +107,7 @@ class StoreActivity : AppCompatActivity(), StoreAdapter.TotalItemsChangedListene val emojiView = dialogView.findViewById(R.id.dlg_emoji_display) // Show a smiley face! - emojiView.text = StoreUtils.getEmojiByUnicode(0x1F642) + emojiView.text = "🙂" AlertDialog.Builder(this) .setView(dialogView) diff --git a/app/src/main/java/com/stripe/samplestore/StoreAdapter.kt b/app/src/main/java/com/stripe/samplestore/StoreAdapter.kt index 8891c2f..4ebcac6 100644 --- a/app/src/main/java/com/stripe/samplestore/StoreAdapter.kt +++ b/app/src/main/java/com/stripe/samplestore/StoreAdapter.kt @@ -49,8 +49,8 @@ class StoreAdapter internal constructor( removeButton.visibility = visibility } - fun setEmoji(emojiUnicode: Int) { - emojiTextView.text = StoreUtils.getEmojiByUnicode(emojiUnicode) + fun setEmoji(emoji: String) { + emojiTextView.text = emoji } fun setPrice(price: Int) { @@ -73,7 +73,7 @@ class StoreAdapter internal constructor( // otherwise functional if you switched that assumption on the backend and passed // currency code as a parameter. currency = Currency.getInstance(Settings.CURRENCY) - quantityOrdered = IntArray(EMOJI_CLOTHES.size) + quantityOrdered = IntArray(Products.values().size) } private fun bumpItemQuantity(index: Int, increase: Boolean) { @@ -92,11 +92,11 @@ class StoreAdapter internal constructor( } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - if (position == EMOJI_CLOTHES.size) { + if (position == Products.values().size) { holder.setHidden(true) } else { holder.setHidden(false) - holder.setEmoji(EMOJI_CLOTHES[position]) + holder.setEmoji(Products.values()[position].emoji) holder.setPrice(getPrice(position)) holder.setQuantity(quantityOrdered[position]) holder.position = position @@ -104,7 +104,7 @@ class StoreAdapter internal constructor( } override fun getItemCount(): Int { - return EMOJI_CLOTHES.size + 1 + return Products.values().size + 1 } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { @@ -115,15 +115,18 @@ class StoreAdapter internal constructor( } internal fun launchPurchaseActivityWithCart() { - val cart = StoreCart(currency) - for (i in quantityOrdered.indices) { + val storeLineItems = quantityOrdered.indices.mapNotNull { i -> if (quantityOrdered[i] > 0) { - cart.addStoreLineItem( - StoreUtils.getEmojiByUnicode(EMOJI_CLOTHES[i]), + StoreLineItem( + Products.values()[i].emoji, quantityOrdered[i], - getPrice(i).toLong()) + getPrice(i).toLong() + ) + } else { + null } } + val cart = StoreCart(currency, storeLineItems) activity.startActivityForResult( PaymentActivity.createIntent(activity, cart), @@ -139,23 +142,29 @@ class StoreAdapter internal constructor( } private fun getPrice(position: Int): Int { - return (EMOJI_PRICES[position] * priceMultiplier).toInt() + return (Products.values()[position].price * priceMultiplier).toInt() } interface TotalItemsChangedListener { fun onTotalItemsChanged(totalItems: Int) } - companion object { - - private val EMOJI_CLOTHES = intArrayOf( - 0x1F455, 0x1F456, 0x1F457, 0x1F458, 0x1F459, 0x1F45A, 0x1F45B, - 0x1F45C, 0x1F45D, 0x1F45E, 0x1F45F, 0x1F460, 0x1F461, 0x1F462 - ) - - private val EMOJI_PRICES = intArrayOf( - 2000, 4000, 3000, 700, 600, 1000, 2000, - 2500, 800, 3000, 2000, 5000, 5500, 6000 - ) + private enum class Products(internal val emoji: String, internal val price: Int) { + Shirt("👕", 2000), + Pants("👖", 4000), + Dress("👗", 3000), + MansShoe("👞", 700), + AthleticShoe("👟", 2000), + HighHeeledShoe("👠", 1000), + WomansSandal("👡", 2000), + WomansBoots("👢", 2500), + WomansHat("👒", 800), + Bikini("👙", 3000), + Lipstick("💄", 2000), + TopHat("🎩", 5000), + Purse("👛", 5500), + Handbag("👜", 6000), + Sunglasses("🕶", 2000), + WomansClothes("👚", 2500) } } diff --git a/app/src/main/java/com/stripe/samplestore/StoreCart.kt b/app/src/main/java/com/stripe/samplestore/StoreCart.kt index bdff278..0d35cef 100644 --- a/app/src/main/java/com/stripe/samplestore/StoreCart.kt +++ b/app/src/main/java/com/stripe/samplestore/StoreCart.kt @@ -1,80 +1,24 @@ package com.stripe.samplestore -import android.os.Parcel import android.os.Parcelable - -import java.util.ArrayList +import kotlinx.android.parcel.Parcelize import java.util.Currency -import java.util.LinkedHashMap -import java.util.UUID - -class StoreCart : Parcelable { - - val currency: Currency - private val storeLineItems: LinkedHashMap - internal val lineItems: List - get() = ArrayList(storeLineItems.values) +@Parcelize +data class StoreCart constructor( + val currency: Currency, + val storeLineItems: List +) : Parcelable { internal val totalPrice: Long get() { - var total = 0L - for (item in storeLineItems.values) { - total += item.totalPrice - } - return total + return storeLineItems.map { it.totalPrice }.sum() } - internal constructor(currency: Currency) { - this.currency = currency - // LinkedHashMap because we want iteration order to be the same. - storeLineItems = LinkedHashMap() - } - - fun addStoreLineItem(description: String, quantity: Int, unitPrice: Long) { - addStoreLineItem(StoreLineItem(description, quantity, unitPrice)) - } - - private fun addStoreLineItem(storeLineItem: StoreLineItem) { - storeLineItems[UUID.randomUUID().toString()] = storeLineItem - } - - fun removeLineItem(itemId: String): Boolean { - return storeLineItems.remove(itemId) != null - } - - override fun describeContents(): Int { - return 0 - } - - override fun writeToParcel(dest: Parcel, flags: Int) { - dest.writeString(currency.currencyCode) - dest.writeInt(storeLineItems.size) - for (key in storeLineItems.keys) { - dest.writeString(key) - dest.writeParcelable(storeLineItems[key], 0) - } - } - - private constructor(input: Parcel) { - currency = Currency.getInstance(input.readString()) - val count = input.readInt() - storeLineItems = LinkedHashMap() - for (i in 0 until count) { - val id = input.readString()!! - val item = input - .readParcelable(StoreLineItem::class.java.classLoader)!! - storeLineItems[id] = item - } - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): StoreCart { - return StoreCart(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) + internal val products: List + get() { + return storeLineItems.flatMap { lineItem -> + (0 until lineItem.quantity).map {lineItem.description } + } } - } } diff --git a/app/src/main/java/com/stripe/samplestore/StoreLineItem.kt b/app/src/main/java/com/stripe/samplestore/StoreLineItem.kt index 6477ffa..88375e5 100644 --- a/app/src/main/java/com/stripe/samplestore/StoreLineItem.kt +++ b/app/src/main/java/com/stripe/samplestore/StoreLineItem.kt @@ -1,49 +1,18 @@ package com.stripe.samplestore -import android.os.Parcel import android.os.Parcelable +import kotlinx.android.parcel.Parcelize /** * Represents a single line item for purchase in this store. */ -class StoreLineItem : Parcelable { - - val description: String - val quantity: Int +@Parcelize +data class StoreLineItem constructor( + val description: String, + val quantity: Int, val unitPrice: Long +) : Parcelable { internal val totalPrice: Long get() = unitPrice * quantity - - internal constructor(description: String, quantity: Int, unitPrice: Long) { - this.description = description - this.quantity = quantity - this.unitPrice = unitPrice - } - - override fun describeContents(): Int { - return 0 - } - - override fun writeToParcel(dest: Parcel, flags: Int) { - dest.writeString(this.description) - dest.writeInt(this.quantity) - dest.writeLong(this.unitPrice) - } - - private constructor(input: Parcel) { - this.description = input.readString()!! - this.quantity = input.readInt() - this.unitPrice = input.readLong() - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): StoreLineItem { - return StoreLineItem(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } } diff --git a/app/src/main/java/com/stripe/samplestore/StoreUtils.kt b/app/src/main/java/com/stripe/samplestore/StoreUtils.kt index 388e42c..3d7c5cd 100644 --- a/app/src/main/java/com/stripe/samplestore/StoreUtils.kt +++ b/app/src/main/java/com/stripe/samplestore/StoreUtils.kt @@ -11,10 +11,6 @@ internal object StoreUtils { private const val CURRENCY_SIGN = '\u00A4' - fun getEmojiByUnicode(unicode: Int): String { - return String(Character.toChars(unicode)) - } - fun getPriceString(price: Long, currency: Currency?): String { val displayCurrency = currency ?: Currency.getInstance(Settings.CURRENCY) diff --git a/app/src/main/java/com/stripe/samplestore/service/BackendApi.kt b/app/src/main/java/com/stripe/samplestore/service/BackendApi.kt index 4b257b6..161e2d4 100644 --- a/app/src/main/java/com/stripe/samplestore/service/BackendApi.kt +++ b/app/src/main/java/com/stripe/samplestore/service/BackendApi.kt @@ -17,8 +17,8 @@ interface BackendApi { * * {"secret": "pi_1Eu5SqCRMb_secret_O2Avhk5V0Pjeo"} */ - @POST("capture_payment") - fun capturePayment(@Body params: HashMap): Observable + @POST("create_payment_intent") + fun createPaymentIntent(@Body params: HashMap): Observable /** * Used for Payment Intent Manual confirmation @@ -29,8 +29,8 @@ interface BackendApi { * * {"secret": "pi_1Eu5SqCRMb_secret_O2Avhk5V0Pjeo"} */ - @POST("confirm_payment") - fun confirmPayment(@Body params: HashMap): Observable + @POST("confirm_payment_intent") + fun confirmPaymentIntent(@Body params: HashMap): Observable @POST("create_setup_intent") fun createSetupIntent(@Body params: HashMap): Observable diff --git a/app/src/main/res/layout/activity_payment.xml b/app/src/main/res/layout/activity_payment.xml index 9532fed..55030ea 100644 --- a/app/src/main/res/layout/activity_payment.xml +++ b/app/src/main/res/layout/activity_payment.xml @@ -29,7 +29,7 @@ android:background="@drawable/item_divider"/>