Skip to content
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

[Not being merged to master] Add public api for primary button #4888

Merged
merged 6 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from 7 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
221 changes: 218 additions & 3 deletions paymentsheet/api/paymentsheet.api

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
Expand Down Expand Up @@ -78,19 +79,19 @@ internal abstract class BasePaymentMethodsListFragment(
}

private fun setEditMenuText() {
val context = context ?: return
val appearance = sheetViewModel.config?.appearance ?: return
editMenuItem?.apply {
context?.let {
title = createTextSpanFromTextStyle(
text = getString(if (isEditing) R.string.done else R.string.edit),
context = it,
fontSizeDp = (
PaymentsThemeDefaults.typography.fontSizeMultiplier
* PaymentsThemeDefaults.typography.smallFontSize.value
).dp,
color = PaymentsThemeDefaults.colors(it.isSystemDarkTheme()).appBarIcon,
fontFamily = PaymentsThemeDefaults.typography.fontFamily
)
}
title = createTextSpanFromTextStyle(
text = getString(if (isEditing) R.string.done else R.string.edit),
context = context,
fontSizeDp = (
appearance.typography.sizeScaleFactor
* PaymentsThemeDefaults.typography.smallFontSize.value
).dp,
color = Color(appearance.getColors(context.isSystemDarkTheme()).appBarIcon),
fontFamily = appearance.typography.fontResId
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ package com.stripe.android.paymentsheet
import android.content.res.ColorStateList
import android.os.Parcelable
import androidx.activity.ComponentActivity
import androidx.annotation.ColorInt
import androidx.annotation.FontRes
import androidx.compose.ui.graphics.toArgb
import androidx.fragment.app.Fragment
import com.stripe.android.model.PaymentIntent
import com.stripe.android.model.SetupIntent
import com.stripe.android.paymentsheet.flowcontroller.FlowControllerFactory
import com.stripe.android.paymentsheet.model.PaymentOption
import com.stripe.android.ui.core.PaymentsThemeDefaults
import kotlinx.parcelize.Parcelize

/**
Expand Down Expand Up @@ -122,7 +126,12 @@ class PaymentSheet internal constructor(
*
* See [payment-notification](https://stripe.com/docs/payments/payment-methods#payment-notification).
*/
val allowsDelayedPaymentMethods: Boolean = false
val allowsDelayedPaymentMethods: Boolean = false,

/**
* Describes the appearance of Payment Sheet
*/
val appearance: Appearance = Appearance()
) : Parcelable {
/**
* [Configuration] builder for cleaner object creation from Java.
Expand All @@ -135,6 +144,7 @@ class PaymentSheet internal constructor(
private var primaryButtonColor: ColorStateList? = null
private var defaultBillingDetails: BillingDetails? = null
private var allowsDelayedPaymentMethods: Boolean = false
private var appearance: Appearance = Appearance()

fun merchantDisplayName(merchantDisplayName: String) =
apply { this.merchantDisplayName = merchantDisplayName }
Expand All @@ -154,17 +164,240 @@ class PaymentSheet internal constructor(
fun allowsDelayedPaymentMethods(allowsDelayedPaymentMethods: Boolean) =
apply { this.allowsDelayedPaymentMethods = allowsDelayedPaymentMethods }

fun appearance(appearance: Appearance) =
apply { this.appearance = appearance }

fun build() = Configuration(
merchantDisplayName,
customer,
googlePay,
primaryButtonColor,
defaultBillingDetails,
allowsDelayedPaymentMethods
allowsDelayedPaymentMethods,
appearance
)
}
}

@Parcelize
data class Appearance(
// Describes the colors used while the system is in light mode
val colorsLight: Colors = Colors.defaultLight,

// Describes the colors used while the system is in dark mode
val colorsDark: Colors = Colors.defaultDark,

// Describes the appearance of shapes
val shapes: Shapes = Shapes.default,

// Describes the typography used for text.
val typography: Typography = Typography.default,

// Describes appearance of the primary button (e.g., the "Pay" button) in PaymentSheet
skyler-stripe marked this conversation as resolved.
Show resolved Hide resolved
val primaryButton: PrimaryButton = PrimaryButton()
) : Parcelable {
fun getColors(isDark: Boolean): Colors {
return if (isDark) colorsDark else colorsLight
}

class Builder {
private var colorsLight = Colors.defaultLight
private var colorsDark = Colors.defaultDark
private var shapes = Shapes.default
private var typography = Typography.default
private var primaryButton: PrimaryButton = PrimaryButton()

fun colorsLight(colors: Colors) = apply { this.colorsLight = colors }
fun colorsDark(colors: Colors) = apply { this.colorsDark = colors }
fun shapes(shapes: Shapes) = apply { this.shapes = shapes }
fun typography(typography: Typography) = apply { this.typography = typography }
fun primaryButton(primaryButton: PrimaryButton) =
apply { this.primaryButton = primaryButton }
}
}

@Parcelize
data class Colors(
// A primary color used throughout PaymentSheet
@ColorInt
val primary: Int,

// The color used for the surfaces (backgrounds) of PaymentSheet
@ColorInt
val surface: Int,

// The color used for the background of inputs, tabs, and other components
@ColorInt
val component: Int,

// The color used for borders of inputs, tabs, and other components
@ColorInt
val componentBorder: Int,

// The color of the divider lines used inside inputs, tabs, and other components
@ColorInt
val componentDivider: Int,

// The default color used for text and on other elements that live on components
@ColorInt
val onComponent: Int,

// The color used for items appearing over the background in Payment Sheet
@ColorInt
val onSurface: Int,

// The color used for text of secondary importance. For example, this color is used for the label above input fields
@ColorInt
val subtitle: Int,

// The color used for input placeholder text
@ColorInt
val placeholderText: Int,

// The color used for icons in PaymentSheet, such as the close or back icons
@ColorInt
val appBarIcon: Int,

// A color used to indicate errors or destructive actions in PaymentSheet
@ColorInt
val error: Int,
) : Parcelable {
companion object {
val defaultLight = Colors(
primary = PaymentsThemeDefaults.colorsLight.primary.toArgb(),
surface = PaymentsThemeDefaults.colorsLight.surface.toArgb(),
component = PaymentsThemeDefaults.colorsLight.component.toArgb(),
componentBorder = PaymentsThemeDefaults.colorsLight.componentBorder.toArgb(),
componentDivider = PaymentsThemeDefaults.colorsLight.componentDivider.toArgb(),
onComponent = PaymentsThemeDefaults.colorsLight.onComponent.toArgb(),
subtitle = PaymentsThemeDefaults.colorsLight.subtitle.toArgb(),
placeholderText = PaymentsThemeDefaults.colorsLight.placeholderText.toArgb(),
onSurface = PaymentsThemeDefaults.colorsLight.onSurface.toArgb(),
appBarIcon = PaymentsThemeDefaults.colorsLight.appBarIcon.toArgb(),
error = PaymentsThemeDefaults.colorsLight.error.toArgb(),
)

val defaultDark = Colors(
primary = PaymentsThemeDefaults.colorsDark.primary.toArgb(),
surface = PaymentsThemeDefaults.colorsDark.surface.toArgb(),
component = PaymentsThemeDefaults.colorsDark.component.toArgb(),
componentBorder = PaymentsThemeDefaults.colorsDark.componentBorder.toArgb(),
componentDivider = PaymentsThemeDefaults.colorsDark.componentDivider.toArgb(),
onComponent = PaymentsThemeDefaults.colorsDark.onComponent.toArgb(),
subtitle = PaymentsThemeDefaults.colorsDark.subtitle.toArgb(),
placeholderText = PaymentsThemeDefaults.colorsDark.placeholderText.toArgb(),
onSurface = PaymentsThemeDefaults.colorsDark.onSurface.toArgb(),
appBarIcon = PaymentsThemeDefaults.colorsDark.appBarIcon.toArgb(),
error = PaymentsThemeDefaults.colorsDark.error.toArgb(),
)
}
}

@Parcelize
data class Shapes(
// The corner radius used for tabs, inputs, buttons, and other components in PaymentSheet
val cornerRadiusDp: Float,

// The border used for inputs, tabs, and other components in PaymentSheet
val borderStrokeWidthDp: Float,
) : Parcelable {
companion object {
val default = Shapes(
cornerRadiusDp = PaymentsThemeDefaults.shapes.cornerRadius,
borderStrokeWidthDp = PaymentsThemeDefaults.shapes.borderStrokeWidth,
)
}
}

@Parcelize
data class Typography(
// The scale factor for all fonts in PaymentSheet, the default value is 1.0.
// When this value increases fonts will increase in size and decrease when this value is lowered
val sizeScaleFactor: Float,

// Base weight for text
val normalWeight: Int,

// Medium weight for text
val mediumWeight: Int,

// Bold weight for text
val boldWeight: Int,

// The font used in text. This should be a resource ID value.
@FontRes
val fontResId: Int?,
) : Parcelable {
companion object {
val default = Typography(
sizeScaleFactor = PaymentsThemeDefaults.typography.fontSizeMultiplier,
normalWeight = PaymentsThemeDefaults.typography.fontWeightNormal,
mediumWeight = PaymentsThemeDefaults.typography.fontWeightMedium,
boldWeight = PaymentsThemeDefaults.typography.fontWeightBold,
fontResId = PaymentsThemeDefaults.typography.fontFamily
)
}
}

@Parcelize
data class PrimaryButton(
skyler-stripe marked this conversation as resolved.
Show resolved Hide resolved
// Describes the colors used while the system is in light mode
val colorsLight: PrimaryButtonColors = PrimaryButtonColors.defaultLight,
// Describes the colors used while the system is in dark mode
val colorsDark: PrimaryButtonColors = PrimaryButtonColors.defaultDark,
// Describes the shape of the primary button.
val shape: PrimaryButtonShape = PrimaryButtonShape(),
// Describes the typography of the primary button.
val typography: PrimaryButtonTypography = PrimaryButtonTypography()
) : Parcelable

@Parcelize
data class PrimaryButtonColors(
// The background color of the primary button
// Note: if 'null' the Appearance.Colors.primary is used.
skyler-stripe marked this conversation as resolved.
Show resolved Hide resolved
@ColorInt
val background: Int?,
// The color appearing on the primary button
skyler-stripe marked this conversation as resolved.
Show resolved Hide resolved
@ColorInt
val onBackground: Int,
// The border color of the primary button
skyler-stripe marked this conversation as resolved.
Show resolved Hide resolved
@ColorInt
val border: Int,
) : Parcelable {
companion object {
val defaultLight = PrimaryButtonColors(
background = null,
onBackground =
PaymentsThemeDefaults.primaryButtonStyle.colorsLight.onBackground.toArgb(),
border = PaymentsThemeDefaults.primaryButtonStyle.colorsLight.border.toArgb(),
)
val defaultDark = PrimaryButtonColors(
background = null,
onBackground =
PaymentsThemeDefaults.primaryButtonStyle.colorsDark.onBackground.toArgb(),
border = PaymentsThemeDefaults.primaryButtonStyle.colorsDark.border.toArgb(),
)
}
}

@Parcelize
data class PrimaryButtonShape(
// The corner radius of the primary button
// Note: if 'null' the Appearance.Shapes.cornerRadiusDp is used.
val cornerRadiusDp: Float? = null,
// The border width of the primary button
// Note: if 'null' the Appearance.Shapes.borderStrokeWidthDp is used.
val borderStrokeWidthDp: Float? = null
) : Parcelable

@Parcelize
data class PrimaryButtonTypography(
// The font used in the primary button.
// Note: if 'null' the Appearance.Typography.fontResId is used.
@FontRes
val fontResId: Int? = null
) : Parcelable

@Parcelize
data class Address(
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.widget.TextView
import androidx.activity.viewModels
import androidx.annotation.IdRes
import androidx.annotation.VisibleForTesting
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.os.bundleOf
Expand All @@ -30,7 +31,6 @@ import com.stripe.android.paymentsheet.ui.AnimationConstants
import com.stripe.android.paymentsheet.ui.BaseSheetActivity
import com.stripe.android.paymentsheet.ui.GooglePayDividerUi
import com.stripe.android.ui.core.PaymentsTheme
import com.stripe.android.ui.core.PaymentsThemeDefaults
import com.stripe.android.ui.core.getBackgroundColor
import com.stripe.android.ui.core.isSystemDarkTheme
import com.stripe.android.ui.core.shouldUseDarkDynamicColor
Expand Down Expand Up @@ -100,6 +100,7 @@ internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {
try {
starterArgs.config?.validate()
starterArgs.clientSecret.validate()
starterArgs.config?.appearance?.parseAppearance()
} catch (e: InvalidParameterException) {
setActivityResult(PaymentSheetResult.Failed(e))
finish()
Expand Down Expand Up @@ -310,8 +311,9 @@ internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {
}

private fun setupGooglePayButton() {
val surfaceColor = PaymentsThemeDefaults.colors(isSystemDarkTheme()).surface
googlePayButton.setBackgroundColor(surfaceColor.shouldUseDarkDynamicColor())
viewModel.config?.appearance?.getColors(isSystemDarkTheme())?.surface?.let {
googlePayButton.setBackgroundColor(Color(it).shouldUseDarkDynamicColor())
}

googlePayButton.setOnClickListener {
// The scroll will be made visible onResume of the activity
Expand Down
Loading