From b487d885861948b220d64c7566d9da384e0ae9fd Mon Sep 17 00:00:00 2001 From: Bella Koch <160939932+amk-stripe@users.noreply.github.com> Date: Thu, 23 May 2024 11:03:12 -0700 Subject: [PATCH] Create empty manage PMs screen (#8523) * Create empty manage PMs screen * comment update * update string resources * Revert "update string resources" This reverts commit 050aa723406db04594f50cbe1b4e1e385f62bf41. * put string in correct spot * reuse existing string * fix broken tests * separate new "Go to manage screen" button from NewPM layout * Add header text tests --- paymentsheet/api/paymentsheet.api | 7 ++ .../navigation/PaymentSheetScreen.kt | 22 +++- .../paymentsheet/ui/HeaderTextFactory.kt | 106 ++++++++++-------- .../ui/PaymentMethodVerticalLayoutUI.kt | 36 ++++++ .../viewmodels/BaseSheetViewModel.kt | 7 +- .../paymentsheet/ui/HeaderTextFactoryTest.kt | 22 ++++ 6 files changed, 149 insertions(+), 51 deletions(-) create mode 100644 paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodVerticalLayoutUI.kt diff --git a/paymentsheet/api/paymentsheet.api b/paymentsheet/api/paymentsheet.api index b5af848e163..ede2d4d01a5 100644 --- a/paymentsheet/api/paymentsheet.api +++ b/paymentsheet/api/paymentsheet.api @@ -1934,6 +1934,13 @@ public final class com/stripe/android/paymentsheet/ui/ComposableSingletons$Manda public final fun getLambda-1$paymentsheet_release ()Lkotlin/jvm/functions/Function2; } +public final class com/stripe/android/paymentsheet/ui/ComposableSingletons$PaymentMethodVerticalLayoutUIKt { + public static final field INSTANCE Lcom/stripe/android/paymentsheet/ui/ComposableSingletons$PaymentMethodVerticalLayoutUIKt; + public static field lambda-1 Lkotlin/jvm/functions/Function3; + public fun ()V + public final fun getLambda-1$paymentsheet_release ()Lkotlin/jvm/functions/Function3; +} + public final class com/stripe/android/paymentsheet/ui/ComposableSingletons$PaymentSheetScreenKt { public static final field INSTANCE Lcom/stripe/android/paymentsheet/ui/ComposableSingletons$PaymentSheetScreenKt; public static field lambda-1 Lkotlin/jvm/functions/Function4; diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/navigation/PaymentSheetScreen.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/navigation/PaymentSheetScreen.kt index 0182a87dab3..b4fa578a5c0 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/navigation/PaymentSheetScreen.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/navigation/PaymentSheetScreen.kt @@ -1,6 +1,7 @@ package com.stripe.android.paymentsheet.navigation import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -15,7 +16,7 @@ import com.stripe.android.paymentsheet.ui.AddPaymentMethod import com.stripe.android.paymentsheet.ui.EditPaymentMethod import com.stripe.android.paymentsheet.ui.FormElement import com.stripe.android.paymentsheet.ui.ModifiableEditPaymentMethodViewInteractor -import com.stripe.android.paymentsheet.ui.NewPaymentMethodVerticalLayoutUI +import com.stripe.android.paymentsheet.ui.PaymentMethodVerticalLayoutUI import com.stripe.android.paymentsheet.ui.SavedPaymentMethodTabLayoutUI import com.stripe.android.paymentsheet.ui.SavedPaymentMethodsTopContentPadding import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel @@ -32,6 +33,7 @@ internal val PaymentSheetScreen.topContentPadding: Dp is PaymentSheetScreen.Form, is PaymentSheetScreen.AddFirstPaymentMethod, is PaymentSheetScreen.AddAnotherPaymentMethod, + is PaymentSheetScreen.ManageSavedPaymentMethods, is PaymentSheetScreen.EditPaymentMethod -> { 0.dp } @@ -64,7 +66,7 @@ internal sealed interface PaymentSheetScreen { } } - object SelectSavedPaymentMethods : PaymentSheetScreen { + data object SelectSavedPaymentMethods : PaymentSheetScreen { override val showsBuyButton: Boolean = true override val showsContinueButton: Boolean = false @@ -172,10 +174,11 @@ internal sealed interface PaymentSheetScreen { val isProcessing by viewModel.processing.collectAsState() - NewPaymentMethodVerticalLayoutUI( + PaymentMethodVerticalLayoutUI( paymentMethods = supportedPaymentMethods, selectedIndex = -1, isEnabled = !isProcessing, + onViewMorePaymentMethods = { viewModel.transitionTo(ManageSavedPaymentMethods) }, onItemSelectedListener = { viewModel.transitionTo(Form(it.code)) }, imageLoader = imageLoader, modifier = Modifier.padding(horizontal = 20.dp) @@ -222,4 +225,17 @@ internal sealed interface PaymentSheetScreen { ) } } + + data object ManageSavedPaymentMethods : PaymentSheetScreen { + override val showsBuyButton: Boolean = false + override val showsContinueButton: Boolean = false + override val canNavigateBack: Boolean = true + + override fun showsWalletsHeader(isCompleteFlow: Boolean): Boolean = false + + @Composable + override fun Content(viewModel: BaseSheetViewModel, modifier: Modifier) { + Text("Manage your saved PMs here") + } + } } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/HeaderTextFactory.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/HeaderTextFactory.kt index d5559bf9dbd..92d357bc5fb 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/HeaderTextFactory.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/HeaderTextFactory.kt @@ -16,55 +16,69 @@ internal class HeaderTextFactory( types: List, ): Int? { return if (isCompleteFlow) { - when (screen) { - is PaymentSheetScreen.SelectSavedPaymentMethods -> { - if (isWalletEnabled) { - null - } else { - R.string.stripe_paymentsheet_select_payment_method - } - } - is PaymentSheetScreen.AddFirstPaymentMethod, PaymentSheetScreen.VerticalMode -> { - R.string.stripe_paymentsheet_add_payment_method_title.takeUnless { - isWalletEnabled - } - } - is PaymentSheetScreen.EditPaymentMethod -> { - StripeR.string.stripe_title_update_card - } - is PaymentSheetScreen.Loading, - is PaymentSheetScreen.AddAnotherPaymentMethod, - is PaymentSheetScreen.Form, - null -> { - null - } - } + createForCompleteFlow(screen, isWalletEnabled) } else { - when (screen) { - is PaymentSheetScreen.Loading, is PaymentSheetScreen.Form -> { - null - } - is PaymentSheetScreen.SelectSavedPaymentMethods -> { - R.string.stripe_paymentsheet_select_payment_method - } - is PaymentSheetScreen.AddFirstPaymentMethod, - is PaymentSheetScreen.AddAnotherPaymentMethod, - is PaymentSheetScreen.VerticalMode -> { - val title = if (types.singleOrNull() == PaymentMethod.Type.Card.code) { - StripeR.string.stripe_title_add_a_card - } else { - R.string.stripe_paymentsheet_choose_payment_method - } + createForFlowController(screen, types, isWalletEnabled) + } + } + + private fun createForCompleteFlow( + screen: PaymentSheetScreen?, + isWalletEnabled: Boolean + ) = when (screen) { + is PaymentSheetScreen.SelectSavedPaymentMethods -> { + if (isWalletEnabled) { + null + } else { + R.string.stripe_paymentsheet_select_payment_method + } + } + is PaymentSheetScreen.AddFirstPaymentMethod, PaymentSheetScreen.VerticalMode -> { + R.string.stripe_paymentsheet_add_payment_method_title.takeUnless { + isWalletEnabled + } + } + is PaymentSheetScreen.EditPaymentMethod -> { + StripeR.string.stripe_title_update_card + } + is PaymentSheetScreen.ManageSavedPaymentMethods -> { + R.string.stripe_paymentsheet_select_payment_method + } + is PaymentSheetScreen.Loading, + is PaymentSheetScreen.AddAnotherPaymentMethod, + is PaymentSheetScreen.Form, + null -> { + null + } + } - title.takeUnless { isWalletEnabled } - } - is PaymentSheetScreen.EditPaymentMethod -> { - StripeR.string.stripe_title_update_card - } - null -> { - null - } + private fun createForFlowController( + screen: PaymentSheetScreen?, + types: List, + isWalletEnabled: Boolean + ) = when (screen) { + is PaymentSheetScreen.Loading, is PaymentSheetScreen.Form -> { + null + } + is PaymentSheetScreen.SelectSavedPaymentMethods, is PaymentSheetScreen.ManageSavedPaymentMethods -> { + R.string.stripe_paymentsheet_select_payment_method + } + is PaymentSheetScreen.AddFirstPaymentMethod, + is PaymentSheetScreen.AddAnotherPaymentMethod, + is PaymentSheetScreen.VerticalMode -> { + val title = if (types.singleOrNull() == PaymentMethod.Type.Card.code) { + StripeR.string.stripe_title_add_a_card + } else { + R.string.stripe_paymentsheet_choose_payment_method } + + title.takeUnless { isWalletEnabled } + } + is PaymentSheetScreen.EditPaymentMethod -> { + StripeR.string.stripe_title_update_card + } + null -> { + null } } } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodVerticalLayoutUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodVerticalLayoutUI.kt new file mode 100644 index 00000000000..837166160a3 --- /dev/null +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodVerticalLayoutUI.kt @@ -0,0 +1,36 @@ +package com.stripe.android.paymentsheet.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.stripe.android.lpmfoundations.luxe.SupportedPaymentMethod +import com.stripe.android.uicore.image.StripeImageLoader + +@Composable +internal fun PaymentMethodVerticalLayoutUI( + paymentMethods: List, + selectedIndex: Int, + isEnabled: Boolean, + onViewMorePaymentMethods: () -> Unit, + onItemSelectedListener: (SupportedPaymentMethod) -> Unit, + imageLoader: StripeImageLoader, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(12.dp)) { + TextButton(onClick = { onViewMorePaymentMethods() }) { + Text(text = "Go to manage screen") + } + + NewPaymentMethodVerticalLayoutUI( + paymentMethods = paymentMethods, + selectedIndex = selectedIndex, + isEnabled = isEnabled, + onItemSelectedListener = onItemSelectedListener, + imageLoader = imageLoader + ) + } +} diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt index e5b5dc7ebd2..8208c9b886d 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt @@ -291,7 +291,7 @@ internal abstract class BaseSheetViewModel( previouslyShownForm = null previouslyInteractedForm = null } - is PaymentSheetScreen.Form -> { + is PaymentSheetScreen.Form, is PaymentSheetScreen.ManageSavedPaymentMethods -> { } } } @@ -362,7 +362,10 @@ internal abstract class BaseSheetViewModel( private fun reportPaymentSheetShown(currentScreen: PaymentSheetScreen) { when (currentScreen) { - is PaymentSheetScreen.Loading, is PaymentSheetScreen.EditPaymentMethod, is PaymentSheetScreen.Form -> { + is PaymentSheetScreen.Loading, + is PaymentSheetScreen.EditPaymentMethod, + is PaymentSheetScreen.Form, + is PaymentSheetScreen.ManageSavedPaymentMethods -> { // Nothing to do here } is PaymentSheetScreen.SelectSavedPaymentMethods -> { diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/HeaderTextFactoryTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/HeaderTextFactoryTest.kt index bedb52a69ed..691252da2f7 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/HeaderTextFactoryTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/HeaderTextFactoryTest.kt @@ -111,4 +111,26 @@ class HeaderTextFactoryTest { assertThat(resource).isEqualTo(R.string.stripe_paymentsheet_choose_payment_method) } + + @Test + fun `Shows correct header for manage saved PMs screen when first opened`() { + val resource = getManagedSavedPaymentMethodsHeaderText(isCompleteFlow = true) + + assertThat(resource).isEqualTo(R.string.stripe_paymentsheet_select_payment_method) + } + + @Test + fun `Shows correct header for manage saved PMs screen when first opened - FlowController`() { + val resource = getManagedSavedPaymentMethodsHeaderText(isCompleteFlow = false) + + assertThat(resource).isEqualTo(R.string.stripe_paymentsheet_select_payment_method) + } + + private fun getManagedSavedPaymentMethodsHeaderText(isCompleteFlow: Boolean): Int? { + return HeaderTextFactory(isCompleteFlow = isCompleteFlow).create( + screen = PaymentSheetScreen.ManageSavedPaymentMethods, + isWalletEnabled = false, + types = emptyList(), + ) + } }