From ce916d08d124451cda00f08d626cc734360beba8 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 13:55:09 +0300 Subject: [PATCH 01/22] po_native_apm_confirm_capture_button_text --- sdk/src/main/res/values-ar/strings.xml | 1 + sdk/src/main/res/values-fr/strings.xml | 1 + sdk/src/main/res/values-pl/strings.xml | 1 + sdk/src/main/res/values-pt/strings.xml | 1 + sdk/src/main/res/values/strings.xml | 1 + 5 files changed, 5 insertions(+) diff --git a/sdk/src/main/res/values-ar/strings.xml b/sdk/src/main/res/values-ar/strings.xml index 65e726fcf..2c58ab3fb 100644 --- a/sdk/src/main/res/values-ar/strings.xml +++ b/sdk/src/main/res/values-ar/strings.xml @@ -15,6 +15,7 @@ الدفع %s الدفع إلغاء + لقد دفعت name@example.com أدخل رقم الهاتف نجاح! تمت الموافقة على الدفع diff --git a/sdk/src/main/res/values-fr/strings.xml b/sdk/src/main/res/values-fr/strings.xml index bddb25711..2e8517a69 100644 --- a/sdk/src/main/res/values-fr/strings.xml +++ b/sdk/src/main/res/values-fr/strings.xml @@ -15,6 +15,7 @@ Payer %s Payer Annuler + J\'ai payé nom@exemple.fr Entrez votre numéro de téléphone Succès !\nPaiement confirmé. diff --git a/sdk/src/main/res/values-pl/strings.xml b/sdk/src/main/res/values-pl/strings.xml index c0770ed1b..538dc202e 100644 --- a/sdk/src/main/res/values-pl/strings.xml +++ b/sdk/src/main/res/values-pl/strings.xml @@ -15,6 +15,7 @@ Zapłać %s Zapłać Anuluj + Płatność wykonana imię@przykład.pl Twój numer telefonu Sukces!\nPłatność przyjęta. diff --git a/sdk/src/main/res/values-pt/strings.xml b/sdk/src/main/res/values-pt/strings.xml index 70725e84b..1c24aa2ad 100644 --- a/sdk/src/main/res/values-pt/strings.xml +++ b/sdk/src/main/res/values-pt/strings.xml @@ -15,6 +15,7 @@ Pagar %s Pagar Cancelar + Já paguei nome@exemplo.pt Insira o seu número de telemóvel Successo!\nPagamento aprovado. diff --git a/sdk/src/main/res/values/strings.xml b/sdk/src/main/res/values/strings.xml index a432a00b2..164fee788 100644 --- a/sdk/src/main/res/values/strings.xml +++ b/sdk/src/main/res/values/strings.xml @@ -15,6 +15,7 @@ Pay %s Pay Cancel + I\'ve paid name@example.com Enter phone number Success!\nPayment approved. From b39d6ef1e5935a007d5cffe3bd569154e2d0d6c9 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 14:23:48 +0300 Subject: [PATCH 02/22] ConfirmAction and paymentConfirmationPrimaryAction in nAPM (Views) config --- ...PONativeAlternativePaymentMethodConfiguration.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt index 55d322bae..808bdb64f 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt @@ -45,6 +45,8 @@ data class PONativeAlternativePaymentMethodConfiguration( * or will complete right after all user’s input is submitted. Default value is _true_. * @param[paymentConfirmationTimeoutSeconds] Amount of time (in seconds) to wait for final payment confirmation. * Default value is 3 minutes, while maximum value is 15 minutes. + * @param[paymentConfirmationPrimaryAction] Optional primary action for payment confirmation. + * To hide action use _null_, this is a default behaviour. * @param[paymentConfirmationSecondaryAction] Action that could be optionally presented to user during payment confirmation stage. * To hide action use _null_, this is a default behaviour. * @param[showPaymentConfirmationProgressIndicatorAfterSeconds] Show progress indicator during payment confirmation after provided delay (in seconds). @@ -61,6 +63,7 @@ data class PONativeAlternativePaymentMethodConfiguration( val skipSuccessScreen: Boolean = false, val waitsPaymentConfirmation: Boolean = true, val paymentConfirmationTimeoutSeconds: Int = DEFAULT_PAYMENT_CONFIRMATION_TIMEOUT_SECONDS, + val paymentConfirmationPrimaryAction: ConfirmAction? = null, val paymentConfirmationSecondaryAction: SecondaryAction? = null, val showPaymentConfirmationProgressIndicatorAfterSeconds: Int? = null ) : Parcelable { @@ -70,6 +73,16 @@ data class PONativeAlternativePaymentMethodConfiguration( } } + /** + * Action for confirmation. + * + * @param[text] Action text. Pass _null_ to use default text. + */ + @Parcelize + data class ConfirmAction( + val text: String? = null + ) : Parcelable + /** * Supported secondary actions. */ From dc6b2e4d4ab207931f6c2678419b4d3db3318303 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 16:35:41 +0300 Subject: [PATCH 03/22] KDoc --- .../PONativeAlternativePaymentMethodConfiguration.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt index 808bdb64f..d3a3124d4 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodConfiguration.kt @@ -93,6 +93,7 @@ data class PONativeAlternativePaymentMethodConfiguration( * @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[confirmation] Specifies action confirmation configuration (e.g. dialog). Disabled by default. */ @Parcelize data class Cancel( @@ -103,9 +104,9 @@ data class PONativeAlternativePaymentMethodConfiguration( } /** - * Specifies action confirmation behaviour and values. + * Specifies action confirmation configuration (e.g. dialog). * - * @param[enabled] Enables action confirmation. + * @param[enabled] Enables action confirmation. Default value is _false_. * @param[title] Custom title. Pass _null_ to use default text. * @param[message] Custom message. Pass _null_ to use default text. Pass empty string to hide. * @param[confirmActionText] Custom confirm action text. Pass _null_ to use default text. From cc9aee758bbe6be38dabd83172f4c18e3d628a68 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 16:38:46 +0300 Subject: [PATCH 04/22] KDoc --- .../sdk/ui/napm/PONativeAlternativePaymentConfiguration.kt | 2 ++ 1 file changed, 2 insertions(+) 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 f6e05b5b7..44afab665 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 @@ -59,6 +59,8 @@ data class PONativeAlternativePaymentConfiguration( * @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[confirmation] Specifies action confirmation configuration (e.g. dialog). + * Use _null_ to disable, this is a default behaviour. */ @Parcelize data class Cancel( From 7b241995a5bf39a24db5f2b8862947934c3e3f92 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 17:16:37 +0300 Subject: [PATCH 05/22] Added payment confirmation button, refactored footer --- .../NativeAlternativePaymentMethodUiState.kt | 1 + ...NativeAlternativePaymentMethodViewModel.kt | 3 ++ ...tiveAlternativePaymentMethodBottomSheet.kt | 51 +++++++++++++------ .../res/layout/po_bottom_sheet_capture.xml | 19 +++++-- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodUiState.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodUiState.kt index e4a31cdcd..c9314d739 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodUiState.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodUiState.kt @@ -45,6 +45,7 @@ internal data class NativeAlternativePaymentMethodUiModel( val customerActionImageUrl: String?, val primaryActionText: String, val secondaryAction: SecondaryActionUiModel?, + val paymentConfirmationPrimaryActionText: String?, val paymentConfirmationSecondaryAction: SecondaryActionUiModel?, val isPaymentConfirmationProgressIndicatorVisible: Boolean, val isSubmitting: Boolean diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt index a27fbf862..b7a405563 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt @@ -616,6 +616,9 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( customerActionImageUrl = gateway.customerActionImageUrl, primaryActionText = options.primaryActionText ?: invoice.formatPrimaryActionText(), secondaryAction = options.secondaryAction?.toUiModel(), + paymentConfirmationPrimaryActionText = options.paymentConfirmationPrimaryAction?.let { + it.text ?: app.getString(R.string.po_native_apm_confirm_capture_button_text) + }, paymentConfirmationSecondaryAction = options.paymentConfirmationSecondaryAction?.toUiModel(), isPaymentConfirmationProgressIndicatorVisible = false, isSubmitting = false diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt index b3fbd64e8..8883ebc08 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt @@ -17,15 +17,13 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.FrameLayout +import android.widget.LinearLayout import androidx.activity.addCallback import androidx.appcompat.view.ContextThemeWrapper import androidx.core.animation.addListener import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat -import androidx.core.view.children -import androidx.core.view.updateLayoutParams +import androidx.core.view.* import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope @@ -586,7 +584,7 @@ class PONativeAlternativePaymentMethodBottomSheet : BottomSheetDialogFragment(), private fun bindCapture(uiModel: NativeAlternativePaymentMethodUiModel) { initCaptureView() - bindPaymentConfirmationSecondaryButton(uiModel) + bindCaptureFooter(uiModel) if (uiModel.showCustomerAction()) { bindingCapture.poCircularProgressIndicator.visibility = View.GONE if (uiModel.isPaymentConfirmationProgressIndicatorVisible) { @@ -665,21 +663,44 @@ class PONativeAlternativePaymentMethodBottomSheet : BottomSheetDialogFragment(), bindingCapture.poMessage.visibility = View.VISIBLE } - private fun bindPaymentConfirmationSecondaryButton( + private fun bindCaptureFooter( uiModel: NativeAlternativePaymentMethodUiModel ) { - uiModel.paymentConfirmationSecondaryAction?.let { action -> + val visible = uiModel.paymentConfirmationPrimaryActionText != null + || uiModel.paymentConfirmationSecondaryAction != null + if (visible) { + bindingCapture.poFooter.visibility = View.VISIBLE + with(bindingCapture.poPrimaryButton) { + uiModel.paymentConfirmationPrimaryActionText?.let { actionText -> + setOnClickListener { + // TODO + } + text = actionText + visibility = View.VISIBLE + } ?: run { visibility = View.GONE } + } with(bindingCapture.poSecondaryButton) { - when (action) { - is SecondaryActionUiModel.Cancel -> { - setOnClickListener { onCancelClick(action.confirmation) } - text = action.text - setState(action.state) - bindingCapture.poFooter.visibility = View.VISIBLE + uiModel.paymentConfirmationSecondaryAction?.let { action -> + when (action) { + is SecondaryActionUiModel.Cancel -> { + setOnClickListener { onCancelClick(action.confirmation) } + if (uiModel.paymentConfirmationPrimaryActionText == null) { + updateLayoutParams { + updateMarginsRelative( + top = resources.getDimensionPixelSize(R.dimen.po_bottomSheet_buttons_marginVertical) + ) + } + } + text = action.text + setState(action.state) + visibility = View.VISIBLE + } } - } + } ?: run { visibility = View.GONE } } - } ?: run { bindingCapture.poFooter.visibility = View.GONE } + } else { + bindingCapture.poFooter.visibility = View.GONE + } } private fun handleSuccess(uiModel: NativeAlternativePaymentMethodUiModel) { diff --git a/sdk/src/main/res/layout/po_bottom_sheet_capture.xml b/sdk/src/main/res/layout/po_bottom_sheet_capture.xml index 2a91490d4..c1559af42 100644 --- a/sdk/src/main/res/layout/po_bottom_sheet_capture.xml +++ b/sdk/src/main/res/layout/po_bottom_sheet_capture.xml @@ -151,6 +151,7 @@ android:id="@+id/po_footer" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/po_bottomSheet_buttons_marginVertical" android:orientation="vertical" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" @@ -164,15 +165,27 @@ android:layout_height="@dimen/po_borderWidth" android:background="@color/po_border_subtle" /> + + + android:layout_marginTop="@dimen/po_button_marginTop" + android:text="@string/po_native_apm_cancel_button_text" + android:visibility="gone" + tools:visibility="visible" /> From aa11649bd18836f161c59d3f684578f24854885c Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 17:19:19 +0300 Subject: [PATCH 06/22] Suppress expected deprecation --- .../ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt index 8883ebc08..fc01b98fc 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt @@ -776,6 +776,7 @@ class PONativeAlternativePaymentMethodBottomSheet : BottomSheetDialogFragment(), bindingCapture.poFooter.visibility = View.GONE } + @Suppress("DEPRECATION") private fun bindSuccessBackground() { val backgroundDecorationSuccessColor = when (val stateStyle = configuration?.style?.backgroundDecoration?.success) { From bd2ff047615e4191c5c61d2d675bf217e564b469 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 17:59:32 +0300 Subject: [PATCH 07/22] set onConfirmPaymentClick() --- .../PONativeAlternativePaymentMethodBottomSheet.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt index fc01b98fc..189074dcf 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/PONativeAlternativePaymentMethodBottomSheet.kt @@ -501,6 +501,11 @@ class PONativeAlternativePaymentMethodBottomSheet : BottomSheetDialogFragment(), viewModel.submitPayment() } + private fun onConfirmPaymentClick() { + bindingCapture.poPrimaryButton.isClickable = false + viewModel.confirmPayment() + } + private fun onCancelClick(confirmation: ActionConfirmation) { with(confirmation) { if (!enabled) { @@ -672,9 +677,7 @@ class PONativeAlternativePaymentMethodBottomSheet : BottomSheetDialogFragment(), bindingCapture.poFooter.visibility = View.VISIBLE with(bindingCapture.poPrimaryButton) { uiModel.paymentConfirmationPrimaryActionText?.let { actionText -> - setOnClickListener { - // TODO - } + setOnClickListener { onConfirmPaymentClick() } text = actionText visibility = View.VISIBLE } ?: run { visibility = View.GONE } From 74dc7c373d76532eb396641921adfb2e102601ea Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 18:06:19 +0300 Subject: [PATCH 08/22] Apply custom button style --- .../com/processout/sdk/ui/nativeapm/StyleCustomization.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/StyleCustomization.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/StyleCustomization.kt index 4496bba25..ad1e1f1d9 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/StyleCustomization.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/StyleCustomization.kt @@ -30,6 +30,7 @@ import com.processout.sdk.ui.shared.style.radio.PORadioButtonStyle import com.processout.sdk.ui.shared.view.extension.dpToPx import com.processout.sdk.ui.shared.view.extension.spToPx +@Suppress("DEPRECATION") internal fun PoBottomSheetNativeApmBinding.applyStyle( style: PONativeAlternativePaymentMethodConfiguration.Style ) { @@ -51,6 +52,7 @@ internal fun PoBottomSheetCaptureBinding.applyStyle( } style.successImageResId?.let { poSuccessImage.setImageResource(it) } style.message?.let { poMessage.applyStyle(it) } + style.primaryButton?.let { poPrimaryButton.applyStyle(it) } style.secondaryButton?.let { poSecondaryButton.applyStyle(it) } style.controlsTintColor?.let { poMessage.applyControlsTintColor(it) From 176a805f61ab21bfc07301e59dc04ff892401024 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 19:09:50 +0300 Subject: [PATCH 09/22] Handle payment confirmation --- ...NativeAlternativePaymentMethodViewModel.kt | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt index b7a405563..fb12bfad6 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt @@ -430,16 +430,12 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( animateViewTransition = true _uiState.value = Capture(updatedUiModel) - options.showPaymentConfirmationProgressIndicatorAfterSeconds?.let { afterSeconds -> - showPaymentConfirmationProgressIndicator( - afterMillis = TimeUnit.SECONDS.toMillis(afterSeconds.toLong()) - ) - } updatedUiModel.paymentConfirmationSecondaryAction?.let { scheduleSecondaryActionEnabling(it) { enablePaymentConfirmationSecondaryAction() } } - - capture() + if (options.paymentConfirmationPrimaryAction == null) { + capture() + } return } _uiState.value = Success(uiModel.copy()) @@ -503,12 +499,26 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( } else originalMessage + fun confirmPayment() { + _uiState.value.doWhenCapture { uiModel -> + _uiState.value = Capture( + uiModel.copy(paymentConfirmationPrimaryActionText = null) + ) + capture() + } + } + private fun capture() { if (captureStartTimestamp != 0L) { return } viewModelScope.launch { captureStartTimestamp = System.currentTimeMillis() + options.showPaymentConfirmationProgressIndicatorAfterSeconds?.let { afterSeconds -> + showPaymentConfirmationProgressIndicator( + afterMillis = TimeUnit.SECONDS.toMillis(afterSeconds.toLong()) + ) + } val iterator = captureRetryStrategy.iterator while (capturePassedTimestamp < options.paymentConfirmationTimeoutSeconds * 1000) { val result = invoicesService.captureNativeAlternativePayment(invoiceId, gatewayConfigurationId) From 0812bd645bcc8383840d0f93fbe207a68430ba8b Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Mon, 23 Sep 2024 19:42:27 +0300 Subject: [PATCH 10/22] Send DidConfirmPayment event --- .../model/event/PONativeAlternativePaymentMethodEvent.kt | 6 ++++++ .../ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt | 2 ++ 2 files changed, 8 insertions(+) diff --git a/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt b/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt index 2d142dd26..9ea4aca15 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt @@ -67,6 +67,12 @@ sealed class PONativeAlternativePaymentMethodEvent { val additionalActionExpected: Boolean ) : PONativeAlternativePaymentMethodEvent() + /** + * Event is sent during the capture stage when the user confirms that they have completed + * any required external actions. Implementation proceeds with the actual capture process. + */ + data object DidConfirmPayment : PONativeAlternativePaymentMethodEvent() + /** * Event is sent when user asked to confirm cancellation, e.g. via dialog. */ diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt index fb12bfad6..565dfd76e 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt @@ -501,6 +501,8 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( fun confirmPayment() { _uiState.value.doWhenCapture { uiModel -> + POLogger.info("User confirmed that required external actions are complete.") + dispatch(DidConfirmPayment) _uiState.value = Capture( uiModel.copy(paymentConfirmationPrimaryActionText = null) ) From 575cbf1c24ef4cc790e3dff25a79019ecabc8f98 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 14:47:35 +0300 Subject: [PATCH 11/22] Adde ConfirmAction to PONativeAlternativePaymentConfiguration --- .../napm/PONativeAlternativePaymentConfiguration.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 44afab665..276c0c12b 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 @@ -49,6 +49,16 @@ data class PONativeAlternativePaymentConfiguration( val successMessage: String? = null ) : Parcelable + /** + * Action for confirmation. + * + * @param[text] Action text. Pass _null_ to use default text. + */ + @Parcelize + data class ConfirmAction( + val text: String? = null + ) : Parcelable + /** * Supported secondary actions. */ @@ -95,6 +105,8 @@ 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. */ @@ -104,6 +116,7 @@ data class PONativeAlternativePaymentConfiguration( val timeoutSeconds: Int = DEFAULT_TIMEOUT_SECONDS, val showProgressIndicatorAfterSeconds: Int? = null, val hideGatewayDetails: Boolean = false, + val primaryAction: ConfirmAction? = null, val secondaryAction: SecondaryAction? = null ) : Parcelable { companion object { From 5316b51dc9dd28b2c8cde0986b8e85780413ac79 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 15:30:37 +0300 Subject: [PATCH 12/22] KDoc and log --- .../api/model/event/PONativeAlternativePaymentMethodEvent.kt | 4 ++-- .../ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt b/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt index 9ea4aca15..bba692684 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/api/model/event/PONativeAlternativePaymentMethodEvent.kt @@ -68,8 +68,8 @@ sealed class PONativeAlternativePaymentMethodEvent { ) : PONativeAlternativePaymentMethodEvent() /** - * Event is sent during the capture stage when the user confirms that they have completed - * any required external actions. Implementation proceeds with the actual capture process. + * Event is sent during the capture stage when the user confirms that they have completed required external action. + * Implementation proceeds with the actual capture process. */ data object DidConfirmPayment : PONativeAlternativePaymentMethodEvent() diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt index 565dfd76e..962850b37 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt @@ -501,7 +501,7 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( fun confirmPayment() { _uiState.value.doWhenCapture { uiModel -> - POLogger.info("User confirmed that required external actions are complete.") + POLogger.info("User confirmed that required external action is complete.") dispatch(DidConfirmPayment) _uiState.value = Capture( uiModel.copy(paymentConfirmationPrimaryActionText = null) From cc730cd9680a6f5d6cb602d93bdf1efb078379e2 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 16:40:54 +0300 Subject: [PATCH 13/22] Hide payment confirmation button when there is no customer action and start capture --- .../nativeapm/NativeAlternativePaymentMethodViewModel.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt index 962850b37..9a6a2e9c3 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt @@ -412,12 +412,14 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( POLogger.info("All payment parameters has been submitted.") if (options.waitsPaymentConfirmation) { + val customerActionMessage = parameterValues?.customerActionMessage ?: uiModel.customerActionMessageMarkdown val updatedUiModel = uiModel.copy( title = parameterValues?.providerName, logoUrl = if (parameterValues?.providerName != null) parameterValues.providerLogoUrl else uiModel.logoUrl, - customerActionMessageMarkdown = parameterValues?.customerActionMessage - ?: uiModel.customerActionMessageMarkdown + customerActionMessageMarkdown = customerActionMessage, + paymentConfirmationPrimaryActionText = if (!customerActionMessage.isNullOrBlank()) + uiModel.paymentConfirmationPrimaryActionText else null ) POLogger.info("Waiting for capture confirmation.") dispatch( @@ -433,7 +435,7 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( updatedUiModel.paymentConfirmationSecondaryAction?.let { scheduleSecondaryActionEnabling(it) { enablePaymentConfirmationSecondaryAction() } } - if (options.paymentConfirmationPrimaryAction == null) { + if (updatedUiModel.paymentConfirmationPrimaryActionText == null) { capture() } return From 936a7f21c5cf60ee6f87555c0f097c48d7af2a97 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 17:19:38 +0300 Subject: [PATCH 14/22] po_native_apm_confirm_payment_button_text --- .../sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt | 2 +- sdk/src/main/res/layout/po_bottom_sheet_capture.xml | 2 +- sdk/src/main/res/values-ar/strings.xml | 2 +- sdk/src/main/res/values-fr/strings.xml | 2 +- sdk/src/main/res/values-pl/strings.xml | 2 +- sdk/src/main/res/values-pt/strings.xml | 2 +- sdk/src/main/res/values/strings.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt index 9a6a2e9c3..920668321 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt @@ -631,7 +631,7 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( primaryActionText = options.primaryActionText ?: invoice.formatPrimaryActionText(), secondaryAction = options.secondaryAction?.toUiModel(), paymentConfirmationPrimaryActionText = options.paymentConfirmationPrimaryAction?.let { - it.text ?: app.getString(R.string.po_native_apm_confirm_capture_button_text) + it.text ?: app.getString(R.string.po_native_apm_confirm_payment_button_text) }, paymentConfirmationSecondaryAction = options.paymentConfirmationSecondaryAction?.toUiModel(), isPaymentConfirmationProgressIndicatorVisible = false, diff --git a/sdk/src/main/res/layout/po_bottom_sheet_capture.xml b/sdk/src/main/res/layout/po_bottom_sheet_capture.xml index c1559af42..89edb232a 100644 --- a/sdk/src/main/res/layout/po_bottom_sheet_capture.xml +++ b/sdk/src/main/res/layout/po_bottom_sheet_capture.xml @@ -172,7 +172,7 @@ android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/po_bottomSheet_buttons_marginHorizontal" android:layout_marginTop="@dimen/po_bottomSheet_buttons_marginVertical" - android:text="@string/po_native_apm_confirm_capture_button_text" + android:text="@string/po_native_apm_confirm_payment_button_text" android:visibility="gone" tools:visibility="visible" /> diff --git a/sdk/src/main/res/values-ar/strings.xml b/sdk/src/main/res/values-ar/strings.xml index 2c58ab3fb..3ed4d8339 100644 --- a/sdk/src/main/res/values-ar/strings.xml +++ b/sdk/src/main/res/values-ar/strings.xml @@ -15,7 +15,7 @@ الدفع %s الدفع إلغاء - لقد دفعت + لقد دفعت name@example.com أدخل رقم الهاتف نجاح! تمت الموافقة على الدفع diff --git a/sdk/src/main/res/values-fr/strings.xml b/sdk/src/main/res/values-fr/strings.xml index 2e8517a69..805a3bbdd 100644 --- a/sdk/src/main/res/values-fr/strings.xml +++ b/sdk/src/main/res/values-fr/strings.xml @@ -15,7 +15,7 @@ Payer %s Payer Annuler - J\'ai payé + J\'ai payé nom@exemple.fr Entrez votre numéro de téléphone Succès !\nPaiement confirmé. diff --git a/sdk/src/main/res/values-pl/strings.xml b/sdk/src/main/res/values-pl/strings.xml index 538dc202e..0bff27ea3 100644 --- a/sdk/src/main/res/values-pl/strings.xml +++ b/sdk/src/main/res/values-pl/strings.xml @@ -15,7 +15,7 @@ Zapłać %s Zapłać Anuluj - Płatność wykonana + Płatność wykonana imię@przykład.pl Twój numer telefonu Sukces!\nPłatność przyjęta. diff --git a/sdk/src/main/res/values-pt/strings.xml b/sdk/src/main/res/values-pt/strings.xml index 1c24aa2ad..4ba264837 100644 --- a/sdk/src/main/res/values-pt/strings.xml +++ b/sdk/src/main/res/values-pt/strings.xml @@ -15,7 +15,7 @@ Pagar %s Pagar Cancelar - Já paguei + Já paguei nome@exemplo.pt Insira o seu número de telemóvel Successo!\nPagamento aprovado. diff --git a/sdk/src/main/res/values/strings.xml b/sdk/src/main/res/values/strings.xml index 164fee788..ab719bd69 100644 --- a/sdk/src/main/res/values/strings.xml +++ b/sdk/src/main/res/values/strings.xml @@ -15,7 +15,7 @@ Pay %s Pay Cancel - I\'ve paid + I\'ve paid name@example.com Enter phone number Success!\nPayment approved. From ad65fc3b0e5180f1579ea39d6fc207362b7be4a3 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 17:34:33 +0300 Subject: [PATCH 15/22] Add payment confirmation button to nAPM Compose --- .../sdk/ui/napm/NativeAlternativePaymentInteractor.kt | 6 ++++++ .../ui/napm/NativeAlternativePaymentInteractorState.kt | 2 ++ .../sdk/ui/napm/NativeAlternativePaymentScreen.kt | 5 ++++- .../sdk/ui/napm/NativeAlternativePaymentViewModel.kt | 9 +++++++++ .../ui/napm/NativeAlternativePaymentViewModelState.kt | 1 + 5 files changed, 22 insertions(+), 1 deletion(-) 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 49fd8a546..6533ca813 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 @@ -192,6 +192,7 @@ internal class NativeAlternativePaymentInteractor( actionImageUrl = gateway.customerActionImageUrl, actionMessage = parameterValues?.customerActionMessage ?: gateway.customerActionMessage?.let { escapedMarkdown(it) }, + primaryActionId = ActionId.CONFIRM_PAYMENT, secondaryAction = NativeAlternativePaymentInteractorState.Action( id = ActionId.CANCEL, enabled = false @@ -398,6 +399,7 @@ internal class NativeAlternativePaymentInteractor( is Action -> when (event.id) { ActionId.SUBMIT -> submit() ActionId.CANCEL -> cancel() + ActionId.CONFIRM_PAYMENT -> confirmPayment() } is ActionConfirmationRequested -> { POLogger.debug("Requested the user to confirm the action: %s", event.id) @@ -667,6 +669,10 @@ internal class NativeAlternativePaymentInteractor( } } + private fun confirmPayment() { + // TODO + } + private fun capture() { if (captureStartTimestamp != 0L) { return diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt index c5ee569b7..8738132fb 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt @@ -54,6 +54,7 @@ internal sealed interface NativeAlternativePaymentInteractorState { val logoUrl: String?, val actionImageUrl: String?, val actionMessage: String?, + val primaryActionId: String, val secondaryAction: Action, val withProgressIndicator: Boolean ) @@ -79,6 +80,7 @@ internal sealed interface NativeAlternativePaymentInteractorState { object ActionId { const val SUBMIT = "submit" const val CANCEL = "cancel" + const val CONFIRM_PAYMENT = "confirm-payment" } } diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt index 66a25c501..f6c5c093e 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentScreen.kt @@ -527,7 +527,10 @@ private fun Actions( primary = state.primaryAction secondary = state.secondaryAction } - is Capture -> secondary = state.secondaryAction + is Capture -> { + primary = state.primaryAction + secondary = state.secondaryAction + } } val actions = mutableListOf() primary?.let { actions.add(it) } 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 0b825f6a7..58975686f 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 @@ -153,11 +153,19 @@ internal class NativeAlternativePaymentViewModel private constructor( secondaryAction = secondaryAction ) } else { + val primaryAction = options.paymentConfirmation.primaryAction?.let { + POActionState( + id = primaryActionId, + text = it.text ?: app.getString(R.string.po_native_apm_confirm_payment_button_text), + primary = true + ) + } NativeAlternativePaymentViewModelState.Capture( title = paymentProviderName, logoUrl = logoUrl, imageUrl = actionImageUrl, message = actionMessage, + primaryAction = primaryAction, secondaryAction = secondaryAction, withProgressIndicator = withProgressIndicator, isCaptured = false @@ -171,6 +179,7 @@ internal class NativeAlternativePaymentViewModel private constructor( logoUrl = logoUrl, imageUrl = null, message = options.successMessage ?: app.getString(R.string.po_native_apm_success_message), + primaryAction = null, secondaryAction = null, withProgressIndicator = false, isCaptured = true diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModelState.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModelState.kt index 693ec0cc1..e1f143474 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModelState.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentViewModelState.kt @@ -30,6 +30,7 @@ internal sealed interface NativeAlternativePaymentViewModelState { val logoUrl: String?, val imageUrl: String?, val message: String, + val primaryAction: POActionState?, val secondaryAction: POActionState?, val withProgressIndicator: Boolean, val isCaptured: Boolean From 383c366dfbf1c35639b267f37aebf5a613c92707 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 17:42:21 +0300 Subject: [PATCH 16/22] enableCapturingProgressIndicator() when capture is actually started --- .../sdk/ui/napm/NativeAlternativePaymentInteractor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6533ca813..24f4d2bd3 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 @@ -663,7 +663,6 @@ internal class NativeAlternativePaymentInteractor( coroutineScope = this@launch ) _state.update { Capturing(stateValue) } - enableCapturingProgressIndicator() enableCapturingSecondaryAction() capture() } @@ -679,6 +678,7 @@ internal class NativeAlternativePaymentInteractor( } interactorScope.launch { captureStartTimestamp = System.currentTimeMillis() + enableCapturingProgressIndicator() val iterator = captureRetryStrategy.iterator while (capturePassedTimestamp < options.paymentConfirmation.timeoutSeconds * 1000) { val result = invoicesService.captureNativeAlternativePayment(invoiceId, gatewayConfigurationId) From d8d35e88b31460e93deedfe2d65e0f4eadc3cc23 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 18:10:39 +0300 Subject: [PATCH 17/22] Decide when to start capture automatically not waiting confirmation --- .../sdk/ui/napm/NativeAlternativePaymentInteractor.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) 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 24f4d2bd3..0ca7f7115 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 @@ -653,18 +653,17 @@ internal class NativeAlternativePaymentInteractor( } interactorScope.launch { POLogger.info("Waiting for capture confirmation.") - dispatch( - WillWaitForCaptureConfirmation( - additionalActionExpected = !stateValue.actionMessage.isNullOrBlank() - ) - ) + val additionalActionExpected = !stateValue.actionMessage.isNullOrBlank() + dispatch(WillWaitForCaptureConfirmation(additionalActionExpected = additionalActionExpected)) preloadAllImages( stateValue = stateValue, coroutineScope = this@launch ) _state.update { Capturing(stateValue) } enableCapturingSecondaryAction() - capture() + if (!additionalActionExpected || options.paymentConfirmation.primaryAction == null) { + capture() + } } } From 676a1459d23692e0d1851ff2e5eac82c5e4f2d25 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 18:46:12 +0300 Subject: [PATCH 18/22] Start capture when confirmed by user and hide button --- .../ui/napm/NativeAlternativePaymentInteractor.kt | 7 ++++++- .../napm/NativeAlternativePaymentInteractorState.kt | 2 +- .../sdk/ui/napm/NativeAlternativePaymentViewModel.kt | 12 +++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) 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 0ca7f7115..774454a4e 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 @@ -668,7 +668,12 @@ internal class NativeAlternativePaymentInteractor( } private fun confirmPayment() { - // TODO + _state.whenCapturing { stateValue -> + POLogger.info("User confirmed that required external action is complete.") + dispatch(DidConfirmPayment) + _state.update { Capturing(stateValue.copy(primaryActionId = null)) } + capture() + } } private fun capture() { diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt index 8738132fb..ab1d5da74 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/napm/NativeAlternativePaymentInteractorState.kt @@ -54,7 +54,7 @@ internal sealed interface NativeAlternativePaymentInteractorState { val logoUrl: String?, val actionImageUrl: String?, val actionMessage: String?, - val primaryActionId: String, + val primaryActionId: String?, val secondaryAction: Action, val withProgressIndicator: Boolean ) 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 58975686f..910a9dda1 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 @@ -154,11 +154,13 @@ internal class NativeAlternativePaymentViewModel private constructor( ) } else { val primaryAction = options.paymentConfirmation.primaryAction?.let { - POActionState( - id = primaryActionId, - text = it.text ?: app.getString(R.string.po_native_apm_confirm_payment_button_text), - primary = true - ) + primaryActionId?.let { id -> + POActionState( + id = id, + text = it.text ?: app.getString(R.string.po_native_apm_confirm_payment_button_text), + primary = true + ) + } } NativeAlternativePaymentViewModelState.Capture( title = paymentProviderName, From cc8cc22b99278cfc48dfd51d288a89e813247b39 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Wed, 25 Sep 2024 18:58:06 +0300 Subject: [PATCH 19/22] Code improvement --- .../NativeAlternativePaymentMethodViewModel.kt | 12 ++++++------ .../ui/napm/NativeAlternativePaymentInteractor.kt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt index 920668321..6fa89b774 100644 --- a/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt +++ b/sdk/src/main/kotlin/com/processout/sdk/ui/nativeapm/NativeAlternativePaymentMethodViewModel.kt @@ -516,13 +516,13 @@ internal class NativeAlternativePaymentMethodViewModel private constructor( if (captureStartTimestamp != 0L) { return } + captureStartTimestamp = System.currentTimeMillis() + options.showPaymentConfirmationProgressIndicatorAfterSeconds?.let { afterSeconds -> + showPaymentConfirmationProgressIndicator( + afterMillis = TimeUnit.SECONDS.toMillis(afterSeconds.toLong()) + ) + } viewModelScope.launch { - captureStartTimestamp = System.currentTimeMillis() - options.showPaymentConfirmationProgressIndicatorAfterSeconds?.let { afterSeconds -> - showPaymentConfirmationProgressIndicator( - afterMillis = TimeUnit.SECONDS.toMillis(afterSeconds.toLong()) - ) - } val iterator = captureRetryStrategy.iterator while (capturePassedTimestamp < options.paymentConfirmationTimeoutSeconds * 1000) { val result = invoicesService.captureNativeAlternativePayment(invoiceId, gatewayConfigurationId) 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 774454a4e..ca44c5b9d 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 @@ -680,9 +680,9 @@ internal class NativeAlternativePaymentInteractor( if (captureStartTimestamp != 0L) { return } + captureStartTimestamp = System.currentTimeMillis() + enableCapturingProgressIndicator() interactorScope.launch { - captureStartTimestamp = System.currentTimeMillis() - enableCapturingProgressIndicator() val iterator = captureRetryStrategy.iterator while (capturePassedTimestamp < options.paymentConfirmation.timeoutSeconds * 1000) { val result = invoicesService.captureNativeAlternativePayment(invoiceId, gatewayConfigurationId) From d819cba74630fed96cb4b2ad00ec9c7bc90db950 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Thu, 26 Sep 2024 15:29:16 +0300 Subject: [PATCH 20/22] DC ConfirmButton config --- .../sdk/ui/checkout/DynamicCheckoutActivity.kt | 1 + .../sdk/ui/checkout/PODynamicCheckoutConfiguration.kt | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) 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 7614f7e62..8cbae9091 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 @@ -114,6 +114,7 @@ internal class DynamicCheckoutActivity : BaseTransparentPortraitActivity() { timeoutSeconds = paymentConfirmation?.timeoutSeconds ?: DEFAULT_TIMEOUT_SECONDS, showProgressIndicatorAfterSeconds = paymentConfirmation?.showProgressIndicatorAfterSeconds, hideGatewayDetails = true, + primaryAction = paymentConfirmation?.confirmButton?.let { ConfirmAction(text = it.text) }, secondaryAction = paymentConfirmation?.cancelButton?.toSecondaryAction() ), inlineSingleSelectValuesLimit = configuration?.alternativePayment?.inlineSingleSelectValuesLimit ?: 5, 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 290ec8ada..47ab6190a 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 @@ -95,8 +95,15 @@ data class PODynamicCheckoutConfiguration( data class PaymentConfirmationConfiguration( val timeoutSeconds: Int = 3 * 60, val showProgressIndicatorAfterSeconds: Int? = null, + val confirmButton: ConfirmButton? = null, val cancelButton: CancelButton? = CancelButton() - ) : Parcelable + ) : Parcelable { + + @Parcelize + data class ConfirmButton( + val text: String? = null + ) : Parcelable + } } @Parcelize From 6e66089f0d7c13dc0bb6d8ac62f509b058989060 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Thu, 26 Sep 2024 16:03:02 +0300 Subject: [PATCH 21/22] Add confirm payment button on DC UI --- .../screen/NativeAlternativePayment.kt | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) 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 bb08e777c..c7b0fd4d8 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 @@ -23,6 +23,7 @@ import com.processout.sdk.ui.checkout.screen.DynamicCheckoutScreen.LongAnimation import com.processout.sdk.ui.checkout.screen.DynamicCheckoutScreen.ShortAnimationDurationMillis import com.processout.sdk.ui.checkout.screen.DynamicCheckoutScreen.isMessageShort import com.processout.sdk.ui.checkout.screen.DynamicCheckoutScreen.messageGravity +import com.processout.sdk.ui.core.component.POButton import com.processout.sdk.ui.core.component.POCircularProgressIndicator import com.processout.sdk.ui.core.component.PORequestFocus import com.processout.sdk.ui.core.component.POText @@ -56,7 +57,7 @@ internal fun NativeAlternativePayment( when (state) { is UserInput -> UserInput(id, state, onEvent, style) is Capture -> if (!state.isCaptured) { - Capture(state, style) + Capture(id, state, onEvent, style) } else -> {} } @@ -321,7 +322,9 @@ private fun DropdownField( @Composable private fun Capture( + id: String, state: Capture, + onEvent: (DynamicCheckoutEvent) -> Unit, style: DynamicCheckoutScreen.Style ) { AnimatedVisibility( @@ -371,6 +374,21 @@ private fun Capture( } ) } + state.primaryAction?.let { action -> + POButton( + text = action.text, + onClick = { + onEvent( + Action( + actionId = action.id, + paymentMethodId = id + ) + ) + }, + modifier = Modifier.fillMaxWidth(), + style = style.actionsContainer.primary + ) + } } } } From 0aa02842c9d10882fdd74efe7f0e6fb21eadb718 Mon Sep 17 00:00:00 2001 From: Vitalii Vanziak Date: Thu, 26 Sep 2024 16:16:06 +0300 Subject: [PATCH 22/22] Enable ConfirmButton by default in example app --- .../example/ui/screen/checkout/DynamicCheckoutFragment.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 34ec9bcf6..b4b9df41f 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 @@ -24,6 +24,8 @@ import com.processout.sdk.core.onFailure 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.PODynamicCheckoutLauncher import com.processout.sdk.ui.shared.view.dialog.POAlertDialog import com.processout.sdk.ui.threeds.PO3DSRedirectCustomTabLauncher @@ -94,7 +96,10 @@ class DynamicCheckoutFragment : BaseFragment( clientSecret = uiModel.clientSecret ), alternativePayment = AlternativePaymentConfiguration( - returnUrl = Constants.RETURN_URL + returnUrl = Constants.RETURN_URL, + paymentConfirmation = PaymentConfirmationConfiguration( + confirmButton = ConfirmButton() + ) ) ) )