diff --git a/build.gradle b/build.gradle
index eeef5433a..581dc29ea 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@
buildscript {
ext {
- androidGradlePluginVersion = '8.10.1'
+ androidGradlePluginVersion = '8.11.0'
kotlinVersion = '2.1.20'
kspVersion = '2.1.20-1.0.32'
dokkaVersion = '1.9.20'
diff --git a/sdk/src/main/kotlin/com/processout/sdk/api/model/response/napm/v2/PONativeAlternativePaymentElement.kt b/sdk/src/main/kotlin/com/processout/sdk/api/model/response/napm/v2/PONativeAlternativePaymentElement.kt
index 7572219e6..71b6ed1c4 100644
--- a/sdk/src/main/kotlin/com/processout/sdk/api/model/response/napm/v2/PONativeAlternativePaymentElement.kt
+++ b/sdk/src/main/kotlin/com/processout/sdk/api/model/response/napm/v2/PONativeAlternativePaymentElement.kt
@@ -78,13 +78,13 @@ sealed class PONativeAlternativePaymentElement {
/**
* Available parameter value.
*
- * @param[value] Parameter value.
+ * @param[key] Parameter value.
* @param[label] Value display label.
* @param[preselected] Indicates whether the value should be preselected by default.
*/
@JsonClass(generateAdapter = true)
data class AvailableValue(
- val value: String,
+ val key: String,
val label: String,
val preselected: Boolean
)
diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt
index cb5ec8392..26fc5b2d5 100644
--- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt
+++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt
@@ -697,8 +697,8 @@ internal class NativeAlternativePaymentMethodViewModel private constructor(
private fun getInputHint(type: ParameterType) =
when (type) {
- EMAIL -> app.getString(R.string.po_native_apm_email_placeholder)
- PHONE -> app.getString(R.string.po_native_apm_phone_placeholder)
+ EMAIL -> app.getString(R.string.po_native_apm_placeholder_email)
+ PHONE -> app.getString(R.string.po_native_apm_placeholder_phone)
else -> null
}
diff --git a/sdk/src/main/res/values-ar/strings.xml b/sdk/src/main/res/values-ar/strings.xml
index 7524ab245..17ba6a447 100644
--- a/sdk/src/main/res/values-ar/strings.xml
+++ b/sdk/src/main/res/values-ar/strings.xml
@@ -29,9 +29,9 @@
فشل حفظ الصورة
لم نتمكن من حفظ الصورة. يرجى التحقق من أذوناتك أو محاولة التقاط لقطة شاشة كبديل.
فهمت
- بلد
- أدخل رقم الهاتف
- name@example.com
+ بلد
+ أدخل رقم الهاتف
+ name@example.com
نجاح! تمت الموافقة على الدفع
البيانات مطلوبة
الرقم غير صحيح
diff --git a/sdk/src/main/res/values-fr/strings.xml b/sdk/src/main/res/values-fr/strings.xml
index 6b47a5e26..c969a6e67 100644
--- a/sdk/src/main/res/values-fr/strings.xml
+++ b/sdk/src/main/res/values-fr/strings.xml
@@ -29,9 +29,9 @@
Échec de l\'enregistrement de l\'image
Nous n\'avons pas pu enregistrer l\'image. Veuillez vérifier vos permissions ou alternativement prendre une capture d\'écran.
Compris
- Pays
- Entrez votre numéro de téléphone
- nom@exemple.fr
+ Pays
+ Entrez votre numéro de téléphone
+ nom@exemple.fr
Succès !\nPaiement confirmé.
Paramètre requis.
Numéro invalide.
diff --git a/sdk/src/main/res/values-pl/strings.xml b/sdk/src/main/res/values-pl/strings.xml
index fee0194b2..43013fafd 100644
--- a/sdk/src/main/res/values-pl/strings.xml
+++ b/sdk/src/main/res/values-pl/strings.xml
@@ -29,9 +29,9 @@
Nie udało się zapisać obrazu
Sprawdź uprawnienia systemu lub zrób zrzut ekranu.
Rozumiem
- Kraj
- Twój numer telefonu
- imię@przykład.pl
+ Kraj
+ Twój numer telefonu
+ imię@przykład.pl
Sukces!\nPłatność przyjęta.
Parametr jest wmagany.
Niepoprawny numer.
diff --git a/sdk/src/main/res/values-pt/strings.xml b/sdk/src/main/res/values-pt/strings.xml
index a69e1e9ba..9fce5156a 100644
--- a/sdk/src/main/res/values-pt/strings.xml
+++ b/sdk/src/main/res/values-pt/strings.xml
@@ -29,9 +29,9 @@
Falha na gravação da imagem
Não conseguimos gravar a imagem. Por favor, verifique as suas permissões ou tire uma captura do ecrā como alternativa.
Compreendi
- País
- Insira o seu número de telemóvel
- nome@exemplo.pt
+ País
+ Insira o seu número de telemóvel
+ nome@exemplo.pt
Successo!\nPagamento aprovado.
Campo obrigatório.
Número inválido.
diff --git a/sdk/src/main/res/values/strings.xml b/sdk/src/main/res/values/strings.xml
index 77be47966..a504d87a2 100644
--- a/sdk/src/main/res/values/strings.xml
+++ b/sdk/src/main/res/values/strings.xml
@@ -29,9 +29,9 @@
Image save failed
We couldn\'t save the image. Please check your permissions or try taking a screenshot as an alternative.
Got it
- Country
- Enter phone number
- name@example.com
+ Country
+ Enter phone number
+ name@example.com
Success!\nPayment approved.
Parameter is required.
Number is not valid.
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt
index 21fdaba19..3ed89ea4b 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt
@@ -136,6 +136,17 @@ object POActionsContainer {
)
}
+ val default2: Style
+ @Composable get() = with(ProcessOutTheme) {
+ Style(
+ primary = POButton.primary2,
+ secondary = POButton.secondary2,
+ dividerColor = colors.border.subtle,
+ backgroundColor = colors.surface.default,
+ axis = POAxis.Vertical
+ )
+ }
+
@Composable
fun custom(style: POActionsContainerStyle) = with(style) {
Style(
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt
index 0a49cb1b9..88345a621 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt
@@ -17,6 +17,7 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
@@ -235,7 +236,7 @@ object POButton {
),
disabled = StateStyle(
text = POText.Style(
- color = colors.text.disabled,
+ color = colors.text.onButtonDisabled,
textStyle = typography.button
),
shape = shapes.roundedCornersSmall,
@@ -252,6 +253,38 @@ object POButton {
)
}
+ val primary2: Style
+ @Composable get() = with(ProcessOutTheme) {
+ Style(
+ normal = StateStyle(
+ text = POText.Style(
+ color = colors.text.inverse,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent),
+ backgroundColor = colors.button.primaryBackgroundDefault,
+ elevation = 0.dp
+ ),
+ disabled = StateStyle(
+ text = POText.Style(
+ color = colors.text.onButtonDisabled,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent),
+ backgroundColor = colors.button.primaryBackgroundDisabled,
+ elevation = 0.dp
+ ),
+ highlighted = HighlightedStyle(
+ textColor = colors.text.inverse,
+ borderColor = Color.Transparent,
+ backgroundColor = colors.button.primaryBackgroundPressed
+ ),
+ progressIndicatorColor = colors.text.inverse
+ )
+ }
+
val secondary: Style
@Composable get() = with(ProcessOutTheme) {
Style(
@@ -261,23 +294,55 @@ object POButton {
textStyle = typography.button
),
shape = shapes.roundedCornersSmall,
- border = POBorderStroke(width = 1.dp, color = colors.button.secondaryBorderDefault),
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent),
backgroundColor = colors.button.secondaryBackgroundDefault,
elevation = 0.dp
),
disabled = StateStyle(
text = POText.Style(
- color = colors.text.disabled,
+ color = colors.text.onButtonDisabled,
textStyle = typography.button
),
shape = shapes.roundedCornersSmall,
- border = POBorderStroke(width = 1.dp, color = colors.button.secondaryBorderDisabled),
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent),
backgroundColor = colors.button.secondaryBackgroundDisabled,
elevation = 0.dp
),
highlighted = HighlightedStyle(
textColor = colors.text.primary,
- borderColor = colors.button.secondaryBorderPressed,
+ borderColor = Color.Transparent,
+ backgroundColor = colors.button.secondaryBackgroundPressed
+ ),
+ progressIndicatorColor = colors.text.primary
+ )
+ }
+
+ val secondary2: Style
+ @Composable get() = with(ProcessOutTheme) {
+ Style(
+ normal = StateStyle(
+ text = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent),
+ backgroundColor = colors.button.secondaryBackgroundDefault,
+ elevation = 0.dp
+ ),
+ disabled = StateStyle(
+ text = POText.Style(
+ color = colors.text.onButtonDisabled,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent),
+ backgroundColor = colors.button.secondaryBackgroundDisabled,
+ elevation = 0.dp
+ ),
+ highlighted = HighlightedStyle(
+ textColor = colors.text.primary,
+ borderColor = Color.Transparent,
backgroundColor = colors.button.secondaryBackgroundPressed
),
progressIndicatorColor = colors.text.primary
@@ -299,12 +364,12 @@ object POButton {
),
disabled = StateStyle(
text = POText.Style(
- color = colors.text.disabled,
+ color = colors.text.onButtonDisabled,
textStyle = typography.button
),
shape = shapes.roundedCornersSmall,
border = POBorderStroke(width = 0.dp, color = Color.Transparent),
- backgroundColor = Color.Transparent,
+ backgroundColor = colors.button.ghostBackgroundDisabled,
elevation = 0.dp
),
highlighted = HighlightedStyle(
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/PODialog.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/PODialog.kt
index 7b766a9d1..1d6a41c05 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/PODialog.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/PODialog.kt
@@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
@@ -30,6 +31,7 @@ import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
import com.processout.sdk.ui.core.theme.ProcessOutTheme.shapes
import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
/** @suppress */
@ProcessOutInternalApi
@@ -166,8 +168,14 @@ object PODialog {
val default: Style
@Composable get() = Style(
- title = POText.title,
- message = POText.body2,
+ title = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s20(FontWeight.SemiBold)
+ ),
+ message = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.paragraph.s16()
+ ),
confirmButton = defaultButton,
dismissButton = defaultButton,
backgroundColor = colors.surface.default
@@ -176,8 +184,22 @@ object PODialog {
private val defaultButton: POButton.Style
@Composable get() = with(POButton.ghost) {
copy(
- normal = normal.copy(paddingHorizontal = spacing.large),
- disabled = disabled.copy(paddingHorizontal = spacing.large)
+ normal = normal.copy(
+ text = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ shape = shapes.roundedCorners6,
+ paddingHorizontal = spacing.space16
+ ),
+ disabled = disabled.copy(
+ text = POText.Style(
+ color = colors.text.onButtonDisabled,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ shape = shapes.roundedCorners6,
+ paddingHorizontal = spacing.space16
+ )
)
}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POIme.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POIme.kt
index b3799bfc0..c629ebb54 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POIme.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POIme.kt
@@ -12,11 +12,13 @@ import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
object POIme {
@Composable
- fun isImeVisibleAsState(): State {
+ fun isImeVisibleAsState(
+ policy: SnapshotMutationPolicy = neverEqualPolicy()
+ ): State {
val isImeVisible = remember {
mutableStateOf(
value = false,
- policy = neverEqualPolicy()
+ policy = policy
)
}
val view = LocalView.current.rootView
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POMessageBox.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POMessageBox.kt
index 11e546e3f..90853fb12 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POMessageBox.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POMessageBox.kt
@@ -18,13 +18,16 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.processout.sdk.ui.core.R
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
+import com.processout.sdk.ui.core.component.POText.Style
import com.processout.sdk.ui.core.style.POMessageBoxStyle
import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
import com.processout.sdk.ui.core.theme.ProcessOutTheme.shapes
import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
/** @suppress */
@ProcessOutInternalApi
@@ -33,7 +36,7 @@ fun POMessageBox(
text: String?,
modifier: Modifier = Modifier,
style: POMessageBox.Style = POMessageBox.error,
- horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
+ horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(spacing.space8),
enterAnimationDelayMillis: Int = 0
) {
AnimatedVisibility(
@@ -51,7 +54,10 @@ fun POMessageBox(
)
.clip(style.shape)
.background(color = style.backgroundColor)
- .padding(spacing.extraLarge)
+ .padding(
+ horizontal = spacing.space12,
+ vertical = spacing.space8
+ )
) {
var currentText by remember { mutableStateOf(String()) }
if (!text.isNullOrBlank()) {
@@ -80,7 +86,9 @@ object POMessageBox {
val error: Style
@Composable get() = Style(
- textWithIcon = POTextWithIcon.default,
+ textWithIcon = POTextWithIcon.default.copy(
+ iconResId = R.drawable.po_icon_warning_diamond
+ ),
shape = shapes.roundedCornersSmall,
border = POBorderStroke(
width = 1.dp,
@@ -89,13 +97,34 @@ object POMessageBox {
backgroundColor = colors.surface.error
)
+ val error2: Style
+ @Composable get() {
+ val text = Style(
+ color = colors.text.onTipError,
+ textStyle = typography.s14(FontWeight.Medium)
+ )
+ return Style(
+ textWithIcon = POTextWithIcon.Style(
+ text = text,
+ iconResId = R.drawable.po_icon_warning_diamond,
+ iconColorFilter = ColorFilter.tint(color = text.color)
+ ),
+ shape = shapes.roundedCorners8,
+ border = POBorderStroke(
+ width = 1.dp,
+ color = colors.input.borderDefault2
+ ),
+ backgroundColor = colors.surface.toastError
+ )
+ }
+
@Composable
fun custom(style: POMessageBoxStyle) = with(style) {
val text = POText.custom(style = text)
Style(
textWithIcon = POTextWithIcon.Style(
text = text,
- iconResId = iconResId ?: R.drawable.po_info_icon,
+ iconResId = iconResId ?: error.textWithIcon.iconResId,
iconColorFilter = if (iconResId != null) null else
ColorFilter.tint(color = text.color)
),
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POTextWithIcon.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POTextWithIcon.kt
index 8de3faaf4..aa9f59a42 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POTextWithIcon.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POTextWithIcon.kt
@@ -93,7 +93,7 @@ object POTextWithIcon {
)
return Style(
text = text,
- iconResId = R.drawable.po_info_icon,
+ iconResId = R.drawable.po_icon_info,
iconColorFilter = ColorFilter.tint(color = text.color)
)
}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POField.kt
index 28c9221f5..4e4daf2c8 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POField.kt
@@ -20,6 +20,7 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDirection
@@ -33,6 +34,9 @@ import com.processout.sdk.ui.core.extension.conditional
import com.processout.sdk.ui.core.style.POFieldStateStyle
import com.processout.sdk.ui.core.style.POFieldStyle
import com.processout.sdk.ui.core.theme.ProcessOutTheme
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
/** @suppress */
@ProcessOutInternalApi
@@ -48,6 +52,7 @@ object POField {
@Immutable
data class StateStyle(
val text: POText.Style,
+ val label: POText.Style,
val placeholderTextColor: Color,
val backgroundColor: Color,
val controlsTintColor: Color,
@@ -61,6 +66,7 @@ object POField {
Style(
normal = StateStyle(
text = POText.body2,
+ label = POText.label1,
placeholderTextColor = colors.text.muted,
backgroundColor = colors.input.backgroundDefault,
controlsTintColor = colors.text.primary,
@@ -70,6 +76,10 @@ object POField {
),
error = StateStyle(
text = POText.body2,
+ label = POText.Style(
+ color = colors.text.error,
+ textStyle = typography.label1
+ ),
placeholderTextColor = colors.text.muted,
backgroundColor = colors.input.backgroundDefault,
controlsTintColor = colors.text.primary,
@@ -79,6 +89,7 @@ object POField {
),
focused = StateStyle(
text = POText.body2,
+ label = POText.label1,
placeholderTextColor = colors.text.muted,
backgroundColor = colors.input.backgroundDefault,
controlsTintColor = colors.text.primary,
@@ -89,24 +100,106 @@ object POField {
)
}
+ val default2: Style
+ @Composable get() = with(ProcessOutTheme) {
+ Style(
+ normal = StateStyle(
+ text = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ label = POText.Style(
+ color = colors.text.placeholder,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ placeholderTextColor = colors.text.placeholder,
+ backgroundColor = colors.input.backgroundDefault,
+ controlsTintColor = colors.text.primary,
+ dropdownRippleColor = colors.text.muted,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 1.5.dp, color = colors.input.borderDefault2)
+ ),
+ error = StateStyle(
+ text = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ label = POText.Style(
+ color = colors.text.error,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ placeholderTextColor = colors.text.placeholder,
+ backgroundColor = colors.input.backgroundDefault,
+ controlsTintColor = colors.text.primary,
+ dropdownRippleColor = colors.text.muted,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 1.5.dp, color = colors.input.borderError)
+ ),
+ focused = StateStyle(
+ text = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ label = POText.Style(
+ color = colors.text.placeholder,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ placeholderTextColor = colors.text.placeholder,
+ backgroundColor = colors.input.backgroundDefault,
+ controlsTintColor = colors.text.primary,
+ dropdownRippleColor = colors.text.muted,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 1.5.dp, color = colors.text.primary)
+ )
+ )
+ }
+
@Composable
fun custom(style: POFieldStyle): Style {
val normal = style.normal.toStateStyle()
- return Style(
+ var customStyle = Style(
normal = normal,
error = style.error.toStateStyle(),
focused = style.focused?.toStateStyle() ?: normal
)
+ if (customStyle.normal.label.color == Color.Unspecified) {
+ customStyle = customStyle.copy(
+ normal = customStyle.normal.copy(
+ label = default.normal.label
+ )
+ )
+ }
+ if (customStyle.error.label.color == Color.Unspecified) {
+ customStyle = customStyle.copy(
+ error = customStyle.error.copy(
+ label = default.error.label
+ )
+ )
+ }
+ if (customStyle.focused.label.color == Color.Unspecified) {
+ customStyle = customStyle.copy(
+ focused = customStyle.focused.copy(
+ label = default.focused.label
+ )
+ )
+ }
+ return customStyle
}
@Composable
private fun POFieldStateStyle.toStateStyle() = StateStyle(
text = POText.custom(style = text),
+ label = if (label.colorResId != 0)
+ POText.custom(style = label) else
+ POText.Style(
+ color = Color.Unspecified,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
placeholderTextColor = colorResource(id = placeholderTextColorResId),
backgroundColor = colorResource(id = backgroundColorResId),
controlsTintColor = colorResource(id = controlsTintColorResId),
dropdownRippleColor = dropdownRippleColorResId?.let { colorResource(id = it) }
- ?: ProcessOutTheme.colors.text.muted,
+ ?: colors.text.muted,
shape = RoundedCornerShape(size = border.radiusDp.dp),
border = POBorderStroke(
width = border.widthDp.dp,
@@ -116,8 +209,14 @@ object POField {
val contentPadding: PaddingValues
@Composable get() = PaddingValues(
- horizontal = ProcessOutTheme.spacing.large,
- vertical = ProcessOutTheme.spacing.medium
+ horizontal = spacing.large,
+ vertical = spacing.medium
+ )
+
+ val contentPadding2: PaddingValues
+ @Composable get() = PaddingValues(
+ horizontal = spacing.space12,
+ vertical = spacing.space6
)
internal fun Style.stateStyle(
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POCheckbox.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POCheckbox.kt
index 671b4e905..ad64da76e 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POCheckbox.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POCheckbox.kt
@@ -3,29 +3,34 @@ package com.processout.sdk.ui.core.component.field.checkbox
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CornerBasedShape
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxColors
+import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
import com.processout.sdk.ui.core.component.POText
import com.processout.sdk.ui.core.component.POText.measuredPaddingTop
-import com.processout.sdk.ui.core.component.field.checkbox.POCheckbox.CheckboxScale
-import com.processout.sdk.ui.core.component.field.checkbox.POCheckbox.CheckboxSize
+import com.processout.sdk.ui.core.component.field.checkbox.POCheckbox.MaterialCheckboxSize
import com.processout.sdk.ui.core.component.field.checkbox.POCheckbox.colors
-import com.processout.sdk.ui.core.component.field.checkbox.POCheckbox.textStyle
+import com.processout.sdk.ui.core.component.field.checkbox.POCheckbox.stateStyle
import com.processout.sdk.ui.core.style.POCheckboxStateStyle
import com.processout.sdk.ui.core.style.POCheckboxStyle
import com.processout.sdk.ui.core.style.POCheckmarkStyle
import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.shapes
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
/** @suppress */
@@ -37,15 +42,23 @@ fun POCheckbox(
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
minHeight: Dp = dimensions.formComponentMinHeight,
+ checkboxSize: Dp = MaterialCheckboxSize,
+ rowShape: CornerBasedShape = shapes.roundedCorners4,
style: POCheckbox.Style = POCheckbox.default,
enabled: Boolean = true,
isError: Boolean = false,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
+ val stateStyle = style.stateStyle(
+ checked = checked,
+ enabled = enabled,
+ isError = isError
+ )
Row(
modifier = modifier
.fillMaxWidth()
.requiredHeightIn(min = minHeight)
+ .clip(shape = rowShape)
.clickable(
onClick = {
if (enabled) {
@@ -53,41 +66,35 @@ fun POCheckbox(
}
},
interactionSource = interactionSource,
- indication = null
+ indication = stateStyle.rippleColor?.let { ripple(color = it) }
)
) {
+ val checkboxScale = checkboxSize.value / MaterialCheckboxSize.value
Checkbox(
checked = checked,
onCheckedChange = onCheckedChange,
modifier = Modifier
- .scale(CheckboxScale)
- .requiredWidth(CheckboxSize)
- .requiredHeight(minHeight)
- .offset(x = (-0.5).dp),
+ .scale(checkboxScale)
+ .requiredWidth(checkboxSize)
+ .requiredHeight(minHeight),
enabled = enabled,
- colors = colors(
- style = style,
+ colors = style.colors(
enabled = enabled,
isError = isError
)
)
- val textStyle = textStyle(
- style = style,
- checked = checked,
- enabled = enabled,
- isError = isError
- )
POText(
text = text,
modifier = Modifier.padding(
- start = 10.dp,
+ start = spacing.space10,
top = measuredPaddingTop(
- textStyle = textStyle.textStyle,
+ textStyle = stateStyle.text.textStyle,
componentHeight = minHeight
- )
+ ),
+ bottom = spacing.space10
),
- color = textStyle.color,
- style = textStyle.textStyle
+ color = stateStyle.text.color,
+ style = stateStyle.text.textStyle
)
}
}
@@ -107,7 +114,8 @@ object POCheckbox {
@Immutable
data class StateStyle(
val checkmark: CheckmarkStyle,
- val text: POText.Style
+ val text: POText.Style,
+ val rippleColor: Color?
)
@Immutable
@@ -125,7 +133,8 @@ object POCheckbox {
borderColor = colors.input.borderDefault,
backgroundColor = colors.surface.default
),
- text = POText.label1
+ text = POText.label1,
+ rippleColor = colors.surface.darkoutRipple
),
selected = StateStyle(
checkmark = CheckmarkStyle(
@@ -133,7 +142,8 @@ object POCheckbox {
borderColor = colors.button.primaryBackgroundDefault,
backgroundColor = colors.button.primaryBackgroundDefault
),
- text = POText.label1
+ text = POText.label1,
+ rippleColor = colors.surface.darkoutRipple
),
error = StateStyle(
checkmark = CheckmarkStyle(
@@ -141,7 +151,8 @@ object POCheckbox {
borderColor = colors.input.borderError,
backgroundColor = colors.surface.default
),
- text = POText.label1
+ text = POText.label1,
+ rippleColor = colors.surface.darkoutRipple
),
disabled = StateStyle(
checkmark = CheckmarkStyle(
@@ -152,7 +163,60 @@ object POCheckbox {
text = POText.Style(
color = colors.text.disabled,
textStyle = typography.label1
- )
+ ),
+ rippleColor = null
+ )
+ )
+
+ val default2: Style
+ @Composable get() = Style(
+ normal = StateStyle(
+ checkmark = CheckmarkStyle(
+ color = colors.checkRadio.iconDefault,
+ borderColor = colors.checkRadio.borderDefault,
+ backgroundColor = colors.checkRadio.surfaceDefault
+ ),
+ text = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ rippleColor = colors.surface.darkoutRipple
+ ),
+ selected = StateStyle(
+ checkmark = CheckmarkStyle(
+ color = colors.checkRadio.iconActive,
+ borderColor = colors.checkRadio.borderActive,
+ backgroundColor = colors.checkRadio.surfaceActive
+ ),
+ text = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ rippleColor = colors.surface.darkoutRipple
+ ),
+ error = StateStyle(
+ checkmark = CheckmarkStyle(
+ color = colors.checkRadio.iconError,
+ borderColor = colors.checkRadio.borderError,
+ backgroundColor = colors.checkRadio.surfaceError
+ ),
+ text = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ rippleColor = colors.surface.darkoutRipple
+ ),
+ disabled = StateStyle(
+ checkmark = CheckmarkStyle(
+ color = colors.checkRadio.iconDisabled,
+ borderColor = colors.checkRadio.borderDisabled,
+ backgroundColor = colors.checkRadio.surfaceDisabled
+ ),
+ text = POText.Style(
+ color = colors.text.disabled,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ rippleColor = null
)
)
@@ -167,7 +231,8 @@ object POCheckbox {
@Composable
private fun POCheckboxStateStyle.toStateStyle() = StateStyle(
checkmark = checkmark.toCheckmarkStyle(),
- text = POText.custom(style = text)
+ text = POText.custom(style = text),
+ rippleColor = rippleColorResId?.let { colorResource(id = it) }
)
@Composable
@@ -177,12 +242,9 @@ object POCheckbox {
backgroundColor = colorResource(id = backgroundColorResId)
)
- private val MaterialCheckboxSize = 20.dp
- internal val CheckboxSize = 22.dp
- internal val CheckboxScale = CheckboxSize.value / MaterialCheckboxSize.value
+ internal val MaterialCheckboxSize = 20.dp
- internal fun colors(
- style: Style,
+ internal fun Style.colors(
enabled: Boolean,
isError: Boolean
): CheckboxColors {
@@ -193,22 +255,22 @@ object POCheckbox {
val checkedBorderColor: Color
val checkedBoxColor: Color
if (isError) {
- with(style.error.checkmark) {
+ with(error.checkmark) {
uncheckedCheckmarkColor = this.color
uncheckedBorderColor = this.borderColor
uncheckedBoxColor = this.backgroundColor
- checkedCheckmarkColor = this.color
+ checkedCheckmarkColor = if (enabled) this.color else disabled.checkmark.color
checkedBorderColor = this.borderColor
checkedBoxColor = this.backgroundColor
}
} else {
- with(style.normal.checkmark) {
- uncheckedCheckmarkColor = if (enabled) this.color else style.disabled.checkmark.color
+ with(normal.checkmark) {
+ uncheckedCheckmarkColor = if (enabled) this.color else disabled.checkmark.color
uncheckedBorderColor = this.borderColor
uncheckedBoxColor = this.backgroundColor
}
- with(style.selected.checkmark) {
- checkedCheckmarkColor = if (enabled) this.color else style.disabled.checkmark.color
+ with(selected.checkmark) {
+ checkedCheckmarkColor = if (enabled) this.color else disabled.checkmark.color
checkedBorderColor = this.borderColor
checkedBoxColor = this.backgroundColor
}
@@ -220,23 +282,22 @@ object POCheckbox {
checkedCheckmarkColor = checkedCheckmarkColor,
checkedBorderColor = checkedBorderColor,
checkedBoxColor = checkedBoxColor,
- disabledUncheckedBorderColor = style.disabled.checkmark.borderColor,
- disabledUncheckedBoxColor = style.disabled.checkmark.backgroundColor,
- disabledBorderColor = style.disabled.checkmark.borderColor,
- disabledCheckedBoxColor = style.disabled.checkmark.backgroundColor,
- disabledIndeterminateBorderColor = style.disabled.checkmark.borderColor,
- disabledIndeterminateBoxColor = style.disabled.checkmark.backgroundColor
+ disabledUncheckedBorderColor = disabled.checkmark.borderColor,
+ disabledUncheckedBoxColor = disabled.checkmark.backgroundColor,
+ disabledBorderColor = disabled.checkmark.borderColor,
+ disabledCheckedBoxColor = disabled.checkmark.backgroundColor,
+ disabledIndeterminateBorderColor = disabled.checkmark.borderColor,
+ disabledIndeterminateBoxColor = disabled.checkmark.backgroundColor
)
}
- internal fun textStyle(
- style: Style,
+ internal fun Style.stateStyle(
checked: Boolean,
enabled: Boolean,
isError: Boolean
- ): POText.Style =
- if (!enabled) style.disabled.text
- else if (isError) style.error.text
- else if (checked) style.selected.text
- else style.normal.text
+ ): StateStyle =
+ if (!enabled) disabled
+ else if (isError) error
+ else if (checked) selected
+ else normal
}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POLabeledCheckboxField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POCheckboxField.kt
similarity index 61%
rename from ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POLabeledCheckboxField.kt
rename to ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POCheckboxField.kt
index 6cc3ae6a6..01f5227d6 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POLabeledCheckboxField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/checkbox/POCheckboxField.kt
@@ -1,45 +1,46 @@
package com.processout.sdk.ui.core.component.field.checkbox
import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
-import com.processout.sdk.ui.core.component.field.LabeledFieldLayout
-import com.processout.sdk.ui.core.component.field.POFieldLabels
+import com.processout.sdk.ui.core.component.POMessageBox
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.shapes
/** @suppress */
@ProcessOutInternalApi
@Composable
-fun POLabeledCheckboxField(
+fun POCheckboxField(
text: String,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
- title: String?,
- description: String?,
modifier: Modifier = Modifier,
- checkboxStyle: POCheckbox.Style = POCheckbox.default,
- labelsStyle: POFieldLabels.Style = POFieldLabels.default,
+ checkboxStyle: POCheckbox.Style = POCheckbox.default2,
+ descriptionStyle: POMessageBox.Style = POMessageBox.error2,
enabled: Boolean = true,
isError: Boolean = false,
+ description: String? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
- LabeledFieldLayout(
- title = title,
- description = description,
- style = labelsStyle
- ) {
+ Column(modifier = modifier) {
POCheckbox(
text = text,
checked = checked,
onCheckedChange = onCheckedChange,
- modifier = modifier,
- minHeight = 30.dp,
+ minHeight = 40.dp,
+ checkboxSize = 16.dp,
+ rowShape = shapes.roundedCorners6,
style = checkboxStyle,
enabled = enabled,
isError = isError,
interactionSource = interactionSource
)
+ POMessageBox(
+ text = description,
+ style = descriptionStyle
+ )
}
}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/code/POCodeField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/code/POCodeField.kt
index 3e8196d6a..b6a20a416 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/code/POCodeField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/code/POCodeField.kt
@@ -17,6 +17,7 @@ import androidx.compose.ui.input.key.*
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.*
import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
@@ -25,14 +26,18 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
import com.processout.sdk.ui.core.component.PORequestFocus
+import com.processout.sdk.ui.core.component.POText
import com.processout.sdk.ui.core.component.field.POField
+import com.processout.sdk.ui.core.component.field.code.POCodeField.align
import com.processout.sdk.ui.core.component.field.code.POCodeField.rememberTextFieldWidth
-import com.processout.sdk.ui.core.component.field.code.POCodeField.style
import com.processout.sdk.ui.core.component.field.code.POCodeField.validLength
import com.processout.sdk.ui.core.component.field.text.POTextField
import com.processout.sdk.ui.core.component.texttoolbar.ProcessOutTextToolbar
import com.processout.sdk.ui.core.state.POInputFilter
-import com.processout.sdk.ui.core.theme.ProcessOutTheme
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
/** @suppress */
@ProcessOutInternalApi
@@ -53,7 +58,7 @@ fun POCodeField(
keyboardActions: KeyboardActions = KeyboardActions.Default
) {
var rowWidthPx by remember { mutableIntStateOf(0) }
- val horizontalSpace = ProcessOutTheme.spacing.small
+ val horizontalSpace = spacing.small
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Row(
modifier = Modifier
@@ -145,7 +150,7 @@ fun POCodeField(
modifier = modifier
.requiredWidth(
rememberTextFieldWidth(
- defaultWidth = ProcessOutTheme.dimensions.interactiveComponentMinSize,
+ defaultWidth = dimensions.interactiveComponentMinSize,
rowWidth = with(LocalDensity.current) { rowWidthPx.toDp() },
space = horizontalSpace,
length = validLength
@@ -176,7 +181,7 @@ fun POCodeField(
}
},
contentPadding = PaddingValues(0.dp),
- style = style(style),
+ style = align(style),
enabled = enabled,
isError = isError,
keyboardOptions = keyboardOptions,
@@ -235,30 +240,65 @@ private fun List.codeValue() = TextFieldValue(
object POCodeField {
val default: POField.Style
- @Composable get() = with(POField.default) {
- copy(
- normal = normal.default(),
- error = error.default(),
- focused = focused.default()
+ @Composable get() = POField.default.let {
+ val text = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.title
+ )
+ it.copy(
+ normal = it.normal.copy(text = text),
+ error = it.error.copy(text = text),
+ focused = it.focused.copy(text = text)
)
}
- internal fun style(style: POField.Style) = with(style) {
- copy(
- normal = normal.textAlignCenter(),
- error = error.textAlignCenter(),
- focused = focused.textAlignCenter()
+ val default2: POField.Style
+ @Composable get() = POField.default2.let {
+ val text = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s20(FontWeight.Medium)
+ )
+ it.copy(
+ normal = it.normal.copy(
+ text = text,
+ label = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s16(FontWeight.Medium)
+ )
+ ),
+ error = it.error.copy(
+ text = text,
+ label = POText.Style(
+ color = colors.text.error,
+ textStyle = typography.s16(FontWeight.Medium)
+ )
+ ),
+ focused = it.focused.copy(
+ text = text,
+ label = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s16(FontWeight.Medium)
+ )
+ )
+ )
+ }
+
+ internal fun align(style: POField.Style) = style.let {
+ it.copy(
+ normal = it.normal.textAlignCenter(),
+ error = it.error.textAlignCenter(),
+ focused = it.focused.textAlignCenter()
)
}
- @Composable
- private fun POField.StateStyle.default() = copy(
- text = text.copy(textStyle = ProcessOutTheme.typography.title)
- )
-
- private fun POField.StateStyle.textAlignCenter() = copy(
- text = text.copy(textStyle = text.textStyle.copy(textAlign = TextAlign.Center))
- )
+ private fun POField.StateStyle.textAlignCenter() =
+ copy(
+ text = text.copy(
+ textStyle = text.textStyle.copy(
+ textAlign = TextAlign.Center
+ )
+ )
+ )
val LengthMin = 1
val LengthMax = 8
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/code/POCodeField2.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/code/POCodeField2.kt
new file mode 100644
index 000000000..66c74caea
--- /dev/null
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/code/POCodeField2.kt
@@ -0,0 +1,279 @@
+package com.processout.sdk.ui.core.component.field.code
+
+import androidx.compose.foundation.focusGroup
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusDirection
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.input.key.*
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.*
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.Lifecycle
+import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
+import com.processout.sdk.ui.core.component.POMessageBox
+import com.processout.sdk.ui.core.component.PORequestFocus
+import com.processout.sdk.ui.core.component.POText
+import com.processout.sdk.ui.core.component.field.POField
+import com.processout.sdk.ui.core.component.field.POField.stateStyle
+import com.processout.sdk.ui.core.component.field.code.POCodeField.align
+import com.processout.sdk.ui.core.component.field.code.POCodeField.rememberTextFieldWidth
+import com.processout.sdk.ui.core.component.field.code.POCodeField.validLength
+import com.processout.sdk.ui.core.component.field.text.POTextField2
+import com.processout.sdk.ui.core.component.texttoolbar.ProcessOutTextToolbar
+import com.processout.sdk.ui.core.state.POInputFilter
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+
+/** @suppress */
+@ProcessOutInternalApi
+@Composable
+fun POCodeField2(
+ value: TextFieldValue,
+ onValueChange: (TextFieldValue) -> Unit,
+ modifier: Modifier = Modifier,
+ textFieldModifier: Modifier = Modifier,
+ fieldStyle: POField.Style = POCodeField.default2,
+ descriptionStyle: POMessageBox.Style = POMessageBox.error2,
+ length: Int = POCodeField.LengthMax,
+ label: String? = null,
+ description: String? = null,
+ enabled: Boolean = true,
+ isError: Boolean = false,
+ isFocused: Boolean = false,
+ lifecycleEvent: Lifecycle.Event? = null,
+ inputFilter: POInputFilter? = null,
+ keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+ keyboardActions: KeyboardActions = KeyboardActions.Default
+) {
+ Column(modifier = modifier) {
+ if (!label.isNullOrBlank()) {
+ val fieldStateStyle = fieldStyle.stateStyle(
+ isError = isError,
+ isFocused = isFocused
+ )
+ POText(
+ text = label,
+ modifier = Modifier.padding(bottom = spacing.space12),
+ color = fieldStateStyle.label.color,
+ style = fieldStateStyle.label.textStyle
+ )
+ }
+ Code(
+ value = value,
+ onValueChange = onValueChange,
+ style = fieldStyle,
+ length = length,
+ enabled = enabled,
+ isError = isError,
+ isFocused = isFocused,
+ lifecycleEvent = lifecycleEvent,
+ inputFilter = inputFilter,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ modifier = textFieldModifier
+ )
+ POMessageBox(
+ text = description,
+ modifier = Modifier.padding(top = spacing.space12),
+ style = descriptionStyle
+ )
+ }
+}
+
+@Composable
+private fun Code(
+ value: TextFieldValue,
+ onValueChange: (TextFieldValue) -> Unit,
+ style: POField.Style,
+ length: Int,
+ enabled: Boolean,
+ isError: Boolean,
+ isFocused: Boolean,
+ lifecycleEvent: Lifecycle.Event?,
+ inputFilter: POInputFilter?,
+ keyboardOptions: KeyboardOptions,
+ keyboardActions: KeyboardActions,
+ modifier: Modifier = Modifier
+) {
+ val validLength = remember(length) { validLength(length) }
+ var values by remember(validLength) { mutableStateOf(values(value.text, validLength, inputFilter)) }
+ var focusedIndex by remember(validLength) { mutableIntStateOf(values.focusedIndex()) }
+ val clipboardManager = LocalClipboardManager.current
+ CompositionLocalProvider(
+ LocalLayoutDirection provides LayoutDirection.Ltr,
+ LocalTextToolbar provides ProcessOutTextToolbar(
+ view = LocalView.current,
+ onPasteRequested = {
+ if (clipboardManager.hasText()) {
+ val pastedValues = values(
+ text = clipboardManager.getText()?.text ?: String(),
+ length = validLength,
+ inputFilter = inputFilter
+ )
+ if (!pastedValues.all { it.text.isEmpty() }) {
+ values = pastedValues
+ focusedIndex = values.focusedIndex()
+ onValueChange(values.codeValue())
+ }
+ }
+ },
+ hideUnspecifiedActions = true
+ )
+ ) {
+ var rowWidthPx by remember { mutableIntStateOf(0) }
+ val horizontalSpace = spacing.space8
+ Row(
+ modifier = Modifier
+ .focusGroup()
+ .fillMaxWidth()
+ .onGloballyPositioned { rowWidthPx = it.size.width },
+ horizontalArrangement = Arrangement.spacedBy(horizontalSpace),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ val focusManager = LocalFocusManager.current
+ for (textFieldIndex in values.indices) {
+ val focusRequester = remember { FocusRequester() }
+ POTextField2(
+ value = values[textFieldIndex],
+ onValueChange = { updatedValue ->
+ if (updatedValue.selection.length == 0) {
+ val currentValue = values[textFieldIndex]
+ val updatedFilteredValue = inputFilter?.filter(updatedValue) ?: updatedValue
+ values = values.mapIndexed { index, textFieldValue ->
+ if (index == textFieldIndex) {
+ val updatedText = updatedFilteredValue.text.firstOrNull()?.toString() ?: String()
+ val isTextChanged = textFieldValue.text != updatedText
+ TextFieldValue(
+ text = updatedText,
+ selection = if (isTextChanged) {
+ TextRange(updatedText.length)
+ } else {
+ updatedFilteredValue.selection
+ }
+ )
+ } else {
+ textFieldValue.copy(selection = TextRange.Zero)
+ }
+ }
+ if (textFieldIndex != values.lastIndex &&
+ updatedFilteredValue.text.length == 2 &&
+ updatedFilteredValue.selection.start == 2
+ ) {
+ val nextText = updatedFilteredValue.text.last().toString()
+ values = values.mapIndexed { index, textFieldValue ->
+ if (index == textFieldIndex + 1) {
+ TextFieldValue(
+ text = nextText,
+ selection = TextRange(nextText.length)
+ )
+ } else {
+ textFieldValue.copy(selection = TextRange.Zero)
+ }
+ }
+ }
+ val isSelectionChangedOnly = currentValue.text == updatedFilteredValue.text &&
+ currentValue.selection != updatedFilteredValue.selection
+ if (updatedFilteredValue.text.isNotEmpty() &&
+ !isSelectionChangedOnly &&
+ textFieldIndex != values.lastIndex
+ ) {
+ focusedIndex = textFieldIndex + 1
+ }
+ onValueChange(values.codeValue())
+ }
+ },
+ modifier = Modifier.requiredWidth(
+ rememberTextFieldWidth(
+ defaultWidth = 40.dp,
+ rowWidth = with(LocalDensity.current) { rowWidthPx.toDp() },
+ space = horizontalSpace,
+ length = validLength
+ )
+ ),
+ textFieldModifier = modifier
+ .onPreviewKeyEvent {
+ if (it.key == Key.Backspace &&
+ it.type == KeyEventType.KeyDown &&
+ textFieldIndex != 0 &&
+ values[textFieldIndex].selection.start == 0
+ ) {
+ values = values.mapIndexed { index, textFieldValue ->
+ if (index == textFieldIndex - 1) {
+ TextFieldValue()
+ } else {
+ textFieldValue.copy(selection = TextRange.Zero)
+ }
+ }
+ focusManager.moveFocus(FocusDirection.Previous)
+ onValueChange(values.codeValue())
+ }
+ false
+ }
+ .focusRequester(focusRequester)
+ .onFocusChanged {
+ if (it.isFocused) {
+ focusedIndex = textFieldIndex
+ }
+ },
+ contentPadding = PaddingValues(spacing.space0),
+ fieldStyle = align(style),
+ enabled = enabled,
+ isError = isError,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions
+ )
+ if (isFocused && textFieldIndex == focusedIndex) {
+ if (lifecycleEvent == Lifecycle.Event.ON_RESUME) {
+ PORequestFocus(focusRequester, lifecycleEvent)
+ } else {
+ PORequestFocus(focusRequester)
+ }
+ }
+ }
+ }
+ }
+}
+
+private fun values(
+ text: String,
+ length: Int,
+ inputFilter: POInputFilter?
+): List {
+ val values = mutableListOf()
+ while (values.size < length) {
+ values.add(TextFieldValue())
+ }
+ val filteredText = inputFilter?.filter(TextFieldValue(text = text))?.text ?: text
+ filteredText
+ .take(length)
+ .forEachIndexed { index, char ->
+ val value = char.toString()
+ values[index] = TextFieldValue(
+ text = value,
+ selection = TextRange(value.length)
+ )
+ }
+ return values
+}
+
+private fun List.focusedIndex(): Int {
+ forEachIndexed { index, textFieldValue ->
+ if (textFieldValue.text.isEmpty()) {
+ return index
+ }
+ }
+ return lastIndex
+}
+
+private fun List.codeValue() = TextFieldValue(
+ text = joinToString(separator = String()) { it.text }
+)
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/PODropdownField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/PODropdownField.kt
index dd1707364..4475c289e 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/PODropdownField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/PODropdownField.kt
@@ -17,8 +17,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -26,6 +28,7 @@ import androidx.compose.ui.window.PopupProperties
import com.processout.sdk.ui.core.R
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
import com.processout.sdk.ui.core.component.POBorderStroke
+import com.processout.sdk.ui.core.component.POIme.isImeVisibleAsState
import com.processout.sdk.ui.core.component.POText
import com.processout.sdk.ui.core.component.field.POField
import com.processout.sdk.ui.core.component.field.POField.stateStyle
@@ -33,7 +36,11 @@ import com.processout.sdk.ui.core.component.field.text.POTextField
import com.processout.sdk.ui.core.state.POAvailableValue
import com.processout.sdk.ui.core.state.POImmutableList
import com.processout.sdk.ui.core.style.PODropdownMenuStyle
-import com.processout.sdk.ui.core.theme.ProcessOutTheme
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.shapes
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
/** @suppress */
@ProcessOutInternalApi
@@ -43,25 +50,39 @@ fun PODropdownField(
onValueChange: (TextFieldValue) -> Unit,
availableValues: POImmutableList,
modifier: Modifier = Modifier,
- fieldContentPadding: PaddingValues = POField.contentPadding,
+ contentPadding: PaddingValues = POField.contentPadding,
fieldStyle: POField.Style = POField.default,
menuStyle: PODropdownField.MenuStyle = PODropdownField.defaultMenu,
menuMatchesTextFieldWidth: Boolean = true,
preferFormattedTextSelection: Boolean = false,
enabled: Boolean = true,
isError: Boolean = false,
- placeholderText: String? = null
+ placeholder: String? = null
) {
MaterialTheme(
colorScheme = MaterialTheme.colorScheme.copy(surface = Color.Transparent),
shapes = MaterialTheme.shapes.copy(extraSmall = menuStyle.shape)
) {
var expanded by remember { mutableStateOf(false) }
+ var expanding by remember { mutableStateOf(false) }
+ val isImeVisible by isImeVisibleAsState(policy = structuralEqualityPolicy())
+ if (expanding && isImeVisible) {
+ LocalFocusManager.current.clearFocus(force = true)
+ }
+ LaunchedEffect(expanding, isImeVisible) {
+ if (expanding && !isImeVisible) {
+ expanding = false
+ expanded = true
+ }
+ }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = {
if (enabled) {
- expanded = it
+ when (it) {
+ true -> expanding = true
+ false -> expanded = false
+ }
}
}
) {
@@ -81,13 +102,13 @@ fun PODropdownField(
.onFocusChanged {
isFocused = it.isFocused
},
- contentPadding = fieldContentPadding,
+ contentPadding = contentPadding,
style = fieldStyle,
enabled = enabled,
readOnly = true,
isDropdown = true,
isError = isError,
- placeholderText = placeholderText,
+ placeholder = placeholder,
trailingIcon = {
Icon(
painter = painterResource(id = R.drawable.po_dropdown_arrow),
@@ -97,8 +118,8 @@ fun PODropdownField(
)
}
)
- val menuItemHeight = ProcessOutTheme.dimensions.formComponentMinHeight
- val menuVerticalPaddings = ProcessOutTheme.spacing.large
+ val menuItemHeight = dimensions.formComponentMinHeight
+ val menuVerticalPaddings = spacing.large
val maxMenuHeight = remember { menuItemHeight * PODropdownField.MaxVisibleMenuItems + menuVerticalPaddings }
DropdownMenu(
expanded = expanded,
@@ -150,7 +171,7 @@ private fun MenuItem(
indication = ripple(color = style.rippleColor)
)
.fillMaxWidth()
- .padding(horizontal = ProcessOutTheme.spacing.large),
+ .padding(horizontal = spacing.large),
contentAlignment = Alignment.CenterStart
) {
POText(
@@ -177,15 +198,25 @@ object PODropdownField {
)
val defaultMenu: MenuStyle
- @Composable get() = with(ProcessOutTheme) {
- MenuStyle(
- text = POText.body2,
- backgroundColor = colors.surface.neutral,
- rippleColor = colors.text.muted,
- shape = shapes.roundedCornersSmall,
- border = POBorderStroke(width = 0.dp, color = Color.Transparent)
- )
- }
+ @Composable get() = MenuStyle(
+ text = POText.body2,
+ backgroundColor = colors.surface.neutral,
+ rippleColor = colors.text.muted,
+ shape = shapes.roundedCornersSmall,
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent)
+ )
+
+ val defaultMenu2: MenuStyle
+ @Composable get() = MenuStyle(
+ text = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ backgroundColor = colors.surface.neutral,
+ rippleColor = colors.text.muted,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 0.dp, color = Color.Transparent)
+ )
@Composable
fun custom(style: PODropdownMenuStyle) = with(style) {
@@ -201,5 +232,5 @@ object PODropdownField {
)
}
- internal val MaxVisibleMenuItems = 6
+ internal val MaxVisibleMenuItems = 10
}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/PODropdownField2.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/PODropdownField2.kt
new file mode 100644
index 000000000..305d417ef
--- /dev/null
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/PODropdownField2.kt
@@ -0,0 +1,187 @@
+@file:OptIn(ExperimentalMaterial3Api::class)
+
+package com.processout.sdk.ui.core.component.field.dropdown
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.draw.scale
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.window.PopupProperties
+import com.processout.sdk.ui.core.R
+import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
+import com.processout.sdk.ui.core.component.POIme.isImeVisibleAsState
+import com.processout.sdk.ui.core.component.POMessageBox
+import com.processout.sdk.ui.core.component.POText
+import com.processout.sdk.ui.core.component.field.POField
+import com.processout.sdk.ui.core.component.field.POField.stateStyle
+import com.processout.sdk.ui.core.component.field.text.POTextField2
+import com.processout.sdk.ui.core.state.POAvailableValue
+import com.processout.sdk.ui.core.state.POImmutableList
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+
+/** @suppress */
+@ProcessOutInternalApi
+@Composable
+fun PODropdownField2(
+ value: TextFieldValue,
+ onValueChange: (TextFieldValue) -> Unit,
+ availableValues: POImmutableList,
+ modifier: Modifier = Modifier,
+ textFieldModifier: Modifier = Modifier,
+ contentPadding: PaddingValues = POField.contentPadding2,
+ fieldStyle: POField.Style = POField.default2,
+ menuStyle: PODropdownField.MenuStyle = PODropdownField.defaultMenu2,
+ descriptionStyle: POMessageBox.Style = POMessageBox.error2,
+ menuMatchesTextFieldWidth: Boolean = true,
+ preferFormattedTextSelection: Boolean = false,
+ enabled: Boolean = true,
+ isError: Boolean = false,
+ label: String? = null,
+ placeholder: String? = null,
+ description: String? = null
+) {
+ MaterialTheme(
+ colorScheme = MaterialTheme.colorScheme.copy(surface = Color.Transparent),
+ shapes = MaterialTheme.shapes.copy(extraSmall = menuStyle.shape)
+ ) {
+ var expanded by remember { mutableStateOf(false) }
+ var expanding by remember { mutableStateOf(false) }
+ val isImeVisible by isImeVisibleAsState(policy = structuralEqualityPolicy())
+ if (expanding && isImeVisible) {
+ LocalFocusManager.current.clearFocus(force = true)
+ }
+ LaunchedEffect(expanding, isImeVisible) {
+ if (expanding && !isImeVisible) {
+ expanding = false
+ expanded = true
+ }
+ }
+ ExposedDropdownMenuBox(
+ modifier = modifier,
+ expanded = expanded,
+ onExpandedChange = {
+ if (enabled) {
+ when (it) {
+ true -> expanding = true
+ false -> expanded = false
+ }
+ }
+ }
+ ) {
+ var isFocused by remember { mutableStateOf(false) }
+ val fieldStateStyle = fieldStyle.stateStyle(isError = isError, isFocused = isFocused)
+ POTextField2(
+ value = availableValues.elements.find { it.value == value.text }
+ ?.let {
+ TextFieldValue(
+ text = if (preferFormattedTextSelection && it.formattedText != null)
+ it.formattedText else it.text
+ )
+ } ?: TextFieldValue(),
+ onValueChange = {},
+ modifier = Modifier.fillMaxWidth(),
+ textFieldModifier = textFieldModifier
+ .menuAnchor(MenuAnchorType.PrimaryNotEditable)
+ .onFocusChanged {
+ isFocused = it.isFocused
+ },
+ contentPadding = contentPadding,
+ fieldStyle = fieldStyle,
+ descriptionStyle = descriptionStyle,
+ enabled = enabled,
+ readOnly = true,
+ isDropdown = true,
+ isError = isError,
+ label = label,
+ placeholder = placeholder,
+ description = description,
+ trailingIcon = {
+ Icon(
+ painter = painterResource(id = R.drawable.po_chevron_down),
+ contentDescription = null,
+ modifier = Modifier
+ .scale(1.1f)
+ .rotate(if (expanded) 180f else 0f),
+ tint = fieldStateStyle.label.color
+ )
+ }
+ )
+ val menuItemHeight = dimensions.formComponentMinHeight
+ val menuVerticalPaddings = spacing.large
+ val maxMenuHeight = remember { menuItemHeight * PODropdownField.MaxVisibleMenuItems + menuVerticalPaddings }
+ DropdownMenu(
+ expanded = expanded,
+ onDismissRequest = { expanded = false },
+ modifier = Modifier
+ .exposedDropdownSize(matchTextFieldWidth = menuMatchesTextFieldWidth)
+ .heightIn(max = maxMenuHeight)
+ .border(
+ width = menuStyle.border.width,
+ color = menuStyle.border.color,
+ shape = menuStyle.shape
+ )
+ .background(color = menuStyle.backgroundColor),
+ properties = PopupProperties(
+ focusable = true,
+ dismissOnBackPress = true,
+ dismissOnClickOutside = true
+ )
+ ) {
+ availableValues.elements.forEach { availableValue ->
+ MenuItem(
+ availableValue = availableValue,
+ onClick = {
+ expanded = false
+ onValueChange(TextFieldValue(it.value))
+ },
+ modifier = Modifier.requiredHeight(menuItemHeight),
+ style = menuStyle
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun MenuItem(
+ availableValue: POAvailableValue,
+ onClick: (POAvailableValue) -> Unit,
+ modifier: Modifier = Modifier,
+ style: PODropdownField.MenuStyle,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+ Box(
+ modifier = modifier
+ .clickable(
+ onClick = { onClick(availableValue) },
+ interactionSource = interactionSource,
+ indication = ripple(color = style.rippleColor)
+ )
+ .fillMaxWidth()
+ .padding(horizontal = spacing.large),
+ contentAlignment = Alignment.CenterStart
+ ) {
+ POText(
+ text = availableValue.text,
+ color = style.text.color,
+ style = style.text.textStyle,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1
+ )
+ }
+}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/POLabeledDropdownField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/POLabeledDropdownField.kt
index a28901455..e758566cc 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/POLabeledDropdownField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/dropdown/POLabeledDropdownField.kt
@@ -27,7 +27,7 @@ fun POLabeledDropdownField(
preferFormattedTextSelection: Boolean = false,
enabled: Boolean = true,
isError: Boolean = false,
- placeholderText: String? = null
+ placeholder: String? = null
) {
LabeledFieldLayout(
title = title,
@@ -45,7 +45,7 @@ fun POLabeledDropdownField(
preferFormattedTextSelection = preferFormattedTextSelection,
enabled = enabled,
isError = isError,
- placeholderText = placeholderText
+ placeholder = placeholder
)
}
}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/phone/POLabeledPhoneNumberField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/phone/POLabeledPhoneNumberField.kt
deleted file mode 100644
index 8c35c954f..000000000
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/phone/POLabeledPhoneNumberField.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.processout.sdk.ui.core.component.field.phone
-
-import androidx.compose.foundation.text.KeyboardActions
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.input.TextFieldValue
-import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
-import com.processout.sdk.ui.core.component.field.LabeledFieldLayout
-import com.processout.sdk.ui.core.component.field.POField
-import com.processout.sdk.ui.core.component.field.POFieldLabels
-import com.processout.sdk.ui.core.component.field.dropdown.PODropdownField
-import com.processout.sdk.ui.core.state.POPhoneNumberFieldState
-
-/** @suppress */
-@ProcessOutInternalApi
-@Composable
-fun POLabeledPhoneNumberField(
- state: POPhoneNumberFieldState,
- onValueChange: (TextFieldValue, TextFieldValue) -> Unit,
- modifier: Modifier = Modifier,
- textFieldModifier: Modifier = Modifier,
- fieldStyle: POField.Style = POField.default,
- dropdownMenuStyle: PODropdownField.MenuStyle = PODropdownField.defaultMenu,
- labelsStyle: POFieldLabels.Style = POFieldLabels.default,
- keyboardActions: KeyboardActions = KeyboardActions.Default
-) {
- LabeledFieldLayout(
- title = state.title ?: String(),
- description = state.description,
- style = labelsStyle
- ) {
- POPhoneNumberField(
- state = state,
- onValueChange = onValueChange,
- modifier = modifier,
- textFieldModifier = textFieldModifier,
- fieldStyle = fieldStyle,
- dropdownMenuStyle = dropdownMenuStyle,
- keyboardActions = keyboardActions
- )
- }
-}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/phone/POPhoneNumberField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/phone/POPhoneNumberField.kt
index d59c87930..aa689b230 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/phone/POPhoneNumberField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/phone/POPhoneNumberField.kt
@@ -2,19 +2,22 @@ package com.processout.sdk.ui.core.component.field.phone
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
-import androidx.compose.ui.unit.dp
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
+import com.processout.sdk.ui.core.component.POMessageBox
+import com.processout.sdk.ui.core.component.PORequestFocus
import com.processout.sdk.ui.core.component.field.POField
import com.processout.sdk.ui.core.component.field.dropdown.PODropdownField
-import com.processout.sdk.ui.core.component.field.text.POTextField
+import com.processout.sdk.ui.core.component.field.dropdown.PODropdownField2
+import com.processout.sdk.ui.core.component.field.text.POTextField2
import com.processout.sdk.ui.core.state.POPhoneNumberFieldState
import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
@@ -26,71 +29,87 @@ fun POPhoneNumberField(
onValueChange: (TextFieldValue, TextFieldValue) -> Unit,
modifier: Modifier = Modifier,
textFieldModifier: Modifier = Modifier,
- fieldStyle: POField.Style = POField.default,
- dropdownMenuStyle: PODropdownField.MenuStyle = PODropdownField.defaultMenu,
+ fieldStyle: POField.Style = POField.default2,
+ dropdownMenuStyle: PODropdownField.MenuStyle = PODropdownField.defaultMenu2,
+ descriptionStyle: POMessageBox.Style = POMessageBox.error2,
keyboardActions: KeyboardActions = KeyboardActions.Default
) {
- Row(modifier = modifier) {
- PODropdownField(
- value = state.regionCode,
- onValueChange = { regionCode ->
- onValueChange(regionCode, state.number)
- },
- availableValues = state.regionCodes,
- modifier = Modifier.width(IntrinsicSize.Min),
- fieldContentPadding = PaddingValues(
- start = spacing.large,
- end = 0.dp,
- top = spacing.medium,
- bottom = spacing.medium
- ),
- fieldStyle = fieldStyle,
- menuStyle = dropdownMenuStyle,
- menuMatchesTextFieldWidth = false,
- preferFormattedTextSelection = true,
- isError = state.isError,
- placeholderText = state.regionCodePlaceholder
- )
- val phoneNumberUtil = remember { PhoneNumberUtil.getInstance() }
- POTextField(
- value = state.number,
- onValueChange = { number ->
- if (number.text.startsWith('+')) {
- try {
- val filteredNumber = number.text.filterIndexed { index, char ->
- (index == 0 && char == '+') || char.isDigit()
- }
- val parsedNumber = phoneNumberUtil.parse(filteredNumber, null)
- val parsedRegionCode = phoneNumberUtil.getRegionCodeForCountryCode(parsedNumber.countryCode)
- var regionCode = state.regionCode
- if (state.regionCodes.elements.any { it.value == parsedRegionCode }) {
- regionCode = TextFieldValue(text = parsedRegionCode)
+ Column(modifier = modifier) {
+ Row(modifier = Modifier.fillMaxWidth()) {
+ var requestFocus by remember { mutableStateOf(false) }
+ PODropdownField2(
+ value = state.regionCode,
+ onValueChange = { regionCode ->
+ requestFocus = true
+ onValueChange(regionCode, state.number)
+ },
+ availableValues = state.regionCodes,
+ modifier = Modifier.width(IntrinsicSize.Min),
+ contentPadding = PaddingValues(
+ start = spacing.space12,
+ end = spacing.space0,
+ top = spacing.space6,
+ bottom = spacing.space6
+ ),
+ fieldStyle = fieldStyle,
+ menuStyle = dropdownMenuStyle,
+ menuMatchesTextFieldWidth = false,
+ preferFormattedTextSelection = true,
+ isError = state.isError,
+ label = state.regionCodeLabel
+ )
+ val focusRequester = remember { FocusRequester() }
+ val phoneNumberUtil = remember { PhoneNumberUtil.getInstance() }
+ POTextField2(
+ value = state.number,
+ onValueChange = { number ->
+ if (number.text.startsWith('+')) {
+ try {
+ val filteredNumber = number.text.filterIndexed { index, char ->
+ (index == 0 && char == '+') || char.isDigit()
+ }
+ val parsedNumber = phoneNumberUtil.parse(filteredNumber, null)
+ val parsedRegionCode = phoneNumberUtil.getRegionCodeForCountryCode(parsedNumber.countryCode)
+ var regionCode = state.regionCode
+ if (state.regionCodes.elements.any { it.value == parsedRegionCode }) {
+ regionCode = TextFieldValue(text = parsedRegionCode)
+ }
+ val parsedNationalNumber = parsedNumber.nationalNumber.toString()
+ val nationalNumber = TextFieldValue(
+ text = parsedNationalNumber,
+ selection = TextRange(parsedNationalNumber.length)
+ )
+ onValueChange(regionCode, nationalNumber)
+ } catch (e: NumberParseException) {
+ // ignore
}
- val parsedNationalNumber = parsedNumber.nationalNumber.toString()
- val nationalNumber = TextFieldValue(
- text = parsedNationalNumber,
- selection = TextRange(parsedNationalNumber.length)
- )
- onValueChange(regionCode, nationalNumber)
- } catch (e: NumberParseException) {
- // ignore
+ } else {
+ val filteredNumber = state.inputFilter?.filter(number) ?: number
+ onValueChange(state.regionCode, filteredNumber)
}
- } else {
- val filteredNumber = state.inputFilter?.filter(number) ?: number
- onValueChange(state.regionCode, filteredNumber)
- }
- },
- modifier = textFieldModifier
- .padding(start = spacing.extraSmall)
- .weight(1f),
- style = fieldStyle,
- enabled = state.enabled,
- isError = state.isError,
- forceTextDirectionLtr = state.forceTextDirectionLtr,
- placeholderText = state.numberPlaceholder,
- visualTransformation = state.visualTransformation ?: VisualTransformation.None,
- keyboardOptions = state.keyboardOptions,
- keyboardActions = keyboardActions
+ },
+ modifier = Modifier
+ .padding(start = spacing.space4)
+ .weight(1f),
+ textFieldModifier = textFieldModifier.focusRequester(focusRequester),
+ fieldStyle = fieldStyle,
+ enabled = state.enabled,
+ isError = state.isError,
+ forceTextDirectionLtr = state.forceTextDirectionLtr,
+ label = state.numberLabel,
+ visualTransformation = state.visualTransformation ?: VisualTransformation.None,
+ keyboardOptions = state.keyboardOptions,
+ keyboardActions = keyboardActions
+ )
+ if (requestFocus) {
+ requestFocus = false
+ PORequestFocus(focusRequester)
+ }
+ }
+ POMessageBox(
+ text = state.description,
+ modifier = Modifier.padding(top = spacing.space12),
+ style = descriptionStyle
)
}
}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioButton.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioButton.kt
index 527328ba7..76f81e3e4 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioButton.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioButton.kt
@@ -10,12 +10,13 @@ import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
-import com.processout.sdk.ui.core.component.field.radio.PORadioButton.RadioButtonScale
-import com.processout.sdk.ui.core.component.field.radio.PORadioButton.RadioButtonSize
+import com.processout.sdk.ui.core.component.field.radio.PORadioButton.MaterialRadioButtonSize
import com.processout.sdk.ui.core.component.field.radio.PORadioButton.colors
-import com.processout.sdk.ui.core.theme.ProcessOutTheme
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
/** @suppress */
@ProcessOutInternalApi
@@ -24,17 +25,19 @@ fun PORadioButton(
selected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
+ radioButtonSize: Dp = MaterialRadioButtonSize,
style: PORadioButton.Style = PORadioButton.default,
enabled: Boolean = true,
isError: Boolean = false
) {
+ val radioButtonScale = radioButtonSize.value / MaterialRadioButtonSize.value
RadioButton(
selected = selected,
onClick = onClick,
modifier = modifier
- .scale(RadioButtonScale)
- .requiredWidth(RadioButtonSize)
- .requiredHeight(ProcessOutTheme.dimensions.formComponentMinHeight),
+ .scale(radioButtonScale)
+ .requiredWidth(radioButtonSize)
+ .requiredHeight(dimensions.formComponentMinHeight),
enabled = enabled,
colors = colors(style = style, isError = isError)
)
@@ -53,18 +56,22 @@ object PORadioButton {
)
val default: Style
- @Composable get() = with(ProcessOutTheme) {
- Style(
- normalColor = colors.input.borderDefault,
- selectedColor = colors.button.primaryBackgroundDefault,
- errorColor = colors.input.borderError,
- disabledColor = colors.input.borderDisabled
- )
- }
+ @Composable get() = Style(
+ normalColor = colors.input.borderDefault,
+ selectedColor = colors.button.primaryBackgroundDefault,
+ errorColor = colors.input.borderError,
+ disabledColor = colors.input.borderDisabled
+ )
+
+ val default2: Style
+ @Composable get() = Style(
+ normalColor = colors.checkRadio.borderDefault,
+ selectedColor = colors.checkRadio.borderActive,
+ errorColor = colors.checkRadio.borderError,
+ disabledColor = colors.checkRadio.iconDisabled
+ )
- private val MaterialRadioButtonSize = 20.dp
- internal val RadioButtonSize = 22.dp
- internal val RadioButtonScale = RadioButtonSize.value / MaterialRadioButtonSize.value
+ internal val MaterialRadioButtonSize = 20.dp
@Composable
internal fun colors(
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioField.kt
new file mode 100644
index 000000000..ecac0ddfe
--- /dev/null
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioField.kt
@@ -0,0 +1,265 @@
+package com.processout.sdk.ui.core.component.field.radio
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.ripple
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.unit.dp
+import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
+import com.processout.sdk.ui.core.component.POBorderStroke
+import com.processout.sdk.ui.core.component.POMessageBox
+import com.processout.sdk.ui.core.component.POText
+import com.processout.sdk.ui.core.component.POText.measuredPaddingTop
+import com.processout.sdk.ui.core.component.field.radio.PORadioField.optionStateStyle
+import com.processout.sdk.ui.core.component.field.radio.PORadioField.radioButtonStyle
+import com.processout.sdk.ui.core.component.field.radio.PORadioField.stateStyle
+import com.processout.sdk.ui.core.state.POAvailableValue
+import com.processout.sdk.ui.core.state.POImmutableList
+import com.processout.sdk.ui.core.style.PORadioFieldStateStyle
+import com.processout.sdk.ui.core.style.PORadioFieldStyle
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.shapes
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
+
+/** @suppress */
+@ProcessOutInternalApi
+@Composable
+fun PORadioField(
+ value: TextFieldValue,
+ onValueChange: (TextFieldValue) -> Unit,
+ availableValues: POImmutableList,
+ modifier: Modifier = Modifier,
+ fieldStyle: PORadioField.Style = PORadioField.default,
+ descriptionStyle: POMessageBox.Style = POMessageBox.error2,
+ title: String? = null,
+ description: String? = null,
+ isError: Boolean = false
+) {
+ Column(modifier = modifier) {
+ val stateStyle = stateStyle(
+ style = fieldStyle,
+ isSelected = value.text.isNotBlank(),
+ isError = isError
+ )
+ if (!title.isNullOrBlank()) {
+ POText(
+ text = title,
+ modifier = Modifier.padding(bottom = spacing.space12),
+ color = stateStyle.title.color,
+ style = stateStyle.title.textStyle
+ )
+ }
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .border(
+ width = stateStyle.border.width,
+ color = stateStyle.border.color,
+ shape = stateStyle.shape
+ )
+ .padding(spacing.space4),
+ verticalArrangement = Arrangement.spacedBy(spacing.space2)
+ ) {
+ availableValues.elements.forEach { availableValue ->
+ val isSelected = availableValue.value == value.text
+ val optionStateStyle = optionStateStyle(
+ style = fieldStyle,
+ isSelected = isSelected,
+ isError = isError
+ )
+ val onClick = { onValueChange(TextFieldValue(text = availableValue.value)) }
+ val interactionSource = remember { MutableInteractionSource() }
+ val rowMinHeight = dimensions.formComponentMinHeight
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .requiredHeightIn(min = rowMinHeight)
+ .clip(shape = shapes.roundedCorners4)
+ .clickable(
+ onClick = onClick,
+ interactionSource = interactionSource,
+ indication = optionStateStyle.rowRippleColor?.let { ripple(color = it) }
+ )
+ .background(optionStateStyle.rowBackgroundColor)
+ .padding(start = spacing.space12)
+ ) {
+ PORadioButton(
+ selected = isSelected,
+ onClick = onClick,
+ radioButtonSize = 16.dp,
+ style = fieldStyle.radioButtonStyle(),
+ isError = isError
+ )
+ POText(
+ text = availableValue.text,
+ modifier = Modifier.padding(
+ start = spacing.space10,
+ top = measuredPaddingTop(
+ textStyle = optionStateStyle.option.textStyle,
+ componentHeight = rowMinHeight
+ ),
+ bottom = spacing.space10
+ ),
+ color = optionStateStyle.option.color,
+ style = optionStateStyle.option.textStyle
+ )
+ }
+ }
+ }
+ POMessageBox(
+ text = description,
+ modifier = Modifier.padding(top = spacing.space12),
+ style = descriptionStyle
+ )
+ }
+}
+
+/** @suppress */
+@ProcessOutInternalApi
+object PORadioField {
+
+ @Immutable
+ data class Style(
+ val normal: StateStyle,
+ val selected: StateStyle,
+ val error: StateStyle,
+ val disabled: StateStyle
+ )
+
+ @Immutable
+ data class StateStyle(
+ val title: POText.Style,
+ val option: POText.Style,
+ val radioButtonColor: Color,
+ val rowBackgroundColor: Color,
+ val rowRippleColor: Color?,
+ val shape: Shape,
+ val border: POBorderStroke
+ )
+
+ val default: Style
+ @Composable get() = Style(
+ normal = StateStyle(
+ title = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s16(FontWeight.Medium)
+ ),
+ option = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ radioButtonColor = PORadioButton.default2.normalColor,
+ rowBackgroundColor = colors.surface.default,
+ rowRippleColor = colors.surface.darkoutRipple,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 1.5.dp, color = colors.input.borderDefault2)
+ ),
+ selected = StateStyle(
+ title = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s16(FontWeight.Medium)
+ ),
+ option = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ radioButtonColor = PORadioButton.default2.selectedColor,
+ rowBackgroundColor = colors.surface.darkout,
+ rowRippleColor = null,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 1.5.dp, color = colors.input.borderDefault2)
+ ),
+ error = StateStyle(
+ title = POText.Style(
+ color = colors.text.error,
+ textStyle = typography.s16(FontWeight.Medium)
+ ),
+ option = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ radioButtonColor = PORadioButton.default2.errorColor,
+ rowBackgroundColor = colors.surface.default,
+ rowRippleColor = colors.surface.darkoutRipple,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 1.5.dp, color = colors.input.borderError)
+ ),
+ disabled = StateStyle(
+ title = POText.Style(
+ color = colors.text.primary,
+ textStyle = typography.s16(FontWeight.Medium)
+ ),
+ option = POText.Style(
+ color = colors.text.disabled,
+ textStyle = typography.s15(FontWeight.Medium)
+ ),
+ radioButtonColor = PORadioButton.default2.disabledColor,
+ rowBackgroundColor = colors.surface.default,
+ rowRippleColor = null,
+ shape = shapes.roundedCorners6,
+ border = POBorderStroke(width = 1.5.dp, color = colors.input.borderDefault2)
+ )
+ )
+
+ @Composable
+ fun custom(style: PORadioFieldStyle) = Style(
+ normal = style.normal.toStateStyle(),
+ selected = style.selected.toStateStyle(),
+ error = style.error.toStateStyle(),
+ disabled = style.disabled?.toStateStyle() ?: default.disabled
+ )
+
+ @Composable
+ private fun PORadioFieldStateStyle.toStateStyle() = StateStyle(
+ title = POText.custom(style = title),
+ option = POText.custom(style = option),
+ radioButtonColor = colorResource(id = radioButtonColorResId),
+ rowBackgroundColor = colorResource(id = rowBackgroundColorResId),
+ rowRippleColor = rowRippleColorResId?.let { colorResource(id = it) },
+ shape = RoundedCornerShape(size = border.radiusDp.dp),
+ border = POBorderStroke(
+ width = border.widthDp.dp,
+ color = colorResource(id = border.colorResId)
+ )
+ )
+
+ internal fun stateStyle(
+ style: Style,
+ isSelected: Boolean,
+ isError: Boolean
+ ): StateStyle =
+ if (isError) style.error
+ else if (isSelected) style.selected
+ else style.normal
+
+ internal fun optionStateStyle(
+ style: Style,
+ isSelected: Boolean,
+ isError: Boolean
+ ): StateStyle =
+ if (isSelected) style.selected
+ else if (isError) style.error
+ else style.normal
+
+ internal fun Style.radioButtonStyle() = PORadioButton.Style(
+ normalColor = normal.radioButtonColor,
+ selectedColor = selected.radioButtonColor,
+ errorColor = error.radioButtonColor,
+ disabledColor = disabled.radioButtonColor
+ )
+}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioGroup.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioGroup.kt
index e27aa6a77..9986579dd 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioGroup.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/radio/PORadioGroup.kt
@@ -9,6 +9,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
import com.processout.sdk.ui.core.component.POText
@@ -19,6 +20,8 @@ import com.processout.sdk.ui.core.state.POAvailableValue
import com.processout.sdk.ui.core.state.POImmutableList
import com.processout.sdk.ui.core.style.PORadioButtonStateStyle
import com.processout.sdk.ui.core.style.PORadioButtonStyle
+import com.processout.sdk.ui.core.style.PORadioFieldStateStyle
+import com.processout.sdk.ui.core.style.PORadioFieldStyle
import com.processout.sdk.ui.core.theme.ProcessOutTheme.colors
import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
import com.processout.sdk.ui.core.theme.ProcessOutTheme.typography
@@ -116,16 +119,45 @@ object PORadioGroup {
)
)
- @Composable
- fun custom(style: PORadioButtonStyle): Style {
- val normal = style.normal.toStateStyle()
- return Style(
- normal = normal,
- selected = style.selected.toStateStyle(),
- error = style.error.toStateStyle(),
- disabled = style.disabled?.toStateStyle() ?: normal
+ val default2: Style
+ @Composable get() = Style(
+ normal = StateStyle(
+ buttonColor = PORadioButton.default2.normalColor,
+ text = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ )
+ ),
+ selected = StateStyle(
+ buttonColor = PORadioButton.default2.selectedColor,
+ text = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ )
+ ),
+ error = StateStyle(
+ buttonColor = PORadioButton.default2.errorColor,
+ text = POText.Style(
+ color = colors.text.secondary,
+ textStyle = typography.s15(FontWeight.Medium)
+ )
+ ),
+ disabled = StateStyle(
+ buttonColor = PORadioButton.default2.disabledColor,
+ text = POText.Style(
+ color = colors.text.disabled,
+ textStyle = typography.s15(FontWeight.Medium)
+ )
+ )
)
- }
+
+ @Composable
+ fun custom(style: PORadioButtonStyle) = Style(
+ normal = style.normal.toStateStyle(),
+ selected = style.selected.toStateStyle(),
+ error = style.error.toStateStyle(),
+ disabled = style.disabled?.toStateStyle() ?: default.disabled
+ )
@Composable
private fun PORadioButtonStateStyle.toStateStyle() = StateStyle(
@@ -133,6 +165,20 @@ object PORadioGroup {
text = POText.custom(style = text)
)
+ @Composable
+ fun custom(style: PORadioFieldStyle) = Style(
+ normal = style.normal.toStateStyle(),
+ selected = style.selected.toStateStyle(),
+ error = style.error.toStateStyle(),
+ disabled = style.disabled?.toStateStyle() ?: default.disabled
+ )
+
+ @Composable
+ private fun PORadioFieldStateStyle.toStateStyle() = StateStyle(
+ buttonColor = colorResource(id = radioButtonColorResId),
+ text = POText.custom(style = option)
+ )
+
fun Style.toRadioButtonStyle() = PORadioButton.Style(
normalColor = normal.buttonColor,
selectedColor = selected.buttonColor,
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POLabeledTextField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POLabeledTextField.kt
index 95cfab7f5..268e7b214 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POLabeledTextField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POLabeledTextField.kt
@@ -36,7 +36,7 @@ fun POLabeledTextField(
isDropdown: Boolean = false,
isError: Boolean = false,
forceTextDirectionLtr: Boolean = false,
- placeholderText: String? = null,
+ placeholder: String? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
visualTransformation: VisualTransformation = VisualTransformation.None,
@@ -63,7 +63,7 @@ fun POLabeledTextField(
isDropdown = isDropdown,
isError = isError,
forceTextDirectionLtr = forceTextDirectionLtr,
- placeholderText = placeholderText,
+ placeholder = placeholder,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
visualTransformation = visualTransformation,
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POTextField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POTextField.kt
index 7f37a7b78..65ac7eca6 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POTextField.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POTextField.kt
@@ -2,6 +2,10 @@
package com.processout.sdk.ui.core.component.field.text
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.spring
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicTextField
@@ -16,8 +20,11 @@ import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
import com.processout.sdk.ui.core.component.POText
import com.processout.sdk.ui.core.component.field.POField
@@ -25,7 +32,8 @@ import com.processout.sdk.ui.core.component.field.POField.ContainerBox
import com.processout.sdk.ui.core.component.field.POField.stateStyle
import com.processout.sdk.ui.core.component.field.POField.textSelectionColors
import com.processout.sdk.ui.core.component.field.POField.textStyle
-import com.processout.sdk.ui.core.theme.ProcessOutTheme
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
/** @suppress */
@ProcessOutInternalApi
@@ -34,6 +42,7 @@ fun POTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
modifier: Modifier = Modifier,
+ minHeight: Dp = dimensions.formComponentMinHeight,
contentPadding: PaddingValues = POField.contentPadding,
style: POField.Style = POField.default,
enabled: Boolean = true,
@@ -41,7 +50,8 @@ fun POTextField(
isDropdown: Boolean = false,
isError: Boolean = false,
forceTextDirectionLtr: Boolean = false,
- placeholderText: String? = null,
+ label: String? = null,
+ placeholder: String? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
visualTransformation: VisualTransformation = VisualTransformation.None,
@@ -61,7 +71,7 @@ fun POTextField(
value = value,
onValueChange = onValueChange,
modifier = modifier
- .requiredHeight(ProcessOutTheme.dimensions.formComponentMinHeight)
+ .requiredHeightIn(min = minHeight)
.onFocusChanged {
isFocused = it.isFocused
},
@@ -82,18 +92,49 @@ fun POTextField(
decorationBox = @Composable { innerTextField ->
OutlinedTextFieldDefaults.DecorationBox(
value = value.text,
- innerTextField = innerTextField,
- enabled = enabled,
- isError = isError,
- placeholder = {
- if (!placeholderText.isNullOrBlank()) {
- POText(
- text = placeholderText,
- color = stateStyle.placeholderTextColor,
- style = stateStyle.text.textStyle
+ innerTextField = {
+ val animationStiffness = Spring.StiffnessMedium
+ Column(
+ modifier = Modifier.animateContentSize(
+ animationSpec = spring(stiffness = animationStiffness)
)
+ ) {
+ val isLabelFloating = value.text.isNotEmpty() || (isFocused && !isDropdown)
+ if (!label.isNullOrBlank()) {
+ val fontSizeValue = stateStyle.text.textStyle.fontSize.value
+ val animatedFontSizeValue by animateFloatAsState(
+ targetValue = if (isLabelFloating) fontSizeValue * 0.8f else fontSizeValue,
+ animationSpec = spring(stiffness = animationStiffness)
+ )
+ POText(
+ text = label,
+ color = stateStyle.label.color,
+ style = stateStyle.label.textStyle.copy(fontSize = animatedFontSizeValue.sp),
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1
+ )
+ if (isLabelFloating) {
+ Spacer(modifier = Modifier.requiredHeight(spacing.space2))
+ }
+ }
+ if (isLabelFloating || label.isNullOrBlank()) {
+ Box {
+ if (value.text.isEmpty() && !placeholder.isNullOrBlank()) {
+ POText(
+ text = placeholder,
+ color = stateStyle.placeholderTextColor,
+ style = stateStyle.text.textStyle,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1
+ )
+ }
+ innerTextField()
+ }
+ }
}
},
+ enabled = enabled,
+ isError = isError,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
singleLine = singleLine,
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POTextField2.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POTextField2.kt
new file mode 100644
index 000000000..1fb1332dd
--- /dev/null
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/text/POTextField2.kt
@@ -0,0 +1,83 @@
+package com.processout.sdk.ui.core.component.field.text
+
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.Dp
+import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
+import com.processout.sdk.ui.core.component.POMessageBox
+import com.processout.sdk.ui.core.component.field.POField
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.dimensions
+import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing
+
+/** @suppress */
+@ProcessOutInternalApi
+@Composable
+fun POTextField2(
+ value: TextFieldValue,
+ onValueChange: (TextFieldValue) -> Unit,
+ modifier: Modifier = Modifier,
+ textFieldModifier: Modifier = Modifier,
+ minHeight: Dp = dimensions.fieldMinHeight,
+ contentPadding: PaddingValues = POField.contentPadding2,
+ fieldStyle: POField.Style = POField.default2,
+ descriptionStyle: POMessageBox.Style = POMessageBox.error2,
+ enabled: Boolean = true,
+ readOnly: Boolean = false,
+ isDropdown: Boolean = false,
+ isError: Boolean = false,
+ forceTextDirectionLtr: Boolean = false,
+ label: String? = null,
+ placeholder: String? = null,
+ description: String? = null,
+ leadingIcon: @Composable (() -> Unit)? = null,
+ trailingIcon: @Composable (() -> Unit)? = null,
+ visualTransformation: VisualTransformation = VisualTransformation.None,
+ keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+ keyboardActions: KeyboardActions = KeyboardActions.Default,
+ singleLine: Boolean = true,
+ maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
+ minLines: Int = 1,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+ Column(modifier = modifier) {
+ POTextField(
+ value = value,
+ onValueChange = onValueChange,
+ modifier = textFieldModifier.fillMaxWidth(),
+ minHeight = minHeight,
+ contentPadding = contentPadding,
+ style = fieldStyle,
+ enabled = enabled,
+ readOnly = readOnly,
+ isDropdown = isDropdown,
+ isError = isError,
+ forceTextDirectionLtr = forceTextDirectionLtr,
+ label = label,
+ placeholder = placeholder,
+ leadingIcon = leadingIcon,
+ trailingIcon = trailingIcon,
+ visualTransformation = visualTransformation,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ singleLine = singleLine,
+ maxLines = maxLines,
+ minLines = minLines,
+ interactionSource = interactionSource
+ )
+ POMessageBox(
+ text = description,
+ modifier = Modifier.padding(top = spacing.space12),
+ style = descriptionStyle
+ )
+ }
+}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POPhoneNumberFieldState.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POPhoneNumberFieldState.kt
index 623a2db96..7a1ac1beb 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POPhoneNumberFieldState.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POPhoneNumberFieldState.kt
@@ -13,10 +13,9 @@ data class POPhoneNumberFieldState(
val id: String,
val regionCode: TextFieldValue,
val regionCodes: POImmutableList,
- val regionCodePlaceholder: String?,
+ val regionCodeLabel: String,
val number: TextFieldValue,
- val numberPlaceholder: String?,
- val title: String? = null,
+ val numberLabel: String,
val description: String? = null,
val enabled: Boolean = true,
val isError: Boolean = false,
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POCheckboxStyle.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POCheckboxStyle.kt
index ceea75dfa..19d3d8e8e 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POCheckboxStyle.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POCheckboxStyle.kt
@@ -15,7 +15,9 @@ data class POCheckboxStyle(
@Parcelize
data class POCheckboxStateStyle(
val checkmark: POCheckmarkStyle,
- val text: POTextStyle
+ val text: POTextStyle,
+ @ColorRes
+ val rippleColorResId: Int? = null
) : Parcelable
@Parcelize
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POFieldStyle.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POFieldStyle.kt
index e334c3d54..51852a6f8 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POFieldStyle.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POFieldStyle.kt
@@ -14,6 +14,7 @@ data class POFieldStyle(
@Parcelize
data class POFieldStateStyle(
val text: POTextStyle,
+ val label: POTextStyle,
@ColorRes
val placeholderTextColorResId: Int,
@ColorRes
@@ -23,4 +24,33 @@ data class POFieldStateStyle(
val border: POBorderStyle,
@ColorRes
val dropdownRippleColorResId: Int? = null
-) : Parcelable
+) : Parcelable {
+
+ @Deprecated(message = "Use alternative constructor.")
+ constructor(
+ text: POTextStyle,
+ @ColorRes
+ placeholderTextColorResId: Int,
+ @ColorRes
+ backgroundColorResId: Int,
+ @ColorRes
+ controlsTintColorResId: Int,
+ border: POBorderStyle,
+ @ColorRes
+ dropdownRippleColorResId: Int? = null
+ ) : this(
+ text = text,
+ label = POTextStyle(
+ colorResId = 0,
+ type = POTextType(
+ textSizeSp = 0,
+ lineHeightSp = 0
+ )
+ ),
+ placeholderTextColorResId = placeholderTextColorResId,
+ backgroundColorResId = backgroundColorResId,
+ controlsTintColorResId = controlsTintColorResId,
+ border = border,
+ dropdownRippleColorResId = dropdownRippleColorResId
+ )
+}
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/PORadioFieldStyle.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/PORadioFieldStyle.kt
new file mode 100644
index 000000000..85c36be18
--- /dev/null
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/PORadioFieldStyle.kt
@@ -0,0 +1,26 @@
+package com.processout.sdk.ui.core.style
+
+import android.os.Parcelable
+import androidx.annotation.ColorRes
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class PORadioFieldStyle(
+ val normal: PORadioFieldStateStyle,
+ val selected: PORadioFieldStateStyle,
+ val error: PORadioFieldStateStyle,
+ val disabled: PORadioFieldStateStyle? = null
+) : Parcelable
+
+@Parcelize
+data class PORadioFieldStateStyle(
+ val title: POTextStyle,
+ val option: POTextStyle,
+ @ColorRes
+ val radioButtonColorResId: Int,
+ @ColorRes
+ val rowBackgroundColorResId: Int,
+ @ColorRes
+ val rowRippleColorResId: Int?,
+ val border: POBorderStyle
+) : Parcelable
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Colors.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Colors.kt
index 62357e77d..53a166706 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Colors.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Colors.kt
@@ -12,6 +12,7 @@ import com.processout.sdk.ui.core.theme.POColors.*
data class POColors(
val text: Text,
val input: Input,
+ val checkRadio: CheckRadio,
val button: Button,
val surface: Surface,
val border: Border
@@ -19,11 +20,15 @@ data class POColors(
@Immutable
data class Text(
val primary: Color,
+ val secondary: Color,
val inverse: Color,
val muted: Color,
+ val placeholder: Color,
val disabled: Color,
+ val onButtonDisabled: Color,
val success: Color,
- val error: Color
+ val error: Color,
+ val onTipError: Color
)
@Immutable
@@ -31,11 +36,28 @@ data class POColors(
val backgroundDefault: Color,
val backgroundDisabled: Color,
val borderDefault: Color,
+ val borderDefault2: Color,
val borderDisabled: Color,
val borderFocused: Color,
val borderError: Color
)
+ @Immutable
+ data class CheckRadio(
+ val iconDefault: Color,
+ val iconActive: Color,
+ val iconError: Color,
+ val iconDisabled: Color,
+ val borderDefault: Color,
+ val borderActive: Color,
+ val borderError: Color,
+ val borderDisabled: Color,
+ val surfaceDefault: Color,
+ val surfaceActive: Color,
+ val surfaceError: Color,
+ val surfaceDisabled: Color
+ )
+
@Immutable
data class Button(
val primaryBackgroundDefault: Color,
@@ -44,9 +66,7 @@ data class POColors(
val secondaryBackgroundDefault: Color,
val secondaryBackgroundDisabled: Color,
val secondaryBackgroundPressed: Color,
- val secondaryBorderDefault: Color,
- val secondaryBorderDisabled: Color,
- val secondaryBorderPressed: Color,
+ val ghostBackgroundDisabled: Color,
val ghostBackgroundPressed: Color
)
@@ -54,8 +74,11 @@ data class POColors(
data class Surface(
val default: Color,
val neutral: Color,
+ val darkout: Color,
+ val darkoutRipple: Color,
val success: Color,
- val error: Color
+ val error: Color,
+ val toastError: Color
)
@Immutable
@@ -67,38 +90,58 @@ data class POColors(
@ProcessOutInternalApi
val POLightColorPalette = POColors(
text = Text(
- primary = Color(0xFF121821),
- inverse = Color(0xFFFAFAFA),
+ primary = Color(0xFF000000),
+ secondary = Color(0xFF585A5F),
+ inverse = Color(0xFFFFFFFF),
muted = Color(0xFF5B6576),
+ placeholder = Color(0xFF707378),
disabled = Color(0xFFADB5BD),
+ onButtonDisabled = Color(0xFFC0C3C8),
success = Color(0xFF00291D),
- error = Color(0xFFD11D2F)
+ error = Color(0xFFBE011B),
+ onTipError = Color(0xFF630407)
),
input = Input(
backgroundDefault = Color(0xFFFFFFFF),
- backgroundDisabled = Color(0xFFEDEEEF),
+ backgroundDisabled = Color(0x0F121314),
borderDefault = Color(0xFF7C8593),
+ borderDefault2 = Color(0x1F121314),
borderDisabled = Color(0xFFADB5BD),
borderFocused = Color(0xFF4791FF),
- borderError = Color(0xFFD11D2F)
+ borderError = Color(0xFFBE011B)
+ ),
+ checkRadio = CheckRadio(
+ iconDefault = Color(0xFFFFFFFF),
+ iconActive = Color(0xFFFFFFFF),
+ iconError = Color(0xFFF03030),
+ iconDisabled = Color(0xFFC0C3C8),
+ borderDefault = Color(0xFFC0C3C8),
+ borderActive = Color(0xFF000000),
+ borderError = Color(0xFFF03030),
+ borderDisabled = Color(0xFFE2E2E2),
+ surfaceDefault = Color(0xFFFFFFFF),
+ surfaceActive = Color(0xFF000000),
+ surfaceError = Color(0xFFFDE3DE),
+ surfaceDisabled = Color(0xFFF1F1F2)
),
button = Button(
- primaryBackgroundDefault = Color(0xFF121821),
- primaryBackgroundDisabled = Color(0xFFEDEEEF),
- primaryBackgroundPressed = Color(0xFF242C38),
- secondaryBackgroundDefault = Color(0xFFFFFFFF),
- secondaryBackgroundDisabled = Color(0xFFFFFFFF),
+ primaryBackgroundDefault = Color(0xFF000000),
+ primaryBackgroundDisabled = Color(0x0A121314),
+ primaryBackgroundPressed = Color(0xFF26292F),
+ secondaryBackgroundDefault = Color(0x0F121314),
+ secondaryBackgroundDisabled = Color(0x0A121314),
secondaryBackgroundPressed = Color(0x29212222),
- secondaryBorderDefault = Color(0xFF121821),
- secondaryBorderDisabled = Color(0xFFEDEEEF),
- secondaryBorderPressed = Color(0xFF242C38),
+ ghostBackgroundDisabled = Color(0x0A121314),
ghostBackgroundPressed = Color(0x1F121314)
),
surface = Surface(
default = Color(0xFFFFFFFF),
neutral = Color(0xFFFAFAFA),
+ darkout = Color(0x0F121314),
+ darkoutRipple = Color(0x0F59595A),
success = Color(0xFFBEFAE9),
- error = Color(0xFFFFC2C8)
+ error = Color(0xFFFFC2C8),
+ toastError = Color(0xFFFDE3DE)
),
border = Border(
subtle = Color(0xFFCCD1D6)
@@ -108,38 +151,58 @@ val POLightColorPalette = POColors(
@ProcessOutInternalApi
val PODarkColorPalette = POColors(
text = Text(
- primary = Color(0xFFFAFAFA),
- inverse = Color(0xFF121821),
+ primary = Color(0xFFFFFFFF),
+ secondary = Color(0xFFC0C3C8),
+ inverse = Color(0xFF000000),
muted = Color(0xFFADB5BD),
+ placeholder = Color(0xFFA7A9AF),
disabled = Color(0xFF5B6576),
+ onButtonDisabled = Color(0xFF707378),
success = Color(0xFFE5FFF8),
- error = Color(0xFFFF5263)
+ error = Color(0xFFFF7D6C),
+ onTipError = Color(0xFFF5D9D9)
),
input = Input(
- backgroundDefault = Color(0xFF121821),
- backgroundDisabled = Color(0xFF242C38),
+ backgroundDefault = Color(0xFF26292F),
+ backgroundDisabled = Color(0x14F6F8FB),
borderDefault = Color(0xFFCCD1D6),
+ borderDefault2 = Color(0x29F6F8FB),
borderDisabled = Color(0xFF7C8593),
borderFocused = Color(0xFFFFE500),
- borderError = Color(0xFFFF5263)
+ borderError = Color(0xFFFF7D6C)
+ ),
+ checkRadio = CheckRadio(
+ iconDefault = Color(0x33121314),
+ iconActive = Color(0xFF000000),
+ iconError = Color(0xFFFF7D6C),
+ iconDisabled = Color(0xFF707378),
+ borderDefault = Color(0x3DF6F8FB),
+ borderActive = Color(0xFFFFFFFF),
+ borderError = Color(0xFFFF7D6C),
+ borderDisabled = Color(0xFF3D4149),
+ surfaceDefault = Color(0x33121314),
+ surfaceActive = Color(0xFFFFFFFF),
+ surfaceError = Color(0xFF3D0D04),
+ surfaceDisabled = Color(0xFF2E3137)
),
button = Button(
primaryBackgroundDefault = Color(0xFFFFFFFF),
- primaryBackgroundDisabled = Color(0xFF242C38),
- primaryBackgroundPressed = Color(0xFFCCD1D6),
- secondaryBackgroundDefault = Color(0xFF121821),
- secondaryBackgroundDisabled = Color(0xFF121821),
+ primaryBackgroundDisabled = Color(0xFF2E3137),
+ primaryBackgroundPressed = Color(0xFF585A5F),
+ secondaryBackgroundDefault = Color(0x14F6F8FB),
+ secondaryBackgroundDisabled = Color(0xFF2E3137),
secondaryBackgroundPressed = Color(0x0FF6F8FB),
- secondaryBorderDefault = Color(0xFFFFFFFF),
- secondaryBorderDisabled = Color(0xFF242C38),
- secondaryBorderPressed = Color(0xFFCCD1D6),
+ ghostBackgroundDisabled = Color(0xFF2E3137),
ghostBackgroundPressed = Color(0x1FF6F8FB)
),
surface = Surface(
- default = Color(0xFF121821),
- neutral = Color(0xFF242C38),
+ default = Color(0xFF26292F),
+ neutral = Color(0xFF2A2D34),
+ darkout = Color(0x0FF6F8FB),
+ darkoutRipple = Color(0x0FACADAF),
success = Color(0xFF1DA37D),
- error = Color(0xFFD11D2F)
+ error = Color(0xFFD11D2F),
+ toastError = Color(0xFF511511)
),
border = Border(
subtle = Color(0xFF7C8593)
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Dimensions.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Dimensions.kt
index 5ad12b4e3..5bee82a3b 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Dimensions.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Dimensions.kt
@@ -10,6 +10,7 @@ import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
@ProcessOutInternalApi
@Immutable
data class PODimensions(
+ val fieldMinHeight: Dp = 52.dp,
val formComponentMinHeight: Dp = 48.dp,
val interactiveComponentMinSize: Dp = 44.dp,
val iconSizeSmall: Dp = 16.dp,
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Shapes.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Shapes.kt
index c725e7306..c98a6335a 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Shapes.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Shapes.kt
@@ -11,6 +11,9 @@ import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
@ProcessOutInternalApi
@Immutable
data class POShapes(
+ val roundedCorners4: CornerBasedShape = RoundedCornerShape(4.dp),
+ val roundedCorners6: CornerBasedShape = RoundedCornerShape(6.dp),
+ val roundedCorners8: CornerBasedShape = RoundedCornerShape(8.dp),
val roundedCornersSmall: CornerBasedShape = RoundedCornerShape(4.dp),
val roundedCornersMedium: CornerBasedShape = RoundedCornerShape(8.dp),
val roundedCornersLarge: CornerBasedShape = RoundedCornerShape(16.dp),
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Spacing.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Spacing.kt
index dfbc48bf0..cebf2061f 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Spacing.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Spacing.kt
@@ -10,6 +10,15 @@ import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi
@ProcessOutInternalApi
@Immutable
data class POSpacing(
+ val space0: Dp = 0.dp,
+ val space2: Dp = 2.dp,
+ val space4: Dp = 4.dp,
+ val space6: Dp = 6.dp,
+ val space8: Dp = 8.dp,
+ val space10: Dp = 10.dp,
+ val space12: Dp = 12.dp,
+ val space16: Dp = 16.dp,
+ val space20: Dp = 20.dp,
val extraSmall: Dp = 4.dp,
val small: Dp = 8.dp,
val medium: Dp = 12.dp,
diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Typography.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Typography.kt
index 11fe578aa..b8eaab73b 100644
--- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Typography.kt
+++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/theme/Typography.kt
@@ -15,13 +15,15 @@ import com.processout.sdk.ui.core.style.POTextType.Weight.*
private val WorkSans = FontFamily(
Font(R.font.work_sans_regular, FontWeight.Normal),
- Font(R.font.work_sans_medium, FontWeight.Medium)
+ Font(R.font.work_sans_medium, FontWeight.Medium),
+ Font(R.font.work_sans_semibold, FontWeight.SemiBold)
)
/** @suppress */
@ProcessOutInternalApi
@Immutable
data class POTypography(
+ val paragraph: Paragraph = Paragraph,
val title: TextStyle = TextStyle(
fontFamily = WorkSans,
fontWeight = FontWeight.Medium,
@@ -76,7 +78,95 @@ data class POTypography(
fontSize = 14.sp,
lineHeight = 18.sp
)
-)
+) {
+
+ fun s12(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 12.sp,
+ lineHeight = 14.sp,
+ letterSpacing = 0.15.sp
+ )
+
+ fun s13(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 13.sp,
+ lineHeight = 16.sp
+ )
+
+ fun s14(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.15.sp
+ )
+
+ fun s15(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 15.sp,
+ lineHeight = 18.sp
+ )
+
+ fun s16(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 16.sp,
+ lineHeight = 20.sp
+ )
+
+ fun s18(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 18.sp,
+ lineHeight = 22.sp,
+ letterSpacing = when (fontWeight) {
+ FontWeight.Medium,
+ FontWeight.SemiBold -> 0.1.sp
+ else -> 0.sp
+ }
+ )
+
+ fun s20(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 20.sp,
+ lineHeight = 24.sp,
+ letterSpacing = when (fontWeight) {
+ FontWeight.Medium -> (-0.15).sp
+ FontWeight.SemiBold -> (-0.1).sp
+ else -> (-0.2).sp
+ }
+ )
+
+ fun s24(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 24.sp,
+ lineHeight = 28.sp
+ )
+
+ object Paragraph {
+
+ fun s16(fontWeight: FontWeight = FontWeight.Normal) =
+ TextStyle(
+ fontFamily = WorkSans,
+ fontWeight = fontWeight,
+ fontSize = 16.sp,
+ lineHeight = 26.sp
+ )
+ }
+}
internal val LocalPOTypography = staticCompositionLocalOf { POTypography() }
diff --git a/ui-core/src/main/res/drawable/po_chevron_down.xml b/ui-core/src/main/res/drawable/po_chevron_down.xml
new file mode 100644
index 000000000..9dbbb88f3
--- /dev/null
+++ b/ui-core/src/main/res/drawable/po_chevron_down.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/ui-core/src/main/res/drawable/po_info_icon.xml b/ui-core/src/main/res/drawable/po_icon_info.xml
similarity index 100%
rename from ui-core/src/main/res/drawable/po_info_icon.xml
rename to ui-core/src/main/res/drawable/po_icon_info.xml
diff --git a/ui-core/src/main/res/drawable/po_icon_warning_diamond.xml b/ui-core/src/main/res/drawable/po_icon_warning_diamond.xml
new file mode 100644
index 000000000..661700537
--- /dev/null
+++ b/ui-core/src/main/res/drawable/po_icon_warning_diamond.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/ui-core/src/main/res/font/work_sans_medium.ttf b/ui-core/src/main/res/font/work_sans_medium.ttf
index 1800fe2d8..216807382 100644
Binary files a/ui-core/src/main/res/font/work_sans_medium.ttf and b/ui-core/src/main/res/font/work_sans_medium.ttf differ
diff --git a/ui-core/src/main/res/font/work_sans_regular.ttf b/ui-core/src/main/res/font/work_sans_regular.ttf
index 20c724037..d24586cc0 100644
Binary files a/ui-core/src/main/res/font/work_sans_regular.ttf and b/ui-core/src/main/res/font/work_sans_regular.ttf differ
diff --git a/ui-core/src/main/res/font/work_sans_semibold.ttf b/ui-core/src/main/res/font/work_sans_semibold.ttf
new file mode 100644
index 000000000..a75721ccf
Binary files /dev/null and b/ui-core/src/main/res/font/work_sans_semibold.ttf differ
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationScreen.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationScreen.kt
index 0878f5da7..6bd090e2b 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationScreen.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationScreen.kt
@@ -300,7 +300,7 @@ private fun TextField(
enabled = state.enabled,
isError = state.isError,
forceTextDirectionLtr = state.forceTextDirectionLtr,
- placeholderText = state.placeholder,
+ placeholder = state.placeholder,
trailingIcon = { state.iconResId?.let { AnimatedFieldIcon(id = it) } },
visualTransformation = state.visualTransformation,
keyboardOptions = state.keyboardOptions,
@@ -373,7 +373,7 @@ private fun DropdownField(
menuStyle = menuStyle,
enabled = state.enabled,
isError = state.isError,
- placeholderText = state.placeholder
+ placeholder = state.placeholder
)
}
@@ -385,7 +385,7 @@ private fun CheckboxField(
modifier: Modifier = Modifier
) {
POCheckbox(
- text = state.title ?: String(),
+ text = state.label ?: String(),
checked = state.value.text.toBooleanStrictOrNull() ?: false,
onCheckedChange = {
if (state.enabled) {
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt
index 29f5cc753..3faee7f0d 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt
@@ -458,7 +458,7 @@ internal class CardTokenizationViewModel private constructor(
FieldState(
id = field.id,
value = field.value,
- title = title,
+ label = title,
enabled = field.enabled,
isError = !field.isValid
)
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateScreen.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateScreen.kt
index 99510d703..8a83be8e2 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateScreen.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateScreen.kt
@@ -149,7 +149,7 @@ private fun Fields(
readOnly = !state.enabled,
isError = state.isError,
forceTextDirectionLtr = state.forceTextDirectionLtr,
- placeholderText = state.placeholder,
+ placeholder = state.placeholder,
trailingIcon = { state.iconResId?.let { AnimatedFieldIcon(id = it) } },
keyboardOptions = state.keyboardOptions,
keyboardActions = POField.keyboardActions(
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutViewModel.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutViewModel.kt
index 91ecab1de..c60ba2cdb 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutViewModel.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutViewModel.kt
@@ -374,7 +374,7 @@ internal class DynamicCheckoutViewModel private constructor(
FieldState(
id = id,
value = value,
- title = title
+ label = title
)
)
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/CardTokenization.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/CardTokenization.kt
index 9905056b0..012a50d07 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/CardTokenization.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/CardTokenization.kt
@@ -245,7 +245,7 @@ private fun TextField(
enabled = state.enabled,
isError = state.isError,
forceTextDirectionLtr = state.forceTextDirectionLtr,
- placeholderText = state.placeholder,
+ placeholder = state.placeholder,
trailingIcon = { state.iconResId?.let { AnimatedFieldIcon(id = it) } },
visualTransformation = state.visualTransformation,
keyboardOptions = state.keyboardOptions,
@@ -330,7 +330,7 @@ private fun DropdownField(
menuStyle = menuStyle,
enabled = state.enabled,
isError = state.isError,
- placeholderText = state.placeholder
+ placeholder = state.placeholder
)
}
@@ -343,7 +343,7 @@ private fun CheckboxField(
modifier: Modifier = Modifier
) {
POCheckbox(
- text = state.title ?: String(),
+ text = state.label ?: String(),
checked = state.value.text.toBooleanStrictOrNull() ?: false,
onCheckedChange = {
if (state.enabled) {
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/DynamicCheckoutScreen.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/DynamicCheckoutScreen.kt
index 5dc582707..7e0fdf078 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/DynamicCheckoutScreen.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/DynamicCheckoutScreen.kt
@@ -546,7 +546,7 @@ private fun CheckboxField(
modifier: Modifier = Modifier
) {
POCheckbox(
- text = state.title ?: String(),
+ text = state.label ?: String(),
checked = state.value.text.toBooleanStrictOrNull() ?: false,
onCheckedChange = {
onEvent(
@@ -790,7 +790,7 @@ internal object DynamicCheckoutScreen {
title = POText.body1,
description = POTextWithIcon.Style(
text = description,
- iconResId = R.drawable.po_info_icon,
+ iconResId = R.drawable.po_icon_info,
iconColorFilter = ColorFilter.tint(color = description.color)
),
shape = shapes.roundedCornersSmall,
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/NativeAlternativePayment.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/NativeAlternativePayment.kt
index 76384b3bf..495797012 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/NativeAlternativePayment.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/screen/NativeAlternativePayment.kt
@@ -149,7 +149,7 @@ private fun TextField(
)
)
},
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier
.focusRequester(focusRequester)
@@ -167,7 +167,7 @@ private fun TextField(
enabled = state.enabled,
isError = state.isError,
forceTextDirectionLtr = state.forceTextDirectionLtr,
- placeholderText = state.placeholder,
+ placeholder = state.placeholder,
visualTransformation = state.visualTransformation,
keyboardOptions = state.keyboardOptions,
keyboardActions = POField.keyboardActions(
@@ -213,7 +213,7 @@ private fun CodeField(
)
)
},
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier
.onFocusChanged {
@@ -271,7 +271,7 @@ private fun RadioField(
)
},
availableValues = state.availableValues ?: POImmutableList(emptyList()),
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier,
radioGroupStyle = radioGroupStyle,
@@ -302,7 +302,7 @@ private fun DropdownField(
)
},
availableValues = state.availableValues ?: POImmutableList(emptyList()),
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier
.onFocusChanged {
@@ -318,7 +318,7 @@ private fun DropdownField(
labelsStyle = labelsStyle,
menuStyle = menuStyle,
isError = state.isError,
- placeholderText = state.placeholder
+ placeholder = state.placeholder
)
}
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt
index 9b2360de8..532ccec9a 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt
@@ -229,7 +229,7 @@ private fun TextField(
)
)
},
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier
.focusRequester(focusRequester)
@@ -246,7 +246,7 @@ private fun TextField(
enabled = state.enabled,
isError = state.isError,
forceTextDirectionLtr = state.forceTextDirectionLtr,
- placeholderText = state.placeholder,
+ placeholder = state.placeholder,
visualTransformation = state.visualTransformation,
keyboardOptions = state.keyboardOptions,
keyboardActions = POField.keyboardActions(
@@ -283,7 +283,7 @@ private fun CodeField(
)
)
},
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier
.onFocusChanged {
@@ -331,7 +331,7 @@ private fun RadioField(
)
},
availableValues = state.availableValues ?: POImmutableList(emptyList()),
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier,
radioGroupStyle = radioGroupStyle,
@@ -360,7 +360,7 @@ private fun DropdownField(
)
},
availableValues = state.availableValues ?: POImmutableList(emptyList()),
- title = state.title ?: String(),
+ title = state.label ?: String(),
description = state.description,
modifier = modifier
.onFocusChanged {
@@ -375,7 +375,7 @@ private fun DropdownField(
labelsStyle = labelsStyle,
menuStyle = menuStyle,
isError = state.isError,
- placeholderText = state.placeholder
+ placeholder = state.placeholder
)
}
@@ -643,7 +643,7 @@ internal object NativeAlternativePaymentScreen {
codeField = custom?.codeField?.let {
POField.custom(style = it)
} ?: POCodeField.default,
- radioGroup = custom?.radioButton?.let {
+ radioGroup = custom?.radioField?.let {
PORadioGroup.custom(style = it)
} ?: PORadioGroup.default,
dropdownMenu = custom?.dropdownMenu?.let {
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModel.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModel.kt
index 217dd9c4c..208105149 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModel.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModel.kt
@@ -231,7 +231,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
FieldState(
id = id,
value = value,
- title = displayName,
+ label = displayName,
description = description,
placeholder = type.placeholder(),
isError = !isValid,
@@ -255,7 +255,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
id = id,
value = value,
length = length,
- title = displayName,
+ label = displayName,
description = description,
isError = !isValid,
keyboardOptions = type.keyboardOptions(keyboardAction.imeAction),
@@ -269,7 +269,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
id = id,
value = value,
availableValues = availableValues?.let { POImmutableList(it) },
- title = displayName,
+ label = displayName,
description = description,
isError = !isValid
)
@@ -281,7 +281,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
id = id,
value = value,
availableValues = availableValues?.let { POImmutableList(it) },
- title = displayName,
+ label = displayName,
description = description,
isError = !isValid
)
@@ -336,8 +336,8 @@ internal class NativeAlternativePaymentViewModel private constructor(
}
private fun ParameterType.placeholder(): String? = when (this) {
- EMAIL -> app.getString(R.string.po_native_apm_email_placeholder)
- PHONE -> app.getString(R.string.po_native_apm_phone_placeholder)
+ EMAIL -> app.getString(R.string.po_native_apm_placeholder_email)
+ PHONE -> app.getString(R.string.po_native_apm_placeholder_phone)
else -> null
}
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/PONativeAlternativePaymentConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/PONativeAlternativePaymentConfiguration.kt
index eadceb8ff..ad4195774 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/PONativeAlternativePaymentConfiguration.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/PONativeAlternativePaymentConfiguration.kt
@@ -294,7 +294,7 @@ data class PONativeAlternativePaymentConfiguration(
* @param[label] Field label style.
* @param[field] Field style.
* @param[codeField] Code field style.
- * @param[radioButton] Radio button style.
+ * @param[radioField] Radio field style.
* @param[checkbox] Checkbox style.
* @param[dropdownMenu] Dropdown menu style.
* @param[actionsContainer] Style of action buttons and their container.
@@ -302,6 +302,7 @@ data class PONativeAlternativePaymentConfiguration(
* @param[background] Background style.
* @param[message] Message style.
* @param[errorMessage] Error message style.
+ * @param[errorMessageBox] Error message box style.
* @param[successMessage] Success message style.
* @param[successImageResId] Success image drawable resource ID.
* @param[progressIndicatorColorResId] Color resource ID for progress indicator.
@@ -315,7 +316,7 @@ data class PONativeAlternativePaymentConfiguration(
val label: POTextStyle? = null,
val field: POFieldStyle? = null,
val codeField: POFieldStyle? = null,
- val radioButton: PORadioButtonStyle? = null,
+ val radioField: PORadioFieldStyle? = null,
val checkbox: POCheckboxStyle? = null,
val dropdownMenu: PODropdownMenuStyle? = null,
val actionsContainer: POActionsContainerStyle? = null,
@@ -323,6 +324,7 @@ data class PONativeAlternativePaymentConfiguration(
val background: POBackgroundStyle? = null,
val message: POTextStyle? = null,
val errorMessage: POTextStyle? = null,
+ val errorMessageBox: POMessageBoxStyle? = null,
val successMessage: POTextStyle? = null,
@DrawableRes
val successImageResId: Int? = null,
@@ -334,7 +336,79 @@ data class PONativeAlternativePaymentConfiguration(
val dividerColorResId: Int? = null,
@ColorRes
val dragHandleColorResId: Int? = null
- ) : Parcelable
+ ) : Parcelable {
+
+ /**
+ * Allows to customize the look and feel.
+ *
+ * @param[title] Title style.
+ * @param[label] Field label style.
+ * @param[field] Field style.
+ * @param[codeField] Code field style.
+ * @param[radioButton] Radio button style. __Deprecated__: not used.
+ * @param[checkbox] Checkbox style.
+ * @param[dropdownMenu] Dropdown menu style.
+ * @param[actionsContainer] Style of action buttons and their container.
+ * @param[dialog] Dialog style.
+ * @param[background] Background style.
+ * @param[message] Message style.
+ * @param[errorMessage] Error message style.
+ * @param[errorMessageBox] Error message box style.
+ * @param[successMessage] Success message style.
+ * @param[successImageResId] Success image drawable resource ID.
+ * @param[progressIndicatorColorResId] Color resource ID for progress indicator.
+ * @param[controlsTintColorResId] Color resource ID for tint that applies to generic components (e.g. selectable text).
+ * @param[dividerColorResId] Color resource ID for title divider.
+ * @param[dragHandleColorResId] Color resource ID for bottom sheet drag handle.
+ */
+ @Deprecated(message = "Use alternative constructor.")
+ constructor(
+ title: POTextStyle? = null,
+ label: POTextStyle? = null,
+ field: POFieldStyle? = null,
+ codeField: POFieldStyle? = null,
+ radioButton: PORadioButtonStyle? = null,
+ checkbox: POCheckboxStyle? = null,
+ dropdownMenu: PODropdownMenuStyle? = null,
+ actionsContainer: POActionsContainerStyle? = null,
+ dialog: PODialogStyle? = null,
+ background: POBackgroundStyle? = null,
+ message: POTextStyle? = null,
+ errorMessage: POTextStyle? = null,
+ errorMessageBox: POMessageBoxStyle? = null,
+ successMessage: POTextStyle? = null,
+ @DrawableRes
+ successImageResId: Int? = null,
+ @ColorRes
+ progressIndicatorColorResId: Int? = null,
+ @ColorRes
+ controlsTintColorResId: Int? = null,
+ @ColorRes
+ dividerColorResId: Int? = null,
+ @ColorRes
+ dragHandleColorResId: Int? = null
+ ) : this(
+ title = title,
+ label = label,
+ field = field,
+ codeField = codeField,
+ radioField = null,
+ checkbox = checkbox,
+ dropdownMenu = dropdownMenu,
+ actionsContainer = actionsContainer,
+ dialog = dialog,
+ background = background,
+ message = message,
+ errorMessage = errorMessage,
+ errorMessageBox = errorMessageBox,
+ successMessage = successMessage,
+ successImageResId = successImageResId,
+ progressIndicatorColorResId = progressIndicatorColorResId,
+ controlsTintColorResId = controlsTintColorResId,
+ dividerColorResId = dividerColorResId,
+ dragHandleColorResId = dragHandleColorResId
+ )
+ }
}
private fun SecondaryAction.toCancelButton(): CancelButton =
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentInteractor.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentInteractor.kt
index 182d8e8ba..39078855f 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentInteractor.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentInteractor.kt
@@ -290,10 +290,9 @@ internal class NativeAlternativePaymentInteractor(
return
}
val fields = parameters.toFields()
- val focusedFieldId = fields.firstFocusableFieldId()
val updatedStateValue = stateValue.copy(
fields = fields,
- focusedFieldId = focusedFieldId
+ focusedFieldId = fields.firstFocusableFieldId()
)
_state.update {
if (_state.value is Loading) {
@@ -327,7 +326,7 @@ internal class NativeAlternativePaymentInteractor(
map { parameter ->
val defaultValue = when (parameter) {
is Parameter.SingleSelect -> FieldValue.Text(
- TextFieldValue(text = parameter.preselectedValue?.value ?: String())
+ TextFieldValue(text = parameter.preselectedValue?.key ?: String())
)
is Parameter.Bool -> FieldValue.Text(TextFieldValue(text = "false"))
is Parameter.PhoneNumber -> FieldValue.PhoneNumber()
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentScreen.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentScreen.kt
index 5ebaf7bb7..5df874a64 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentScreen.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentScreen.kt
@@ -36,17 +36,15 @@ import coil.compose.AsyncImage
import com.processout.sdk.ui.R
import com.processout.sdk.ui.core.component.*
import com.processout.sdk.ui.core.component.field.POField
-import com.processout.sdk.ui.core.component.field.POFieldLabels
import com.processout.sdk.ui.core.component.field.checkbox.POCheckbox
-import com.processout.sdk.ui.core.component.field.checkbox.POLabeledCheckboxField
+import com.processout.sdk.ui.core.component.field.checkbox.POCheckboxField
import com.processout.sdk.ui.core.component.field.code.POCodeField
-import com.processout.sdk.ui.core.component.field.code.POLabeledCodeField
+import com.processout.sdk.ui.core.component.field.code.POCodeField2
import com.processout.sdk.ui.core.component.field.dropdown.PODropdownField
-import com.processout.sdk.ui.core.component.field.dropdown.POLabeledDropdownField
-import com.processout.sdk.ui.core.component.field.phone.POLabeledPhoneNumberField
-import com.processout.sdk.ui.core.component.field.radio.POLabeledRadioField
-import com.processout.sdk.ui.core.component.field.radio.PORadioGroup
-import com.processout.sdk.ui.core.component.field.text.POLabeledTextField
+import com.processout.sdk.ui.core.component.field.dropdown.PODropdownField2
+import com.processout.sdk.ui.core.component.field.phone.POPhoneNumberField
+import com.processout.sdk.ui.core.component.field.radio.PORadioField
+import com.processout.sdk.ui.core.component.field.text.POTextField2
import com.processout.sdk.ui.core.state.POActionState
import com.processout.sdk.ui.core.state.POImmutableList
import com.processout.sdk.ui.core.state.POPhoneNumberFieldState
@@ -60,7 +58,6 @@ import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentScreen.CaptureImage
import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentScreen.CaptureLogoHeight
import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentScreen.CrossfadeAnimationDurationMillis
import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentScreen.animatedBackgroundColor
-import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentScreen.codeFieldHorizontalAlignment
import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentScreen.messageGravity
import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentViewModelState.*
import com.processout.sdk.ui.napm.v2.NativeAlternativePaymentViewModelState.Field.*
@@ -165,10 +162,6 @@ private fun UserInput(
verticalArrangement = Arrangement.spacedBy(ProcessOutTheme.spacing.extraLarge)
) {
val lifecycleEvent = rememberLifecycleEvent()
- val labelsStyle = POFieldLabels.Style(
- title = style.label,
- description = style.errorMessage
- )
val isPrimaryActionEnabled = with(state.primaryAction) { enabled && !loading }
state.fields.elements.forEach { field ->
when (field) {
@@ -179,7 +172,7 @@ private fun UserInput(
focusedFieldId = state.focusedFieldId,
isPrimaryActionEnabled = isPrimaryActionEnabled,
fieldStyle = style.field,
- labelsStyle = labelsStyle,
+ descriptionStyle = style.errorMessageBox,
modifier = Modifier.fillMaxWidth()
)
is CodeField -> CodeField(
@@ -189,28 +182,29 @@ private fun UserInput(
focusedFieldId = state.focusedFieldId,
isPrimaryActionEnabled = isPrimaryActionEnabled,
fieldStyle = style.codeField,
- labelsStyle = labelsStyle,
- horizontalAlignment = codeFieldHorizontalAlignment(state.fields.elements)
+ descriptionStyle = style.errorMessageBox,
+ modifier = Modifier.fillMaxWidth()
)
is RadioField -> RadioField(
state = field.state,
onEvent = onEvent,
- radioGroupStyle = style.radioGroup,
- labelsStyle = labelsStyle
+ fieldStyle = style.radioField,
+ descriptionStyle = style.errorMessageBox,
+ modifier = Modifier.fillMaxWidth()
)
is DropdownField -> DropdownField(
state = field.state,
onEvent = onEvent,
fieldStyle = style.field,
- labelsStyle = labelsStyle,
menuStyle = style.dropdownMenu,
+ descriptionStyle = style.errorMessageBox,
modifier = Modifier.fillMaxWidth()
)
is CheckboxField -> CheckboxField(
state = field.state,
onEvent = onEvent,
checkboxStyle = style.checkbox,
- labelsStyle = labelsStyle,
+ descriptionStyle = style.errorMessageBox,
modifier = Modifier.fillMaxWidth()
)
is PhoneNumberField -> PhoneNumberField(
@@ -221,7 +215,7 @@ private fun UserInput(
isPrimaryActionEnabled = isPrimaryActionEnabled,
fieldStyle = style.field,
dropdownMenuStyle = style.dropdownMenu,
- labelsStyle = labelsStyle,
+ descriptionStyle = style.errorMessageBox,
modifier = Modifier.fillMaxWidth()
)
}
@@ -238,11 +232,11 @@ private fun TextField(
focusedFieldId: String?,
isPrimaryActionEnabled: Boolean,
fieldStyle: POField.Style,
- labelsStyle: POFieldLabels.Style,
+ descriptionStyle: POMessageBox.Style,
modifier: Modifier = Modifier
) {
val focusRequester = remember { FocusRequester() }
- POLabeledTextField(
+ POTextField2(
value = state.value,
onValueChange = {
onEvent(
@@ -252,9 +246,8 @@ private fun TextField(
)
)
},
- title = state.title ?: String(),
- description = state.description,
- modifier = modifier
+ modifier = modifier,
+ textFieldModifier = Modifier
.focusRequester(focusRequester)
.onFocusChanged {
onEvent(
@@ -265,11 +258,13 @@ private fun TextField(
)
},
fieldStyle = fieldStyle,
- labelsStyle = labelsStyle,
+ descriptionStyle = descriptionStyle,
+ label = state.label,
+ placeholder = state.placeholder,
+ description = state.description,
enabled = state.enabled,
isError = state.isError,
forceTextDirectionLtr = state.forceTextDirectionLtr,
- placeholderText = state.placeholder,
visualTransformation = state.visualTransformation,
keyboardOptions = state.keyboardOptions,
keyboardActions = POField.keyboardActions(
@@ -292,11 +287,10 @@ private fun CodeField(
focusedFieldId: String?,
isPrimaryActionEnabled: Boolean,
fieldStyle: POField.Style,
- labelsStyle: POFieldLabels.Style,
- horizontalAlignment: Alignment.Horizontal,
+ descriptionStyle: POMessageBox.Style,
modifier: Modifier = Modifier
) {
- POLabeledCodeField(
+ POCodeField2(
value = state.value,
onValueChange = {
onEvent(
@@ -306,9 +300,8 @@ private fun CodeField(
)
)
},
- title = state.title ?: String(),
- description = state.description,
- modifier = modifier
+ modifier = modifier,
+ textFieldModifier = Modifier
.onFocusChanged {
onEvent(
FieldFocusChanged(
@@ -318,9 +311,10 @@ private fun CodeField(
)
},
fieldStyle = fieldStyle,
- labelsStyle = labelsStyle,
+ descriptionStyle = descriptionStyle,
length = state.length ?: POCodeField.LengthMax,
- horizontalAlignment = horizontalAlignment,
+ label = state.label,
+ description = state.description,
enabled = state.enabled,
isError = state.isError,
isFocused = state.id == focusedFieldId,
@@ -340,11 +334,11 @@ private fun CodeField(
private fun RadioField(
state: FieldState,
onEvent: (NativeAlternativePaymentEvent) -> Unit,
- radioGroupStyle: PORadioGroup.Style,
- labelsStyle: POFieldLabels.Style,
+ fieldStyle: PORadioField.Style,
+ descriptionStyle: POMessageBox.Style,
modifier: Modifier = Modifier
) {
- POLabeledRadioField(
+ PORadioField(
value = state.value,
onValueChange = {
onEvent(
@@ -355,11 +349,11 @@ private fun RadioField(
)
},
availableValues = state.availableValues ?: POImmutableList(emptyList()),
- title = state.title ?: String(),
- description = state.description,
modifier = modifier,
- radioGroupStyle = radioGroupStyle,
- labelsStyle = labelsStyle,
+ fieldStyle = fieldStyle,
+ descriptionStyle = descriptionStyle,
+ title = state.label,
+ description = state.description,
isError = state.isError
)
}
@@ -369,11 +363,11 @@ private fun DropdownField(
state: FieldState,
onEvent: (NativeAlternativePaymentEvent) -> Unit,
fieldStyle: POField.Style,
- labelsStyle: POFieldLabels.Style,
menuStyle: PODropdownField.MenuStyle,
+ descriptionStyle: POMessageBox.Style,
modifier: Modifier = Modifier
) {
- POLabeledDropdownField(
+ PODropdownField2(
value = state.value,
onValueChange = {
onEvent(
@@ -384,9 +378,8 @@ private fun DropdownField(
)
},
availableValues = state.availableValues ?: POImmutableList(emptyList()),
- title = state.title ?: String(),
- description = state.description,
- modifier = modifier
+ modifier = modifier,
+ textFieldModifier = Modifier
.onFocusChanged {
onEvent(
FieldFocusChanged(
@@ -396,10 +389,12 @@ private fun DropdownField(
)
},
fieldStyle = fieldStyle,
- labelsStyle = labelsStyle,
menuStyle = menuStyle,
+ descriptionStyle = descriptionStyle,
isError = state.isError,
- placeholderText = state.placeholder
+ label = state.label,
+ placeholder = state.placeholder,
+ description = state.description
)
}
@@ -408,11 +403,11 @@ private fun CheckboxField(
state: FieldState,
onEvent: (NativeAlternativePaymentEvent) -> Unit,
checkboxStyle: POCheckbox.Style,
- labelsStyle: POFieldLabels.Style,
+ descriptionStyle: POMessageBox.Style,
modifier: Modifier = Modifier
) {
- POLabeledCheckboxField(
- text = state.title ?: String(),
+ POCheckboxField(
+ text = state.label ?: String(),
checked = state.value.text.toBooleanStrictOrNull() ?: false,
onCheckedChange = {
onEvent(
@@ -424,12 +419,11 @@ private fun CheckboxField(
)
)
},
- title = null,
- description = state.description,
modifier = modifier,
checkboxStyle = checkboxStyle,
- labelsStyle = labelsStyle,
- isError = state.isError
+ descriptionStyle = descriptionStyle,
+ isError = state.isError,
+ description = state.description
)
}
@@ -442,11 +436,11 @@ private fun PhoneNumberField(
isPrimaryActionEnabled: Boolean,
fieldStyle: POField.Style,
dropdownMenuStyle: PODropdownField.MenuStyle,
- labelsStyle: POFieldLabels.Style,
+ descriptionStyle: POMessageBox.Style,
modifier: Modifier = Modifier
) {
val focusRequester = remember { FocusRequester() }
- POLabeledPhoneNumberField(
+ POPhoneNumberField(
state = state,
onValueChange = { regionCode, number ->
onEvent(
@@ -472,7 +466,7 @@ private fun PhoneNumberField(
},
fieldStyle = fieldStyle,
dropdownMenuStyle = dropdownMenuStyle,
- labelsStyle = labelsStyle,
+ descriptionStyle = descriptionStyle,
keyboardActions = POField.keyboardActions(
imeAction = state.keyboardOptions.imeAction,
actionId = state.keyboardActionId,
@@ -718,7 +712,7 @@ internal object NativeAlternativePaymentScreen {
val label: POText.Style,
val field: POField.Style,
val codeField: POField.Style,
- val radioGroup: PORadioGroup.Style,
+ val radioField: PORadioField.Style,
val checkbox: POCheckbox.Style,
val dropdownMenu: PODropdownField.MenuStyle,
val actionsContainer: POActionsContainer.Style,
@@ -727,6 +721,7 @@ internal object NativeAlternativePaymentScreen {
val successBackgroundColor: Color,
val message: AndroidTextView.Style,
val errorMessage: POText.Style,
+ val errorMessageBox: POMessageBox.Style,
val successMessage: POText.Style,
@DrawableRes val successImageResId: Int,
val progressIndicatorColor: Color,
@@ -746,22 +741,22 @@ internal object NativeAlternativePaymentScreen {
} ?: POText.label1,
field = custom?.field?.let {
POField.custom(style = it)
- } ?: POField.default,
+ } ?: POField.default2,
codeField = custom?.codeField?.let {
POField.custom(style = it)
- } ?: POCodeField.default,
- radioGroup = custom?.radioButton?.let {
- PORadioGroup.custom(style = it)
- } ?: PORadioGroup.default,
+ } ?: POCodeField.default2,
+ radioField = custom?.radioField?.let {
+ PORadioField.custom(style = it)
+ } ?: PORadioField.default,
checkbox = custom?.checkbox?.let {
POCheckbox.custom(style = it)
- } ?: POCheckbox.default,
+ } ?: POCheckbox.default2,
dropdownMenu = custom?.dropdownMenu?.let {
PODropdownField.custom(style = it)
- } ?: PODropdownField.defaultMenu,
+ } ?: PODropdownField.defaultMenu2,
actionsContainer = custom?.actionsContainer?.let {
POActionsContainer.custom(style = it)
- } ?: POActionsContainer.default,
+ } ?: POActionsContainer.default2,
dialog = custom?.dialog?.let {
PODialog.custom(style = it)
} ?: PODialog.default,
@@ -781,6 +776,9 @@ internal object NativeAlternativePaymentScreen {
errorMessage = custom?.errorMessage?.let {
POText.custom(style = it)
} ?: POText.errorLabel,
+ errorMessageBox = custom?.errorMessageBox?.let {
+ POMessageBox.custom(style = it)
+ } ?: POMessageBox.error2,
successMessage = custom?.successMessage?.let {
POText.custom(style = it)
} ?: POText.Style(
@@ -824,10 +822,6 @@ internal object NativeAlternativePaymentScreen {
)
).value
- fun codeFieldHorizontalAlignment(fields: List): Alignment.Horizontal =
- if (fields.size == 1 && fields[0] is CodeField)
- Alignment.CenterHorizontally else Alignment.Start
-
private val ShortMessageMaxLength = 150
fun messageGravity(text: String): Int =
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentViewModel.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentViewModel.kt
index 4c0bd514e..5b852d98a 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentViewModel.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/v2/NativeAlternativePaymentViewModel.kt
@@ -250,9 +250,8 @@ internal class NativeAlternativePaymentViewModel private constructor(
FieldState(
id = id,
value = value.textFieldValue(),
- title = label,
+ label = label,
description = description,
- placeholder = parameter.placeholder(),
isError = !isValid,
forceTextDirectionLtr = ltrParameterTypes.contains(parameter::class.java),
inputFilter = parameter.inputFilter(),
@@ -270,7 +269,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
id = id,
value = value.textFieldValue(),
length = maxLength,
- title = label,
+ label = label,
description = description,
isError = !isValid,
inputFilter = parameter.inputFilter(),
@@ -285,7 +284,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
id = id,
value = value.textFieldValue(),
availableValues = parameter.availableValues(),
- title = label,
+ label = label,
description = description,
isError = !isValid
)
@@ -297,7 +296,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
id = id,
value = value.textFieldValue(),
availableValues = parameter.availableValues(),
- title = label,
+ label = label,
description = description,
isError = !isValid
)
@@ -308,7 +307,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
FieldState(
id = id,
value = value.textFieldValue(),
- title = label,
+ label = label,
description = description,
isError = !isValid
)
@@ -326,13 +325,12 @@ internal class NativeAlternativePaymentViewModel private constructor(
id = id,
regionCode = regionCode,
regionCodes = parameter.phoneNumberRegionCodes(),
- regionCodePlaceholder = app.getString(R.string.po_native_apm_country_placeholder),
+ regionCodeLabel = app.getString(R.string.po_native_apm_label_country),
number = when (value) {
is FieldValue.PhoneNumber -> value.number
else -> TextFieldValue()
},
- numberPlaceholder = app.getString(R.string.po_native_apm_phone_placeholder),
- title = label,
+ numberLabel = label,
description = description,
isError = !isValid,
forceTextDirectionLtr = true,
@@ -358,7 +356,7 @@ internal class NativeAlternativePaymentViewModel private constructor(
is SingleSelect -> POImmutableList(
availableValues.map {
POAvailableValue(
- value = it.value,
+ value = it.key,
text = it.label
)
}
@@ -460,12 +458,6 @@ internal class NativeAlternativePaymentViewModel private constructor(
Unknown -> KeyboardOptions.Default
}
- private fun Parameter.placeholder(): String? =
- when (this) {
- is Email -> app.getString(R.string.po_native_apm_email_placeholder)
- else -> null
- }
-
private fun Invoice.formatPrimaryActionText() =
try {
val price = NumberFormat.getCurrencyInstance().apply {
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/shared/state/FieldState.kt b/ui/src/main/kotlin/com/processout/sdk/ui/shared/state/FieldState.kt
index 3c4bb10f6..f99e648cf 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/shared/state/FieldState.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/shared/state/FieldState.kt
@@ -15,9 +15,9 @@ internal data class FieldState(
val value: TextFieldValue = TextFieldValue(),
val availableValues: POImmutableList? = null,
val length: Int? = null,
- val title: String? = null,
- val description: String? = null,
+ val label: String? = null,
val placeholder: String? = null,
+ val description: String? = null,
@DrawableRes val iconResId: Int? = null,
val enabled: Boolean = true,
val isError: Boolean = false,