Skip to content

Allow text input inset changes for Payment Element #10902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import com.stripe.android.paymentsheet.example.playground.activity.FawryActivity
import com.stripe.android.paymentsheet.example.playground.activity.QrCodeActivity
import com.stripe.android.paymentsheet.example.playground.activity.getEmbeddedAppearance
import com.stripe.android.paymentsheet.example.playground.activity.getFormInsetsAppearance
import com.stripe.android.paymentsheet.example.playground.activity.getTextFieldInsetsAppearance
import com.stripe.android.paymentsheet.example.playground.embedded.EmbeddedPlaygroundOneStepContract
import com.stripe.android.paymentsheet.example.playground.embedded.EmbeddedPlaygroundTwoStepContract
import com.stripe.android.paymentsheet.example.playground.settings.CheckoutMode
Expand All @@ -63,6 +64,7 @@ import com.stripe.android.paymentsheet.example.playground.settings.Initializatio
import com.stripe.android.paymentsheet.example.playground.settings.PlaygroundConfigurationData
import com.stripe.android.paymentsheet.example.playground.settings.PlaygroundSettings
import com.stripe.android.paymentsheet.example.playground.settings.SettingsUi
import com.stripe.android.paymentsheet.example.playground.settings.TextFieldInsetsAppearanceSettingDefinition
import com.stripe.android.paymentsheet.example.playground.settings.WalletButtonsSettingsDefinition
import com.stripe.android.paymentsheet.example.samples.ui.shared.BuyButton
import com.stripe.android.paymentsheet.example.samples.ui.shared.CHECKOUT_TEST_TAG
Expand Down Expand Up @@ -259,6 +261,8 @@ internal class PaymentSheetPlaygroundActivity :
val settings = viewModel.playgroundSettingsFlow.collectAsState().value
val embeddedAppearance = settings?.get(EmbeddedAppearanceSettingsDefinition)?.collectAsState()?.value
val insetsAppearance = settings?.get(FormInsetsAppearanceSettingDefinition)?.collectAsState()?.value
val textFieldInsetsAppearance =
settings?.get(TextFieldInsetsAppearanceSettingDefinition)?.collectAsState()?.value
supportFragmentManager.setFragmentResultListener(
AppearanceBottomSheetDialogFragment.REQUEST_KEY,
this@PaymentSheetPlaygroundActivity
Expand All @@ -271,13 +275,18 @@ internal class PaymentSheetPlaygroundActivity :
FormInsetsAppearanceSettingDefinition,
bundle.getFormInsetsAppearance()
)
viewModel.updateFormInsetsAppearance(
TextFieldInsetsAppearanceSettingDefinition,
bundle.getTextFieldInsetsAppearance()
)
}
Button(
onClick = {
val bottomSheet = AppearanceBottomSheetDialogFragment.newInstance()
bottomSheet.arguments = Bundle().apply {
putParcelable(AppearanceBottomSheetDialogFragment.EMBEDDED_KEY, embeddedAppearance)
putParcelable(AppearanceBottomSheetDialogFragment.INSETS_KEY, insetsAppearance)
putParcelable(AppearanceBottomSheetDialogFragment.TEXT_FIELD_INSETS_KEY, textFieldInsetsAppearance)
}
bottomSheet.show(supportFragmentManager, bottomSheet.tag)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ import com.stripe.android.paymentsheet.example.playground.settings.CustomerType
import com.stripe.android.paymentsheet.example.playground.settings.EmbeddedAppearance
import com.stripe.android.paymentsheet.example.playground.settings.EmbeddedAppearanceSettingsDefinition
import com.stripe.android.paymentsheet.example.playground.settings.FormInsetsAppearance
import com.stripe.android.paymentsheet.example.playground.settings.FormInsetsAppearanceSettingDefinition
import com.stripe.android.paymentsheet.example.playground.settings.InitializationType
import com.stripe.android.paymentsheet.example.playground.settings.PlaygroundConfigurationData
import com.stripe.android.paymentsheet.example.playground.settings.PlaygroundSettingDefinition
import com.stripe.android.paymentsheet.example.playground.settings.PlaygroundSettings
import com.stripe.android.paymentsheet.example.playground.settings.ShippingAddressSettingsDefinition
import com.stripe.android.paymentsheet.example.samples.networking.awaitModel
Expand Down Expand Up @@ -642,7 +642,7 @@ internal class PaymentSheetPlaygroundViewModel(
}

fun updateFormInsetsAppearance(
appearanceSetting: FormInsetsAppearanceSettingDefinition,
appearanceSetting: PlaygroundSettingDefinition<FormInsetsAppearance>,
value: FormInsetsAppearance
) {
playgroundSettingsFlow.value?.let { settings ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import com.stripe.android.paymentsheet.PaymentSheet
import com.stripe.android.paymentsheet.example.R
import com.stripe.android.paymentsheet.example.playground.activity.AppearanceBottomSheetDialogFragment.Companion.EMBEDDED_KEY
import com.stripe.android.paymentsheet.example.playground.activity.AppearanceBottomSheetDialogFragment.Companion.INSETS_KEY
import com.stripe.android.paymentsheet.example.playground.activity.AppearanceBottomSheetDialogFragment.Companion.TEXT_FIELD_INSETS_KEY
import com.stripe.android.paymentsheet.example.playground.settings.EmbeddedAppearance
import com.stripe.android.paymentsheet.example.playground.settings.EmbeddedRow
import com.stripe.android.paymentsheet.example.playground.settings.FormInsetsAppearance
Expand All @@ -84,6 +85,7 @@ internal class AppearanceBottomSheetDialogFragment : BottomSheetDialogFragment()

private var embeddedAppearance by mutableStateOf(EmbeddedAppearance())
private var formInsetsAppearance by mutableStateOf(FormInsetsAppearance())
private var textFieldInsetsAppearance by mutableStateOf(FormInsetsAppearance())

override fun onCreateView(
inflater: LayoutInflater,
Expand All @@ -92,6 +94,7 @@ internal class AppearanceBottomSheetDialogFragment : BottomSheetDialogFragment()
): View {
embeddedAppearance = arguments.getEmbeddedAppearance()
formInsetsAppearance = arguments.getFormInsetsAppearance()
textFieldInsetsAppearance = arguments.getTextFieldInsetsAppearance()

return ComposeView(requireContext()).apply {
setContent {
Expand All @@ -101,7 +104,9 @@ internal class AppearanceBottomSheetDialogFragment : BottomSheetDialogFragment()
embeddedAppearance = embeddedAppearance,
updateEmbedded = { embeddedAppearance = it },
formInsetsAppearance = formInsetsAppearance,
textFieldInsetsAppearance = textFieldInsetsAppearance,
updateInsets = { formInsetsAppearance = it },
updateTextFieldInsets = { textFieldInsetsAppearance = it },
resetAppearance = ::resetAppearance
)
}
Expand All @@ -112,13 +117,15 @@ internal class AppearanceBottomSheetDialogFragment : BottomSheetDialogFragment()
AppearanceStore.reset()
embeddedAppearance = EmbeddedAppearance()
formInsetsAppearance = FormInsetsAppearance()
textFieldInsetsAppearance = FormInsetsAppearance(start = 0f, end = 0f, top = 0f, bottom = 0f)
}

override fun onDestroy() {
super.onDestroy()
val result = Bundle().apply {
putParcelable(EMBEDDED_KEY, embeddedAppearance)
putParcelable(INSETS_KEY, formInsetsAppearance)
putParcelable(TEXT_FIELD_INSETS_KEY, textFieldInsetsAppearance)
}
setFragmentResult(REQUEST_KEY, result)
}
Expand All @@ -131,6 +138,7 @@ internal class AppearanceBottomSheetDialogFragment : BottomSheetDialogFragment()
const val REQUEST_KEY = "REQUEST_KEY"
const val EMBEDDED_KEY = "EMBEDDED_APPEARANCE"
const val INSETS_KEY = "INSETS_APPEARANCE"
const val TEXT_FIELD_INSETS_KEY = "TEXT_FIELD_INSETS_APPEARANCE"
}
}

Expand All @@ -141,7 +149,9 @@ private fun AppearancePicker(
embeddedAppearance: EmbeddedAppearance,
updateEmbedded: (EmbeddedAppearance) -> Unit,
formInsetsAppearance: FormInsetsAppearance,
textFieldInsetsAppearance: FormInsetsAppearance,
updateInsets: (FormInsetsAppearance) -> Unit,
updateTextFieldInsets: (FormInsetsAppearance) -> Unit,
resetAppearance: () -> Unit,
) {
val scrollState = rememberScrollState()
Expand Down Expand Up @@ -180,6 +190,12 @@ private fun AppearancePicker(
updateInsets = updateInsets
)
}
CustomizationCard("Text Field Insets") {
Insets(
insetsAppearance = textFieldInsetsAppearance,
updateInsets = updateTextFieldInsets
)
}
CustomizationCard("Typography") {
Typography(
currentAppearance = currentAppearance,
Expand Down Expand Up @@ -1145,3 +1161,13 @@ internal fun Bundle?.getFormInsetsAppearance(): FormInsetsAppearance {
}
return appearance ?: FormInsetsAppearance()
}

internal fun Bundle?.getTextFieldInsetsAppearance(): FormInsetsAppearance {
val appearance = if (SDK_INT >= 33) {
this?.getParcelable(TEXT_FIELD_INSETS_KEY, FormInsetsAppearance::class.java)
} else {
@Suppress("DEPRECATION")
this?.getParcelable(TEXT_FIELD_INSETS_KEY)
}
return appearance ?: FormInsetsAppearance()
}
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,8 @@ internal class PlaygroundSettings private constructor(
CustomEndpointDefinition,
ShippingAddressSettingsDefinition,
EmbeddedAppearanceSettingsDefinition,
FormInsetsAppearanceSettingDefinition
FormInsetsAppearanceSettingDefinition,
TextFieldInsetsAppearanceSettingDefinition,
)

private val allSettingDefinitions: List<PlaygroundSettingDefinition<*>> =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.stripe.android.paymentsheet.example.playground.settings

import com.stripe.android.paymentsheet.PaymentSheet
import com.stripe.android.paymentsheet.example.playground.activity.AppearanceStore
import kotlinx.serialization.json.Json

internal object TextFieldInsetsAppearanceSettingDefinition :
PlaygroundSettingDefinition<FormInsetsAppearance>,
PlaygroundSettingDefinition.Saveable<FormInsetsAppearance> {
override val key: String
get() = "textFieldInsetsAppearance"

override val defaultValue: FormInsetsAppearance
get() = FormInsetsAppearance(start = 0f, end = 0f, top = 0f, bottom = 0f)

override fun convertToValue(value: String): FormInsetsAppearance {
return Json.decodeFromString<FormInsetsAppearance>(value)
}

override fun convertToString(value: FormInsetsAppearance): String {
return Json.encodeToString(value)
}

override fun setValue(value: FormInsetsAppearance) {
super.setValue(value)
AppearanceStore.state = AppearanceStore.state.copy(
textFieldInsets = PaymentSheet.Insets(
startDp = value.start,
topDp = value.top,
endDp = value.end,
bottomDp = value.bottom,
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ class PaymentSheet internal constructor(
}

@Parcelize
data class Appearance(
data class Appearance @ExtendedAppearancePreview constructor(
/**
* Describes the colors used while the system is in light mode.
*/
Expand Down Expand Up @@ -1039,7 +1039,12 @@ class PaymentSheet internal constructor(
/**
* Describes the inset values used for all forms
*/
internal val formInsetValues: Insets = Insets.defaultFormInsetValues
internal val formInsetValues: Insets = Insets.defaultFormInsetValues,

/**
* Describes the inset values used inside text fields
*/
internal val textFieldInsets: Insets = Insets.defaultTextFieldInsets
) : Parcelable {
constructor() : this(
colorsLight = Colors.defaultLight,
Expand All @@ -1064,6 +1069,26 @@ class PaymentSheet internal constructor(
embeddedAppearance = Embedded.default
)

@OptIn(ExtendedAppearancePreview::class)
constructor(
colorsLight: Colors = Colors.defaultLight,
colorsDark: Colors = Colors.defaultDark,
shapes: Shapes = Shapes.default,
typography: Typography = Typography.default,
primaryButton: PrimaryButton = PrimaryButton(),
embeddedAppearance: Embedded = Embedded.default,
formInsetValues: Insets = Insets.defaultFormInsetValues,
) : this(
colorsLight = colorsLight,
colorsDark = colorsDark,
shapes = shapes,
typography = typography,
primaryButton = primaryButton,
embeddedAppearance = embeddedAppearance,
formInsetValues = formInsetValues,
textFieldInsets = Insets.defaultTextFieldInsets
)

fun getColors(isDark: Boolean): Colors {
return if (isDark) colorsDark else colorsLight
}
Expand Down Expand Up @@ -1379,6 +1404,7 @@ class PaymentSheet internal constructor(
private var shapes = Shapes.default
private var typography = Typography.default
private var primaryButton: PrimaryButton = PrimaryButton()
private var textFieldInsets = Insets.defaultTextFieldInsets

@ExperimentalEmbeddedPaymentElementApi
private var embeddedAppearance: Embedded =
Expand Down Expand Up @@ -1409,9 +1435,23 @@ class PaymentSheet internal constructor(
this.embeddedAppearance = embeddedAppearance
}

@OptIn(ExperimentalEmbeddedPaymentElementApi::class)
@ExtendedAppearancePreview
fun textFieldInsets(textFieldInsets: Insets) = apply {
this.textFieldInsets = textFieldInsets
}

@OptIn(ExperimentalEmbeddedPaymentElementApi::class, ExtendedAppearancePreview::class)
fun build(): Appearance {
return Appearance(colorsLight, colorsDark, shapes, typography, primaryButton, embeddedAppearance)
return Appearance(
colorsLight = colorsLight,
colorsDark = colorsDark,
shapes = shapes,
typography = typography,
primaryButton = primaryButton,
embeddedAppearance = embeddedAppearance,
formInsetValues = Insets.defaultFormInsetValues,
textFieldInsets = textFieldInsets,
)
}
}
}
Expand Down Expand Up @@ -1859,6 +1899,13 @@ class PaymentSheet internal constructor(
endDp = 20f,
bottomDp = 40f,
)

internal val defaultTextFieldInsets = Insets(
startDp = 0f,
topDp = 0f,
endDp = 0f,
bottomDp = 0f,
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,11 @@ internal fun PaymentSheet.Appearance.parseAppearance() {
end = formInsetValues.endDp,
bottom = formInsetValues.bottomDp
)

StripeTheme.textFieldInsets = StripeThemeDefaults.textFieldInsets.copy(
start = textFieldInsets.startDp,
top = textFieldInsets.topDp,
end = textFieldInsets.endDp,
bottom = textFieldInsets.bottomDp
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.stripe.android.paymentsheet.ui

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.ZeroCornerSize
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
Expand All @@ -10,11 +12,16 @@ import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import com.stripe.android.uicore.StripeTheme
import com.stripe.android.uicore.elements.TextFieldColors
import com.stripe.android.uicore.elements.compat.CompatTextField
import com.stripe.android.uicore.stripeColors

@Composable
Expand All @@ -36,9 +43,12 @@ internal fun CommonTextField(
enabled = enabled
),
) {
TextField(
modifier = modifier.fillMaxWidth(),
value = value,
val textFieldInsets = StripeTheme.textFieldInsets

CompatTextField(
modifier = modifier
.fillMaxWidth(),
value = TextFieldValue(value),
enabled = enabled,
label = {
Label(
Expand All @@ -51,7 +61,18 @@ internal fun CommonTextField(
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
visualTransformation = visualTransformation,
onValueChange = onValueChange,
onValueChange = { textFieldValue ->
onValueChange(textFieldValue.text)
},
errorMessage = null,
contentPadding = remember(textFieldInsets) {
PaddingValues(
start = textFieldInsets.start.dp,
end = textFieldInsets.end.dp,
top = textFieldInsets.top.dp,
bottom = textFieldInsets.bottom.dp,
)
}
)
}

Expand Down
Loading
Loading