From 9a55c51edbb77246c08d811027a46d9d7e76f4fc Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Fri, 20 Dec 2024 15:18:50 +0200 Subject: [PATCH 01/17] Custom icon on submit button on DC --- .../sdk/ui/core/component/POButton.kt | 20 ++++++++++++++++++- .../sdk/ui/core/state/POActionState.kt | 2 ++ .../ui/checkout/DynamicCheckoutActivity.kt | 4 ++-- .../ui/checkout/DynamicCheckoutViewModel.kt | 16 +++++++++++---- .../PODynamicCheckoutConfiguration.kt | 9 ++++++++- .../checkout/screen/DynamicCheckoutScreen.kt | 3 ++- 6 files changed, 45 insertions(+), 9 deletions(-) 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 eb0c1d8b5..e79953330 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 @@ -1,6 +1,8 @@ package com.processout.sdk.ui.core.component +import androidx.annotation.DrawableRes import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.* @@ -10,8 +12,10 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier 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.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -25,6 +29,7 @@ import com.processout.sdk.ui.core.style.POButtonDefaults import com.processout.sdk.ui.core.style.POButtonStateStyle import com.processout.sdk.ui.core.style.POButtonStyle import com.processout.sdk.ui.core.theme.ProcessOutTheme +import com.processout.sdk.ui.core.theme.ProcessOutTheme.spacing /** @suppress */ @ProcessOutInternalApi @@ -37,9 +42,11 @@ fun POButton( enabled: Boolean = true, loading: Boolean = false, leadingContent: @Composable RowScope.() -> Unit = {}, + @DrawableRes iconResId: Int? = null, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } ) { val pressed by interactionSource.collectIsPressedAsState() + val colors = colors(style = style, enabled = enabled, loading = loading, pressed = pressed) CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides Dp.Unspecified) { Button( onClick = onClick, @@ -47,7 +54,7 @@ fun POButton( min = ProcessOutTheme.dimensions.interactiveComponentMinSize ), enabled = enabled && !loading, - colors = colors(style = style, enabled = enabled, loading = loading, pressed = pressed), + colors = colors, shape = if (enabled) style.normal.shape else style.disabled.shape, border = border(style = style, enabled = enabled, pressed = pressed), elevation = elevation(style = style, enabled = enabled, loading = loading), @@ -65,6 +72,17 @@ fun POButton( } } else { leadingContent() + iconResId?.let { + val iconColor = if (enabled) colors.contentColor else colors.disabledContentColor + Image( + painter = painterResource(it), + contentDescription = null, + modifier = Modifier + .padding(end = spacing.small) + .requiredSize(20.dp), + colorFilter = ColorFilter.tint(color = iconColor) + ) + } POText( text = text, style = if (enabled) style.normal.text.textStyle else style.disabled.text.textStyle, diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POActionState.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POActionState.kt index 940a36256..cae5fa472 100644 --- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POActionState.kt +++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/state/POActionState.kt @@ -1,5 +1,6 @@ package com.processout.sdk.ui.core.state +import androidx.annotation.DrawableRes import androidx.compose.runtime.Immutable import com.processout.sdk.ui.core.annotation.ProcessOutInternalApi @@ -12,6 +13,7 @@ data class POActionState( val primary: Boolean, val enabled: Boolean = true, val loading: Boolean = false, + @DrawableRes val iconResId: Int? = null, val confirmation: Confirmation? = null ) { diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt index 9f435299f..011e19eb4 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt @@ -103,7 +103,7 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { defaultAddress = billingAddress?.defaultAddress, attachDefaultsToPaymentMethod = billingAddress?.attachDefaultsToPaymentMethod ?: false ), - primaryActionText = configuration?.submitButtonText, + primaryActionText = configuration?.submitButton?.text, secondaryActionText = configuration?.cancelButton?.text, cancellation = POCancellationConfiguration( secondaryAction = configuration?.cancelButton != null @@ -115,7 +115,7 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { private fun nativeAlternativePaymentConfiguration(): Options { val paymentConfirmation = configuration?.alternativePayment?.paymentConfirmation return Options( - primaryActionText = configuration?.submitButtonText, + primaryActionText = configuration?.submitButton?.text, secondaryAction = configuration?.cancelButton?.toSecondaryAction(), paymentConfirmation = PaymentConfirmationConfiguration( waitsConfirmation = true, 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 101963354..9815ebf2b 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 @@ -233,7 +233,7 @@ internal class DynamicCheckoutViewModel private constructor( interactorState.paymentMethods.mapNotNull { paymentMethod -> val id = paymentMethod.id val selected = id == interactorState.selectedPaymentMethod?.id - val submitButtonText = configuration.submitButtonText ?: app.getString(R.string.po_dynamic_checkout_button_pay) + val submitButtonText = configuration.submitButton.text ?: app.getString(R.string.po_dynamic_checkout_button_pay) when (paymentMethod) { is Card -> RegularPayment( id = id, @@ -243,7 +243,11 @@ internal class DynamicCheckoutViewModel private constructor( selected = selected ), content = if (selected) Content.Card(cardTokenizationState) else null, - submitAction = if (selected) cardTokenizationState.primaryAction.copy(text = submitButtonText) else null + submitAction = if (selected) + cardTokenizationState.primaryAction.copy( + text = submitButtonText, + iconResId = configuration.submitButton.iconResId + ) else null ) is AlternativePayment -> if (!paymentMethod.isExpress) RegularPayment( @@ -260,7 +264,8 @@ internal class DynamicCheckoutViewModel private constructor( text = submitButtonText, primary = true, loading = id == interactorState.processingPaymentMethod?.id || - interactorState.invoice == null + interactorState.invoice == null, + iconResId = configuration.submitButton.iconResId ) ) else null is NativeAlternativePayment -> RegularPayment( @@ -273,7 +278,10 @@ internal class DynamicCheckoutViewModel private constructor( ), content = if (selected) Content.NativeAlternativePayment(nativeAlternativePaymentState) else null, submitAction = if (selected && nativeAlternativePaymentState is UserInput) - nativeAlternativePaymentState.primaryAction.copy(text = submitButtonText) else null + nativeAlternativePaymentState.primaryAction.copy( + text = submitButtonText, + iconResId = configuration.submitButton.iconResId + ) else null ) else -> null } diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt index 135601857..ccf58ae7c 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt @@ -21,7 +21,7 @@ data class PODynamicCheckoutConfiguration( val googlePay: GooglePayConfiguration = GooglePayConfiguration(), val alternativePayment: AlternativePaymentConfiguration = AlternativePaymentConfiguration(), val preselectSinglePaymentMethod: Boolean = true, - val submitButtonText: String? = null, + val submitButton: SubmitButton = SubmitButton(), val cancelButton: CancelButton? = CancelButton(), val paymentSuccess: PaymentSuccess? = PaymentSuccess(), val style: Style? = null @@ -110,6 +110,13 @@ data class PODynamicCheckoutConfiguration( } } + @Parcelize + data class SubmitButton( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null + ) : Parcelable + @Parcelize data class CancelButton( val text: String? = null, 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 eda31def8..413a963a9 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 @@ -443,7 +443,8 @@ private fun RegularPaymentContent( .padding(top = spacing.extraLarge), style = style.actionsContainer.primary, enabled = enabled, - loading = loading + loading = loading, + iconResId = iconResId ) } } From ba4c79254051adea69e038a2c359d2fb7a60d24f Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Fri, 20 Dec 2024 16:12:34 +0200 Subject: [PATCH 02/17] Custom icon on cancel button on DC --- .../processout/sdk/ui/core/component/POActionsContainer.kt | 3 ++- .../processout/sdk/ui/checkout/DynamicCheckoutViewModel.kt | 5 ++++- .../sdk/ui/checkout/PODynamicCheckoutConfiguration.kt | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) 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 2cbe65cde..b0f0be12e 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 @@ -109,7 +109,8 @@ private fun Actions( modifier = modifier.fillMaxWidth(), style = if (primary) primaryActionStyle else secondaryActionStyle, enabled = enabled, - loading = loading + loading = loading, + iconResId = iconResId ) if (requestConfirmation) { confirmation?.run { 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 9815ebf2b..b002cbd61 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 @@ -146,7 +146,10 @@ internal class DynamicCheckoutViewModel private constructor( } } else -> defaultCancelAction - }?.copy(id = interactorState.cancelActionId) + }?.copy( + id = interactorState.cancelActionId, + iconResId = configuration.cancelButton?.iconResId + ) } private fun CancelButton.toActionState( diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt index ccf58ae7c..0af210bca 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt @@ -120,6 +120,8 @@ data class PODynamicCheckoutConfiguration( @Parcelize data class CancelButton( val text: String? = null, + @DrawableRes + val iconResId: Int? = null, val disabledForSeconds: Int = 0, val confirmation: POActionConfirmationConfiguration? = null ) : Parcelable From 323092796cb5fb9c7c036d64a81bf1af462c4c13 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 6 Jan 2025 18:10:02 +0200 Subject: [PATCH 03/17] Custom icon on nAPM payment confirmation button (standalone and DC) --- .../processout/sdk/ui/checkout/DynamicCheckoutActivity.kt | 7 ++++++- .../sdk/ui/checkout/PODynamicCheckoutConfiguration.kt | 4 +++- .../sdk/ui/checkout/screen/NativeAlternativePayment.kt | 3 ++- .../sdk/ui/napm/NativeAlternativePaymentViewModel.kt | 3 ++- .../sdk/ui/napm/PONativeAlternativePaymentConfiguration.kt | 5 ++++- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt index 011e19eb4..c6a9a89de 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt @@ -122,7 +122,12 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { timeoutSeconds = paymentConfirmation?.timeoutSeconds ?: DEFAULT_TIMEOUT_SECONDS, showProgressIndicatorAfterSeconds = paymentConfirmation?.showProgressIndicatorAfterSeconds, hideGatewayDetails = true, - primaryAction = paymentConfirmation?.confirmButton?.let { ConfirmAction(text = it.text) }, + primaryAction = paymentConfirmation?.confirmButton?.let { + ConfirmAction( + text = it.text, + iconResId = it.iconResId + ) + }, secondaryAction = paymentConfirmation?.cancelButton?.toSecondaryAction() ), barcode = configuration?.alternativePayment?.barcode ?: POBarcodeConfiguration(), diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt index 0af210bca..268decf76 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt @@ -105,7 +105,9 @@ data class PODynamicCheckoutConfiguration( @Parcelize data class ConfirmButton( - val text: String? = null + val text: String? = null, + @DrawableRes + val iconResId: Int? = null ) : Parcelable } } 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 4cfc5437b..45fed9897 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 @@ -403,7 +403,8 @@ private fun Capture( ) }, modifier = Modifier.fillMaxWidth(), - style = style.actionsContainer.primary + style = style.actionsContainer.primary, + iconResId = action.iconResId ) } state.saveBarcodeAction?.let { action -> 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 465b10045..31cf95a00 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 @@ -167,7 +167,8 @@ internal class NativeAlternativePaymentViewModel private constructor( POActionState( id = id, text = it.text ?: app.getString(R.string.po_native_apm_confirm_payment_button_text), - primary = true + primary = true, + iconResId = it.iconResId ) } } 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 a76e65e1b..4ce28577c 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 @@ -56,10 +56,13 @@ data class PONativeAlternativePaymentConfiguration( * Action for confirmation. * * @param[text] Action text. Pass _null_ to use default text. + * @param[iconResId] Action icon drawable resource ID. Pass _null_ to hide. */ @Parcelize data class ConfirmAction( - val text: String? = null + val text: String? = null, + @DrawableRes + val iconResId: Int? = null ) : Parcelable /** From 3c39dbda5f74ff3648deebba081d2bc664923a04 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Tue, 7 Jan 2025 14:12:43 +0200 Subject: [PATCH 04/17] Refactor POBarcodeConfiguration --- .../ui/checkout/DynamicCheckoutActivity.kt | 3 +- .../PODynamicCheckoutConfiguration.kt | 2 +- ...PONativeAlternativePaymentConfiguration.kt | 2 +- .../configuration/POBarcodeConfiguration.kt | 46 +++++++++++++++++-- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt index c6a9a89de..4218ac7ac 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt @@ -130,7 +130,8 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { }, secondaryAction = paymentConfirmation?.cancelButton?.toSecondaryAction() ), - barcode = configuration?.alternativePayment?.barcode ?: POBarcodeConfiguration(), + barcode = configuration?.alternativePayment?.barcode + ?: POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), inlineSingleSelectValuesLimit = configuration?.alternativePayment?.inlineSingleSelectValuesLimit ?: 5, skipSuccessScreen = true ) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt index 268decf76..8d0843ad0 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt @@ -91,7 +91,7 @@ data class PODynamicCheckoutConfiguration( data class AlternativePaymentConfiguration( val returnUrl: String? = null, val inlineSingleSelectValuesLimit: Int = 5, - val barcode: POBarcodeConfiguration = POBarcodeConfiguration(), + val barcode: POBarcodeConfiguration = POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), val paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration() ) : Parcelable { 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 4ce28577c..119a611f3 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 @@ -46,7 +46,7 @@ data class PONativeAlternativePaymentConfiguration( val secondaryAction: SecondaryAction? = null, val cancellation: CancellationConfiguration = CancellationConfiguration(), val paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration(), - val barcode: POBarcodeConfiguration = POBarcodeConfiguration(), + val barcode: POBarcodeConfiguration = POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), val inlineSingleSelectValuesLimit: Int = 5, val skipSuccessScreen: Boolean = false, val successMessage: String? = null diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt index 0d2da6911..42e935471 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt @@ -1,16 +1,54 @@ package com.processout.sdk.ui.shared.configuration import android.os.Parcelable +import androidx.annotation.DrawableRes +import com.processout.sdk.core.annotation.ProcessOutInternalApi import kotlinx.parcelize.Parcelize /** * Specifies barcode configuration. * - * @param[saveActionText] Text on the button that saves barcode. - * @param[saveErrorConfirmation] Requests user confirmation (e.g. dialog) when saving barcode has failed. Use _null_ to disable. + * @param[saveActionText] Text on the save button. + * @param[saveButton] Save button configuration. + * @param[saveErrorConfirmation] Requests user confirmation (e.g. dialog) when barcode saving has failed. Use _null_ to disable. */ @Parcelize -data class POBarcodeConfiguration( +data class POBarcodeConfiguration @ProcessOutInternalApi constructor( + @Deprecated(message = "Use 'saveButton.text' property.") val saveActionText: String? = null, + val saveButton: Button = Button(), val saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() -) : Parcelable +) : Parcelable { + + @Deprecated(message = "Use constructor POBarcodeConfiguration(saveButton, saveErrorConfirmation)") + constructor( + saveActionText: String? = null, + saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() + ) : this( + saveActionText = saveActionText, + saveButton = Button(text = saveActionText), + saveErrorConfirmation = saveErrorConfirmation + ) + + constructor( + saveButton: Button = Button(), + saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() + ) : this( + saveActionText = saveButton.text, + saveButton = saveButton, + saveErrorConfirmation = saveErrorConfirmation + ) + + /** + * Button configuration. + * + * @param[text] Button text. Pass _null_ to use default text. + * @param[iconResId] Button icon drawable resource ID. Pass _null_ to hide. + */ + @Parcelize + data class Button( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null + ) : Parcelable +} From 0fa022c8389856ac4284d383aa273e7b5b34829b Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Tue, 7 Jan 2025 14:25:49 +0200 Subject: [PATCH 05/17] Apply save barcode button icon --- .../sdk/ui/checkout/screen/NativeAlternativePayment.kt | 3 ++- .../sdk/ui/napm/NativeAlternativePaymentViewModel.kt | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) 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 45fed9897..c03d0ad46 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 @@ -419,7 +419,8 @@ private fun Capture( ) }, modifier = Modifier.fillMaxWidth(), - style = style.actionsContainer.secondary + style = style.actionsContainer.secondary, + iconResId = action.iconResId ) } } 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 31cf95a00..096159f0b 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 @@ -183,12 +183,13 @@ internal class NativeAlternativePaymentViewModel private constructor( saveBarcodeAction = customerAction?.barcode?.let { POActionState( id = it.actionId, - text = options.barcode.saveActionText + text = options.barcode.saveButton.text ?: app.getString( R.string.po_native_apm_save_barcode_button_text_format, it.type.rawType.uppercase() ), - primary = false + primary = false, + iconResId = options.barcode.saveButton.iconResId ) }, confirmationDialog = confirmationDialog(), From edf12e9dfb1ad23142eab12d21cdecdb124fc2c2 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Tue, 7 Jan 2025 14:38:20 +0200 Subject: [PATCH 06/17] Add button icon padding only if text is not blank --- .../kotlin/com/processout/sdk/ui/core/component/POButton.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 e79953330..8b5cd9776 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 @@ -25,6 +25,7 @@ import com.processout.sdk.ui.core.component.POButton.border import com.processout.sdk.ui.core.component.POButton.colors import com.processout.sdk.ui.core.component.POButton.contentPadding import com.processout.sdk.ui.core.component.POButton.elevation +import com.processout.sdk.ui.core.extension.conditional import com.processout.sdk.ui.core.style.POButtonDefaults import com.processout.sdk.ui.core.style.POButtonStateStyle import com.processout.sdk.ui.core.style.POButtonStyle @@ -78,7 +79,9 @@ fun POButton( painter = painterResource(it), contentDescription = null, modifier = Modifier - .padding(end = spacing.small) + .conditional(text.isNotBlank()) { + padding(end = spacing.small) + } .requiredSize(20.dp), colorFilter = ColorFilter.tint(color = iconColor) ) From a64257ac6e9597d8a76962fa3d417b8b895fcc8d Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Tue, 7 Jan 2025 19:00:13 +0200 Subject: [PATCH 07/17] Update POBarcodeConfiguration --- .../sdk/ui/shared/configuration/POBarcodeConfiguration.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt index 42e935471..98ca9cd87 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt @@ -2,7 +2,6 @@ package com.processout.sdk.ui.shared.configuration import android.os.Parcelable import androidx.annotation.DrawableRes -import com.processout.sdk.core.annotation.ProcessOutInternalApi import kotlinx.parcelize.Parcelize /** @@ -13,14 +12,14 @@ import kotlinx.parcelize.Parcelize * @param[saveErrorConfirmation] Requests user confirmation (e.g. dialog) when barcode saving has failed. Use _null_ to disable. */ @Parcelize -data class POBarcodeConfiguration @ProcessOutInternalApi constructor( - @Deprecated(message = "Use 'saveButton.text' property.") +data class POBarcodeConfiguration internal constructor( + @Deprecated(message = "Use 'saveButton.text' instead.") val saveActionText: String? = null, val saveButton: Button = Button(), val saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() ) : Parcelable { - @Deprecated(message = "Use constructor POBarcodeConfiguration(saveButton, saveErrorConfirmation)") + @Deprecated(message = "Use alternative constructor.") constructor( saveActionText: String? = null, saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() From b842adf25203fafa2370b85cb8de3c9b1edbdb5b Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Tue, 7 Jan 2025 19:41:26 +0200 Subject: [PATCH 08/17] Refactored PONativeAlternativePaymentConfiguration --- .../NativeAlternativePaymentBottomSheet.kt | 3 +- ...PONativeAlternativePaymentConfiguration.kt | 171 +++++++++++++++++- 2 files changed, 166 insertions(+), 8 deletions(-) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt index 937d41df1..47ff0cf54 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt @@ -29,6 +29,7 @@ import com.processout.sdk.ui.napm.NativeAlternativePaymentScreen.AnimationDurati import com.processout.sdk.ui.napm.NativeAlternativePaymentSideEffect.PermissionRequest import com.processout.sdk.ui.napm.NativeAlternativePaymentViewModelState.Capture import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.Options +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SubmitButton import com.processout.sdk.ui.shared.component.isImeVisibleAsState import com.processout.sdk.ui.shared.component.screenModeAsState import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration @@ -54,7 +55,7 @@ internal class NativeAlternativePaymentBottomSheet : BaseBottomSheetDialogFragme app = requireActivity().application, invoiceId = configuration?.invoiceId ?: String(), gatewayConfigurationId = configuration?.gatewayConfigurationId ?: String(), - options = configuration?.options ?: Options(), + options = configuration?.options ?: Options(submitButton = SubmitButton()), eventDispatcher = PODefaultEventDispatchers.defaultNativeAlternativePaymentMethod ) } 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 119a611f3..f16454ff6 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 @@ -4,6 +4,8 @@ import android.os.Parcelable import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import com.processout.sdk.ui.core.style.* +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.CancelButton +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SecondaryAction import com.processout.sdk.ui.shared.configuration.POActionConfirmationConfiguration import com.processout.sdk.ui.shared.configuration.POBarcodeConfiguration import kotlinx.parcelize.Parcelize @@ -20,7 +22,7 @@ import kotlinx.parcelize.Parcelize data class PONativeAlternativePaymentConfiguration( val invoiceId: String, val gatewayConfigurationId: String, - val options: Options = Options(), + val options: Options = Options(submitButton = SubmitButton()), val style: Style? = null ) : Parcelable { @@ -30,6 +32,8 @@ data class PONativeAlternativePaymentConfiguration( * @param[title] Custom title. * @param[primaryActionText] Custom primary action text (e.g. "Pay"). * @param[secondaryAction] Secondary action (e.g. "Cancel"). Use _null_ to hide, this is a default behaviour. + * @param[submitButton] Submit button configuration. + * @param[cancelButton] Cancel button configuration. Use _null_ to hide, this is a default behaviour. * @param[cancellation] Specifies cancellation behaviour. * @param[paymentConfirmation] Specifies payment confirmation behaviour. * @param[barcode] Specifies barcode configuration. @@ -40,16 +44,102 @@ data class PONativeAlternativePaymentConfiguration( * @param[successMessage] Custom success message when payment is completed. */ @Parcelize - data class Options( + data class Options internal constructor( val title: String? = null, + @Deprecated(message = "Use 'submitButton.text' instead.") val primaryActionText: String? = null, + @Deprecated(message = "Use 'cancelButton' instead.") val secondaryAction: SecondaryAction? = null, + val submitButton: SubmitButton = SubmitButton(), + val cancelButton: CancelButton? = null, val cancellation: CancellationConfiguration = CancellationConfiguration(), - val paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration(), + val paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration(confirmButton = null), val barcode: POBarcodeConfiguration = POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), val inlineSingleSelectValuesLimit: Int = 5, val skipSuccessScreen: Boolean = false, val successMessage: String? = null + ) : Parcelable { + + @Deprecated(message = "Use alternative constructor.") + constructor( + title: String? = null, + primaryActionText: String? = null, + secondaryAction: SecondaryAction? = null, + cancellation: CancellationConfiguration = CancellationConfiguration(), + paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration(confirmButton = null), + barcode: POBarcodeConfiguration = POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), + inlineSingleSelectValuesLimit: Int = 5, + skipSuccessScreen: Boolean = false, + successMessage: String? = null + ) : this( + title = title, + primaryActionText = primaryActionText, + secondaryAction = secondaryAction, + submitButton = SubmitButton(text = primaryActionText), + cancelButton = secondaryAction?.toCancelButton(), + cancellation = cancellation, + paymentConfirmation = paymentConfirmation, + barcode = barcode, + inlineSingleSelectValuesLimit = inlineSingleSelectValuesLimit, + skipSuccessScreen = skipSuccessScreen, + successMessage = successMessage + ) + + constructor( + title: String? = null, + submitButton: SubmitButton = SubmitButton(), + cancelButton: CancelButton? = null, + cancellation: CancellationConfiguration = CancellationConfiguration(), + paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration(confirmButton = null), + barcode: POBarcodeConfiguration = POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), + inlineSingleSelectValuesLimit: Int = 5, + skipSuccessScreen: Boolean = false, + successMessage: String? = null + ) : this( + title = title, + primaryActionText = submitButton.text, + secondaryAction = cancelButton?.toSecondaryAction(), + submitButton = submitButton, + cancelButton = cancelButton, + cancellation = cancellation, + paymentConfirmation = paymentConfirmation, + barcode = barcode, + inlineSingleSelectValuesLimit = inlineSingleSelectValuesLimit, + skipSuccessScreen = skipSuccessScreen, + successMessage = successMessage + ) + } + + /** + * Submit button configuration. + * + * @param[text] Button text. Pass _null_ to use default text. + * @param[iconResId] Button icon drawable resource ID. Pass _null_ to hide. + */ + @Parcelize + data class SubmitButton( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null + ) : Parcelable + + /** + * Cancel button configuration. + * + * @param[text] Button text. Pass _null_ to use default text. + * @param[iconResId] Button icon drawable resource ID. Pass _null_ to hide. + * @param[disabledForSeconds] Initially disables the button for the given amount of time in seconds. + * By default user can interact with the button immediately when it's visible. + * @param[confirmation] Specifies action confirmation configuration (e.g. dialog). + * Use _null_ to disable, this is a default behaviour. + */ + @Parcelize + data class CancelButton( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null, + val disabledForSeconds: Int = 0, + val confirmation: POActionConfirmationConfiguration? = null ) : Parcelable /** @@ -59,6 +149,7 @@ data class PONativeAlternativePaymentConfiguration( * @param[iconResId] Action icon drawable resource ID. Pass _null_ to hide. */ @Parcelize + @Deprecated(message = "Use 'SubmitButton' instead.") data class ConfirmAction( val text: String? = null, @DrawableRes @@ -68,17 +159,19 @@ data class PONativeAlternativePaymentConfiguration( /** * Supported secondary actions. */ + @Deprecated(message = "Use 'CancelButton' instead.") sealed class SecondaryAction : Parcelable { /** * Action for cancellation. * * @param[text] Action text. Pass _null_ to use default text. - * @param[disabledForSeconds] Initially disables action for the given amount of time in seconds. - * By default user can interact with action immediately when it's visible. + * @param[disabledForSeconds] Initially disables the action for the given amount of time in seconds. + * By default user can interact with the action immediately when it's visible. * @param[confirmation] Specifies action confirmation configuration (e.g. dialog). * Use _null_ to disable, this is a default behaviour. */ @Parcelize + @Deprecated(message = "Use 'CancelButton' instead.") data class Cancel( val text: String? = null, val disabledForSeconds: Int = 0, @@ -115,20 +208,68 @@ data class PONativeAlternativePaymentConfiguration( * To hide action use _null_, this is a default behaviour. * @param[secondaryAction] Secondary action (e.g. "Cancel") that could be optionally presented to user during payment confirmation stage. * Use _null_ to hide, this is a default behaviour. + * @param[confirmButton] Confirm button configuration. + * @param[cancelButton] Cancel button configuration. */ @Parcelize - data class PaymentConfirmationConfiguration( + data class PaymentConfirmationConfiguration internal constructor( val waitsConfirmation: Boolean = true, val timeoutSeconds: Int = DEFAULT_TIMEOUT_SECONDS, val showProgressIndicatorAfterSeconds: Int? = null, val hideGatewayDetails: Boolean = false, + @Deprecated(message = "Use 'confirmButton' instead.") val primaryAction: ConfirmAction? = null, - val secondaryAction: SecondaryAction? = null + @Deprecated(message = "Use 'cancelButton' instead.") + val secondaryAction: SecondaryAction? = null, + val confirmButton: SubmitButton? = null, + val cancelButton: CancelButton? = null ) : Parcelable { + companion object { const val MAX_TIMEOUT_SECONDS = 15 * 60 const val DEFAULT_TIMEOUT_SECONDS = 3 * 60 } + + @Deprecated(message = "Use alternative constructor.") + constructor( + waitsConfirmation: Boolean = true, + timeoutSeconds: Int = DEFAULT_TIMEOUT_SECONDS, + showProgressIndicatorAfterSeconds: Int? = null, + hideGatewayDetails: Boolean = false, + primaryAction: ConfirmAction? = null, + secondaryAction: SecondaryAction? = null + ) : this( + waitsConfirmation = waitsConfirmation, + timeoutSeconds = timeoutSeconds, + showProgressIndicatorAfterSeconds = showProgressIndicatorAfterSeconds, + hideGatewayDetails = hideGatewayDetails, + primaryAction = primaryAction, + secondaryAction = secondaryAction, + confirmButton = primaryAction?.let { + SubmitButton(text = it.text, iconResId = it.iconResId) + }, + cancelButton = secondaryAction?.toCancelButton() + ) + + constructor( + waitsConfirmation: Boolean = true, + timeoutSeconds: Int = DEFAULT_TIMEOUT_SECONDS, + showProgressIndicatorAfterSeconds: Int? = null, + hideGatewayDetails: Boolean = false, + confirmButton: SubmitButton? = null, + cancelButton: CancelButton? = null + ) : this( + waitsConfirmation = waitsConfirmation, + timeoutSeconds = timeoutSeconds, + showProgressIndicatorAfterSeconds = showProgressIndicatorAfterSeconds, + hideGatewayDetails = hideGatewayDetails, + primaryAction = confirmButton?.let { + ConfirmAction(text = it.text, iconResId = it.iconResId) + }, + secondaryAction = cancelButton?.toSecondaryAction(), + confirmButton = confirmButton, + cancelButton = cancelButton + ) } /** @@ -178,3 +319,19 @@ data class PONativeAlternativePaymentConfiguration( val dragHandleColorResId: Int? = null ) : Parcelable } + +private fun SecondaryAction.toCancelButton(): CancelButton = + when (this) { + is SecondaryAction.Cancel -> CancelButton( + text = text, + disabledForSeconds = disabledForSeconds, + confirmation = confirmation + ) + } + +private fun CancelButton.toSecondaryAction() = + SecondaryAction.Cancel( + text = text, + disabledForSeconds = disabledForSeconds, + confirmation = confirmation + ) From b6ab222ae6dd22bf2f2159aa610ce5341260e761 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 12:53:44 +0200 Subject: [PATCH 09/17] Update POBarcodeConfiguration constructor --- .../configuration/POBarcodeConfiguration.kt | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt index 98ca9cd87..277936248 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POBarcodeConfiguration.kt @@ -7,37 +7,30 @@ import kotlinx.parcelize.Parcelize /** * Specifies barcode configuration. * - * @param[saveActionText] Text on the save button. * @param[saveButton] Save button configuration. * @param[saveErrorConfirmation] Requests user confirmation (e.g. dialog) when barcode saving has failed. Use _null_ to disable. */ @Parcelize -data class POBarcodeConfiguration internal constructor( - @Deprecated(message = "Use 'saveButton.text' instead.") - val saveActionText: String? = null, +data class POBarcodeConfiguration( val saveButton: Button = Button(), val saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() ) : Parcelable { + /** + * Specifies barcode configuration. + * + * @param[saveActionText] Save button text. + * @param[saveErrorConfirmation] Requests user confirmation (e.g. dialog) when barcode saving has failed. Use _null_ to disable. + */ @Deprecated(message = "Use alternative constructor.") constructor( saveActionText: String? = null, saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() ) : this( - saveActionText = saveActionText, saveButton = Button(text = saveActionText), saveErrorConfirmation = saveErrorConfirmation ) - constructor( - saveButton: Button = Button(), - saveErrorConfirmation: POActionConfirmationConfiguration? = POActionConfirmationConfiguration() - ) : this( - saveActionText = saveButton.text, - saveButton = saveButton, - saveErrorConfirmation = saveErrorConfirmation - ) - /** * Button configuration. * From 95f669bc5dae1692412814751561159312fa93df Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 14:01:59 +0200 Subject: [PATCH 10/17] Refactor all buttons on nAPM and DC --- .../checkout/DynamicCheckoutFragment.kt | 4 +- .../ui/checkout/DynamicCheckoutActivity.kt | 26 ++-- .../PODynamicCheckoutConfiguration.kt | 12 +- .../NativeAlternativePaymentInteractor.kt | 16 +-- .../napm/NativeAlternativePaymentViewModel.kt | 51 ++++---- ...PONativeAlternativePaymentConfiguration.kt | 115 ++++++------------ 6 files changed, 86 insertions(+), 138 deletions(-) diff --git a/example/src/main/kotlin/com/processout/example/ui/screen/checkout/DynamicCheckoutFragment.kt b/example/src/main/kotlin/com/processout/example/ui/screen/checkout/DynamicCheckoutFragment.kt index 7bb84ff96..ade773923 100644 --- a/example/src/main/kotlin/com/processout/example/ui/screen/checkout/DynamicCheckoutFragment.kt +++ b/example/src/main/kotlin/com/processout/example/ui/screen/checkout/DynamicCheckoutFragment.kt @@ -26,7 +26,7 @@ import com.processout.sdk.core.onSuccess import com.processout.sdk.ui.checkout.PODynamicCheckoutConfiguration import com.processout.sdk.ui.checkout.PODynamicCheckoutConfiguration.AlternativePaymentConfiguration import com.processout.sdk.ui.checkout.PODynamicCheckoutConfiguration.AlternativePaymentConfiguration.PaymentConfirmationConfiguration -import com.processout.sdk.ui.checkout.PODynamicCheckoutConfiguration.AlternativePaymentConfiguration.PaymentConfirmationConfiguration.ConfirmButton +import com.processout.sdk.ui.checkout.PODynamicCheckoutConfiguration.SubmitButton import com.processout.sdk.ui.checkout.PODynamicCheckoutLauncher import com.processout.sdk.ui.shared.view.dialog.POAlertDialog import com.processout.sdk.ui.threeds.PO3DSRedirectCustomTabLauncher @@ -99,7 +99,7 @@ class DynamicCheckoutFragment : BaseFragment( alternativePayment = AlternativePaymentConfiguration( returnUrl = Constants.RETURN_URL, paymentConfirmation = PaymentConfirmationConfiguration( - confirmButton = ConfirmButton() + confirmButton = SubmitButton() ) ) ) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt index 4218ac7ac..6e28799f1 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt @@ -47,11 +47,14 @@ import com.processout.sdk.ui.checkout.DynamicCheckoutCompletion.Success import com.processout.sdk.ui.checkout.DynamicCheckoutEvent.* import com.processout.sdk.ui.checkout.DynamicCheckoutSideEffect.* import com.processout.sdk.ui.checkout.PODynamicCheckoutConfiguration.CancelButton +import com.processout.sdk.ui.checkout.PODynamicCheckoutConfiguration.SubmitButton import com.processout.sdk.ui.checkout.screen.DynamicCheckoutScreen import com.processout.sdk.ui.core.theme.ProcessOutTheme import com.processout.sdk.ui.googlepay.POGooglePayCardTokenizationLauncher import com.processout.sdk.ui.napm.NativeAlternativePaymentViewModel -import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.* +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.Options +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.PaymentConfirmationConfiguration import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.PaymentConfirmationConfiguration.Companion.DEFAULT_TIMEOUT_SECONDS import com.processout.sdk.ui.shared.configuration.POBarcodeConfiguration import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration @@ -115,20 +118,15 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { private fun nativeAlternativePaymentConfiguration(): Options { val paymentConfirmation = configuration?.alternativePayment?.paymentConfirmation return Options( - primaryActionText = configuration?.submitButton?.text, - secondaryAction = configuration?.cancelButton?.toSecondaryAction(), + submitButton = configuration?.submitButton?.map() ?: PONativeAlternativePaymentConfiguration.SubmitButton(), + cancelButton = configuration?.cancelButton?.map(), paymentConfirmation = PaymentConfirmationConfiguration( waitsConfirmation = true, timeoutSeconds = paymentConfirmation?.timeoutSeconds ?: DEFAULT_TIMEOUT_SECONDS, showProgressIndicatorAfterSeconds = paymentConfirmation?.showProgressIndicatorAfterSeconds, hideGatewayDetails = true, - primaryAction = paymentConfirmation?.confirmButton?.let { - ConfirmAction( - text = it.text, - iconResId = it.iconResId - ) - }, - secondaryAction = paymentConfirmation?.cancelButton?.toSecondaryAction() + confirmButton = paymentConfirmation?.confirmButton?.map(), + cancelButton = paymentConfirmation?.cancelButton?.map() ), barcode = configuration?.alternativePayment?.barcode ?: POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), @@ -137,8 +135,14 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { ) } - private fun CancelButton.toSecondaryAction() = SecondaryAction.Cancel( + private fun SubmitButton.map() = PONativeAlternativePaymentConfiguration.SubmitButton( + text = text, + iconResId = iconResId + ) + + private fun CancelButton.map() = PONativeAlternativePaymentConfiguration.CancelButton( text = text, + iconResId = iconResId, disabledForSeconds = disabledForSeconds, confirmation = confirmation ) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt index 8d0843ad0..bb61da186 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt @@ -99,17 +99,9 @@ data class PODynamicCheckoutConfiguration( data class PaymentConfirmationConfiguration( val timeoutSeconds: Int = 3 * 60, val showProgressIndicatorAfterSeconds: Int? = null, - val confirmButton: ConfirmButton? = null, + val confirmButton: SubmitButton? = null, val cancelButton: CancelButton? = CancelButton() - ) : Parcelable { - - @Parcelize - data class ConfirmButton( - val text: String? = null, - @DrawableRes - val iconResId: Int? = null - ) : Parcelable - } + ) : Parcelable } @Parcelize diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractor.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractor.kt index 92d5e5692..fa35d033b 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractor.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractor.kt @@ -45,9 +45,8 @@ import com.processout.sdk.ui.napm.NativeAlternativePaymentEvent.* import com.processout.sdk.ui.napm.NativeAlternativePaymentEvent.Action import com.processout.sdk.ui.napm.NativeAlternativePaymentInteractorState.* import com.processout.sdk.ui.napm.NativeAlternativePaymentSideEffect.PermissionRequest +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.CancelButton import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.Options -import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SecondaryAction -import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SecondaryAction.Cancel import com.processout.sdk.ui.shared.extension.dpToPx import com.processout.sdk.ui.shared.provider.BarcodeBitmapProvider import com.processout.sdk.ui.shared.provider.MediaStorageProvider @@ -714,7 +713,7 @@ internal class NativeAlternativePaymentInteractor( dispatch(WillWaitForCaptureConfirmation(additionalActionExpected = additionalActionExpected)) _state.update { Capturing(captureStateValue) } enableCapturingSecondaryAction() - if (!additionalActionExpected || options.paymentConfirmation.primaryAction == null) { + if (!additionalActionExpected || options.paymentConfirmation.confirmButton == null) { capture() } } @@ -829,14 +828,11 @@ internal class NativeAlternativePaymentInteractor( //region Features - private val SecondaryAction?.disabledForMillis: Long - get() = when (this) { - is Cancel -> disabledForSeconds * 1000L - null -> 0 - } + private val CancelButton?.disabledForMillis: Long + get() = this?.disabledForSeconds?.let { it * 1000L } ?: 0 private fun enableUserInputSecondaryAction() { - handler.postDelayed(delayInMillis = options.secondaryAction.disabledForMillis) { + handler.postDelayed(delayInMillis = options.cancelButton.disabledForMillis) { _state.whenUserInput { stateValue -> _state.update { with(stateValue) { @@ -848,7 +844,7 @@ internal class NativeAlternativePaymentInteractor( } private fun enableCapturingSecondaryAction() { - handler.postDelayed(delayInMillis = options.paymentConfirmation.secondaryAction.disabledForMillis) { + handler.postDelayed(delayInMillis = options.paymentConfirmation.cancelButton.disabledForMillis) { _state.whenCapturing { stateValue -> _state.update { with(stateValue) { 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 096159f0b..baba4382c 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 @@ -22,11 +22,10 @@ import com.processout.sdk.ui.core.state.POImmutableList import com.processout.sdk.ui.napm.NativeAlternativePaymentInteractorState.* import com.processout.sdk.ui.napm.NativeAlternativePaymentViewModelState.Field.* import com.processout.sdk.ui.napm.NativeAlternativePaymentViewModelState.Image +import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.CancelButton import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.Options import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.PaymentConfirmationConfiguration.Companion.DEFAULT_TIMEOUT_SECONDS import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.PaymentConfirmationConfiguration.Companion.MAX_TIMEOUT_SECONDS -import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SecondaryAction -import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SecondaryAction.Cancel import com.processout.sdk.ui.shared.extension.map import com.processout.sdk.ui.shared.filter.PhoneNumberInputFilter import com.processout.sdk.ui.shared.provider.BarcodeBitmapProvider @@ -139,12 +138,13 @@ internal class NativeAlternativePaymentViewModel private constructor( focusedFieldId = focusedFieldId, primaryAction = POActionState( id = primaryActionId, - text = options.primaryActionText ?: invoice.formatPrimaryActionText(), + text = options.submitButton.text ?: invoice.formatPrimaryActionText(), primary = true, enabled = submitAllowed, - loading = submitting + loading = submitting, + iconResId = options.submitButton.iconResId ), - secondaryAction = options.secondaryAction?.toActionState( + secondaryAction = options.cancelButton?.toActionState( id = secondaryAction.id, enabled = secondaryAction.enabled && !submitting ) @@ -152,7 +152,7 @@ internal class NativeAlternativePaymentViewModel private constructor( } private fun Capturing.map() = with(value) { - val secondaryAction = options.paymentConfirmation.secondaryAction?.toActionState( + val secondaryAction = options.paymentConfirmation.cancelButton?.toActionState( id = secondaryAction.id, enabled = secondaryAction.enabled ) @@ -162,7 +162,7 @@ internal class NativeAlternativePaymentViewModel private constructor( secondaryAction = secondaryAction ) } else { - val primaryAction = options.paymentConfirmation.primaryAction?.let { + val primaryAction = options.paymentConfirmation.confirmButton?.let { primaryActionId?.let { id -> POActionState( id = id, @@ -361,27 +361,26 @@ internal class NativeAlternativePaymentViewModel private constructor( app.getString(R.string.po_native_apm_submit_button_text) } - private fun SecondaryAction.toActionState( + private fun CancelButton.toActionState( id: String, enabled: Boolean - ): POActionState = when (this) { - is Cancel -> POActionState( - id = id, - text = text ?: app.getString(R.string.po_native_apm_cancel_button_text), - primary = false, - enabled = enabled, - confirmation = confirmation?.run { - Confirmation( - title = title ?: app.getString(R.string.po_cancel_payment_confirmation_title), - message = message, - confirmActionText = confirmActionText - ?: app.getString(R.string.po_cancel_payment_confirmation_confirm), - dismissActionText = dismissActionText - ?: app.getString(R.string.po_cancel_payment_confirmation_dismiss) - ) - } - ) - } + ) = POActionState( + id = id, + text = text ?: app.getString(R.string.po_native_apm_cancel_button_text), + primary = false, + enabled = enabled, + iconResId = iconResId, + confirmation = confirmation?.run { + Confirmation( + title = title ?: app.getString(R.string.po_cancel_payment_confirmation_title), + message = message, + confirmActionText = confirmActionText + ?: app.getString(R.string.po_cancel_payment_confirmation_confirm), + dismissActionText = dismissActionText + ?: app.getString(R.string.po_cancel_payment_confirmation_dismiss) + ) + } + ) private fun CaptureStateValue.confirmationDialog(): ConfirmationDialogState? = customerAction?.barcode?.let { barcode -> 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 f16454ff6..9f5ec9446 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 @@ -30,8 +30,6 @@ data class PONativeAlternativePaymentConfiguration( * Allows to customize behaviour and pre-define the values. * * @param[title] Custom title. - * @param[primaryActionText] Custom primary action text (e.g. "Pay"). - * @param[secondaryAction] Secondary action (e.g. "Cancel"). Use _null_ to hide, this is a default behaviour. * @param[submitButton] Submit button configuration. * @param[cancelButton] Cancel button configuration. Use _null_ to hide, this is a default behaviour. * @param[cancellation] Specifies cancellation behaviour. @@ -44,12 +42,8 @@ data class PONativeAlternativePaymentConfiguration( * @param[successMessage] Custom success message when payment is completed. */ @Parcelize - data class Options internal constructor( + data class Options( val title: String? = null, - @Deprecated(message = "Use 'submitButton.text' instead.") - val primaryActionText: String? = null, - @Deprecated(message = "Use 'cancelButton' instead.") - val secondaryAction: SecondaryAction? = null, val submitButton: SubmitButton = SubmitButton(), val cancelButton: CancelButton? = null, val cancellation: CancellationConfiguration = CancellationConfiguration(), @@ -60,6 +54,21 @@ data class PONativeAlternativePaymentConfiguration( val successMessage: String? = null ) : Parcelable { + /** + * Allows to customize behaviour and pre-define the values. + * + * @param[title] Custom title. + * @param[primaryActionText] Custom primary action text (e.g. "Pay"). + * @param[secondaryAction] Secondary action (e.g. "Cancel"). Use _null_ to hide, this is a default behaviour. + * @param[cancellation] Specifies cancellation behaviour. + * @param[paymentConfirmation] Specifies payment confirmation behaviour. + * @param[barcode] Specifies barcode configuration. + * @param[inlineSingleSelectValuesLimit] Defines maximum number of options that will be + * displayed inline for parameters where user should select single option (e.g. radio buttons). + * Default value is _5_. + * @param[skipSuccessScreen] Only applies when [PaymentConfirmationConfiguration.waitsConfirmation] is _true_. + * @param[successMessage] Custom success message when payment is completed. + */ @Deprecated(message = "Use alternative constructor.") constructor( title: String? = null, @@ -73,8 +82,6 @@ data class PONativeAlternativePaymentConfiguration( successMessage: String? = null ) : this( title = title, - primaryActionText = primaryActionText, - secondaryAction = secondaryAction, submitButton = SubmitButton(text = primaryActionText), cancelButton = secondaryAction?.toCancelButton(), cancellation = cancellation, @@ -84,30 +91,6 @@ data class PONativeAlternativePaymentConfiguration( skipSuccessScreen = skipSuccessScreen, successMessage = successMessage ) - - constructor( - title: String? = null, - submitButton: SubmitButton = SubmitButton(), - cancelButton: CancelButton? = null, - cancellation: CancellationConfiguration = CancellationConfiguration(), - paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration(confirmButton = null), - barcode: POBarcodeConfiguration = POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), - inlineSingleSelectValuesLimit: Int = 5, - skipSuccessScreen: Boolean = false, - successMessage: String? = null - ) : this( - title = title, - primaryActionText = submitButton.text, - secondaryAction = cancelButton?.toSecondaryAction(), - submitButton = submitButton, - cancelButton = cancelButton, - cancellation = cancellation, - paymentConfirmation = paymentConfirmation, - barcode = barcode, - inlineSingleSelectValuesLimit = inlineSingleSelectValuesLimit, - skipSuccessScreen = skipSuccessScreen, - successMessage = successMessage - ) } /** @@ -143,17 +126,14 @@ data class PONativeAlternativePaymentConfiguration( ) : Parcelable /** - * Action for confirmation. + * Confirmation action. * * @param[text] Action text. Pass _null_ to use default text. - * @param[iconResId] Action icon drawable resource ID. Pass _null_ to hide. */ @Parcelize @Deprecated(message = "Use 'SubmitButton' instead.") data class ConfirmAction( - val text: String? = null, - @DrawableRes - val iconResId: Int? = null + val text: String? = null ) : Parcelable /** @@ -204,23 +184,15 @@ data class PONativeAlternativePaymentConfiguration( * Use _null_ to hide, this is a default behaviour. * @param[hideGatewayDetails] Specifies whether gateway information (such as name/logo) should be hidden during payment confirmation * even when specific payment provider details are not available. Default value is _false_. - * @param[primaryAction] Optional primary action for payment confirmation. - * To hide action use _null_, this is a default behaviour. - * @param[secondaryAction] Secondary action (e.g. "Cancel") that could be optionally presented to user during payment confirmation stage. - * Use _null_ to hide, this is a default behaviour. * @param[confirmButton] Confirm button configuration. * @param[cancelButton] Cancel button configuration. */ @Parcelize - data class PaymentConfirmationConfiguration internal constructor( + data class PaymentConfirmationConfiguration( val waitsConfirmation: Boolean = true, val timeoutSeconds: Int = DEFAULT_TIMEOUT_SECONDS, val showProgressIndicatorAfterSeconds: Int? = null, val hideGatewayDetails: Boolean = false, - @Deprecated(message = "Use 'confirmButton' instead.") - val primaryAction: ConfirmAction? = null, - @Deprecated(message = "Use 'cancelButton' instead.") - val secondaryAction: SecondaryAction? = null, val confirmButton: SubmitButton? = null, val cancelButton: CancelButton? = null ) : Parcelable { @@ -230,6 +202,22 @@ data class PONativeAlternativePaymentConfiguration( const val DEFAULT_TIMEOUT_SECONDS = 3 * 60 } + /** + * Specifies payment confirmation behaviour. + * + * @param[waitsConfirmation] Specifies whether flow should wait for payment confirmation from PSP + * or will complete right after all user input is submitted. Default value is _true_. + * @param[timeoutSeconds] Amount of time (in seconds) to wait for final payment confirmation. + * Default value is 3 minutes, while maximum value is 15 minutes. + * @param[showProgressIndicatorAfterSeconds] Show progress indicator during payment confirmation after provided delay (in seconds). + * Use _null_ to hide, this is a default behaviour. + * @param[hideGatewayDetails] Specifies whether gateway information (such as name/logo) should be hidden during payment confirmation + * even when specific payment provider details are not available. Default value is _false_. + * @param[primaryAction] Optional primary action for payment confirmation. + * To hide action use _null_, this is a default behaviour. + * @param[secondaryAction] Secondary action (e.g. "Cancel") that could be optionally presented to user during payment confirmation stage. + * Use _null_ to hide, this is a default behaviour. + */ @Deprecated(message = "Use alternative constructor.") constructor( waitsConfirmation: Boolean = true, @@ -243,33 +231,9 @@ data class PONativeAlternativePaymentConfiguration( timeoutSeconds = timeoutSeconds, showProgressIndicatorAfterSeconds = showProgressIndicatorAfterSeconds, hideGatewayDetails = hideGatewayDetails, - primaryAction = primaryAction, - secondaryAction = secondaryAction, - confirmButton = primaryAction?.let { - SubmitButton(text = it.text, iconResId = it.iconResId) - }, + confirmButton = primaryAction?.let { SubmitButton(text = it.text) }, cancelButton = secondaryAction?.toCancelButton() ) - - constructor( - waitsConfirmation: Boolean = true, - timeoutSeconds: Int = DEFAULT_TIMEOUT_SECONDS, - showProgressIndicatorAfterSeconds: Int? = null, - hideGatewayDetails: Boolean = false, - confirmButton: SubmitButton? = null, - cancelButton: CancelButton? = null - ) : this( - waitsConfirmation = waitsConfirmation, - timeoutSeconds = timeoutSeconds, - showProgressIndicatorAfterSeconds = showProgressIndicatorAfterSeconds, - hideGatewayDetails = hideGatewayDetails, - primaryAction = confirmButton?.let { - ConfirmAction(text = it.text, iconResId = it.iconResId) - }, - secondaryAction = cancelButton?.toSecondaryAction(), - confirmButton = confirmButton, - cancelButton = cancelButton - ) } /** @@ -328,10 +292,3 @@ private fun SecondaryAction.toCancelButton(): CancelButton = confirmation = confirmation ) } - -private fun CancelButton.toSecondaryAction() = - SecondaryAction.Cancel( - text = text, - disabledForSeconds = disabledForSeconds, - confirmation = confirmation - ) From ae42132e6b660d45c52373a2c772ec2173f39cb4 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 17:22:49 +0200 Subject: [PATCH 11/17] Refactored POCancellationConfiguration and its usages --- .../ui/screen/features/FeaturesFragment.kt | 1 - .../NativeAlternativePaymentBottomSheet.kt | 11 +-------- ...PONativeAlternativePaymentConfiguration.kt | 12 ++++++++-- .../POCancellationConfiguration.kt | 24 +++++++++++++++++-- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt b/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt index 8ae77ded1..b4f7c024a 100644 --- a/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt +++ b/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt @@ -98,7 +98,6 @@ class FeaturesFragment : BaseFragment( preferredScheme = card?.coScheme ), cancellation = POCancellationConfiguration( - secondaryAction = true, backPressed = true, dragDown = true, touchOutside = false diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt index 47ff0cf54..a8dd3664b 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentBottomSheet.kt @@ -32,7 +32,6 @@ import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.Option import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SubmitButton import com.processout.sdk.ui.shared.component.isImeVisibleAsState import com.processout.sdk.ui.shared.component.screenModeAsState -import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration import com.processout.sdk.ui.shared.extension.collectImmediately import com.processout.sdk.ui.shared.extension.dpToPx import kotlinx.coroutines.delay @@ -133,15 +132,7 @@ internal class NativeAlternativePaymentBottomSheet : BaseBottomSheetDialogFragme override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - configuration?.options?.cancellation?.let { - apply( - POCancellationConfiguration( - backPressed = it.backPressed, - dragDown = it.dragDown, - touchOutside = it.touchOutside - ) - ) - } + configuration?.let { apply(it.options.cancellation) } } private fun handle(sideEffect: NativeAlternativePaymentSideEffect) { 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 9f5ec9446..8191bfc4e 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 @@ -8,6 +8,7 @@ import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.Cancel import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.SecondaryAction import com.processout.sdk.ui.shared.configuration.POActionConfirmationConfiguration import com.processout.sdk.ui.shared.configuration.POBarcodeConfiguration +import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration import kotlinx.parcelize.Parcelize /** @@ -46,7 +47,7 @@ data class PONativeAlternativePaymentConfiguration( val title: String? = null, val submitButton: SubmitButton = SubmitButton(), val cancelButton: CancelButton? = null, - val cancellation: CancellationConfiguration = CancellationConfiguration(), + val cancellation: POCancellationConfiguration = POCancellationConfiguration(), val paymentConfirmation: PaymentConfirmationConfiguration = PaymentConfirmationConfiguration(confirmButton = null), val barcode: POBarcodeConfiguration = POBarcodeConfiguration(saveButton = POBarcodeConfiguration.Button()), val inlineSingleSelectValuesLimit: Int = 5, @@ -84,7 +85,13 @@ data class PONativeAlternativePaymentConfiguration( title = title, submitButton = SubmitButton(text = primaryActionText), cancelButton = secondaryAction?.toCancelButton(), - cancellation = cancellation, + cancellation = with(cancellation) { + POCancellationConfiguration( + backPressed = backPressed, + dragDown = dragDown, + touchOutside = touchOutside + ) + }, paymentConfirmation = paymentConfirmation, barcode = barcode, inlineSingleSelectValuesLimit = inlineSingleSelectValuesLimit, @@ -167,6 +174,7 @@ data class PONativeAlternativePaymentConfiguration( * @param[touchOutside] Cancel on touch of the outside dimmed area of the bottom sheet. Default value is _true_. */ @Parcelize + @Deprecated(message = "Use 'POCancellationConfiguration' instead.") data class CancellationConfiguration( val backPressed: Boolean = true, val dragDown: Boolean = true, diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt index 29f24f7cb..dbdd4f569 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt @@ -12,9 +12,29 @@ import kotlinx.parcelize.Parcelize * @param[touchOutside] Cancel on touch of the outside dimmed area of the bottom sheet. Default value is _true_. */ @Parcelize -data class POCancellationConfiguration( +data class POCancellationConfiguration @Deprecated(message = "Use alternative constructor.") constructor( + @Deprecated(message = "Use configuration of specific button.") val secondaryAction: Boolean = true, val backPressed: Boolean = true, val dragDown: Boolean = true, val touchOutside: Boolean = true -) : Parcelable +) : Parcelable { + + /** + * Specifies cancellation behaviour. + * + * @param[backPressed] Cancel on back button press or back gesture. Default value is _true_. + * @param[dragDown] Cancel when bottom sheet is dragged down out of the screen. Default value is _true_. + * @param[touchOutside] Cancel on touch of the outside dimmed area of the bottom sheet. Default value is _true_. + */ + constructor( + backPressed: Boolean = true, + dragDown: Boolean = true, + touchOutside: Boolean = true + ) : this( + secondaryAction = false, + backPressed = backPressed, + dragDown = dragDown, + touchOutside = touchOutside + ) +} From e68f93a650bc4be93891d71e938a4276c6bbdfb6 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 17:53:44 +0200 Subject: [PATCH 12/17] Refactored POCardUpdateConfiguration --- .../ui/screen/features/FeaturesFragment.kt | 6 +- .../ui/card/update/CardUpdateBottomSheet.kt | 4 +- .../sdk/ui/card/update/CardUpdateViewModel.kt | 18 +++-- .../card/update/POCardUpdateConfiguration.kt | 67 +++++++++++++++++-- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt b/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt index b4f7c024a..9b75c0711 100644 --- a/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt +++ b/example/src/main/kotlin/com/processout/example/ui/screen/features/FeaturesFragment.kt @@ -20,6 +20,7 @@ import com.processout.sdk.api.model.response.POCard import com.processout.sdk.api.model.response.POGooglePayCardTokenizationData import com.processout.sdk.core.* import com.processout.sdk.ui.card.update.POCardUpdateConfiguration +import com.processout.sdk.ui.card.update.POCardUpdateConfiguration.* import com.processout.sdk.ui.card.update.POCardUpdateLauncher import com.processout.sdk.ui.googlepay.POGooglePayCardTokenizationLauncher import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration @@ -90,13 +91,14 @@ class FeaturesFragment : BaseFragment( cardUpdateLauncher.launch( POCardUpdateConfiguration( cardId = card?.id ?: String(), - options = POCardUpdateConfiguration.Options( - cardInformation = POCardUpdateConfiguration.CardInformation( + options = Options( + cardInformation = CardInformation( maskedNumber = maskedNumber, iin = card?.iin, scheme = card?.scheme, preferredScheme = card?.coScheme ), + submitButton = SubmitButton(), cancellation = POCancellationConfiguration( backPressed = true, dragDown = true, diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateBottomSheet.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateBottomSheet.kt index ee9848edd..3a156750e 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateBottomSheet.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateBottomSheet.kt @@ -21,6 +21,8 @@ import com.processout.sdk.ui.base.BaseBottomSheetDialogFragment import com.processout.sdk.ui.card.update.CardUpdateCompletion.Failure import com.processout.sdk.ui.card.update.CardUpdateCompletion.Success import com.processout.sdk.ui.card.update.CardUpdateEvent.Dismiss +import com.processout.sdk.ui.card.update.POCardUpdateConfiguration.Options +import com.processout.sdk.ui.card.update.POCardUpdateConfiguration.SubmitButton import com.processout.sdk.ui.core.theme.ProcessOutTheme import com.processout.sdk.ui.shared.component.screenModeAsState import com.processout.sdk.ui.shared.extension.dpToPx @@ -40,7 +42,7 @@ internal class CardUpdateBottomSheet : BaseBottomSheetDialogFragment() { CardUpdateViewModel.Factory( app = requireActivity().application, cardId = configuration?.cardId ?: String(), - options = configuration?.options ?: POCardUpdateConfiguration.Options() + options = configuration?.options ?: Options(submitButton = SubmitButton()) ) } diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt index 184fcc67a..56ff997fa 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt @@ -100,14 +100,18 @@ internal class CardUpdateViewModel private constructor( focusedFieldId = CardFieldId.CVC, primaryAction = POActionState( id = ActionId.SUBMIT, - text = primaryActionText ?: app.getString(R.string.po_card_update_button_submit), - primary = true + text = submitButton.text ?: app.getString(R.string.po_card_update_button_submit), + primary = true, + iconResId = submitButton.iconResId ), - secondaryAction = if (cancellation.secondaryAction) POActionState( - id = ActionId.CANCEL, - text = secondaryActionText ?: app.getString(R.string.po_card_update_button_cancel), - primary = false - ) else null, + secondaryAction = cancelButton?.let { + POActionState( + id = ActionId.CANCEL, + text = it.text ?: app.getString(R.string.po_card_update_button_cancel), + primary = false, + iconResId = it.iconResId + ) + }, draggable = cancellation.dragDown ) } diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt index 8b6fe9360..df74777c4 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt @@ -2,9 +2,11 @@ package com.processout.sdk.ui.card.update import android.os.Parcelable import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes import com.processout.sdk.ui.core.style.POActionsContainerStyle import com.processout.sdk.ui.core.style.POFieldStyle import com.processout.sdk.ui.core.style.POTextStyle +import com.processout.sdk.ui.shared.configuration.POActionConfirmationConfiguration import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration import kotlinx.parcelize.Parcelize @@ -18,7 +20,7 @@ import kotlinx.parcelize.Parcelize @Parcelize data class POCardUpdateConfiguration( val cardId: String, - val options: Options = Options(), + val options: Options = Options(submitButton = SubmitButton()), val style: Style? = null ) : Parcelable { @@ -27,17 +29,72 @@ data class POCardUpdateConfiguration( * * @param[title] Custom title. * @param[cardInformation] Allows to provide card information that will be visible in UI. - * @param[primaryActionText] Custom primary action text (e.g. "Submit"). - * @param[secondaryActionText] Custom secondary action text (e.g. "Cancel"). + * @param[submitButton] Submit button configuration. + * @param[cancelButton] Cancel button configuration. Use _null_ to hide. * @param[cancellation] Specifies cancellation behaviour. */ @Parcelize data class Options( val title: String? = null, val cardInformation: CardInformation? = null, - val primaryActionText: String? = null, - val secondaryActionText: String? = null, + val submitButton: SubmitButton = SubmitButton(), + val cancelButton: CancelButton? = CancelButton(), val cancellation: POCancellationConfiguration = POCancellationConfiguration() + ) : Parcelable { + + /** + * Allows to customize behaviour and pre-define the values. + * + * @param[title] Custom title. + * @param[cardInformation] Allows to provide card information that will be visible in UI. + * @param[primaryActionText] Custom primary action text (e.g. "Submit"). + * @param[secondaryActionText] Custom secondary action text (e.g. "Cancel"). + * @param[cancellation] Specifies cancellation behaviour. + */ + @Deprecated(message = "Use alternative constructor.") + constructor( + title: String? = null, + cardInformation: CardInformation? = null, + primaryActionText: String? = null, + secondaryActionText: String? = null, + cancellation: POCancellationConfiguration = POCancellationConfiguration() + ) : this( + title = title, + cardInformation = cardInformation, + submitButton = SubmitButton(text = primaryActionText), + cancelButton = if (cancellation.secondaryAction) + CancelButton(text = secondaryActionText) else null, + cancellation = cancellation + ) + } + + /** + * Submit button configuration. + * + * @param[text] Button text. Pass _null_ to use default text. + * @param[iconResId] Button icon drawable resource ID. Pass _null_ to hide. + */ + @Parcelize + data class SubmitButton( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null + ) : Parcelable + + /** + * Cancel button configuration. + * + * @param[text] Button text. Pass _null_ to use default text. + * @param[iconResId] Button icon drawable resource ID. Pass _null_ to hide. + * @param[confirmation] Specifies action confirmation configuration (e.g. dialog). + * Use _null_ to disable, this is a default behaviour. + */ + @Parcelize + data class CancelButton( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null, + val confirmation: POActionConfirmationConfiguration? = null ) : Parcelable /** From 8ed99be3e1c45c18c2559c3af4798432c77ed540 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 18:15:25 +0200 Subject: [PATCH 13/17] Refactored POCardTokenizationConfiguration --- .../card/payment/CardPaymentFragment.kt | 4 +- .../CardTokenizationBottomSheet.kt | 3 +- .../tokenization/CardTokenizationViewModel.kt | 20 +++-- .../POCardTokenizationConfiguration.kt | 79 ++++++++++++++++++- 4 files changed, 92 insertions(+), 14 deletions(-) diff --git a/example/src/main/kotlin/com/processout/example/ui/screen/card/payment/CardPaymentFragment.kt b/example/src/main/kotlin/com/processout/example/ui/screen/card/payment/CardPaymentFragment.kt index 93672dbd9..835cfbe87 100644 --- a/example/src/main/kotlin/com/processout/example/ui/screen/card/payment/CardPaymentFragment.kt +++ b/example/src/main/kotlin/com/processout/example/ui/screen/card/payment/CardPaymentFragment.kt @@ -27,6 +27,7 @@ import com.processout.sdk.core.ProcessOutActivityResult import com.processout.sdk.core.onFailure import com.processout.sdk.core.onSuccess import com.processout.sdk.ui.card.tokenization.POCardTokenizationConfiguration +import com.processout.sdk.ui.card.tokenization.POCardTokenizationConfiguration.SubmitButton import com.processout.sdk.ui.card.tokenization.POCardTokenizationLauncher import com.processout.sdk.ui.shared.view.dialog.POAlertDialog import com.processout.sdk.ui.threeds.PO3DSRedirectCustomTabLauncher @@ -98,7 +99,8 @@ class CardPaymentFragment : BaseFragment( viewModel.onTokenizing() launcher.launch( POCardTokenizationConfiguration( - savingAllowed = true + savingAllowed = true, + submitButton = SubmitButton() ) ) } diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationBottomSheet.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationBottomSheet.kt index 360c3532f..0f54f1f2d 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationBottomSheet.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationBottomSheet.kt @@ -23,6 +23,7 @@ import com.processout.sdk.ui.card.tokenization.CardTokenizationActivityContract. import com.processout.sdk.ui.card.tokenization.CardTokenizationCompletion.Failure import com.processout.sdk.ui.card.tokenization.CardTokenizationCompletion.Success import com.processout.sdk.ui.card.tokenization.CardTokenizationEvent.Dismiss +import com.processout.sdk.ui.card.tokenization.POCardTokenizationConfiguration.SubmitButton import com.processout.sdk.ui.core.theme.ProcessOutTheme import com.processout.sdk.ui.shared.component.displayCutoutHeight import com.processout.sdk.ui.shared.component.screenModeAsState @@ -41,7 +42,7 @@ internal class CardTokenizationBottomSheet : BaseBottomSheetDialogFragment? = null, val style: Style? = null ) : Parcelable { + /** + * Defines card tokenization configuration. + * + * @param[title] Custom title. + * @param[cvcRequired] Specifies whether the card CVC should be collected. Default value is _true_. + * @param[isCardholderNameFieldVisible] Specifies whether the cardholder name field should be displayed. Default value is _true_. + * @param[billingAddress] Allows to customize the collection of billing address. + * @param[savingAllowed] Displays checkbox that allows to save the card details for future payments. + * @param[primaryActionText] Custom primary action text (e.g. "Submit"). + * @param[secondaryActionText] Custom secondary action text (e.g. "Cancel"). + * @param[cancellation] Specifies cancellation behaviour. + * @param[metadata] Metadata related to the card. + * @param[style] Allows to customize the look and feel. + */ + @Deprecated(message = "Use alternative constructor.") + constructor( + title: String? = null, + cvcRequired: Boolean = true, + isCardholderNameFieldVisible: Boolean = true, + billingAddress: BillingAddressConfiguration = BillingAddressConfiguration(), + savingAllowed: Boolean = false, + primaryActionText: String? = null, + secondaryActionText: String? = null, + cancellation: POCancellationConfiguration = POCancellationConfiguration(), + metadata: Map? = null, + style: Style? = null + ) : this( + title = title, + cvcRequired = cvcRequired, + isCardholderNameFieldVisible = isCardholderNameFieldVisible, + billingAddress = billingAddress, + savingAllowed = savingAllowed, + submitButton = SubmitButton(text = primaryActionText), + cancelButton = if (cancellation.secondaryAction) + CancelButton(text = secondaryActionText) else null, + cancellation = cancellation, + metadata = metadata, + style = style + ) + /** * Defines billing address configuration. * @@ -69,6 +111,35 @@ data class POCardTokenizationConfiguration( } } + /** + * Submit button configuration. + * + * @param[text] Button text. Pass _null_ to use default text. + * @param[iconResId] Button icon drawable resource ID. Pass _null_ to hide. + */ + @Parcelize + data class SubmitButton( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null + ) : Parcelable + + /** + * Cancel button configuration. + * + * @param[text] Button text. Pass _null_ to use default text. + * @param[iconResId] Button icon drawable resource ID. Pass _null_ to hide. + * @param[confirmation] Specifies action confirmation configuration (e.g. dialog). + * Use _null_ to disable, this is a default behaviour. + */ + @Parcelize + data class CancelButton( + val text: String? = null, + @DrawableRes + val iconResId: Int? = null, + val confirmation: POActionConfirmationConfiguration? = null + ) : Parcelable + /** * Allows to customize the look and feel. * From aee22f821606b092b5e4587157a9a18685cbf9d5 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 18:40:44 +0200 Subject: [PATCH 14/17] Apply updated POCardTokenizationConfiguration on DC --- .../ui/checkout/DynamicCheckoutActivity.kt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt index 6e28799f1..895ec33a9 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt @@ -57,7 +57,6 @@ import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.Option import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.PaymentConfirmationConfiguration import com.processout.sdk.ui.napm.PONativeAlternativePaymentConfiguration.PaymentConfirmationConfiguration.Companion.DEFAULT_TIMEOUT_SECONDS import com.processout.sdk.ui.shared.configuration.POBarcodeConfiguration -import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration import com.processout.sdk.ui.shared.extension.collectImmediately import com.processout.sdk.ui.web.customtab.POCustomTabAuthorizationActivity import com.processout.sdk.ui.web.customtab.POCustomTabAuthorizationActivityContract @@ -106,11 +105,19 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { defaultAddress = billingAddress?.defaultAddress, attachDefaultsToPaymentMethod = billingAddress?.attachDefaultsToPaymentMethod ?: false ), - primaryActionText = configuration?.submitButton?.text, - secondaryActionText = configuration?.cancelButton?.text, - cancellation = POCancellationConfiguration( - secondaryAction = configuration?.cancelButton != null - ), + submitButton = configuration?.submitButton?.let { + POCardTokenizationConfiguration.SubmitButton( + text = it.text, + iconResId = it.iconResId + ) + } ?: POCardTokenizationConfiguration.SubmitButton(), + cancelButton = configuration?.cancelButton?.let { + POCardTokenizationConfiguration.CancelButton( + text = it.text, + iconResId = it.iconResId, + confirmation = it.confirmation + ) + }, metadata = configuration?.card?.metadata ) } From 55c83def25431fd6ad7eec8c58db18661cccdff8 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 19:18:53 +0200 Subject: [PATCH 15/17] 'cancelOnBackPressed' for DC --- .../sdk/ui/checkout/DynamicCheckoutActivity.kt | 14 ++++++++------ .../ui/checkout/PODynamicCheckoutConfiguration.kt | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt index 895ec33a9..407af91f7 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/DynamicCheckoutActivity.kt @@ -225,14 +225,16 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { private fun dispatchBackPressed() { onBackPressedDispatcher.addCallback(this) { - viewModel.onEvent( - Dismiss( - ProcessOutResult.Failure( - code = Cancelled, - message = "Cancelled by the user with back press or gesture." + if (configuration?.cancelOnBackPressed == true) { + viewModel.onEvent( + Dismiss( + ProcessOutResult.Failure( + code = Cancelled, + message = "Cancelled by the user with back press or gesture." + ) ) ) - ) + } } } diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt index bb61da186..371fdbc80 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/checkout/PODynamicCheckoutConfiguration.kt @@ -20,9 +20,10 @@ data class PODynamicCheckoutConfiguration( val card: CardConfiguration = CardConfiguration(), val googlePay: GooglePayConfiguration = GooglePayConfiguration(), val alternativePayment: AlternativePaymentConfiguration = AlternativePaymentConfiguration(), - val preselectSinglePaymentMethod: Boolean = true, val submitButton: SubmitButton = SubmitButton(), val cancelButton: CancelButton? = CancelButton(), + val cancelOnBackPressed: Boolean = true, + val preselectSinglePaymentMethod: Boolean = true, val paymentSuccess: PaymentSuccess? = PaymentSuccess(), val style: Style? = null ) : Parcelable { From e6ae9d72a308ce65ae70760ca8dac6991460be01 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 21:29:14 +0200 Subject: [PATCH 16/17] Cancel Confirmation strings --- sdk/src/main/res/values-ar/strings.xml | 5 +++++ sdk/src/main/res/values-fr/strings.xml | 5 +++++ sdk/src/main/res/values-pl/strings.xml | 5 +++++ sdk/src/main/res/values-pt/strings.xml | 5 +++++ sdk/src/main/res/values/strings.xml | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/sdk/src/main/res/values-ar/strings.xml b/sdk/src/main/res/values-ar/strings.xml index 832a99ca2..b0b99cf7c 100644 --- a/sdk/src/main/res/values-ar/strings.xml +++ b/sdk/src/main/res/values-ar/strings.xml @@ -92,4 +92,9 @@ إلغاء الدفع ليس الآن + + إلغاء؟ + إلغاء + ليس الآن + diff --git a/sdk/src/main/res/values-fr/strings.xml b/sdk/src/main/res/values-fr/strings.xml index ce36959bf..775d57145 100644 --- a/sdk/src/main/res/values-fr/strings.xml +++ b/sdk/src/main/res/values-fr/strings.xml @@ -90,4 +90,9 @@ Annuler le paiement Pas maintenant + + Annuler ? + Annuler + Pas maintenant + diff --git a/sdk/src/main/res/values-pl/strings.xml b/sdk/src/main/res/values-pl/strings.xml index 42c08035f..4db7d47a2 100644 --- a/sdk/src/main/res/values-pl/strings.xml +++ b/sdk/src/main/res/values-pl/strings.xml @@ -91,4 +91,9 @@ Anuluj płatność Nie teraz + + Anulować? + Anuluj + Nie teraz + diff --git a/sdk/src/main/res/values-pt/strings.xml b/sdk/src/main/res/values-pt/strings.xml index 2adabbfdd..3f133113f 100644 --- a/sdk/src/main/res/values-pt/strings.xml +++ b/sdk/src/main/res/values-pt/strings.xml @@ -90,4 +90,9 @@ Cancelar pagamento Agora não + + Cancelar? + Cancelar + Agora não + diff --git a/sdk/src/main/res/values/strings.xml b/sdk/src/main/res/values/strings.xml index 0656094f6..3c9b94560 100644 --- a/sdk/src/main/res/values/strings.xml +++ b/sdk/src/main/res/values/strings.xml @@ -89,4 +89,9 @@ Cancel payment Not now + + Cancel? + Cancel + Not now + From 2766eba61e4e3b9a31e36461fd6e3df62fcccea7 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 8 Jan 2025 21:48:33 +0200 Subject: [PATCH 17/17] Apply cancel confirmation dialog on Card Update & Tokenization --- .../card/tokenization/CardTokenizationViewModel.kt | 13 ++++++++++++- .../sdk/ui/card/update/CardUpdateViewModel.kt | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) 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 f73740fdc..6a2d6d913 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 @@ -16,6 +16,7 @@ import com.processout.sdk.api.dispatcher.card.tokenization.PODefaultCardTokeniza import com.processout.sdk.ui.card.tokenization.CardTokenizationInteractorState.* import com.processout.sdk.ui.card.tokenization.CardTokenizationViewModelState.* import com.processout.sdk.ui.core.state.POActionState +import com.processout.sdk.ui.core.state.POActionState.Confirmation import com.processout.sdk.ui.core.state.POImmutableList import com.processout.sdk.ui.shared.extension.map import com.processout.sdk.ui.shared.filter.CardExpirationInputFilter @@ -103,7 +104,17 @@ internal class CardTokenizationViewModel private constructor( text = it.text ?: app.getString(R.string.po_card_tokenization_button_cancel), primary = false, enabled = !state.submitting, - iconResId = it.iconResId + iconResId = it.iconResId, + confirmation = it.confirmation?.run { + Confirmation( + title = title ?: app.getString(R.string.po_cancel_confirmation_title), + message = message, + confirmActionText = confirmActionText + ?: app.getString(R.string.po_cancel_confirmation_confirm), + dismissActionText = dismissActionText + ?: app.getString(R.string.po_cancel_confirmation_dismiss) + ) + } ) }, draggable = cancellation.dragDown diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt index 56ff997fa..57d3e7bf0 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/CardUpdateViewModel.kt @@ -28,6 +28,7 @@ import com.processout.sdk.core.onSuccess import com.processout.sdk.ui.card.update.CardUpdateCompletion.* import com.processout.sdk.ui.card.update.CardUpdateEvent.* import com.processout.sdk.ui.core.state.POActionState +import com.processout.sdk.ui.core.state.POActionState.Confirmation import com.processout.sdk.ui.core.state.POImmutableList import com.processout.sdk.ui.shared.extension.orElse import com.processout.sdk.ui.shared.filter.CardSecurityCodeInputFilter @@ -109,7 +110,17 @@ internal class CardUpdateViewModel private constructor( id = ActionId.CANCEL, text = it.text ?: app.getString(R.string.po_card_update_button_cancel), primary = false, - iconResId = it.iconResId + iconResId = it.iconResId, + confirmation = it.confirmation?.run { + Confirmation( + title = title ?: app.getString(R.string.po_cancel_confirmation_title), + message = message, + confirmActionText = confirmActionText + ?: app.getString(R.string.po_cancel_confirmation_confirm), + dismissActionText = dismissActionText + ?: app.getString(R.string.po_cancel_confirmation_dismiss) + ) + } ) }, draggable = cancellation.dragDown