From b2a5b3faaab44a22fe851c084b95042872079d29 Mon Sep 17 00:00:00 2001 From: Till Hellmund Date: Tue, 16 Aug 2022 09:39:30 -0400 Subject: [PATCH 1/3] Update payment methods list to use content padding --- .../com/stripe/android/paymentsheet/PaymentMethodsUI.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt index e30784b29fc..1b5a17b118f 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt @@ -4,6 +4,7 @@ import androidx.annotation.VisibleForTesting import androidx.compose.foundation.Image import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width @@ -26,8 +27,8 @@ import androidx.compose.ui.unit.dp import com.stripe.android.paymentsheet.ui.LpmSelectorText import com.stripe.android.ui.core.MeasureComposableWidth import com.stripe.android.ui.core.PaymentsTheme -import com.stripe.android.ui.core.forms.resources.LpmRepository.SupportedPaymentMethod import com.stripe.android.ui.core.elements.SectionCard +import com.stripe.android.ui.core.forms.resources.LpmRepository.SupportedPaymentMethod import com.stripe.android.ui.core.paymentsColors internal const val ADD_PM_DEFAULT_PADDING = 12.0f @@ -71,9 +72,8 @@ internal fun PaymentMethodsUI( // TODO: userScrollEnabled will be available in compose version 1.2.0-alpha01+ LazyRow( state = state, - modifier = Modifier - .padding(start = PM_LIST_PADDING.dp) - .testTag(TEST_TAG_LIST) + contentPadding = PaddingValues(horizontal = PM_LIST_PADDING.dp), + modifier = Modifier.testTag(TEST_TAG_LIST) ) { itemsIndexed(items = paymentMethods, itemContent = { index, item -> PaymentMethodUI( From 9210ff3bdaa660e115375f9cdbcda933e3b736ae Mon Sep 17 00:00:00 2001 From: Till Hellmund Date: Thu, 18 Aug 2022 15:43:29 -0400 Subject: [PATCH 2/3] Add screenshot tests --- ...PaymentMethodsCarouselScrolledToTheEnd.png | Bin 0 -> 16742 bytes ...tMethodsCarouselWithInitialScrollState.png | Bin 0 -> 16741 bytes .../screenshot/PaymentMethodsUIScreenshot.kt | 66 ++++++++++++++++++ .../utils/MockPaymentMethodsFactory.kt | 56 +++++++++++++++ .../android/paymentsheet/PaymentMethodsUI.kt | 3 +- 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 paymentsheet/screenshots/debug/com.stripe.android.paymentsheet.screenshot.PaymentMethodsUIScreenshot_testPaymentMethodsCarouselScrolledToTheEnd.png create mode 100644 paymentsheet/screenshots/debug/com.stripe.android.paymentsheet.screenshot.PaymentMethodsUIScreenshot_testPaymentMethodsCarouselWithInitialScrollState.png create mode 100644 paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/screenshot/PaymentMethodsUIScreenshot.kt create mode 100644 paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/MockPaymentMethodsFactory.kt diff --git a/paymentsheet/screenshots/debug/com.stripe.android.paymentsheet.screenshot.PaymentMethodsUIScreenshot_testPaymentMethodsCarouselScrolledToTheEnd.png b/paymentsheet/screenshots/debug/com.stripe.android.paymentsheet.screenshot.PaymentMethodsUIScreenshot_testPaymentMethodsCarouselScrolledToTheEnd.png new file mode 100644 index 0000000000000000000000000000000000000000..8ffa4dac89afb107fe7c42e28a22a5fa0612e3f3 GIT binary patch literal 16742 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 literal 0 HcmV?d00001 diff --git a/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/screenshot/PaymentMethodsUIScreenshot.kt b/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/screenshot/PaymentMethodsUIScreenshot.kt new file mode 100644 index 00000000000..cb0033b12fb --- /dev/null +++ b/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/screenshot/PaymentMethodsUIScreenshot.kt @@ -0,0 +1,66 @@ +package com.stripe.android.paymentsheet.screenshot + +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Surface +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.unit.dp +import com.karumi.shot.ScreenshotTest +import com.stripe.android.paymentsheet.PaymentMethodsUI +import com.stripe.android.paymentsheet.utils.MockPaymentMethodsFactory +import com.stripe.android.ui.core.PaymentsTheme +import com.stripe.android.ui.core.PaymentsThemeDefaults +import org.junit.Rule +import org.junit.Test + +class PaymentMethodsUIScreenshot : ScreenshotTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun testPaymentMethodsCarouselWithInitialScrollState() { + val colors = PaymentsThemeDefaults.colorsLight + val paymentMethods = MockPaymentMethodsFactory.create() + + composeTestRule.setContent { + PaymentsTheme(colors = PaymentsThemeDefaults.colorsLight) { + Surface( + color = colors.materialColors.surface, + modifier = Modifier.padding(vertical = 16.dp) + ) { + PaymentMethodsUI( + paymentMethods = paymentMethods, + selectedIndex = 0, + isEnabled = true, + onItemSelectedListener = {} + ) + } + } + } + compareScreenshot(composeTestRule) + } + + @Test + fun testPaymentMethodsCarouselScrolledToTheEnd() { + val colors = PaymentsThemeDefaults.colorsLight + val paymentMethods = MockPaymentMethodsFactory.create() + + composeTestRule.setContent { + PaymentsTheme(colors = PaymentsThemeDefaults.colorsLight) { + Surface( + color = colors.materialColors.surface, + modifier = Modifier.padding(vertical = 16.dp) + ) { + PaymentMethodsUI( + paymentMethods = paymentMethods, + selectedIndex = 3, + isEnabled = true, + onItemSelectedListener = {} + ) + } + } + } + compareScreenshot(composeTestRule) + } +} diff --git a/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/MockPaymentMethodsFactory.kt b/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/MockPaymentMethodsFactory.kt new file mode 100644 index 00000000000..bc390ab536c --- /dev/null +++ b/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/MockPaymentMethodsFactory.kt @@ -0,0 +1,56 @@ +package com.stripe.android.paymentsheet.utils + +import com.stripe.android.paymentsheet.forms.PaymentMethodRequirements +import com.stripe.android.ui.core.R +import com.stripe.android.ui.core.elements.LayoutSpec +import com.stripe.android.ui.core.forms.resources.LpmRepository + +object MockPaymentMethodsFactory { + + fun create(): List { + return listOf( + mockPaymentMethod( + code = "card", + displayNameResource = R.string.stripe_paymentsheet_payment_method_card, + iconResource = R.drawable.stripe_ic_paymentsheet_pm_card, + tintIconOnSelection = true + ), + mockPaymentMethod( + code = "klarna", + displayNameResource = R.string.stripe_paymentsheet_payment_method_klarna, + iconResource = R.drawable.stripe_ic_paymentsheet_pm_klarna + ), + mockPaymentMethod( + code = "affirm", + displayNameResource = R.string.stripe_paymentsheet_payment_method_affirm, + iconResource = R.drawable.stripe_ic_paymentsheet_pm_affirm + ), + mockPaymentMethod( + code = "paypal", + displayNameResource = R.string.stripe_paymentsheet_payment_method_paypal, + iconResource = R.drawable.stripe_ic_paymentsheet_pm_paypal + ) + ) + } + + private fun mockPaymentMethod( + code: String, + displayNameResource: Int, + iconResource: Int, + tintIconOnSelection: Boolean = false + ): LpmRepository.SupportedPaymentMethod { + return LpmRepository.SupportedPaymentMethod( + code, + requiresMandate = false, + displayNameResource = displayNameResource, + iconResource = iconResource, + tintIconOnSelection = tintIconOnSelection, + requirement = PaymentMethodRequirements( + piRequirements = emptySet(), + siRequirements = emptySet(), + confirmPMFromCustomer = true + ), + formSpec = LayoutSpec(items = emptyList()) + ) + } +} diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt index 1b5a17b118f..c2e6d98fa93 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState @@ -43,7 +44,7 @@ internal fun PaymentMethodsUI( paymentMethods: List, selectedIndex: Int, isEnabled: Boolean, - onItemSelectedListener: (SupportedPaymentMethod) -> Unit + onItemSelectedListener: (SupportedPaymentMethod) -> Unit, ) { val scope = rememberCoroutineScope() val state = rememberLazyListState() From d5b71c32d43cc598b4137b5b6ad0eacd46298f9c Mon Sep 17 00:00:00 2001 From: Till Hellmund Date: Fri, 19 Aug 2022 14:41:19 -0400 Subject: [PATCH 3/3] Switch to userScrollEnabled for the carousel --- .../android/paymentsheet/LazyListEnabable.kt | 24 ------------------- .../android/paymentsheet/PaymentMethodsUI.kt | 14 ++--------- 2 files changed, 2 insertions(+), 36 deletions(-) delete mode 100644 paymentsheet/src/main/java/com/stripe/android/paymentsheet/LazyListEnabable.kt diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/LazyListEnabable.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/LazyListEnabable.kt deleted file mode 100644 index e37ccac16eb..00000000000 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/LazyListEnabable.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.stripe.android.paymentsheet - -import androidx.compose.foundation.MutatePriority -import androidx.compose.foundation.lazy.LazyListState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.awaitCancellation -import kotlinx.coroutines.launch - -internal fun LazyListState.disableScrolling(scope: CoroutineScope) { - scope.launch { - scroll(scrollPriority = MutatePriority.PreventUserInput) { - // Await indefinitely, blocking scrolls - awaitCancellation() - } - } -} - -internal fun LazyListState.reenableScrolling(scope: CoroutineScope) { - scope.launch { - scroll(scrollPriority = MutatePriority.PreventUserInput) { - // Do nothing, just cancel the previous indefinite "scroll" - } - } -} diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt index c2e6d98fa93..1b0084a13f8 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentMethodsUI.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState @@ -16,7 +15,6 @@ import androidx.compose.foundation.selection.selectable import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.ColorFilter @@ -44,22 +42,14 @@ internal fun PaymentMethodsUI( paymentMethods: List, selectedIndex: Int, isEnabled: Boolean, - onItemSelectedListener: (SupportedPaymentMethod) -> Unit, + onItemSelectedListener: (SupportedPaymentMethod) -> Unit ) { - val scope = rememberCoroutineScope() val state = rememberLazyListState() LaunchedEffect(selectedIndex) { state.scrollToItem(selectedIndex, 0) } - LaunchedEffect(isEnabled) { - if (isEnabled) { - state.reenableScrolling(scope) - } else { - state.disableScrolling(scope) - } - } PaymentsTheme { BoxWithConstraints( modifier = Modifier @@ -70,10 +60,10 @@ internal fun PaymentMethodsUI( paymentMethods.size ) - // TODO: userScrollEnabled will be available in compose version 1.2.0-alpha01+ LazyRow( state = state, contentPadding = PaddingValues(horizontal = PM_LIST_PADDING.dp), + userScrollEnabled = isEnabled, modifier = Modifier.testTag(TEST_TAG_LIST) ) { itemsIndexed(items = paymentMethods, itemContent = { index, item ->