From a73f8c024324b11c0e3a87375eb51a016fa261e8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 07:47:46 +0000 Subject: [PATCH 001/255] Update hilt_version to v2.50 --- dependencies.gradle | 2 +- gradle/verification-metadata.xml | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 8e986e6324..12ac72ca15 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -23,7 +23,7 @@ ext { kotlin_version = '1.9.21' detekt_gradle_plugin_version = "1.23.4" dokka_version = "1.9.10" - hilt_version = "2.49" + hilt_version = "2.50" compose_compiler_version = '1.5.7' // Code quality diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index ad73ab43e2..6beabd7ce6 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5492,6 +5492,14 @@ + + + + + + + + @@ -5532,6 +5540,14 @@ + + + + + + + + @@ -5572,6 +5588,14 @@ + + + + + + + + @@ -5644,6 +5668,14 @@ + + + + + + + + @@ -5684,6 +5716,14 @@ + + + + + + + + @@ -5724,6 +5764,14 @@ + + + + + + + + @@ -5764,6 +5812,14 @@ + + + + + + + + @@ -5804,6 +5860,14 @@ + + + + + + + + @@ -5829,6 +5893,11 @@ + + + + + From 8f30716fab4f878353c90f9f6f39aba85b7baff3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 09:37:13 +0000 Subject: [PATCH 002/255] Update actions/setup-java action to v4 --- .github/workflows/assemble.yml | 2 +- .github/workflows/check_release.yml | 2 +- .github/workflows/code_analysis.yml | 4 ++-- .github/workflows/publish_docs.yml | 2 +- .github/workflows/publish_release.yml | 2 +- .github/workflows/run_tests.yml | 4 ++-- .github/workflows/sonar_cloud.yml | 2 +- .github/workflows/update_verification_metadata.yml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/assemble.yml b/.github/workflows/assemble.yml index ddf64463e6..2795869d2c 100644 --- a/.github/workflows/assemble.yml +++ b/.github/workflows/assemble.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/check_release.yml b/.github/workflows/check_release.yml index fa4bcfcea2..fedb53cce3 100644 --- a/.github/workflows/check_release.yml +++ b/.github/workflows/check_release.yml @@ -20,7 +20,7 @@ jobs: # Setup Java 17 # https://github.com/marketplace/actions/setup-java-jdk - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index a9f947c96f..552daf7cd8 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 @@ -32,7 +32,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml index a9785155b0..0aaf928ebf 100644 --- a/.github/workflows/publish_docs.yml +++ b/.github/workflows/publish_docs.yml @@ -19,7 +19,7 @@ jobs: # Setup Java 17 # https://github.com/marketplace/actions/setup-java-jdk - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index 7fe8eaeb22..0ee9a8f674 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -17,7 +17,7 @@ jobs: ref: main - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 5220997b56..28e21ff83d 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 @@ -37,7 +37,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/sonar_cloud.yml b/.github/workflows/sonar_cloud.yml index e6f9d7acd6..4a4bf2d4ec 100644 --- a/.github/workflows/sonar_cloud.yml +++ b/.github/workflows/sonar_cloud.yml @@ -14,7 +14,7 @@ jobs: fetch-depth: '0' - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/update_verification_metadata.yml b/.github/workflows/update_verification_metadata.yml index ece0fc2ff0..a14782b84d 100644 --- a/.github/workflows/update_verification_metadata.yml +++ b/.github/workflows/update_verification_metadata.yml @@ -14,7 +14,7 @@ jobs: ref: ${{ github.head_ref }} - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 From e96b1dfca552e1b4b5efe7e8fdd4368fd46e7c81 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:45:52 +0000 Subject: [PATCH 003/255] Update dependency com.google.android.material:material to v1.11.0 --- dependencies.gradle | 2 +- gradle/verification-metadata.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 12ac72ca15..4c3a465d85 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -39,7 +39,7 @@ ext { coroutines_version = "1.6.4" fragment_version = "1.6.2" lifecycle_version = "2.5.1" - material_version = "1.10.0" + material_version = "1.11.0" recyclerview_version = "1.3.2" constraintlayout_version = '2.1.4' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 6beabd7ce6..5d043871bf 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5303,6 +5303,14 @@ + + + + + + + + From 4a146154c3f41e7d25a626d9b77cddef4b601d39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 11:24:54 +0000 Subject: [PATCH 004/255] Update dependency androidx.activity:activity-compose to v1.8.2 --- dependencies.gradle | 2 +- gradle/verification-metadata.xml | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 4c3a465d85..a60df1546c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -44,7 +44,7 @@ ext { constraintlayout_version = '2.1.4' // Compose Dependencies - compose_activity_version = '1.8.1' + compose_activity_version = '1.8.2' compose_bom_version = '2023.10.01' compose_hilt_version = '1.1.0' compose_viewmodel_version = '2.6.2' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 5d043871bf..63e35b3fca 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -89,6 +89,14 @@ + + + + + + + + @@ -121,6 +129,14 @@ + + + + + + + + @@ -187,6 +203,14 @@ + + + + + + + + From 6e4cf96f66f5e4c2ae53fcd0fc97ece778e02951 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:07:42 +0000 Subject: [PATCH 005/255] Update dependency androidx.annotation:annotation to v1.7.1 --- dependencies.gradle | 2 +- gradle/verification-metadata.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index a60df1546c..7ee39aafcc 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -33,7 +33,7 @@ ext { sonarqube_version = '4.4.1.3373' // Android Dependencies - annotation_version = "1.7.0" + annotation_version = "1.7.1" appcompat_version = "1.6.1" browser_version = "1.7.0" coroutines_version = "1.6.4" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 63e35b3fca..ad346bc074 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -267,6 +267,14 @@ + + + + + + + + @@ -312,6 +320,14 @@ + + + + + + + + From 7bfd121cc5b3f72e4d54e517f71af47e26a5a5f7 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 21 Dec 2023 10:19:45 +0100 Subject: [PATCH 006/255] Add Multibanco as a supported voucher payment method COAND-372 --- .../adyen/checkout/components/core/PaymentMethodTypes.kt | 4 ++-- .../qrcode/internal/ui/model/QRCodePaymentMethodConfig.kt | 2 +- .../voucher/internal/provider/VoucherComponentProvider.kt | 3 ++- .../checkout/voucher/internal/ui/VoucherViewProvider.kt | 6 ++++-- .../voucher/internal/ui/model/VoucherPaymentMethodConfig.kt | 5 +++++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt b/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt index db25896506..ed9101b9b7 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt @@ -56,6 +56,7 @@ object PaymentMethodTypes { const val PIX = "pix" const val PROMPT_PAY = "promptpay" const val WECHAT_PAY_SDK = "wechatpaySDK" + const val MULTIBANCO = "multibanco" // Voucher payment methods that are not yet supported const val DOKU = "doku" @@ -79,7 +80,6 @@ object PaymentMethodTypes { const val ECONTEXT_ONLINE = "econtext_online" const val ECONTEXT_SEVEN_ELEVEN = "econtext_seven_eleven" const val ECONTEXT_STORES = "econtext_stores" - const val MULTIBANCO = "multibanco" const val OXXO = "oxxo" // Payment methods that might be interpreted as redirect, but are actually not supported @@ -137,6 +137,7 @@ object PaymentMethodTypes { PIX, PROMPT_PAY, WECHAT_PAY_SDK, + MULTIBANCO, ) // Payment methods that are explicitly unsupported @@ -164,7 +165,6 @@ object PaymentMethodTypes { ECONTEXT_ONLINE, ECONTEXT_SEVEN_ELEVEN, ECONTEXT_STORES, - MULTIBANCO, OXXO, WECHAT_PAY_MINI_PROGRAM, WECHAT_PAY_QR, diff --git a/qr-code/src/main/java/com/adyen/checkout/qrcode/internal/ui/model/QRCodePaymentMethodConfig.kt b/qr-code/src/main/java/com/adyen/checkout/qrcode/internal/ui/model/QRCodePaymentMethodConfig.kt index cff159f0b7..822dd544dd 100644 --- a/qr-code/src/main/java/com/adyen/checkout/qrcode/internal/ui/model/QRCodePaymentMethodConfig.kt +++ b/qr-code/src/main/java/com/adyen/checkout/qrcode/internal/ui/model/QRCodePaymentMethodConfig.kt @@ -54,7 +54,7 @@ internal enum class QRCodePaymentMethodConfig( companion object { fun getByPaymentMethodType(paymentMethodType: String): QRCodePaymentMethodConfig { - return values().firstOrNull { it.paymentMethodType == paymentMethodType } ?: DEFAULT + return entries.firstOrNull { it.paymentMethodType == paymentMethodType } ?: DEFAULT } } } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/provider/VoucherComponentProvider.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/provider/VoucherComponentProvider.kt index 13f3dc0e02..04a03240bc 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/provider/VoucherComponentProvider.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/provider/VoucherComponentProvider.kt @@ -97,7 +97,8 @@ constructor( PaymentMethodTypes.BOLETOBANCARIO_HSBC, PaymentMethodTypes.BOLETOBANCARIO_ITAU, PaymentMethodTypes.BOLETOBANCARIO_SANTANDER, - PaymentMethodTypes.BOLETO_PRIMEIRO_PAY + PaymentMethodTypes.BOLETO_PRIMEIRO_PAY, + PaymentMethodTypes.MULTIBANCO ) } } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt index 116009c189..d4f16c32a1 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt @@ -12,6 +12,8 @@ import android.content.Context import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.ViewProvider +import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.FULL_VOUCHER +import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.SIMPLE_VOUCHER import com.adyen.checkout.voucher.internal.ui.view.FullVoucherView import com.adyen.checkout.voucher.internal.ui.view.VoucherView @@ -22,8 +24,8 @@ internal object VoucherViewProvider : ViewProvider { context: Context, ): ComponentView { return when (viewType) { - VoucherComponentViewType.SIMPLE_VOUCHER -> VoucherView(context) - VoucherComponentViewType.FULL_VOUCHER -> FullVoucherView(context) + SIMPLE_VOUCHER -> VoucherView(context) + FULL_VOUCHER -> FullVoucherView(context) else -> throw IllegalArgumentException("Unsupported view type") } } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt index 4cce19ad75..819a6ad990 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt @@ -20,6 +20,9 @@ internal enum class VoucherPaymentMethodConfig( ), BOLETO( viewType = VoucherComponentViewType.FULL_VOUCHER, + ), + MULTIBANCO( + viewType = VoucherComponentViewType.FULL_VOUCHER, ); companion object { @@ -36,6 +39,8 @@ internal enum class VoucherPaymentMethodConfig( PaymentMethodTypes.BOLETOBANCARIO_SANTANDER, PaymentMethodTypes.BOLETO_PRIMEIRO_PAY -> BOLETO + PaymentMethodTypes.MULTIBANCO -> MULTIBANCO + else -> null } } From b6eed65a4d204d80f15a16d7f2cffa4cbdde403c Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 21 Dec 2023 15:27:39 +0100 Subject: [PATCH 007/255] Separate Boleto voucher from full screen voucher to keep the implementation backward compatible. Add a comment that the Boleto style is deprecated. COAND-372 diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt index e6dcf605e..98ef5ffb0 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt @@ -74,21 +74,23 @@ internal class DefaultVoucherDelegate( return } - val viewType = VoucherPaymentMethodConfig.getByPaymentMethodType(action.paymentMethodType)?.viewType - - if (viewType == null) { + val config = VoucherPaymentMethodConfig.getByPaymentMethodType(action.paymentMethodType) + if (config == null) { exceptionChannel.trySend( ComponentException("Payment method ${action.paymentMethodType} not supported for this action") ) return } - _viewFlow.tryEmit(viewType) + _viewFlow.tryEmit(config.viewType) - createOutputData(action) + createOutputData(action, config) } - private fun createOutputData(action: VoucherAction) { + private fun createOutputData( + action: VoucherAction, + config: VoucherPaymentMethodConfig + ) { val outputData = VoucherOutputData( isValid = true, paymentMethodType = action.paymentMethodType, @@ -97,6 +99,7 @@ internal class DefaultVoucherDelegate( expiresAt = action.expiresAt, reference = action.reference, totalAmount = action.totalAmount, + introductionTextResource = config.introductionTextResource ) _outputDataFlow.tryEmit(outputData) } @@ -107,7 +110,8 @@ internal class DefaultVoucherDelegate( downloadUrl = null, expiresAt = null, reference = null, - totalAmount = null + totalAmount = null, + introductionTextResource = null, ) override fun downloadVoucher(context: Context) { diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt index d4f16c32a..c81aa4c3a 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt @@ -12,8 +12,10 @@ import android.content.Context import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.ViewProvider +import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.BOLETO_VOUCHER import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.FULL_VOUCHER import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.SIMPLE_VOUCHER +import com.adyen.checkout.voucher.internal.ui.view.BoletoVoucherView import com.adyen.checkout.voucher.internal.ui.view.FullVoucherView import com.adyen.checkout.voucher.internal.ui.view.VoucherView @@ -25,6 +27,7 @@ internal object VoucherViewProvider : ViewProvider { ): ComponentView { return when (viewType) { SIMPLE_VOUCHER -> VoucherView(context) + BOLETO_VOUCHER -> BoletoVoucherView(context) FULL_VOUCHER -> FullVoucherView(context) else -> throw IllegalArgumentException("Unsupported view type") } @@ -32,8 +35,7 @@ internal object VoucherViewProvider : ViewProvider { } internal enum class VoucherComponentViewType : ComponentViewType { - SIMPLE_VOUCHER, - FULL_VOUCHER; + SIMPLE_VOUCHER, BOLETO_VOUCHER, FULL_VOUCHER; override val viewProvider: ViewProvider = VoucherViewProvider } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt index d69877680..9d0c5be6d 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt @@ -20,4 +20,5 @@ data class VoucherOutputData( val expiresAt: String?, val reference: String?, val totalAmount: Amount?, + val introductionTextResource: Int?, ) : OutputData diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt index 819a6ad99..e367b9f3f 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt @@ -8,21 +8,29 @@ package com.adyen.checkout.voucher.internal.ui.model +import androidx.annotation.StringRes import com.adyen.checkout.components.core.PaymentMethodTypes +import com.adyen.checkout.voucher.R import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType internal enum class VoucherPaymentMethodConfig( val viewType: VoucherComponentViewType, + // TODO: If we do not want to introduce braking changes, then this should become style, instead of text resource. Which I do not like. + @StringRes val introductionTextResource: Int?, ) { BACS( viewType = VoucherComponentViewType.SIMPLE_VOUCHER, + introductionTextResource = R.string.checkout_voucher_introduction_bacs, ), BOLETO( - viewType = VoucherComponentViewType.FULL_VOUCHER, + viewType = VoucherComponentViewType.BOLETO_VOUCHER, + introductionTextResource = null, ), MULTIBANCO( viewType = VoucherComponentViewType.FULL_VOUCHER, + // TODO: To be changed to checkout_voucher_introduction + introductionTextResource = R.string.checkout_voucher_introduction_boleto, ); companion object { diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt new file mode 100644 index 000000000..ccfeae266 --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ararat on 21/12/2023. + */ + +package com.adyen.checkout.voucher.internal.ui.view + +import android.content.Context +import android.util.AttributeSet +import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle +import com.adyen.checkout.voucher.R +import kotlinx.coroutines.CoroutineScope + +// TODO: After removing BoletoVoucherView, make sure to make FullVoucherView non open, binding to private and remove Bolet styles. +class BoletoVoucherView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FullVoucherView(context, attrs, defStyleAttr) { + override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { + super.initView(delegate, coroutineScope, localizedContext) + + binding.textViewIntroduction.setLocalizedTextFromStyle( + R.style.AdyenCheckout_Voucher_Description_Boleto, + localizedContext + ) + } +} diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt index b31152c87..d4d7da176 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt @@ -12,6 +12,7 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.view.View +import androidx.annotation.StringRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import com.adyen.checkout.components.core.Amount @@ -35,7 +36,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") -class FullVoucherView @JvmOverloads constructor( +open class FullVoucherView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 @@ -47,7 +48,7 @@ class FullVoucherView @JvmOverloads constructor( ), ComponentView { - private val binding: FullVoucherViewBinding = FullVoucherViewBinding.inflate(LayoutInflater.from(context), this) + protected val binding: FullVoucherViewBinding = FullVoucherViewBinding.inflate(LayoutInflater.from(context), this) private lateinit var localizedContext: Context @@ -55,7 +56,7 @@ class FullVoucherView @JvmOverloads constructor( init { val padding = resources.getDimension(R.dimen.standard_margin).toInt() - setPadding(padding, padding, padding, padding) + this.setPadding(padding, padding, padding, padding) } override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { @@ -73,10 +74,6 @@ class FullVoucherView @JvmOverloads constructor( } private fun initLocalizedStrings(localizedContext: Context) { - binding.textViewIntroduction.setLocalizedTextFromStyle( - R.style.AdyenCheckout_Voucher_Description_Boleto, - localizedContext - ) binding.textViewPaymentReference.setLocalizedTextFromStyle( R.style.AdyenCheckout_Voucher_PaymentReference, localizedContext @@ -105,6 +102,7 @@ class FullVoucherView @JvmOverloads constructor( Logger.d(TAG, "outputDataChanged") loadLogo(outputData.paymentMethodType) + updateIntroductionText(outputData.introductionTextResource) updateAmount(outputData.totalAmount) updateCodeReference(outputData.reference) updateExpirationDate(outputData.expiresAt) @@ -120,6 +118,11 @@ class FullVoucherView @JvmOverloads constructor( } } + private fun updateIntroductionText(@StringRes introductionTextResource: Int?) { + if (introductionTextResource == null) return + binding.textViewIntroduction.text = localizedContext.getString(introductionTextResource) + } + private fun updateAmount(amount: Amount?) { if (amount != null && !amount.isEmpty) { val formattedAmount = CurrencyUtils.formatAmount( diff --git a/voucher/src/main/res/layout/full_voucher_view.xml b/voucher/src/main/res/layout/full_voucher_view.xml index b5bc08f05..186c74f6b 100644 --- a/voucher/src/main/res/layout/full_voucher_view.xml +++ b/voucher/src/main/res/layout/full_voucher_view.xml @@ -35,7 +35,7 @@ center_horizontal + + + --- .../internal/ui/DefaultVoucherDelegate.kt | 18 +++++++---- .../internal/ui/VoucherViewProvider.kt | 6 ++-- .../internal/ui/model/VoucherOutputData.kt | 1 + .../ui/model/VoucherPaymentMethodConfig.kt | 10 +++++- .../internal/ui/view/BoletoVoucherView.kt | 32 +++++++++++++++++++ .../internal/ui/view/FullVoucherView.kt | 17 ++++++---- .../src/main/res/layout/full_voucher_view.xml | 2 +- voucher/src/main/res/values/styles.xml | 10 ++++++ 8 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt index e6dcf605ea..98ef5ffb07 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt @@ -74,21 +74,23 @@ internal class DefaultVoucherDelegate( return } - val viewType = VoucherPaymentMethodConfig.getByPaymentMethodType(action.paymentMethodType)?.viewType - - if (viewType == null) { + val config = VoucherPaymentMethodConfig.getByPaymentMethodType(action.paymentMethodType) + if (config == null) { exceptionChannel.trySend( ComponentException("Payment method ${action.paymentMethodType} not supported for this action") ) return } - _viewFlow.tryEmit(viewType) + _viewFlow.tryEmit(config.viewType) - createOutputData(action) + createOutputData(action, config) } - private fun createOutputData(action: VoucherAction) { + private fun createOutputData( + action: VoucherAction, + config: VoucherPaymentMethodConfig + ) { val outputData = VoucherOutputData( isValid = true, paymentMethodType = action.paymentMethodType, @@ -97,6 +99,7 @@ internal class DefaultVoucherDelegate( expiresAt = action.expiresAt, reference = action.reference, totalAmount = action.totalAmount, + introductionTextResource = config.introductionTextResource ) _outputDataFlow.tryEmit(outputData) } @@ -107,7 +110,8 @@ internal class DefaultVoucherDelegate( downloadUrl = null, expiresAt = null, reference = null, - totalAmount = null + totalAmount = null, + introductionTextResource = null, ) override fun downloadVoucher(context: Context) { diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt index d4f16c32a1..c81aa4c3a3 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt @@ -12,8 +12,10 @@ import android.content.Context import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.ViewProvider +import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.BOLETO_VOUCHER import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.FULL_VOUCHER import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.SIMPLE_VOUCHER +import com.adyen.checkout.voucher.internal.ui.view.BoletoVoucherView import com.adyen.checkout.voucher.internal.ui.view.FullVoucherView import com.adyen.checkout.voucher.internal.ui.view.VoucherView @@ -25,6 +27,7 @@ internal object VoucherViewProvider : ViewProvider { ): ComponentView { return when (viewType) { SIMPLE_VOUCHER -> VoucherView(context) + BOLETO_VOUCHER -> BoletoVoucherView(context) FULL_VOUCHER -> FullVoucherView(context) else -> throw IllegalArgumentException("Unsupported view type") } @@ -32,8 +35,7 @@ internal object VoucherViewProvider : ViewProvider { } internal enum class VoucherComponentViewType : ComponentViewType { - SIMPLE_VOUCHER, - FULL_VOUCHER; + SIMPLE_VOUCHER, BOLETO_VOUCHER, FULL_VOUCHER; override val viewProvider: ViewProvider = VoucherViewProvider } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt index d69877680f..9d0c5be6de 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt @@ -20,4 +20,5 @@ data class VoucherOutputData( val expiresAt: String?, val reference: String?, val totalAmount: Amount?, + val introductionTextResource: Int?, ) : OutputData diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt index 819a6ad990..e367b9f3fb 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt @@ -8,21 +8,29 @@ package com.adyen.checkout.voucher.internal.ui.model +import androidx.annotation.StringRes import com.adyen.checkout.components.core.PaymentMethodTypes +import com.adyen.checkout.voucher.R import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType internal enum class VoucherPaymentMethodConfig( val viewType: VoucherComponentViewType, + // TODO: If we do not want to introduce braking changes, then this should become style, instead of text resource. Which I do not like. + @StringRes val introductionTextResource: Int?, ) { BACS( viewType = VoucherComponentViewType.SIMPLE_VOUCHER, + introductionTextResource = R.string.checkout_voucher_introduction_bacs, ), BOLETO( - viewType = VoucherComponentViewType.FULL_VOUCHER, + viewType = VoucherComponentViewType.BOLETO_VOUCHER, + introductionTextResource = null, ), MULTIBANCO( viewType = VoucherComponentViewType.FULL_VOUCHER, + // TODO: To be changed to checkout_voucher_introduction + introductionTextResource = R.string.checkout_voucher_introduction_boleto, ); companion object { diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt new file mode 100644 index 0000000000..ccfeae2668 --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ararat on 21/12/2023. + */ + +package com.adyen.checkout.voucher.internal.ui.view + +import android.content.Context +import android.util.AttributeSet +import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle +import com.adyen.checkout.voucher.R +import kotlinx.coroutines.CoroutineScope + +// TODO: After removing BoletoVoucherView, make sure to make FullVoucherView non open, binding to private and remove Bolet styles. +class BoletoVoucherView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FullVoucherView(context, attrs, defStyleAttr) { + override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { + super.initView(delegate, coroutineScope, localizedContext) + + binding.textViewIntroduction.setLocalizedTextFromStyle( + R.style.AdyenCheckout_Voucher_Description_Boleto, + localizedContext + ) + } +} diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt index b31152c874..d4d7da1769 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt @@ -12,6 +12,7 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.view.View +import androidx.annotation.StringRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import com.adyen.checkout.components.core.Amount @@ -35,7 +36,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") -class FullVoucherView @JvmOverloads constructor( +open class FullVoucherView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 @@ -47,7 +48,7 @@ class FullVoucherView @JvmOverloads constructor( ), ComponentView { - private val binding: FullVoucherViewBinding = FullVoucherViewBinding.inflate(LayoutInflater.from(context), this) + protected val binding: FullVoucherViewBinding = FullVoucherViewBinding.inflate(LayoutInflater.from(context), this) private lateinit var localizedContext: Context @@ -55,7 +56,7 @@ class FullVoucherView @JvmOverloads constructor( init { val padding = resources.getDimension(R.dimen.standard_margin).toInt() - setPadding(padding, padding, padding, padding) + this.setPadding(padding, padding, padding, padding) } override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { @@ -73,10 +74,6 @@ class FullVoucherView @JvmOverloads constructor( } private fun initLocalizedStrings(localizedContext: Context) { - binding.textViewIntroduction.setLocalizedTextFromStyle( - R.style.AdyenCheckout_Voucher_Description_Boleto, - localizedContext - ) binding.textViewPaymentReference.setLocalizedTextFromStyle( R.style.AdyenCheckout_Voucher_PaymentReference, localizedContext @@ -105,6 +102,7 @@ class FullVoucherView @JvmOverloads constructor( Logger.d(TAG, "outputDataChanged") loadLogo(outputData.paymentMethodType) + updateIntroductionText(outputData.introductionTextResource) updateAmount(outputData.totalAmount) updateCodeReference(outputData.reference) updateExpirationDate(outputData.expiresAt) @@ -120,6 +118,11 @@ class FullVoucherView @JvmOverloads constructor( } } + private fun updateIntroductionText(@StringRes introductionTextResource: Int?) { + if (introductionTextResource == null) return + binding.textViewIntroduction.text = localizedContext.getString(introductionTextResource) + } + private fun updateAmount(amount: Amount?) { if (amount != null && !amount.isEmpty) { val formattedAmount = CurrencyUtils.formatAmount( diff --git a/voucher/src/main/res/layout/full_voucher_view.xml b/voucher/src/main/res/layout/full_voucher_view.xml index b5bc08f05a..186c74f6b9 100644 --- a/voucher/src/main/res/layout/full_voucher_view.xml +++ b/voucher/src/main/res/layout/full_voucher_view.xml @@ -35,7 +35,7 @@ center_horizontal + + + From d51bf9eb4d572f6c74758f548d3ceac95bb3167e Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 21 Dec 2023 15:56:32 +0100 Subject: [PATCH 008/255] Update voucher introduction string key to make it more generic COAND-372 --- .../voucher/internal/ui/model/VoucherPaymentMethodConfig.kt | 2 +- voucher/src/main/res/template/values/strings.xml.tt | 2 +- voucher/src/main/res/values-ar/strings.xml | 2 +- voucher/src/main/res/values-cs-rCZ/strings.xml | 2 +- voucher/src/main/res/values-da-rDK/strings.xml | 2 +- voucher/src/main/res/values-de-rDE/strings.xml | 2 +- voucher/src/main/res/values-el-rGR/strings.xml | 2 +- voucher/src/main/res/values-es-rES/strings.xml | 2 +- voucher/src/main/res/values-fi-rFI/strings.xml | 2 +- voucher/src/main/res/values-fr-rFR/strings.xml | 2 +- voucher/src/main/res/values-hr-rHR/strings.xml | 2 +- voucher/src/main/res/values-hu-rHU/strings.xml | 2 +- voucher/src/main/res/values-it-rIT/strings.xml | 2 +- voucher/src/main/res/values-ja-rJP/strings.xml | 2 +- voucher/src/main/res/values-ko-rKR/strings.xml | 2 +- voucher/src/main/res/values-nb-rNO/strings.xml | 2 +- voucher/src/main/res/values-nl-rNL/strings.xml | 2 +- voucher/src/main/res/values-pl-rPL/strings.xml | 2 +- voucher/src/main/res/values-pt-rBR/strings.xml | 2 +- voucher/src/main/res/values-pt-rPT/strings.xml | 2 +- voucher/src/main/res/values-ro-rRO/strings.xml | 2 +- voucher/src/main/res/values-ru-rRU/strings.xml | 2 +- voucher/src/main/res/values-sk-rSK/strings.xml | 2 +- voucher/src/main/res/values-sl-rSI/strings.xml | 2 +- voucher/src/main/res/values-sv-rSE/strings.xml | 2 +- voucher/src/main/res/values-zh-rCN/strings.xml | 2 +- voucher/src/main/res/values-zh-rTW/strings.xml | 2 +- voucher/src/main/res/values/strings.xml | 2 +- voucher/src/main/res/values/styles.xml | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt index e367b9f3fb..f6060445ce 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt @@ -30,7 +30,7 @@ internal enum class VoucherPaymentMethodConfig( MULTIBANCO( viewType = VoucherComponentViewType.FULL_VOUCHER, // TODO: To be changed to checkout_voucher_introduction - introductionTextResource = R.string.checkout_voucher_introduction_boleto, + introductionTextResource = R.string.checkout_voucher_introduction, ); companion object { diff --git a/voucher/src/main/res/template/values/strings.xml.tt b/voucher/src/main/res/template/values/strings.xml.tt index 7e5bdd9343..66aafba54c 100644 --- a/voucher/src/main/res/template/values/strings.xml.tt +++ b/voucher/src/main/res/template/values/strings.xml.tt @@ -9,7 +9,7 @@ %%bacs.result.introduction%% - %%voucher.introduction%% + %%voucher.introduction%% %%voucher.paymentReferenceLabel%% %%voucher.expirationDate%% %%pix.instructions.copyButton%% diff --git a/voucher/src/main/res/values-ar/strings.xml b/voucher/src/main/res/values-ar/strings.xml index fd96db990f..1cae394d72 100644 --- a/voucher/src/main/res/values-ar/strings.xml +++ b/voucher/src/main/res/values-ar/strings.xml @@ -9,7 +9,7 @@ تنزيل تعليمات الخصم المباشر (تعليمات / تفويض DDI) - شكرًا لك على شرائك، يرجى استخدام القسيمة التالية لإتمام عملية الدفع. + شكرًا لك على شرائك، يرجى استخدام القسيمة التالية لإتمام عملية الدفع. مرجع الدفع تاريخ الانتهاء نسخ الرمز diff --git a/voucher/src/main/res/values-cs-rCZ/strings.xml b/voucher/src/main/res/values-cs-rCZ/strings.xml index 2a1683587d..91afcf8f49 100644 --- a/voucher/src/main/res/values-cs-rCZ/strings.xml +++ b/voucher/src/main/res/values-cs-rCZ/strings.xml @@ -9,7 +9,7 @@ Stáhněte si pokyny k přímému inkasu (DDI / podpisové právo) - Děkujeme za nákup. K dokončení platby použijte prosím následující kupón. + Děkujeme za nákup. K dokončení platby použijte prosím následující kupón. Číslo platby Datum konce platnosti Kopírovat kód diff --git a/voucher/src/main/res/values-da-rDK/strings.xml b/voucher/src/main/res/values-da-rDK/strings.xml index ae5532daef..f3745a6eab 100644 --- a/voucher/src/main/res/values-da-rDK/strings.xml +++ b/voucher/src/main/res/values-da-rDK/strings.xml @@ -9,7 +9,7 @@ Download vejledningen til direkte debitering (fuldmagt til direkte debitering) - Tak for dit køb. Brug følgende kupon til at gennemføre din betaling. + Tak for dit køb. Brug følgende kupon til at gennemføre din betaling. Betalingsreference Udløbsdato Kopiér koden diff --git a/voucher/src/main/res/values-de-rDE/strings.xml b/voucher/src/main/res/values-de-rDE/strings.xml index b61ae763ff..0fd1beb2c3 100644 --- a/voucher/src/main/res/values-de-rDE/strings.xml +++ b/voucher/src/main/res/values-de-rDE/strings.xml @@ -9,7 +9,7 @@ Laden Sie Ihre Lastschriftanweisung (DDI/Einzugsermächtigung) herunter - Vielen Dank für Ihren Kauf. Bitte schließen Sie Ihre Zahlung unter Verwendung des folgenden Gutscheins ab. + Vielen Dank für Ihren Kauf. Bitte schließen Sie Ihre Zahlung unter Verwendung des folgenden Gutscheins ab. Zahlungsreferenz Gültig bis Code kopieren diff --git a/voucher/src/main/res/values-el-rGR/strings.xml b/voucher/src/main/res/values-el-rGR/strings.xml index 100c2d154a..0190d3e792 100644 --- a/voucher/src/main/res/values-el-rGR/strings.xml +++ b/voucher/src/main/res/values-el-rGR/strings.xml @@ -9,7 +9,7 @@ Κατεβάστε την Εντολή Άμεσης Χρέωσης (DDI/Εντολή) - Σας ευχαριστούμε για την αγορά. Χρησιμοποιήστε το παρακάτω κουπόνι για να ολοκληρώσετε την πληρωμή. + Σας ευχαριστούμε για την αγορά. Χρησιμοποιήστε το παρακάτω κουπόνι για να ολοκληρώσετε την πληρωμή. Αναφορά πληρωμής Ημερομηνία λήξης Αντιγραφή κωδικού diff --git a/voucher/src/main/res/values-es-rES/strings.xml b/voucher/src/main/res/values-es-rES/strings.xml index e626a82277..6a0dc74e4a 100644 --- a/voucher/src/main/res/values-es-rES/strings.xml +++ b/voucher/src/main/res/values-es-rES/strings.xml @@ -9,7 +9,7 @@ Descargue su instrucción de débito directo (IDD/mandato) - Gracias por su compra. Use el siguiente cupón para completar su pago. + Gracias por su compra. Use el siguiente cupón para completar su pago. Referencia de pago Fecha de caducidad Copiar código diff --git a/voucher/src/main/res/values-fi-rFI/strings.xml b/voucher/src/main/res/values-fi-rFI/strings.xml index 2b323b4176..935909f475 100644 --- a/voucher/src/main/res/values-fi-rFI/strings.xml +++ b/voucher/src/main/res/values-fi-rFI/strings.xml @@ -9,7 +9,7 @@ Lataa suoraveloitusohjeet (DDI / Mandate) - Kiitos hankinnastasi, käytä seuraavaa kuponkia viedäksesi maksusi päätökseen. + Kiitos hankinnastasi, käytä seuraavaa kuponkia viedäksesi maksusi päätökseen. Maksun viite Vanhenemispäivämäärä Kopioi koodi diff --git a/voucher/src/main/res/values-fr-rFR/strings.xml b/voucher/src/main/res/values-fr-rFR/strings.xml index 66f08b0925..6178175d7b 100644 --- a/voucher/src/main/res/values-fr-rFR/strings.xml +++ b/voucher/src/main/res/values-fr-rFR/strings.xml @@ -9,7 +9,7 @@ Téléchargez votre mandat de prélèvement (DDI) - Merci pour votre achat, veuillez utiliser le coupon suivant pour finaliser votre paiement. + Merci pour votre achat, veuillez utiliser le coupon suivant pour finaliser votre paiement. Référence du paiement Date d\'expiration Copier le code diff --git a/voucher/src/main/res/values-hr-rHR/strings.xml b/voucher/src/main/res/values-hr-rHR/strings.xml index ea14dd50c9..a207650235 100644 --- a/voucher/src/main/res/values-hr-rHR/strings.xml +++ b/voucher/src/main/res/values-hr-rHR/strings.xml @@ -9,7 +9,7 @@ Preuzmite upute za izravno terećenje (DDI / mandat) - Zahvaljujemo na kupnji, upotrijebite sljedeći kupon za dovršetak plaćanja. + Zahvaljujemo na kupnji, upotrijebite sljedeći kupon za dovršetak plaćanja. Referenca za plaćanje Datum isteka Kopiraj kôd diff --git a/voucher/src/main/res/values-hu-rHU/strings.xml b/voucher/src/main/res/values-hu-rHU/strings.xml index 36f483f75e..042d586e66 100644 --- a/voucher/src/main/res/values-hu-rHU/strings.xml +++ b/voucher/src/main/res/values-hu-rHU/strings.xml @@ -9,7 +9,7 @@ Beszedési megbízási utasítás (meghatalmazás) letöltése - Köszönjük a vásárlást! Kérjük, a fizetéshez használja a következő kupont. + Köszönjük a vásárlást! Kérjük, a fizetéshez használja a következő kupont. Fizetési referencia Lejárati dátum Kód másolása diff --git a/voucher/src/main/res/values-it-rIT/strings.xml b/voucher/src/main/res/values-it-rIT/strings.xml index e7ecba8cb4..a79f3e730c 100644 --- a/voucher/src/main/res/values-it-rIT/strings.xml +++ b/voucher/src/main/res/values-it-rIT/strings.xml @@ -9,7 +9,7 @@ Scarica le Istruzioni per l\'addebito diretto (DDI / Mandato) - Grazie per il tuo acquisto, utilizza il seguente coupon per completare il pagamento. + Grazie per il tuo acquisto, utilizza il seguente coupon per completare il pagamento. Riferimento del pagamento Data di scadenza Copia codice diff --git a/voucher/src/main/res/values-ja-rJP/strings.xml b/voucher/src/main/res/values-ja-rJP/strings.xml index e663229f03..e0f0a42bfc 100644 --- a/voucher/src/main/res/values-ja-rJP/strings.xml +++ b/voucher/src/main/res/values-ja-rJP/strings.xml @@ -9,7 +9,7 @@ 自動引き落としの説明 (DDI/委任状) をダウンロードする - お買い上げありがとうございます。以下のクーポンを使用して、お支払いを完了してください。 + お買い上げありがとうございます。以下のクーポンを使用して、お支払いを完了してください。 支払いの参照 有効期限 コードをコピー diff --git a/voucher/src/main/res/values-ko-rKR/strings.xml b/voucher/src/main/res/values-ko-rKR/strings.xml index e6ccd42b0c..6059b2abc6 100644 --- a/voucher/src/main/res/values-ko-rKR/strings.xml +++ b/voucher/src/main/res/values-ko-rKR/strings.xml @@ -9,7 +9,7 @@ 자동 이체 안내(DDI/필수) 다운로드 - 구매해 주셔서 감사합니다. 다음 쿠폰을 사용하여 결제를 완료하십시오. + 구매해 주셔서 감사합니다. 다음 쿠폰을 사용하여 결제를 완료하십시오. 결제 참조번호 만료일 코드 복사하기 diff --git a/voucher/src/main/res/values-nb-rNO/strings.xml b/voucher/src/main/res/values-nb-rNO/strings.xml index a416da41c9..a308220a5d 100644 --- a/voucher/src/main/res/values-nb-rNO/strings.xml +++ b/voucher/src/main/res/values-nb-rNO/strings.xml @@ -9,7 +9,7 @@ Last ned instruksjoner for direktebelastning (DDI/ mandat) - Takk for ditt kjøp. Vennligst bruk den følgende kupongen til å fullføre betalingen. + Takk for ditt kjøp. Vennligst bruk den følgende kupongen til å fullføre betalingen. Betalingsreferanse Utløpsdato Kopier kode diff --git a/voucher/src/main/res/values-nl-rNL/strings.xml b/voucher/src/main/res/values-nl-rNL/strings.xml index a3bb49e508..aea687d4d8 100644 --- a/voucher/src/main/res/values-nl-rNL/strings.xml +++ b/voucher/src/main/res/values-nl-rNL/strings.xml @@ -9,7 +9,7 @@ Download uw machtiging automatische incasso - Bedankt voor uw aankoop. Gebruik deze coupon om uw betaling te voltooien. + Bedankt voor uw aankoop. Gebruik deze coupon om uw betaling te voltooien. Betalingsreferentie Vervaldatum Code kopiëren diff --git a/voucher/src/main/res/values-pl-rPL/strings.xml b/voucher/src/main/res/values-pl-rPL/strings.xml index ca46547eb7..c1f00ea491 100644 --- a/voucher/src/main/res/values-pl-rPL/strings.xml +++ b/voucher/src/main/res/values-pl-rPL/strings.xml @@ -9,7 +9,7 @@ Pobierz dyspozycję polecenia zapłaty (DDI/upoważnienie) - Dziękujemy za zakup, dokończ płatność przy użyciu tego kuponu. + Dziękujemy za zakup, dokończ płatność przy użyciu tego kuponu. Nr referencyjny płatności Data ważności Skopiuj kod diff --git a/voucher/src/main/res/values-pt-rBR/strings.xml b/voucher/src/main/res/values-pt-rBR/strings.xml index 5492175b15..f0ecf64703 100644 --- a/voucher/src/main/res/values-pt-rBR/strings.xml +++ b/voucher/src/main/res/values-pt-rBR/strings.xml @@ -9,7 +9,7 @@ Baixar instrução de débito direto (DDI) - Obrigado pela sua compra, use o cupom a seguir para concluir o seu pagamento. + Obrigado pela sua compra, use o cupom a seguir para concluir o seu pagamento. Referência de pagamento Data de validade Copiar código diff --git a/voucher/src/main/res/values-pt-rPT/strings.xml b/voucher/src/main/res/values-pt-rPT/strings.xml index 2aa1cdad24..5b363d8aab 100644 --- a/voucher/src/main/res/values-pt-rPT/strings.xml +++ b/voucher/src/main/res/values-pt-rPT/strings.xml @@ -9,7 +9,7 @@ Descarregue a sua Instrução de Débito Direto (DDI / Mandato) - Obrigado pela sua compra, utilize o seguinte cupão para completar o seu pagamento. + Obrigado pela sua compra, utilize o seguinte cupão para completar o seu pagamento. Referência de pagamento Data de validade Copiar código diff --git a/voucher/src/main/res/values-ro-rRO/strings.xml b/voucher/src/main/res/values-ro-rRO/strings.xml index ce0d6da110..105eb9567e 100644 --- a/voucher/src/main/res/values-ro-rRO/strings.xml +++ b/voucher/src/main/res/values-ro-rRO/strings.xml @@ -9,7 +9,7 @@ Descărcați instrucțiunile de debitare directă (DDI/mandat) - Vă mulțumim pentru cumpărături, vă rugăm să utilizați următorul cupon pentru a vă finaliza plata. + Vă mulțumim pentru cumpărături, vă rugăm să utilizați următorul cupon pentru a vă finaliza plata. Referința plății Data de expirare Copiați codul diff --git a/voucher/src/main/res/values-ru-rRU/strings.xml b/voucher/src/main/res/values-ru-rRU/strings.xml index 09e168abcc..ada3a554c6 100644 --- a/voucher/src/main/res/values-ru-rRU/strings.xml +++ b/voucher/src/main/res/values-ru-rRU/strings.xml @@ -9,7 +9,7 @@ Загрузить распоряжение прямого дебетования (DDI / поручение) - Благодарим за покупку. Для завершения оплаты используйте следующий купон. + Благодарим за покупку. Для завершения оплаты используйте следующий купон. Код оплаты Срок действия Скопировать код diff --git a/voucher/src/main/res/values-sk-rSK/strings.xml b/voucher/src/main/res/values-sk-rSK/strings.xml index b904c77969..da1b44b348 100644 --- a/voucher/src/main/res/values-sk-rSK/strings.xml +++ b/voucher/src/main/res/values-sk-rSK/strings.xml @@ -9,7 +9,7 @@ Stiahnite si pokyny k inkasu (DDI/Mandát) - Ďakujeme vám za nákup; na dokončenie platby použite nasledujúci kupón. + Ďakujeme vám za nákup; na dokončenie platby použite nasledujúci kupón. Platobná referencia Dátum vypršania platnosti Skopírovať kód diff --git a/voucher/src/main/res/values-sl-rSI/strings.xml b/voucher/src/main/res/values-sl-rSI/strings.xml index 0d4b45416b..0c37131f36 100644 --- a/voucher/src/main/res/values-sl-rSI/strings.xml +++ b/voucher/src/main/res/values-sl-rSI/strings.xml @@ -9,7 +9,7 @@ Prenesite navodila za neposredno bremenitev (DDI/mandat) - Zahvaljujemo se vam za nakup. Za dokončanje plačila uporabite naslednji kupon. + Zahvaljujemo se vam za nakup. Za dokončanje plačila uporabite naslednji kupon. Referenčna številka plačila Datum poteka veljavnosti Kopiraj kodo diff --git a/voucher/src/main/res/values-sv-rSE/strings.xml b/voucher/src/main/res/values-sv-rSE/strings.xml index 5e09b49e2a..6e6ea30a80 100644 --- a/voucher/src/main/res/values-sv-rSE/strings.xml +++ b/voucher/src/main/res/values-sv-rSE/strings.xml @@ -9,7 +9,7 @@ Ladda ner din instruktion för autogiro/direktdebitering (DDI / Mandate) - Tack för ditt köp, vänligen använd följande kupong för att slutföra din betalning. + Tack för ditt köp, vänligen använd följande kupong för att slutföra din betalning. Betalreferens Utgångsdatum Kopiera kod diff --git a/voucher/src/main/res/values-zh-rCN/strings.xml b/voucher/src/main/res/values-zh-rCN/strings.xml index f9064b9f5b..d54e383b90 100644 --- a/voucher/src/main/res/values-zh-rCN/strings.xml +++ b/voucher/src/main/res/values-zh-rCN/strings.xml @@ -9,7 +9,7 @@ 下载您的直接借记指示(DDI/委托) - 感谢您的购买,请使用以下优惠券完成支付。 + 感谢您的购买,请使用以下优惠券完成支付。 交易号 有效期 复制代码 diff --git a/voucher/src/main/res/values-zh-rTW/strings.xml b/voucher/src/main/res/values-zh-rTW/strings.xml index 9f176d3d0e..e46f1bc3f1 100644 --- a/voucher/src/main/res/values-zh-rTW/strings.xml +++ b/voucher/src/main/res/values-zh-rTW/strings.xml @@ -9,7 +9,7 @@ 下載您的直接扣款指示(DDI/授權) - 多謝惠顧,請使用以下優惠券完成付款。 + 多謝惠顧,請使用以下優惠券完成付款。 付款參照號碼 到期日期 複製代碼 diff --git a/voucher/src/main/res/values/strings.xml b/voucher/src/main/res/values/strings.xml index 840f53f17a..752b16ab0a 100644 --- a/voucher/src/main/res/values/strings.xml +++ b/voucher/src/main/res/values/strings.xml @@ -9,7 +9,7 @@ Download your Direct Debit Instruction (DDI / Mandate) - Thank you for your purchase, please use the following coupon to complete your payment. + Thank you for your purchase, please use the following coupon to complete your payment. Payment Reference Expiration Date Copy code diff --git a/voucher/src/main/res/values/styles.xml b/voucher/src/main/res/values/styles.xml index c55f194655..11905caa6e 100644 --- a/voucher/src/main/res/values/styles.xml +++ b/voucher/src/main/res/values/styles.xml @@ -27,7 +27,7 @@ @dimen/standard_double_margin @dimen/standard_double_margin @dimen/standard_one_half_margin - @string/checkout_voucher_introduction_boleto + @string/checkout_voucher_introduction center_horizontal From 97f4facb692218f3acccd2b11990e8639764ddb9 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Fri, 22 Dec 2023 10:38:05 +0100 Subject: [PATCH 009/255] Separate Bacs voucher from simple voucher to keep the implementation backward compatible. Add a comment that the Bacs style is deprecated. COAND-372 diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt index c81aa4c3a..9a817a789 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/VoucherViewProvider.kt @@ -12,9 +12,11 @@ import android.content.Context import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.ViewProvider +import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.BACS_VOUCHER import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.BOLETO_VOUCHER import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.FULL_VOUCHER import com.adyen.checkout.voucher.internal.ui.VoucherComponentViewType.SIMPLE_VOUCHER +import com.adyen.checkout.voucher.internal.ui.view.BacsVoucherView import com.adyen.checkout.voucher.internal.ui.view.BoletoVoucherView import com.adyen.checkout.voucher.internal.ui.view.FullVoucherView import com.adyen.checkout.voucher.internal.ui.view.VoucherView @@ -26,6 +28,7 @@ internal object VoucherViewProvider : ViewProvider { context: Context, ): ComponentView { return when (viewType) { + BACS_VOUCHER -> BacsVoucherView(context) SIMPLE_VOUCHER -> VoucherView(context) BOLETO_VOUCHER -> BoletoVoucherView(context) FULL_VOUCHER -> FullVoucherView(context) @@ -35,7 +38,7 @@ internal object VoucherViewProvider : ViewProvider { } internal enum class VoucherComponentViewType : ComponentViewType { - SIMPLE_VOUCHER, BOLETO_VOUCHER, FULL_VOUCHER; + BACS_VOUCHER, SIMPLE_VOUCHER, BOLETO_VOUCHER, FULL_VOUCHER; override val viewProvider: ViewProvider = VoucherViewProvider } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt index f6060445c..5d77a326b 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherPaymentMethodConfig.kt @@ -20,8 +20,8 @@ internal enum class VoucherPaymentMethodConfig( ) { BACS( - viewType = VoucherComponentViewType.SIMPLE_VOUCHER, - introductionTextResource = R.string.checkout_voucher_introduction_bacs, + viewType = VoucherComponentViewType.BACS_VOUCHER, + introductionTextResource = null, ), BOLETO( viewType = VoucherComponentViewType.BOLETO_VOUCHER, diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BacsVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BacsVoucherView.kt new file mode 100644 index 000000000..0b70e6dae --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BacsVoucherView.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ararat on 21/12/2023. + */ + +package com.adyen.checkout.voucher.internal.ui.view + +import android.content.Context +import android.util.AttributeSet +import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle +import com.adyen.checkout.voucher.R +import kotlinx.coroutines.CoroutineScope + +// TODO: After removing BacsVoucherView, make sure to make SimpleVoucherView non open, binding to private and remove Bacs styles. +internal class BacsVoucherView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : VoucherView(context, attrs, defStyleAttr) { + override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { + super.initView(delegate, coroutineScope, localizedContext) + + binding.textViewDescription.setLocalizedTextFromStyle( + R.style.AdyenCheckout_Voucher_Description_Bacs, + localizedContext + ) + } +} diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt index ccfeae266..24582769a 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt @@ -16,7 +16,7 @@ import com.adyen.checkout.voucher.R import kotlinx.coroutines.CoroutineScope // TODO: After removing BoletoVoucherView, make sure to make FullVoucherView non open, binding to private and remove Bolet styles. -class BoletoVoucherView @JvmOverloads constructor( +internal class BoletoVoucherView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt index d4d7da176..2525669b8 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt @@ -36,7 +36,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") -open class FullVoucherView @JvmOverloads constructor( +internal open class FullVoucherView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/VoucherView.kt index de86c6de4..36d421028 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/VoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/VoucherView.kt @@ -13,6 +13,7 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout +import androidx.annotation.StringRes import com.adyen.checkout.components.core.internal.ui.ComponentDelegate import com.adyen.checkout.core.internal.util.LogUtil import com.adyen.checkout.core.internal.util.Logger @@ -28,7 +29,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -internal class VoucherView @JvmOverloads constructor( +internal open class VoucherView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 @@ -40,7 +41,7 @@ internal class VoucherView @JvmOverloads constructor( ), ComponentView { - private val binding: VoucherViewBinding = VoucherViewBinding.inflate(LayoutInflater.from(context), this) + protected val binding: VoucherViewBinding = VoucherViewBinding.inflate(LayoutInflater.from(context), this) private lateinit var localizedContext: Context @@ -49,7 +50,7 @@ internal class VoucherView @JvmOverloads constructor( init { orientation = VERTICAL val padding = resources.getDimension(R.dimen.standard_margin).toInt() - setPadding(padding, padding, padding, padding) + this.setPadding(padding, padding, padding, padding) } override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { @@ -66,10 +67,6 @@ internal class VoucherView @JvmOverloads constructor( } private fun initLocalizedStrings(localizedContext: Context) { - binding.textViewDescription.setLocalizedTextFromStyle( - R.style.AdyenCheckout_Voucher_Description_Bacs, - localizedContext - ) binding.textViewDownload.setLocalizedTextFromStyle( R.style.AdyenCheckout_Voucher_DownloadTextAppearance, localizedContext @@ -85,6 +82,7 @@ internal class VoucherView @JvmOverloads constructor( private fun outputDataChanged(outputData: VoucherOutputData) { Logger.d(TAG, "outputDataChanged") loadLogo(outputData.paymentMethodType) + updateIntroductionText(outputData.introductionTextResource) } private fun loadLogo(paymentMethodType: String?) { @@ -97,6 +95,11 @@ internal class VoucherView @JvmOverloads constructor( } } + private fun updateIntroductionText(@StringRes introductionTextResource: Int?) { + if (introductionTextResource == null) return + binding.textViewDescription.text = localizedContext.getString(introductionTextResource) + } + override fun highlightValidationErrors() { // No validation required } diff --git a/voucher/src/main/res/layout/voucher_view.xml b/voucher/src/main/res/layout/voucher_view.xml index 09bbf0daf..688b3ed21 100644 --- a/voucher/src/main/res/layout/voucher_view.xml +++ b/voucher/src/main/res/layout/voucher_view.xml @@ -22,7 +22,7 @@ diff --git a/voucher/src/main/res/values/styles.xml b/voucher/src/main/res/values/styles.xml index 11905caa6..2cc001f87 100644 --- a/voucher/src/main/res/values/styles.xml +++ b/voucher/src/main/res/values/styles.xml @@ -10,8 +10,8 @@ + + + + - - + + + + + + From 105bcda6c37102bc3ec2a1e5ccf15ab1182e9d0b Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Wed, 27 Dec 2023 14:56:04 +0100 Subject: [PATCH 013/255] Use Flexbox to align voucher buttons on the screen and wrap them when text size is too big COAND-372 diff --git a/dependencies.gradle b/dependencies.gradle index 368b82eff..545b97065 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -41,6 +41,7 @@ ext { material_version = "1.10.0" recyclerview_version = "1.3.2" constraintlayout_version = '2.1.4' + flexbox_version = "3.0.0" // Compose Dependencies compose_activity_version = '1.8.1' @@ -108,6 +109,7 @@ ext { ], viewmodel: "androidx.lifecycle:lifecycle-viewmodel-compose:$compose_viewmodel_version" ], + flexbox : "com.google.android.flexbox:flexbox:$flexbox_version", googlePay : [ composeButton : "com.google.pay.button:compose-pay-button:$google_pay_compose_button_version", playServicesWallet: "com.google.android.gms:play-services-wallet:$play_services_wallet_version", diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index ad73ab43e..2d9fbca15 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5231,6 +5231,14 @@ + + + + + + + + diff --git a/voucher/build.gradle b/voucher/build.gradle index 6e689999a..679698d43 100644 --- a/voucher/build.gradle +++ b/voucher/build.gradle @@ -48,6 +48,7 @@ dependencies { // Dependencies implementation libraries.androidx.browser + implementation libraries.flexbox //Tests testImplementation project(':test-core') diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt index feda72c45..bb91a6c39 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt @@ -150,7 +150,7 @@ internal open class FullVoucherView @JvmOverloads constructor( if (informationFields.isNullOrEmpty()) return if (informationFieldsAdapter == null) { informationFieldsAdapter = VoucherInformationFieldsAdapter() - binding.listViewInformationFields.adapter = informationFieldsAdapter + binding.recyclerViewInformationFields.adapter = informationFieldsAdapter } informationFieldsAdapter?.submitList(informationFields) } diff --git a/voucher/src/main/res/layout/full_voucher_view.xml b/voucher/src/main/res/layout/full_voucher_view.xml index ec76d8354..2fac830a2 100644 --- a/voucher/src/main/res/layout/full_voucher_view.xml +++ b/voucher/src/main/res/layout/full_voucher_view.xml @@ -91,35 +91,40 @@ app:layout_constraintTop_toBottomOf="@id/paymentReferenceSeparator" tools:text="12345.1234.12345.12345.12345678901 123456789012345" /> - + app:layout_constraintTop_toBottomOf="@id/textView_reference_code"> - + + + + + + app:layout_constraintTop_toBottomOf="@id/flexboxLayout_buttons" /> + + + + + + + + diff --git a/voucher/build.gradle b/voucher/build.gradle index 6e689999ae..679698d431 100644 --- a/voucher/build.gradle +++ b/voucher/build.gradle @@ -48,6 +48,7 @@ dependencies { // Dependencies implementation libraries.androidx.browser + implementation libraries.flexbox //Tests testImplementation project(':test-core') diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt index feda72c456..bb91a6c39e 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt @@ -150,7 +150,7 @@ internal open class FullVoucherView @JvmOverloads constructor( if (informationFields.isNullOrEmpty()) return if (informationFieldsAdapter == null) { informationFieldsAdapter = VoucherInformationFieldsAdapter() - binding.listViewInformationFields.adapter = informationFieldsAdapter + binding.recyclerViewInformationFields.adapter = informationFieldsAdapter } informationFieldsAdapter?.submitList(informationFields) } diff --git a/voucher/src/main/res/layout/full_voucher_view.xml b/voucher/src/main/res/layout/full_voucher_view.xml index ec76d8354e..2fac830a29 100644 --- a/voucher/src/main/res/layout/full_voucher_view.xml +++ b/voucher/src/main/res/layout/full_voucher_view.xml @@ -91,35 +91,40 @@ app:layout_constraintTop_toBottomOf="@id/paymentReferenceSeparator" tools:text="12345.1234.12345.12345.12345678901 123456789012345" /> - + app:layout_constraintTop_toBottomOf="@id/textView_reference_code"> - + + + + + + app:layout_constraintTop_toBottomOf="@id/flexboxLayout_buttons" /> Date: Thu, 28 Dec 2023 09:57:03 +0100 Subject: [PATCH 014/255] Make BoletoVoucherView a duplicate of old FullVoucherView with Boleto specific layout to not introduce breaking changes. COAND-372 --- .../internal/ui/DefaultVoucherDelegate.kt | 2 + .../internal/ui/model/VoucherOutputData.kt | 2 + .../internal/ui/view/BoletoVoucherView.kt | 153 +++++++++++++++++- .../internal/ui/view/FullVoucherView.kt | 4 +- .../main/res/layout/boleto_voucher_view.xml | 141 ++++++++++++++++ voucher/src/main/res/values/styles.xml | 17 +- 6 files changed, 307 insertions(+), 12 deletions(-) create mode 100644 voucher/src/main/res/layout/boleto_voucher_view.xml diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt index 578b134648..6f1ac05667 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/DefaultVoucherDelegate.kt @@ -98,6 +98,7 @@ internal class DefaultVoucherDelegate( paymentMethodType = action.paymentMethodType, // TODO: remove action.url when it's fixed from backend side downloadUrl = action.downloadUrl ?: action.url, + expiresAt = action.expiresAt, reference = action.reference, totalAmount = action.totalAmount, introductionTextResource = config.introductionTextResource, @@ -110,6 +111,7 @@ internal class DefaultVoucherDelegate( isValid = false, paymentMethodType = null, downloadUrl = null, + expiresAt = null, reference = null, totalAmount = null, introductionTextResource = null, diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt index b0758468fc..8dee9f510c 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/model/VoucherOutputData.kt @@ -17,6 +17,8 @@ data class VoucherOutputData( override val isValid: Boolean, val paymentMethodType: String?, val downloadUrl: String?, + // TODO: Should be removed with BoletoVoucherView + val expiresAt: String?, val reference: String?, val totalAmount: Amount?, val introductionTextResource: Int?, diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt index 24582769a0..1385482785 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/BoletoVoucherView.kt @@ -3,30 +3,175 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ararat on 21/12/2023. + * Created by ararat on 28/12/2023. */ package com.adyen.checkout.voucher.internal.ui.view import android.content.Context import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible +import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.components.core.internal.util.CurrencyUtils +import com.adyen.checkout.components.core.internal.util.DateUtils +import com.adyen.checkout.components.core.internal.util.copyTextToClipboard +import com.adyen.checkout.components.core.internal.util.isEmpty +import com.adyen.checkout.core.internal.util.LogUtil +import com.adyen.checkout.core.internal.util.Logger +import com.adyen.checkout.ui.core.internal.ui.ComponentView +import com.adyen.checkout.ui.core.internal.ui.LogoSize +import com.adyen.checkout.ui.core.internal.ui.loadLogo import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle import com.adyen.checkout.voucher.R +import com.adyen.checkout.voucher.databinding.BoletoVoucherViewBinding +import com.adyen.checkout.voucher.internal.ui.VoucherDelegate +import com.adyen.checkout.voucher.internal.ui.model.VoucherOutputData import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach -// TODO: After removing BoletoVoucherView, make sure to make FullVoucherView non open, binding to private and remove Bolet styles. +@Suppress("TooManyFunctions") internal class BoletoVoucherView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : FullVoucherView(context, attrs, defStyleAttr) { +) : + ConstraintLayout( + context, + attrs, + defStyleAttr + ), + ComponentView { + + private val binding: BoletoVoucherViewBinding = BoletoVoucherViewBinding.inflate(LayoutInflater.from(context), this) + + private lateinit var localizedContext: Context + + private lateinit var delegate: VoucherDelegate + + init { + val padding = resources.getDimension(R.dimen.standard_margin).toInt() + setPadding(padding, padding, padding, padding) + } + override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { - super.initView(delegate, coroutineScope, localizedContext) + require(delegate is VoucherDelegate) { "Unsupported delegate type" } + + this.delegate = delegate + + this.localizedContext = localizedContext + initLocalizedStrings(localizedContext) + + observeDelegate(delegate, coroutineScope) + + binding.buttonCopyCode.setOnClickListener { copyCode(delegate.outputData.reference) } + binding.buttonDownloadPdf.setOnClickListener { delegate.downloadVoucher(context) } + } + private fun initLocalizedStrings(localizedContext: Context) { binding.textViewIntroduction.setLocalizedTextFromStyle( R.style.AdyenCheckout_Voucher_Description_Boleto, localizedContext ) + binding.textViewPaymentReference.setLocalizedTextFromStyle( + R.style.AdyenCheckout_Voucher_PaymentReference, + localizedContext + ) + binding.buttonCopyCode.setLocalizedTextFromStyle( + R.style.AdyenCheckout_Voucher_ButtonCopyCode, + localizedContext + ) + binding.buttonDownloadPdf.setLocalizedTextFromStyle( + R.style.AdyenCheckout_Voucher_ButtonDownloadPdf, + localizedContext + ) + binding.textViewExpirationLabel.setLocalizedTextFromStyle( + R.style.AdyenCheckout_Voucher_ExpirationDateLabel, + localizedContext + ) + } + + private fun observeDelegate(delegate: VoucherDelegate, coroutineScope: CoroutineScope) { + delegate.outputDataFlow + .onEach { outputDataChanged(it) } + .launchIn(coroutineScope) + } + + private fun outputDataChanged(outputData: VoucherOutputData) { + Logger.d(TAG, "outputDataChanged") + + loadLogo(outputData.paymentMethodType) + updateAmount(outputData.totalAmount) + updateCodeReference(outputData.reference) + updateExpirationDate(outputData.expiresAt) + } + + private fun loadLogo(paymentMethodType: String?) { + if (!paymentMethodType.isNullOrEmpty()) { + binding.imageViewLogo.loadLogo( + environment = delegate.componentParams.environment, + txVariant = paymentMethodType, + size = LogoSize.MEDIUM, + ) + } + } + + private fun updateAmount(amount: Amount?) { + if (amount != null && !amount.isEmpty) { + val formattedAmount = CurrencyUtils.formatAmount( + amount, + delegate.componentParams.shopperLocale + ) + binding.textViewAmount.isVisible = true + binding.textViewAmount.text = formattedAmount + } else { + binding.textViewAmount.isVisible = false + } + } + + private fun updateCodeReference(codeReference: String?) { + binding.textViewReferenceCode.text = codeReference + + val isVisible = !codeReference.isNullOrEmpty() + binding.textViewReferenceCode.isVisible = isVisible + binding.buttonCopyCode.isVisible = isVisible + } + + private fun updateExpirationDate(expiresAt: String?) { + binding.textViewExpirationDate.text = expiresAt?.let { + DateUtils.formatStringDate( + expiresAt, + delegate.componentParams.shopperLocale + ) + } + + val isVisible = !expiresAt.isNullOrEmpty() + binding.textViewExpirationLabel.isVisible = isVisible + binding.textViewExpirationDate.isVisible = isVisible + binding.expiryDateSeparator.isVisible = isVisible + } + + private fun copyCode(codeReference: String?) { + codeReference ?: return + context.copyTextToClipboard( + COPY_LABEL, + codeReference, + localizedContext.getString(R.string.checkout_voucher_copied_toast) + ) + } + + override fun highlightValidationErrors() { + // No validation required + } + + override fun getView(): View = this + + companion object { + private val TAG = LogUtil.getTag() + private const val COPY_LABEL = "Voucher code reference" } } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt index bb91a6c39e..b9e169450b 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/internal/ui/view/FullVoucherView.kt @@ -36,7 +36,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") -internal open class FullVoucherView @JvmOverloads constructor( +internal class FullVoucherView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 @@ -48,7 +48,7 @@ internal open class FullVoucherView @JvmOverloads constructor( ), ComponentView { - protected val binding: FullVoucherViewBinding = FullVoucherViewBinding.inflate(LayoutInflater.from(context), this) + private val binding: FullVoucherViewBinding = FullVoucherViewBinding.inflate(LayoutInflater.from(context), this) private lateinit var localizedContext: Context private lateinit var delegate: VoucherDelegate diff --git a/voucher/src/main/res/layout/boleto_voucher_view.xml b/voucher/src/main/res/layout/boleto_voucher_view.xml new file mode 100644 index 0000000000..35d11d78ab --- /dev/null +++ b/voucher/src/main/res/layout/boleto_voucher_view.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/voucher/src/main/res/values/styles.xml b/voucher/src/main/res/values/styles.xml index 40b4387e77..1ce757d6cc 100644 --- a/voucher/src/main/res/values/styles.xml +++ b/voucher/src/main/res/values/styles.xml @@ -10,8 +10,7 @@ @@ -23,8 +22,7 @@ center_horizontal - + + + - + + + - + @@ -22,7 +23,8 @@ center_horizontal - + - - - - - - - - + + - - - - - - - - - - - - - - - - - - - + + + + + + + + - - @@ -75,6 +70,23 @@ center_horizontal + + + + + + + + @@ -97,14 +109,4 @@ + + - From 44d97ae2d801eb89f4231e0e12b6205afc2d99a8 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:27:00 +0100 Subject: [PATCH 094/255] Implement AddressLookupView COAND-730 --- .../card/internal/ui/model/CardInputData.kt | 3 +- .../internal/ui/view/AddressLookupView.kt | 61 ++++++++++++++++--- .../main/res/layout/address_lookup_view.xml | 17 +++--- card/src/main/res/values/styles.xml | 4 ++ 4 files changed, 70 insertions(+), 15 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt index 52f0d917d0..e082ca9f95 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt @@ -22,8 +22,9 @@ data class CardInputData( var kcpBirthDateOrTaxNumber: String = "", var kcpCardPassword: String = "", var postalCode: String = "", + var addressLookupQuery: String = "", var address: AddressInputModel = AddressInputModel(), var isStorePaymentMethodSwitchChecked: Boolean = false, var selectedCardIndex: Int = -1, - var installmentOption: InstallmentModel? = null + var installmentOption: InstallmentModel? = null, ) : InputData diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt index 903184b9fb..45360372d7 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt @@ -12,11 +12,18 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.view.View +import android.view.View.OnFocusChangeListener import android.widget.LinearLayout +import com.adyen.checkout.card.R import com.adyen.checkout.card.databinding.AddressLookupViewBinding import com.adyen.checkout.card.internal.ui.CardDelegate import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.components.core.internal.ui.model.Validation import com.adyen.checkout.ui.core.internal.ui.ComponentView +import com.adyen.checkout.ui.core.internal.ui.view.AdyenTextInputEditText +import com.adyen.checkout.ui.core.internal.util.hideError +import com.adyen.checkout.ui.core.internal.util.setLocalizedHintFromStyle +import com.adyen.checkout.ui.core.internal.util.showError import kotlinx.coroutines.CoroutineScope internal class AddressLookupView @JvmOverloads constructor( @@ -31,27 +38,67 @@ internal class AddressLookupView @JvmOverloads constructor( ), ComponentView { - // TODO address lookup - @Suppress("UnusedPrivateProperty") private val binding: AddressLookupViewBinding = AddressLookupViewBinding.inflate(LayoutInflater.from(context), this) + private lateinit var localizedContext: Context + private lateinit var cardDelegate: CardDelegate + init { + orientation = VERTICAL + val padding = resources.getDimension(R.dimen.standard_margin).toInt() + setPadding(padding, padding, padding, 0) + } + override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { require(delegate is CardDelegate) { "Unsupported delegate type" } cardDelegate = delegate - // TODO address lookup init views + this.localizedContext = localizedContext + initLocalizedStrings(localizedContext) + + initAddressLookupQuery() + initAddressFormInput(coroutineScope) } - // TODO address lookup - @Suppress("UnusedPrivateProperty") override fun highlightValidationErrors() { cardDelegate.outputData.let { - var isErrorFocused = false - // TODO address lookup validation + binding.addressFormInput.highlightValidationErrors(false) } } + private fun initLocalizedStrings(localizedContext: Context) { + binding.textInputLayoutAddressLookupQuery.setLocalizedHintFromStyle( + R.style.AdyenCheckout_Card_AddressLookupQuery, + localizedContext + ) + binding.addressFormInput.initLocalizedContext(localizedContext) + } + + private fun initAddressLookupQuery() { + val addressLookupQueryEditText = binding.textInputLayoutAddressLookupQuery.editText as? AdyenTextInputEditText + addressLookupQueryEditText?.setOnChangeListener { + cardDelegate.updateInputData { + addressLookupQuery = it.toString() + binding.textInputLayoutAddressLookupQuery.hideError() + } + } + + addressLookupQueryEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> + val postalCodeValidation = cardDelegate.outputData.addressState.postalCode.validation + if (hasFocus) { + binding.textInputLayoutAddressLookupQuery.hideError() + } else if (postalCodeValidation is Validation.Invalid) { + binding.textInputLayoutAddressLookupQuery.showError( + localizedContext.getString(postalCodeValidation.reason) + ) + } + } + } + + private fun initAddressFormInput(coroutineScope: CoroutineScope) { + binding.addressFormInput.attachDelegate(cardDelegate, coroutineScope) + } + override fun getView(): View = this } diff --git a/card/src/main/res/layout/address_lookup_view.xml b/card/src/main/res/layout/address_lookup_view.xml index 4b2d844080..b1e43b6202 100644 --- a/card/src/main/res/layout/address_lookup_view.xml +++ b/card/src/main/res/layout/address_lookup_view.xml @@ -13,19 +13,22 @@ android:orientation="vertical" tools:parentTag="android.widget.LinearLayout"> - + android:descendantFocusability="afterDescendants"> + + + + android:focusableInTouchMode="true" /> diff --git a/card/src/main/res/values/styles.xml b/card/src/main/res/values/styles.xml index 3bd54789f5..63f68818f2 100644 --- a/card/src/main/res/values/styles.xml +++ b/card/src/main/res/values/styles.xml @@ -78,6 +78,10 @@ 2 + + + + + + diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index 6563fc2f0d..7bb3cbaf39 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -1289,6 +1289,7 @@ internal class DefaultCardDelegateTest( isDualBranded = isDualBranded, kcpBirthDateOrTaxNumberHint = kcpBirthDateOrTaxNumberHint, isCardListVisible = isCardListVisible, + addressLookupOptions = emptyList() // TODO address lookup ) } diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt index d6a7c3ed06..3908b110d9 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt @@ -568,6 +568,7 @@ internal class StoredCardDelegateTest( isDualBranded = false, kcpBirthDateOrTaxNumberHint = null, isCardListVisible = isCardListVisible, + addressLookupOptions = emptyList() // TODO address lookup ) } From bb5f1105a3b5f2bb1e22c27b6f8884814a266bc8 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 5 Dec 2023 14:30:05 +0100 Subject: [PATCH 099/255] Fill in the address form when an address option is selected COAND-730 --- .../card/internal/ui/DefaultCardDelegate.kt | 20 ++++++++------ .../ui/view/AddressLookupOptionsAdapter.kt | 12 ++++++--- .../internal/ui/view/AddressLookupView.kt | 14 +++++++--- .../util/CardAddressValidationUtils.kt | 3 +-- .../service/ExampleAdvancedDropInService.kt | 26 ++++++++++++++++++- .../core/internal/ui/view/AddressFormInput.kt | 20 +++++++++----- .../ui/core/internal/util/AddressFormUtils.kt | 7 +++++ .../internal/util/AddressValidationUtils.kt | 6 +++-- 8 files changed, 82 insertions(+), 26 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index 0a4718055e..618ec34b1e 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -152,7 +152,9 @@ class DefaultCardDelegate( fetchPublicKey() subscribeToDetectedCardTypes() - if (componentParams.addressParams is AddressParams.FullAddress) { + if (componentParams.addressParams is AddressParams.FullAddress || + componentParams.addressParams is AddressParams.Lookup + ) { subscribeToStatesList() subscribeToCountryList() requestCountryList() @@ -327,6 +329,14 @@ class DefaultCardDelegate( val addressFormUIState = AddressFormUIState.fromAddressParams(componentParams.addressParams) + val addressState = validateAddress( + inputData.address, + addressFormUIState, + selectedOrFirstCardType, + updatedCountryOptions, + updatedStateOptions, + ) + return CardOutputData( cardNumberState = validateCardNumber( cardNumber = inputData.cardNumber, @@ -339,13 +349,7 @@ class DefaultCardDelegate( socialSecurityNumberState = validateSocialSecurityNumber(inputData.socialSecurityNumber), kcpBirthDateOrTaxNumberState = validateKcpBirthDateOrTaxNumber(inputData.kcpBirthDateOrTaxNumber), kcpCardPasswordState = validateKcpCardPassword(inputData.kcpCardPassword), - addressState = validateAddress( - inputData.address, - addressFormUIState, - selectedOrFirstCardType, - updatedCountryOptions, - updatedStateOptions, - ), + addressState = addressState, installmentState = makeInstallmentFieldState(inputData.installmentOption), shouldStorePaymentMethod = inputData.isStorePaymentMethodSwitchChecked, cvcUIState = makeCvcUIState(selectedOrFirstCardType), diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupOptionsAdapter.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupOptionsAdapter.kt index 8c40a3fc8f..8119abf89c 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupOptionsAdapter.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupOptionsAdapter.kt @@ -16,14 +16,16 @@ import androidx.recyclerview.widget.RecyclerView import com.adyen.checkout.card.databinding.AddressLookupOptionItemViewBinding import com.adyen.checkout.card.internal.data.model.LookupAddress -internal class AddressLookupOptionsAdapter : +internal class AddressLookupOptionsAdapter( + private val onItemClicked: (LookupAddress) -> Unit +) : ListAdapter( AddressLookupOptionDiffCallback ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddressLookupOptionViewHolder { val binding = AddressLookupOptionItemViewBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return AddressLookupOptionViewHolder(binding) + return AddressLookupOptionViewHolder(binding, onItemClicked) } override fun onBindViewHolder(holder: AddressLookupOptionViewHolder, position: Int) { @@ -31,9 +33,13 @@ internal class AddressLookupOptionsAdapter : } internal class AddressLookupOptionViewHolder( - private val binding: AddressLookupOptionItemViewBinding + private val binding: AddressLookupOptionItemViewBinding, + private val onItemClicked: (LookupAddress) -> Unit ) : RecyclerView.ViewHolder(binding.root) { fun bindItem(lookupAddress: LookupAddress) { + binding.root.setOnClickListener { + onItemClicked(lookupAddress) + } binding.textViewAddressHeader.text = lookupAddress.id binding.textViewAddressDescription.text = lookupAddress.toString() } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt index bb7cf13790..f74dc5cc95 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt @@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +@Suppress("TooManyFunctions") internal class AddressLookupView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @@ -117,7 +118,7 @@ internal class AddressLookupView @JvmOverloads constructor( } private fun initAddressOptions() { - addressLookupOptionsAdapter = AddressLookupOptionsAdapter() + addressLookupOptionsAdapter = AddressLookupOptionsAdapter(::onAddressSelected) addressLookupOptionsAdapter?.let { adapter -> binding.recyclerViewAddressLookupOptions.adapter = adapter } @@ -131,11 +132,18 @@ internal class AddressLookupView @JvmOverloads constructor( binding.recyclerViewAddressLookupOptions.isVisible = options.isNotEmpty() binding.addressFormInput.isVisible = options.isEmpty() if (addressLookupOptionsAdapter == null) { - addressLookupOptionsAdapter = AddressLookupOptionsAdapter() - binding.recyclerViewAddressLookupOptions.adapter = addressLookupOptionsAdapter + initAddressOptions() } addressLookupOptionsAdapter?.submitList(options) } + private fun onAddressSelected(lookupAddress: LookupAddress) { + cardDelegate.updateInputData { + this.address = lookupAddress.address + } + binding.recyclerViewAddressLookupOptions.isVisible = false + binding.addressFormInput.isVisible = true + } + override fun getView(): View = this } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/util/CardAddressValidationUtils.kt b/card/src/main/java/com/adyen/checkout/card/internal/util/CardAddressValidationUtils.kt index 7d014825e2..2577f750bf 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/util/CardAddressValidationUtils.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/util/CardAddressValidationUtils.kt @@ -28,8 +28,7 @@ internal object CardAddressValidationUtils { true } is AddressParams.Lookup -> { - // TODO validate address - true + false } } ?: true } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt index 9d768a2e6d..67ff1940cf 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt @@ -71,6 +71,7 @@ class ExampleAdvancedDropInService : DropInService() { private val _addressLookupQueryFlow = MutableStateFlow(null) init { + _addressLookupQueryFlow .debounce(ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION) .filterNotNull() @@ -78,7 +79,30 @@ class ExampleAdvancedDropInService : DropInService() { sendAddressLookupResult( AddressLookupDropInServiceResult.LookupResult( // TODO address lookup populate better data - listOf(LookupAddress(it, AddressInputModel(postalCode = "1234AB"))), + listOf( + LookupAddress( + id = it, + address = AddressInputModel( + country = "NL", + postalCode = "1234AB", + houseNumberOrName = "1HS", + street = "Simon Carmiggeltstraat", + stateOrProvince = "Noord-Holland", + city = "Amsterdam", + ), + ), + LookupAddress( + id = it, + address = AddressInputModel( + country = "TR", + postalCode = "38090", + houseNumberOrName = "93", + street = "12. Cadde", + stateOrProvince = "Kayseri", + city = "Kayseri", + ), + ), + ), ), ) }.launchIn(this) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt index 57d855834a..aa9c6e988c 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt @@ -22,6 +22,7 @@ import com.adyen.checkout.ui.core.internal.ui.AddressDelegate import com.adyen.checkout.ui.core.internal.ui.AddressSpecification import com.adyen.checkout.ui.core.internal.ui.SimpleTextListAdapter import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem +import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.hideError import com.adyen.checkout.ui.core.internal.util.setLocalizedHintFromStyle import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle @@ -135,6 +136,7 @@ class AddressFormInput @JvmOverloads constructor( delegate.addressOutputDataFlow.onEach { addressOutputData -> updateCountries(addressOutputData.countryOptions) updateStates(addressOutputData.stateOptions) + updateInputFields(addressOutputData) }.launchIn(coroutineScope) } @@ -303,7 +305,6 @@ class AddressFormInput @JvmOverloads constructor( private fun initStreetInput(styleResId: Int?) { styleResId?.let { textInputLayoutStreet?.setLocalizedHintFromStyle(it, localizedContext) } editTextStreet?.apply { - setText(delegate.addressOutputData.street.value) setOnChangeListener { delegate.updateAddressInputData { street = it.toString() } textInputLayoutStreet?.hideError() @@ -322,7 +323,6 @@ class AddressFormInput @JvmOverloads constructor( private fun initHouseNumberInput(styleResId: Int?) { styleResId?.let { textInputLayoutHouseNumber?.setLocalizedHintFromStyle(it, localizedContext) } editTextHouseNumber?.apply { - setText(delegate.addressOutputData.houseNumberOrName.value) setOnChangeListener { delegate.updateAddressInputData { houseNumberOrName = it.toString() } textInputLayoutHouseNumber?.hideError() @@ -341,7 +341,6 @@ class AddressFormInput @JvmOverloads constructor( private fun initApartmentSuiteInput(styleResId: Int?) { styleResId?.let { textInputLayoutApartmentSuite?.setLocalizedHintFromStyle(it, localizedContext) } editTextApartmentSuite?.apply { - setText(delegate.addressOutputData.apartmentSuite.value) setOnChangeListener { delegate.updateAddressInputData { apartmentSuite = it.toString() } } @@ -359,7 +358,6 @@ class AddressFormInput @JvmOverloads constructor( private fun initPostalCodeInput(styleResId: Int?) { styleResId?.let { textInputLayoutPostalCode?.setLocalizedHintFromStyle(it, localizedContext) } editTextPostalCode?.apply { - setText(delegate.addressOutputData.postalCode.value) setOnChangeListener { delegate.updateAddressInputData { postalCode = it.toString() } textInputLayoutPostalCode?.hideError() @@ -378,7 +376,6 @@ class AddressFormInput @JvmOverloads constructor( private fun initCityInput(styleResId: Int?) { styleResId?.let { textInputLayoutCity?.setLocalizedHintFromStyle(it, localizedContext) } editTextCity?.apply { - setText(delegate.addressOutputData.city.value) setOnChangeListener { delegate.updateAddressInputData { city = it.toString() } textInputLayoutCity?.hideError() @@ -397,7 +394,6 @@ class AddressFormInput @JvmOverloads constructor( private fun initProvinceTerritoryInput(styleResId: Int?) { styleResId?.let { textInputLayoutProvinceTerritory?.setLocalizedHintFromStyle(it, localizedContext) } editTextProvinceTerritory?.apply { - setText(delegate.addressOutputData.stateOrProvince.value) setOnChangeListener { delegate.updateAddressInputData { stateOrProvince = it.toString() } textInputLayoutProvinceTerritory?.hideError() @@ -416,7 +412,6 @@ class AddressFormInput @JvmOverloads constructor( private fun initStatesInput(styleResId: Int?) { styleResId?.let { textInputLayoutState?.setLocalizedHintFromStyle(it, localizedContext) } autoCompleteTextViewState?.apply { - setText(statesAdapter.getItem { it.selected }?.name) inputType = 0 setAdapter(statesAdapter) onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> @@ -462,4 +457,15 @@ class AddressFormInput @JvmOverloads constructor( val statesStyleResId = spec.stateProvince.getStyleResId(isOptional) statesStyleResId?.let { textInputLayoutState?.setLocalizedHintFromStyle(it, localizedContext) } } + + private fun updateInputFields(addressOutputData: AddressOutputData) { + autoCompleteTextViewCountry.setText(addressOutputData.countryOptions.firstOrNull { it.selected }?.name) + editTextStreet?.setText(delegate.addressOutputData.street.value) + editTextHouseNumber?.setText(delegate.addressOutputData.houseNumberOrName.value) + editTextApartmentSuite?.setText(delegate.addressOutputData.apartmentSuite.value) + editTextPostalCode?.setText(delegate.addressOutputData.postalCode.value) + editTextCity?.setText(delegate.addressOutputData.city.value) + editTextProvinceTerritory?.setText(delegate.addressOutputData.stateOrProvince.value) + autoCompleteTextViewState?.setText(statesAdapter.getItem { it.selected }?.name) + } } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt index 164317ac0e..fdd58dc709 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt @@ -74,6 +74,11 @@ object AddressFormUtils { ) markAddressListItemSelected(mapToListItem(filteredCountryList), defaultCountryCode) } + + is AddressParams.Lookup -> { + mapToListItem(countryList) + } + else -> emptyList() } } @@ -136,6 +141,7 @@ object AddressFormUtils { city = addressOutputData.city.value.ifEmpty { Address.ADDRESS_NULL_PLACEHOLDER }, country = addressOutputData.country.value, ) + AddressFormUIState.POSTAL_CODE -> Address( postalCode = addressOutputData.postalCode.value, street = Address.ADDRESS_NULL_PLACEHOLDER, @@ -144,6 +150,7 @@ object AddressFormUtils { city = Address.ADDRESS_NULL_PLACEHOLDER, country = Address.ADDRESS_COUNTRY_NULL_PLACEHOLDER, ) + else -> null } } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt index b67ff3e32b..af6380e942 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt @@ -33,18 +33,20 @@ object AddressValidationUtils { isOptional: Boolean, ): AddressOutputData { return when (addressFormUIState) { - AddressFormUIState.FULL_ADDRESS -> validateAddressInput( + AddressFormUIState.FULL_ADDRESS, AddressFormUIState.LOOKUP -> validateAddressInput( addressInputModel, isOptional, countryOptions, stateOptions ) + AddressFormUIState.POSTAL_CODE -> validatePostalCode( addressInputModel, isOptional, countryOptions, stateOptions ) + else -> makeValidEmptyAddressOutput(addressInputModel) } } @@ -77,7 +79,7 @@ object AddressValidationUtils { countryOptions: List, stateOptions: List, ): AddressOutputData { - val spec = AddressSpecification.fromString(addressInputModel.country) + val spec = AddressSpecification.fromString(addressInputModel.country) ?: AddressSpecification.DEFAULT return with(addressInputModel) { AddressOutputData( postalCode = validateAddressField(postalCode, spec.postalCode.isRequired && !isOptional), From ba87ed941dfa753fd53f8312ec595caccad049f2 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 7 Dec 2023 10:43:41 +0100 Subject: [PATCH 100/255] Add example standalone component integration for address lookup COAND-730 --- .../service/ExampleAdvancedDropInService.kt | 67 ++++++++++--------- .../checkout/example/ui/card/CardActivity.kt | 11 +++ .../checkout/example/ui/card/CardEvent.kt | 3 + .../checkout/example/ui/card/CardViewModel.kt | 57 +++++++++++++++- .../ui/card/SessionsCardTakenOverActivity.kt | 11 +++ .../ui/card/SessionsCardTakenOverViewModel.kt | 56 ++++++++++++++-- 6 files changed, 166 insertions(+), 39 deletions(-) diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt index 67ff1940cf..b9799b0fdc 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt @@ -68,44 +68,45 @@ class ExampleAdvancedDropInService : DropInService() { @Inject lateinit var keyValueStorage: KeyValueStorage - private val _addressLookupQueryFlow = MutableStateFlow(null) + private val addressLookupQueryFlow = MutableStateFlow(null) init { - - _addressLookupQueryFlow - .debounce(ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION) - .filterNotNull() - .onEach { - sendAddressLookupResult( - AddressLookupDropInServiceResult.LookupResult( - // TODO address lookup populate better data - listOf( - LookupAddress( - id = it, - address = AddressInputModel( - country = "NL", - postalCode = "1234AB", - houseNumberOrName = "1HS", - street = "Simon Carmiggeltstraat", - stateOrProvince = "Noord-Holland", - city = "Amsterdam", + launch(Dispatchers.IO) { + addressLookupQueryFlow + .debounce(ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION) + .filterNotNull() + .onEach { + sendAddressLookupResult( + AddressLookupDropInServiceResult.LookupResult( + // TODO address lookup populate better data + listOf( + LookupAddress( + id = it, + address = AddressInputModel( + country = "NL", + postalCode = "1234AB", + houseNumberOrName = "1HS", + street = "Simon Carmiggeltstraat", + stateOrProvince = "Noord-Holland", + city = "Amsterdam", + ), ), - ), - LookupAddress( - id = it, - address = AddressInputModel( - country = "TR", - postalCode = "38090", - houseNumberOrName = "93", - street = "12. Cadde", - stateOrProvince = "Kayseri", - city = "Kayseri", + LookupAddress( + id = it, + address = AddressInputModel( + country = "TR", + postalCode = "12345", + houseNumberOrName = "1", + street = "1. Sokak", + stateOrProvince = "Istanbul", + city = "Istanbul", + ), ), ), ), - ), - ) - }.launchIn(this) + ) + }.launchIn(this) + } } override fun onSubmit( @@ -425,7 +426,7 @@ class ExampleAdvancedDropInService : DropInService() { override fun onAddressLookupQuery(query: String) { Log.d(TAG, "On address lookup query: $query") - _addressLookupQueryFlow.tryEmit(query) + addressLookupQueryFlow.tryEmit(query) } companion object { diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt index 9fc8996d53..39819513ef 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt @@ -11,6 +11,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.adyen.checkout.card.CardComponent +import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.example.databinding.ActivityCardBinding import com.adyen.checkout.example.extensions.getLogTag @@ -108,6 +109,11 @@ class CardActivity : AppCompatActivity() { Log.d(TAG, "On bin lookup: ${data.map { it.brand }}") } + cardComponent.setAddressLookupQueryChangedListener { + Log.d(TAG, "On address lookup query changed: $it") + cardViewModel.onAddressLookupQueryChanged(it) + } + this.cardComponent = cardComponent binding.cardView.attach(cardComponent, this) @@ -117,6 +123,7 @@ class CardActivity : AppCompatActivity() { when (event) { is CardEvent.PaymentResult -> onPaymentResult(event.result) is CardEvent.AdditionalAction -> onAction(event.action) + is CardEvent.AddressLookup -> onAddressLookup(event.options) } } @@ -129,6 +136,10 @@ class CardActivity : AppCompatActivity() { cardComponent?.handleAction(action, this) } + private fun onAddressLookup(options: List) { + cardComponent?.updateAddressLookupOptions(options) + } + override fun onDestroy() { super.onDestroy() cardComponent = null diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt index 9681d38b4b..3be28aa5f9 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt @@ -8,6 +8,7 @@ package com.adyen.checkout.example.ui.card +import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.action.Action internal sealed class CardEvent { @@ -15,4 +16,6 @@ internal sealed class CardEvent { data class PaymentResult(val result: String) : CardEvent() data class AdditionalAction(val action: Action) : CardEvent() + + data class AddressLookup(val options: List) : CardEvent() } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 8957a252ce..89d701a90f 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.adyen.checkout.card.CardComponent import com.adyen.checkout.card.CardComponentState +import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.ComponentCallback import com.adyen.checkout.components.core.ComponentError @@ -14,17 +15,24 @@ import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest +import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.json.JSONObject import javax.inject.Inject +@OptIn(FlowPreview::class) +@Suppress("TooManyFunctions") @HiltViewModel internal class CardViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, @@ -38,11 +46,45 @@ internal class CardViewModel @Inject constructor( private val _cardViewState = MutableStateFlow(CardViewState.Loading) val cardViewState: Flow = _cardViewState + private val addressLookupQueryFlow = MutableStateFlow(null) + private val _events = MutableSharedFlow() val events: Flow = _events init { viewModelScope.launch { fetchPaymentMethods() } + addressLookupQueryFlow + .filterNotNull() + .debounce(ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION) + .onEach { + // TODO address lookup populate better data + val options = listOf( + LookupAddress( + id = it, + address = AddressInputModel( + country = "NL", + postalCode = "1234AB", + houseNumberOrName = "1HS", + street = "Simon Carmiggeltstraat", + stateOrProvince = "Noord-Holland", + city = "Amsterdam", + ), + ), + LookupAddress( + id = it, + address = AddressInputModel( + country = "TR", + postalCode = "12345", + houseNumberOrName = "1", + street = "1. Sokak", + stateOrProvince = "Istanbul", + city = "Istanbul", + ), + ), + ) + _events.emit(CardEvent.AddressLookup(options)) + } + .launchIn(viewModelScope) } private suspend fun fetchPaymentMethods() = withContext(Dispatchers.IO) { @@ -54,7 +96,7 @@ internal class CardViewModel @Inject constructor( countryCode = keyValueStorage.getCountry(), shopperLocale = keyValueStorage.getShopperLocale(), splitCardFundingSources = keyValueStorage.isSplitCardFundingSources(), - ) + ), ) val cardPaymentMethod = paymentMethodResponse @@ -68,7 +110,7 @@ internal class CardViewModel @Inject constructor( CardComponentData( paymentMethod = cardPaymentMethod, callback = this@CardViewModel, - ) + ), ) _cardViewState.emit(CardViewState.ShowComponent) } @@ -86,6 +128,12 @@ internal class CardViewModel @Inject constructor( onComponentError(componentError) } + fun onAddressLookupQueryChanged(query: String) { + viewModelScope.launch { + addressLookupQueryFlow.emit(query) + } + } + // no ops override fun onStateChanged(state: CardComponentState) = Unit @@ -119,6 +167,7 @@ internal class CardViewModel @Inject constructor( val action = Action.SERIALIZER.deserialize(json.getJSONObject("action")) handleAction(action) } + else -> _events.emit(CardEvent.PaymentResult("Finished: ${json.optString("resultCode")}")) } } ?: _events.emit(CardEvent.PaymentResult("Failed")) @@ -138,4 +187,8 @@ internal class CardViewModel @Inject constructor( private fun onComponentError(error: ComponentError) { viewModelScope.launch { _events.emit(CardEvent.PaymentResult("Failed: ${error.errorMessage}")) } } + + companion object { + private const val ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION = 300L + } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt index a5173126eb..847ae07eb5 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt @@ -19,6 +19,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.adyen.checkout.card.CardComponent +import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.example.databinding.ActivityCardBinding import com.adyen.checkout.example.extensions.getLogTag @@ -109,6 +110,11 @@ class SessionsCardTakenOverActivity : AppCompatActivity() { Log.d(TAG, "On redirect") } + cardComponent.setAddressLookupQueryChangedListener { + Log.d(TAG, "On address lookup query changed: $it") + cardViewModel.onAddressLookupQueryChanged(it) + } + this.cardComponent = cardComponent binding.cardView.attach(cardComponent, this) @@ -118,6 +124,7 @@ class SessionsCardTakenOverActivity : AppCompatActivity() { when (event) { is CardEvent.PaymentResult -> onPaymentResult(event.result) is CardEvent.AdditionalAction -> onAction(event.action) + is CardEvent.AddressLookup -> onAddressLookup(event.options) } } @@ -130,6 +137,10 @@ class SessionsCardTakenOverActivity : AppCompatActivity() { finish() } + private fun onAddressLookup(options: List) { + cardComponent?.updateAddressLookupOptions(options) + } + override fun onDestroy() { super.onDestroy() cardComponent = null diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt index aa5b67cf5c..1d8f0b8f20 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt @@ -15,6 +15,7 @@ import androidx.lifecycle.viewModelScope import com.adyen.checkout.card.CardBrand import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.card.CardType +import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.CheckoutConfiguration import com.adyen.checkout.components.core.ComponentError @@ -34,12 +35,16 @@ import com.adyen.checkout.sessions.core.CheckoutSessionResult import com.adyen.checkout.sessions.core.SessionComponentCallback import com.adyen.checkout.sessions.core.SessionModel import com.adyen.checkout.sessions.core.SessionPaymentResult +import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.json.JSONObject import javax.inject.Inject @@ -62,6 +67,8 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( private val _events = MutableSharedFlow() val events: Flow = _events + private val addressLookupQueryFlow = MutableStateFlow(null) + private val checkoutConfiguration = checkoutConfigurationProvider.checkoutConfig private var isFlowTakenOver: Boolean @@ -72,6 +79,38 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( init { viewModelScope.launch { launchComponent() } + addressLookupQueryFlow + .filterNotNull() + .debounce(ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION) + .onEach { + // TODO address lookup populate better data + val options = listOf( + LookupAddress( + id = it, + address = AddressInputModel( + country = "NL", + postalCode = "1234AB", + houseNumberOrName = "1HS", + street = "Simon Carmiggeltstraat", + stateOrProvince = "Noord-Holland", + city = "Amsterdam", + ), + ), + LookupAddress( + id = it, + address = AddressInputModel( + country = "TR", + postalCode = "12345", + houseNumberOrName = "1", + street = "1. Sokak", + stateOrProvince = "Istanbul", + city = "Istanbul", + ), + ), + ) + _events.emit(CardEvent.AddressLookup(options)) + } + .launchIn(viewModelScope) } private suspend fun launchComponent() { @@ -93,8 +132,8 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( SessionsCardComponentData( checkoutSession = checkoutSession, paymentMethod = paymentMethod, - callback = this - ) + callback = this, + ), ) _cardViewState.emit(CardViewState.ShowComponent) } @@ -115,8 +154,8 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( shopperEmail = keyValueStorage.getShopperEmail(), allowedPaymentMethods = listOf(paymentMethodType), installmentOptions = getSettingsInstallmentOptionsMode(keyValueStorage.getInstallmentOptionsMode()), - showInstallmentAmount = keyValueStorage.isInstallmentAmountShown() - ) + showInstallmentAmount = keyValueStorage.isInstallmentAmountShown(), + ), ) ?: return null return getCheckoutSession(sessionModel, checkoutConfiguration) @@ -192,6 +231,7 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( val action = Action.SERIALIZER.deserialize(json.getJSONObject("action")) handleAction(action) } + else -> _events.emit(CardEvent.PaymentResult("Finished: ${json.optString("resultCode")}")) } } ?: _events.emit(CardEvent.PaymentResult("Failed")) @@ -219,8 +259,16 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( _cardViewState.tryEmit(state) } + fun onAddressLookupQueryChanged(query: String) { + viewModelScope.launch { + addressLookupQueryFlow.emit(query) + } + } + companion object { private val TAG = getLogTag() private const val IS_SESSIONS_FLOW_TAKEN_OVER_KEY = "IS_SESSIONS_FLOW_TAKEN_OVER_KEY" + + private const val ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION = 300L } } From 6f4d0702c54677ae9a2dea6109c004761e7c7d3f Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:31:14 +0100 Subject: [PATCH 101/255] Handle save address button click in address lookup view COAND-730 --- .../card/internal/ui/CardViewProvider.kt | 24 ++++++++++++------- .../card/internal/ui/DefaultCardDelegate.kt | 6 ++++- .../card/internal/ui/StoredCardDelegate.kt | 2 +- card/src/main/res/values/strings.xml | 3 +++ 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt index a4a8c7163a..5732ac8ac1 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.card.internal.ui import android.content.Context +import com.adyen.checkout.card.R import com.adyen.checkout.card.internal.ui.view.AddressLookupView import com.adyen.checkout.card.internal.ui.view.CardView import com.adyen.checkout.card.internal.ui.view.StoredCardView @@ -25,19 +26,26 @@ internal object CardViewProvider : ViewProvider { context: Context, ): ComponentView { return when (viewType) { - CardComponentViewType.DefaultCardView -> CardView(context) - CardComponentViewType.StoredCardView -> StoredCardView(context) - CardComponentViewType.AddressLookup -> AddressLookupView(context) + is CardComponentViewType.DefaultCardView -> CardView(context) + is CardComponentViewType.StoredCardView -> StoredCardView(context) + is CardComponentViewType.AddressLookup -> AddressLookupView(context) else -> throw IllegalArgumentException("Unsupported view type") } } } -internal sealed class CardComponentViewType : AmountButtonComponentViewType { - object DefaultCardView : CardComponentViewType() - object StoredCardView : CardComponentViewType() - object AddressLookup : CardComponentViewType() +internal sealed class CardComponentViewType : ButtonComponentViewType { + data object DefaultCardView : CardComponentViewType(), AmountButtonComponentViewType { + override val buttonTextResId: Int = ButtonComponentViewType.DEFAULT_BUTTON_TEXT_RES_ID + } + + data object StoredCardView : CardComponentViewType(), AmountButtonComponentViewType { + override val buttonTextResId: Int = ButtonComponentViewType.DEFAULT_BUTTON_TEXT_RES_ID + } + + data object AddressLookup : CardComponentViewType() { + override val buttonTextResId: Int = R.string.checkout_address_lookup_button_text + } override val viewProvider: ViewProvider = CardViewProvider - override val buttonTextResId: Int = ButtonComponentViewType.DEFAULT_BUTTON_TEXT_RES_ID } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index 618ec34b1e..b6de779d82 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -469,7 +469,11 @@ class DefaultCardDelegate( override fun onSubmit() { val state = _componentStateFlow.value - submitHandler.onSubmit(state = state) + if (_viewFlow.value == CardComponentViewType.AddressLookup) { + _viewFlow.tryEmit(CardComponentViewType.DefaultCardView) + } else { + submitHandler.onSubmit(state = state) + } } override fun startAddressLookup() { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt index 15f88c680e..c8d794fe2b 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt @@ -315,7 +315,7 @@ internal class StoredCardDelegate( override fun handleBackPress(): Boolean { return if (_viewFlow.value == CardComponentViewType.AddressLookup) { - _viewFlow.tryEmit(CardComponentViewType.DefaultCardView) + _viewFlow.tryEmit(CardComponentViewType.StoredCardView) true } else { false diff --git a/card/src/main/res/values/strings.xml b/card/src/main/res/values/strings.xml index 29efdc76a4..423327ad52 100644 --- a/card/src/main/res/values/strings.xml +++ b/card/src/main/res/values/strings.xml @@ -40,4 +40,7 @@ CPF/CNPJ •••• %s + + + Use this address From f60416d20ba4644719269b84a0431bfdc22ad0de Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:10:23 +0100 Subject: [PATCH 102/255] Display selected adress lookup option in CardView COAND-730 --- .../card/internal/data/model/LookupAddress.kt | 11 +++++++++-- .../checkout/card/internal/ui/view/CardView.kt | 6 ++++++ card/src/main/res/layout/card_view.xml | 1 + .../ui/core/internal/ui/model/AddressOutputData.kt | 13 +++++++++++++ ui-core/src/main/res/values/styles.xml | 2 +- 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/data/model/LookupAddress.kt b/card/src/main/java/com/adyen/checkout/card/internal/data/model/LookupAddress.kt index 072af50c9d..882033c05d 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/data/model/LookupAddress.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/data/model/LookupAddress.kt @@ -15,7 +15,14 @@ data class LookupAddress( val address: AddressInputModel ) { override fun toString(): String { - return "${address.street} ${address.houseNumberOrName} ${address.apartmentSuite} " + - "${address.postalCode} ${address.city} ${address.stateOrProvince} ${address.country}" + return listOf( + address.street, + address.houseNumberOrName, + address.apartmentSuite, + address.postalCode, + address.city, + address.stateOrProvince, + address.country + ).filter { it.isNotBlank() }.joinToString(" ") } } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt index b08a334388..65bb4e1020 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt @@ -41,6 +41,7 @@ import com.adyen.checkout.core.internal.util.BuildUtils import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.loadLogo +import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.view.AdyenTextInputEditText import com.adyen.checkout.ui.core.internal.ui.view.RoundCornerImageView import com.adyen.checkout.ui.core.internal.util.hideError @@ -187,6 +188,7 @@ class CardView @JvmOverloads constructor( updateInstallments(cardOutputData) updateAddressHint(cardOutputData.addressUIState, cardOutputData.addressState.isOptional) setCardList(cardOutputData.cardBrands, cardOutputData.isCardListVisible) + updateAddressLookupInputText(cardOutputData.addressState) } @Suppress("ComplexMethod", "LongMethod") @@ -702,6 +704,10 @@ class CardView @JvmOverloads constructor( } } + private fun updateAddressLookupInputText(addressOutputData: AddressOutputData) { + binding.editTextAddressLookup.setText(addressOutputData.toString()) + } + private fun updateAddressHint(addressFormUIState: AddressFormUIState, isOptional: Boolean) { when (addressFormUIState) { AddressFormUIState.FULL_ADDRESS -> binding.addressFormInput.updateAddressHint(isOptional) diff --git a/card/src/main/res/layout/card_view.xml b/card/src/main/res/layout/card_view.xml index 23e9b940e4..ac2b740618 100644 --- a/card/src/main/res/layout/card_view.xml +++ b/card/src/main/res/layout/card_view.xml @@ -162,6 +162,7 @@ style="@style/AdyenCheckout.AddressLookup" android:clickable="false" android:focusable="false" + android:inputType="textMultiLine" android:nextFocusDown="@id/editText_socialSecurityNumber" android:nextFocusForward="@id/editText_socialSecurityNumber" /> diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressOutputData.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressOutputData.kt index d6df4baeb2..c8d8b2ed03 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressOutputData.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressOutputData.kt @@ -33,4 +33,17 @@ data class AddressOutputData( apartmentSuite.validation.isValid() && city.validation.isValid() && country.validation.isValid() + + override fun toString(): String { + // TODO check order with ios + return listOf( + street.value, + houseNumberOrName.value, + apartmentSuite.value, + postalCode.value, + city.value, + stateOrProvince.value, + country.value + ).filter { it.isNotBlank() }.joinToString(" ") + } } diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index 47a61e1b5b..ce97344d0b 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -205,7 +205,7 @@ - + + + - - - - - - - - - - - diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index e9e0878cf7..fa5cbcae26 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -28,7 +28,6 @@ import com.adyen.checkout.card.internal.data.api.TestDetectedCardType import com.adyen.checkout.card.internal.data.model.Brand import com.adyen.checkout.card.internal.data.model.DetectedCardType import com.adyen.checkout.card.internal.ui.model.AddressFieldPolicyParams -import com.adyen.checkout.card.internal.ui.model.AddressLookupState import com.adyen.checkout.card.internal.ui.model.CardComponentParamsMapper import com.adyen.checkout.card.internal.ui.model.CardListItem import com.adyen.checkout.card.internal.ui.model.CardOutputData @@ -64,6 +63,7 @@ import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams import com.adyen.checkout.ui.core.internal.util.AddressFormUtils diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt index 8e2fbc7725..a6d407b1e5 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt @@ -22,7 +22,6 @@ import com.adyen.checkout.card.SocialSecurityNumberVisibility import com.adyen.checkout.card.card import com.adyen.checkout.card.internal.data.model.Brand import com.adyen.checkout.card.internal.data.model.DetectedCardType -import com.adyen.checkout.card.internal.ui.model.AddressLookupState import com.adyen.checkout.card.internal.ui.model.CardComponentParamsMapper import com.adyen.checkout.card.internal.ui.model.CardListItem import com.adyen.checkout.card.internal.ui.model.CardOutputData @@ -49,6 +48,7 @@ import com.adyen.checkout.test.TestDispatcherExtension import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import kotlinx.coroutines.CoroutineScope diff --git a/card/src/main/java/com/adyen/checkout/card/AddressLookupCallback.kt b/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt similarity index 87% rename from card/src/main/java/com/adyen/checkout/card/AddressLookupCallback.kt rename to components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt index 7b74f6e7dd..2eb9c04f43 100644 --- a/card/src/main/java/com/adyen/checkout/card/AddressLookupCallback.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt @@ -6,7 +6,7 @@ * Created by ozgur on 11/12/2023. */ -package com.adyen.checkout.card +package com.adyen.checkout.components.core interface AddressLookupCallback { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt index 13caac2658..896694b81d 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt @@ -8,11 +8,11 @@ package com.adyen.checkout.dropin -import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.BalanceResult import com.adyen.checkout.components.core.OrderResponse import com.adyen.checkout.components.core.PaymentMethodsApiResponse import com.adyen.checkout.sessions.core.SessionPaymentResult +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import com.adyen.checkout.components.core.action.Action as ActionResponse sealed class BaseDropInServiceResult diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt index 03d22ebd18..6de6d0cb6a 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt @@ -13,8 +13,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.lifecycle.viewModelScope -import com.adyen.checkout.card.AddressLookupCallback import com.adyen.checkout.card.CardComponent +import com.adyen.checkout.components.core.AddressLookupCallback import com.adyen.checkout.core.internal.util.LogUtil import com.adyen.checkout.core.internal.util.Logger import com.adyen.checkout.dropin.databinding.FragmentCardComponentBinding diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt index 14f93d2ad6..89fa60a81a 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt @@ -11,7 +11,6 @@ package com.adyen.checkout.dropin.internal.ui import android.content.ComponentName import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.BalanceResult import com.adyen.checkout.components.core.CheckoutConfiguration @@ -45,6 +44,7 @@ import com.adyen.checkout.giftcard.internal.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent import com.adyen.checkout.sessions.core.internal.data.model.SessionDetails import com.adyen.checkout.sessions.core.internal.data.model.mapToModel +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt index acce367ead..a8ced66dfa 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt @@ -11,7 +11,6 @@ package com.adyen.checkout.example.service import android.util.Log import com.adyen.checkout.card.BinLookupData import com.adyen.checkout.card.CardComponentState -import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.BalanceResult @@ -37,6 +36,7 @@ import com.adyen.checkout.example.extensions.toStringPretty import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt index d2fe9d25ea..2050ac667c 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt @@ -10,14 +10,14 @@ import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import com.adyen.checkout.card.AddressLookupCallback import com.adyen.checkout.card.CardComponent -import com.adyen.checkout.card.internal.data.model.LookupAddress +import com.adyen.checkout.components.core.AddressLookupCallback import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.example.databinding.ActivityCardBinding import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.ui.configuration.CheckoutConfigurationProvider import com.adyen.checkout.redirect.RedirectComponent +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import javax.inject.Inject diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt index 9b8a51e8a2..202b39eed4 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt @@ -8,8 +8,8 @@ package com.adyen.checkout.example.ui.card -import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress internal sealed class CardEvent { diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 5a390bfc08..9066eddd53 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -5,7 +5,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.adyen.checkout.card.CardComponent import com.adyen.checkout.card.CardComponentState -import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.ComponentCallback import com.adyen.checkout.components.core.ComponentError @@ -16,6 +15,7 @@ import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt index c2fb3b9914..cd4f6ca96a 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt @@ -18,14 +18,14 @@ import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import com.adyen.checkout.card.AddressLookupCallback import com.adyen.checkout.card.CardComponent -import com.adyen.checkout.card.internal.data.model.LookupAddress +import com.adyen.checkout.components.core.AddressLookupCallback import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.example.databinding.ActivityCardBinding import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.ui.configuration.CheckoutConfigurationProvider import com.adyen.checkout.redirect.RedirectComponent +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import javax.inject.Inject diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt index 6a0e73c45f..942a0b00bf 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt @@ -15,7 +15,6 @@ import androidx.lifecycle.viewModelScope import com.adyen.checkout.card.CardBrand import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.card.CardType -import com.adyen.checkout.card.internal.data.model.LookupAddress import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.CheckoutConfiguration import com.adyen.checkout.components.core.ComponentError @@ -36,6 +35,7 @@ import com.adyen.checkout.sessions.core.SessionComponentCallback import com.adyen.checkout.sessions.core.SessionModel import com.adyen.checkout.sessions.core.SessionPaymentResult import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt new file mode 100644 index 0000000000..3b42dfb0f0 --- /dev/null +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 19/12/2023. + */ + +package com.adyen.checkout.ui.core.internal.ui + +import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.Flow + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +interface AddressLookupDelegate { + + val addressLookupStateFlow: Flow + val addressLookupEventChannel: Channel + + val addressDelegate: AddressDelegate + + fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) + fun startAddressLookup() + fun updateAddressLookupOptions(options: List) + fun setAddressLookupResult(lookupAddress: LookupAddress) + fun onAddressQueryChanged(query: String) + fun onAddressLookupCompleted(id: String): Boolean + fun updateAddressLookupInputData(update: AddressLookupInputData.() -> Unit) +} diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupEvent.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt similarity index 80% rename from card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupEvent.kt rename to ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt index 5699cf0268..a71ea49479 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupEvent.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt @@ -3,13 +3,12 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ozgur on 12/12/2023. + * Created by ozgur on 19/12/2023. */ -package com.adyen.checkout.card.internal.ui.model +package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo -import com.adyen.checkout.card.internal.data.model.LookupAddress @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) sealed class AddressLookupEvent { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupInputData.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt similarity index 63% rename from card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupInputData.kt rename to ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt index 64947e3a40..e64f23a771 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupInputData.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt @@ -3,16 +3,17 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ozgur on 8/12/2023. + * Created by ozgur on 19/12/2023. */ -package com.adyen.checkout.card.internal.ui.model +package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class AddressLookupInputData( - var query: String = "" + var query: String = "", + var selectedAddress: AddressInputModel = AddressInputModel() ) { fun reset() { query = "" diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupState.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt similarity index 72% rename from card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupState.kt rename to ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt index 47c7098a42..1b0c499293 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/AddressLookupState.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt @@ -3,14 +3,12 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ozgur on 8/12/2023. + * Created by ozgur on 19/12/2023. */ -package com.adyen.checkout.card.internal.ui.model +package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo -import com.adyen.checkout.card.internal.data.model.LookupAddress -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) sealed class AddressLookupState { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/data/model/LookupAddress.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LookupAddress.kt similarity index 84% rename from card/src/main/java/com/adyen/checkout/card/internal/data/model/LookupAddress.kt rename to ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LookupAddress.kt index 7f03438691..a6f1a1f46b 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/data/model/LookupAddress.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LookupAddress.kt @@ -3,12 +3,10 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ozgur on 28/11/2023. + * Created by ozgur on 19/12/2023. */ -package com.adyen.checkout.card.internal.data.model - -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel +package com.adyen.checkout.ui.core.internal.ui.model data class LookupAddress( val id: String, diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupOptionsAdapter.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt similarity index 89% rename from card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupOptionsAdapter.kt rename to ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt index 85c41f1b55..651200f1ee 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupOptionsAdapter.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt @@ -3,10 +3,10 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ozgur on 29/11/2023. + * Created by ozgur on 19/12/2023. */ -package com.adyen.checkout.card.internal.ui.view +package com.adyen.checkout.ui.core.internal.ui.view import android.view.LayoutInflater import android.view.ViewGroup @@ -14,8 +14,8 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.adyen.checkout.card.databinding.AddressLookupOptionItemViewBinding -import com.adyen.checkout.card.internal.data.model.LookupAddress +import com.adyen.checkout.ui.core.databinding.AddressLookupOptionItemViewBinding +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress internal class AddressLookupOptionsAdapter( private val onItemClicked: (LookupAddress) -> Boolean diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt similarity index 71% rename from card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt rename to ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index ff39500654..d9e26eab3f 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -3,39 +3,36 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ozgur on 1/12/2023. + * Created by ozgur on 19/12/2023. */ -package com.adyen.checkout.card.internal.ui.view +package com.adyen.checkout.ui.core.internal.ui.view import android.content.Context import android.text.Editable import android.util.AttributeSet import android.view.LayoutInflater import android.view.View -import android.view.View.OnFocusChangeListener import android.widget.LinearLayout +import androidx.annotation.RestrictTo import androidx.core.view.isVisible -import com.adyen.checkout.card.R -import com.adyen.checkout.card.databinding.AddressLookupViewBinding -import com.adyen.checkout.card.internal.data.model.LookupAddress -import com.adyen.checkout.card.internal.ui.CardDelegate -import com.adyen.checkout.card.internal.ui.model.AddressLookupEvent -import com.adyen.checkout.card.internal.ui.model.AddressLookupState import com.adyen.checkout.components.core.internal.ui.ComponentDelegate -import com.adyen.checkout.components.core.internal.ui.model.Validation +import com.adyen.checkout.ui.core.R +import com.adyen.checkout.ui.core.databinding.AddressLookupViewBinding +import com.adyen.checkout.ui.core.internal.ui.AddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.ComponentView -import com.adyen.checkout.ui.core.internal.ui.view.AdyenTextInputEditText +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState +import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import com.adyen.checkout.ui.core.internal.util.hideError import com.adyen.checkout.ui.core.internal.util.setLocalizedHintFromStyle -import com.adyen.checkout.ui.core.internal.util.showError import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") -internal class AddressLookupView @JvmOverloads constructor( +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +class AddressLookupView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 @@ -51,7 +48,7 @@ internal class AddressLookupView @JvmOverloads constructor( private lateinit var localizedContext: Context - private lateinit var cardDelegate: CardDelegate + private lateinit var addressLookupDelegate: AddressLookupDelegate private var addressLookupOptionsAdapter: AddressLookupOptionsAdapter? = null @@ -62,14 +59,14 @@ internal class AddressLookupView @JvmOverloads constructor( } override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { - require(delegate is CardDelegate) { "Unsupported delegate type" } - cardDelegate = delegate + require(delegate is AddressLookupDelegate) { "Unsupported delegate type" } + addressLookupDelegate = delegate this.localizedContext = localizedContext initLocalizedStrings(localizedContext) - cardDelegate.updateInputData { - addressLookupInputData.reset() + addressLookupDelegate.updateAddressLookupInputData { + reset() } observeDelegate(delegate, coroutineScope) @@ -82,21 +79,18 @@ internal class AddressLookupView @JvmOverloads constructor( } override fun highlightValidationErrors() { - cardDelegate.outputData.let { - binding.addressFormInput.highlightValidationErrors(false) - } + binding.addressFormInput.highlightValidationErrors(false) } - private fun observeDelegate(delegate: CardDelegate, coroutineScope: CoroutineScope) { - delegate.outputDataFlow - .mapNotNull { it.addressLookupState } + private fun observeDelegate(delegate: AddressLookupDelegate, coroutineScope: CoroutineScope) { + delegate.addressLookupStateFlow .onEach { outputDataChanged(it) } .launchIn(coroutineScope) } private fun initLocalizedStrings(localizedContext: Context) { binding.textInputLayoutAddressLookupQuery.setLocalizedHintFromStyle( - R.style.AdyenCheckout_Card_AddressLookup_Query, + R.style.AdyenCheckout_AddressLookup_Query, localizedContext ) binding.addressFormInput.initLocalizedContext(localizedContext) @@ -107,21 +101,10 @@ internal class AddressLookupView @JvmOverloads constructor( addressLookupQueryEditText?.setOnChangeListener { onQueryChanged(it) } - - addressLookupQueryEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> - val postalCodeValidation = cardDelegate.outputData.addressState.postalCode.validation - if (hasFocus) { - binding.textInputLayoutAddressLookupQuery.hideError() - } else if (postalCodeValidation is Validation.Invalid) { - binding.textInputLayoutAddressLookupQuery.showError( - localizedContext.getString(postalCodeValidation.reason) - ) - } - } } private fun initAddressFormInput(coroutineScope: CoroutineScope) { - binding.addressFormInput.attachDelegate(cardDelegate, coroutineScope) + binding.addressFormInput.attachDelegate(addressLookupDelegate.addressDelegate, coroutineScope) } private fun initAddressOptions() { @@ -134,14 +117,14 @@ internal class AddressLookupView @JvmOverloads constructor( private fun initManualEntryErrorTextView() { binding.textViewManualEntryError.setOnClickListener { clearQuery() - cardDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.Manual) + addressLookupDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.Manual) } } private fun initManualEntryInitialTextView() { binding.textViewManualEntryInitial.setOnClickListener { clearQuery() - cardDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.Manual) + addressLookupDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.Manual) } } @@ -181,11 +164,11 @@ internal class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryError.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false - cardDelegate.updateInputData { + addressLookupDelegate.updateAddressLookupInputData { if (addressLookupState.selectedAddress == null) { - address.resetAll() + selectedAddress.resetAll() } else { - address.set(addressLookupState.selectedAddress) + selectedAddress.set(addressLookupState.selectedAddress) } } } @@ -209,7 +192,7 @@ internal class AddressLookupView @JvmOverloads constructor( } private fun onQueryChanged(editable: Editable) { - cardDelegate.onAddressQueryChanged(editable.toString()) + addressLookupDelegate.onAddressQueryChanged(editable.toString()) binding.textInputLayoutAddressLookupQuery.hideError() } @@ -221,8 +204,13 @@ internal class AddressLookupView @JvmOverloads constructor( } private fun onAddressSelected(lookupAddress: LookupAddress): Boolean { - val isLoading = cardDelegate.onAddressLookupCompleted(lookupAddress.id) - cardDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.OptionSelected(lookupAddress, isLoading)) + val isLoading = addressLookupDelegate.onAddressLookupCompleted(lookupAddress.id) + addressLookupDelegate.addressLookupEventChannel.trySend( + AddressLookupEvent.OptionSelected( + lookupAddress, + isLoading + ) + ) clearQuery() return isLoading } diff --git a/card/src/main/res/layout/address_lookup_option_item_view.xml b/ui-core/src/main/res/layout/address_lookup_option_item_view.xml similarity index 96% rename from card/src/main/res/layout/address_lookup_option_item_view.xml rename to ui-core/src/main/res/layout/address_lookup_option_item_view.xml index 68f16efaef..693fd15c8c 100644 --- a/card/src/main/res/layout/address_lookup_option_item_view.xml +++ b/ui-core/src/main/res/layout/address_lookup_option_item_view.xml @@ -3,7 +3,7 @@ ~ ~ This file is open source and available under the MIT license. See the LICENSE file for more info. ~ - ~ Created by ozgur on 29/11/2023. + ~ Created by ozgur on 19/12/2023. --> @string/checkout_address_form_billing_address_title + + + + + + + + + From a75596e8102b805fa63aa42b6a618bed3ca63557 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:01:03 +0100 Subject: [PATCH 109/255] Add docs for address lookup related functionality COAND-730 --- .../checkout/card/AddressConfiguration.kt | 7 ++++--- .../com/adyen/checkout/card/CardComponent.kt | 20 +++++++++++++++++-- .../checkout/card/internal/ui/CardDelegate.kt | 1 - .../card/internal/ui/StoredCardDelegate.kt | 9 +-------- .../ui/model/CardComponentParamsMapper.kt | 2 +- .../internal/ui/DefaultCardDelegateTest.kt | 2 +- .../internal/ui/StoredCardDelegateTest.kt | 2 +- .../dropin/BaseDropInServiceContract.kt | 18 ++++++++++++++--- .../checkout/dropin/DropInServiceResult.kt | 19 +++++++++++++++++- .../internal/ui/model/AddressInputModel.kt | 6 +++++- .../core/internal/ui/model/AddressParams.kt | 4 +++- ui-core/src/main/res/values/styles.xml | 4 ++-- 12 files changed, 69 insertions(+), 25 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/AddressConfiguration.kt b/card/src/main/java/com/adyen/checkout/card/AddressConfiguration.kt index 3c060c29f8..0d3a4adc7b 100644 --- a/card/src/main/java/com/adyen/checkout/card/AddressConfiguration.kt +++ b/card/src/main/java/com/adyen/checkout/card/AddressConfiguration.kt @@ -37,10 +37,11 @@ sealed class AddressConfiguration : Parcelable { val addressFieldPolicy: CardAddressFieldPolicy = CardAddressFieldPolicy.Required() ) : AddressConfiguration() - // TODO address lookup configuration - @Suppress("PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY", "EmptyDefaultConstructor") + /** + * Address Lookup option will be shown as part of card component. + */ @Parcelize - class Lookup() : AddressConfiguration() + class Lookup : AddressConfiguration() /** * Configuration for requirement of the address fields. diff --git a/card/src/main/java/com/adyen/checkout/card/CardComponent.kt b/card/src/main/java/com/adyen/checkout/card/CardComponent.kt index fb1b47328d..172d6f6853 100644 --- a/card/src/main/java/com/adyen/checkout/card/CardComponent.kt +++ b/card/src/main/java/com/adyen/checkout/card/CardComponent.kt @@ -115,16 +115,32 @@ open class CardComponent constructor( cardDelegate.setOnBinLookupListener(listener) } - // TODO address lookup + /** + * Set a callback that will be triggered to perform address lookup actions. + * + * @param addressLookupCallback The callback that will be triggered to perform address lookup options such as + * query changes, completion of the lookup. + */ fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) { cardDelegate.setAddressLookupCallback(addressLookupCallback) } - // TODO address lookup + /** + * Updates the address options that will be displayed to the shopper in + * [com.adyen.checkout.ui.core.internal.ui.view.AddressLookupView] as part of [CardComponent]. + * + * @param options Address option list to be displayed. + */ fun updateAddressLookupOptions(options: List) { cardDelegate.updateAddressLookupOptions(options) } + /** + * Set the complete address lookup option to be prefilled in + * [com.adyen.checkout.ui.core.internal.ui.view.AddressLookupView]. + * + * @param lookupAddress Complete address details. + */ fun setAddressLookupResult(lookupAddress: LookupAddress) { cardDelegate.setAddressLookupResult(lookupAddress) } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt index face17a21e..4c07c34ef0 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt @@ -22,7 +22,6 @@ import com.adyen.checkout.ui.core.internal.ui.UIStateDelegate import com.adyen.checkout.ui.core.internal.ui.ViewProvidingDelegate import kotlinx.coroutines.flow.Flow -// TODO address lookup extract lookup related code @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) @Suppress("TooManyFunctions") interface CardDelegate : diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt index b9522c7cd7..11f934745a 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt @@ -320,12 +320,8 @@ internal class StoredCardDelegate( submitHandler.onSubmit(state) } - // TODO address lookup check - override fun startAddressLookup() { - _viewFlow.tryEmit(CardComponentViewType.AddressLookup) - } + override fun startAddressLookup() = Unit - // TODO address lookup not used override fun onAddressQueryChanged(query: String) = Unit override fun onAddressLookupCompleted(id: String) = false @@ -450,13 +446,10 @@ internal class StoredCardDelegate( // Bin lookup is not performed for stored cards override fun setOnBinLookupListener(listener: ((data: List) -> Unit)?) = Unit - // TODO address lookup not used override fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) = Unit - // TODO address lookup not used override fun updateAddressLookupOptions(options: List) = Unit - // TODO address lookup not used override fun setAddressLookupResult(lookupAddress: LookupAddress) = Unit override fun onCleared() { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapper.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapper.kt index 0d0b2375be..1fa46b3e69 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapper.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapper.kt @@ -153,8 +153,8 @@ internal class CardComponentParamsMapper( is AddressConfiguration.PostalCode -> { AddressParams.PostalCode(addressFieldPolicy.mapToAddressParamFieldPolicy()) } + is AddressConfiguration.Lookup -> { - // TODO address lookup AddressParams.Lookup() } } diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index fa5cbcae26..77328b4504 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -1291,7 +1291,7 @@ internal class DefaultCardDelegateTest( kcpBirthDateOrTaxNumberHint = kcpBirthDateOrTaxNumberHint, isCardListVisible = isCardListVisible, addressLookupState = AddressLookupState.Initial, - addressLookupOptions = emptyList(), // TODO address lookup + addressLookupOptions = emptyList(), // TODO address lookup test ) } diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt index a6d407b1e5..b3bed6aedc 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt @@ -570,7 +570,7 @@ internal class StoredCardDelegateTest( kcpBirthDateOrTaxNumberHint = null, isCardListVisible = isCardListVisible, addressLookupState = AddressLookupState.Initial, - addressLookupOptions = emptyList(), // TODO address lookup + addressLookupOptions = emptyList(), // TODO address lookup test ) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt index 8fe9aa79e3..4fb77639e4 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt @@ -86,7 +86,15 @@ interface BaseDropInServiceContract { */ fun sendRecurringResult(result: RecurringDropInServiceResult) - // TODO address lookup docs + /** + * Allows sending the result of Address Lookup operations. + * + * Call this method with a [AddressLookupDropInServiceResult] depending on the performed address lookup action. + * + * Check the subclasses of [AddressLookupDropInServiceResult] for more information. + * + * @param result the result of the action. + */ fun sendAddressLookupResult(result: AddressLookupDropInServiceResult) /** @@ -114,9 +122,13 @@ interface BaseDropInServiceContract { */ fun onBinLookup(data: List) = Unit - // TODO address lookup docs + /** + * Set a callback that will be called when shopper inputs a query to perform address lookup. + * + * @param query Query inputted by shopper. + */ fun onAddressLookupQuery(query: String) = Unit - // TODO address lookup + // TODO address lookup replace id with LookupAddress fun onAddressLookupCompleted(id: String) = false } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt index 896694b81d..0238a131dd 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt @@ -186,13 +186,30 @@ sealed class RecurringDropInServiceResult : BaseDropInServiceResult() { ) : RecurringDropInServiceResult(), DropInServiceResultError } -// TODO address lookup docs sealed class AddressLookupDropInServiceResult : BaseDropInServiceResult() { + /** + * Only applicable to address lookup flow. + * + * Send this to display the options received for the query shopper has inputted. + * + * @param options Address options to be displayed to the shopper. + */ class LookupResult( val options: List ) : AddressLookupDropInServiceResult() + /** + * * Only applicable to address lookup flow. + * + * Send this to display an error dialog and optionally dismiss Drop-in. + * + * @param errorDialog If set, a dialog will be shown with the data passed in [ErrorDialog]. If null, no + * dialog will be displayed. + * @param reason the reason of the error. You will receive this value back in your [DropInCallback] class. This + * value is not used internally by Drop-in. + * @param dismissDropIn whether Drop-in should be dismissed after presenting the Alert Dialog. + */ class Error( override val errorDialog: ErrorDialog?, override val reason: String? = null, diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressInputModel.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressInputModel.kt index 6b334e9b9c..0c55f4b5d2 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressInputModel.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressInputModel.kt @@ -43,7 +43,11 @@ data class AddressInputModel( city = "" } - // TODO address lookup + /** + * Reset the data. + * + * Note: This method is called from address lookup and all the form needs to be reset. + */ fun resetAll() { country = "" postalCode = "" diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressParams.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressParams.kt index 4b53288e22..a0f6566145 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressParams.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressParams.kt @@ -42,7 +42,9 @@ sealed class AddressParams { val addressFieldPolicy: AddressFieldPolicy ) : AddressParams() - // TODO address lookup + /** + * Address Lookup option will be shown as part of card component. + */ class Lookup : AddressParams() } diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index 34b7817156..f1698d766b 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -326,12 +326,12 @@ @string/checkout_address_form_billing_address_title - + - + From 6c4578ce2222d5433ee649ea1c20a251b153f7dc Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:16:05 +0100 Subject: [PATCH 110/255] Replace id with LookupAddress in onAddressLookupCompletion callback COAND-730 --- .../ui/DefaultACHDirectDebitDelegate.kt | 36 +++++++++---------- .../ui/StoredACHDirectDebitDelegate.kt | 6 ++-- .../ui/model/ACHDirectDebitInputData.kt | 2 +- .../ui/DefaultACHDirectDebitDelegateTest.kt | 2 +- .../internal/ui/DefaultBoletoDelegate.kt | 32 ++++++++--------- .../internal/ui/model/BoletoInputData.kt | 2 +- .../internal/ui/DefaultBoletoDelegateTest.kt | 2 +- .../com/adyen/checkout/card/CardComponent.kt | 2 +- .../card/internal/ui/DefaultCardDelegate.kt | 8 ++--- .../card/internal/ui/StoredCardDelegate.kt | 6 ++-- .../card/internal/ui/model/CardInputData.kt | 2 +- .../card/internal/ui/model/CardOutputData.kt | 2 +- .../internal/ui/DefaultCardDelegateTest.kt | 2 +- .../internal/ui/StoredCardDelegateTest.kt | 2 +- .../components/core}/AddressInputModel.kt | 6 ++-- .../components/core/AddressLookupCallback.kt | 2 +- .../components/core}/LookupAddress.kt | 2 +- .../dropin/BaseDropInServiceContract.kt | 10 ++++-- .../checkout/dropin/DropInServiceResult.kt | 2 +- .../internal/service/BaseDropInService.kt | 5 +-- .../service/BaseDropInServiceInterfaces.kt | 3 +- .../ui/CardComponentDialogFragment.kt | 5 +-- .../dropin/internal/ui/DropInActivity.kt | 5 +-- .../ui/DropInBottomSheetDialogFragment.kt | 5 +-- .../dropin/internal/ui/DropInViewModel.kt | 2 +- .../service/ExampleAdvancedDropInService.kt | 8 ++--- .../checkout/example/ui/card/CardActivity.kt | 8 ++--- .../checkout/example/ui/card/CardEvent.kt | 2 +- .../checkout/example/ui/card/CardViewModel.kt | 8 ++--- .../ui/card/SessionsCardTakenOverActivity.kt | 4 +-- .../ui/card/SessionsCardTakenOverViewModel.kt | 4 +-- .../ui/core/internal/ui/AddressDelegate.kt | 2 +- .../core/internal/ui/AddressLookupDelegate.kt | 4 +-- .../internal/ui/model/AddressLookupEvent.kt | 1 + .../ui/model/AddressLookupInputData.kt | 1 + .../internal/ui/model/AddressLookupState.kt | 2 ++ .../ui/view/AddressLookupOptionsAdapter.kt | 4 +-- .../internal/ui/view/AddressLookupView.kt | 12 +++---- .../internal/util/AddressValidationUtils.kt | 12 +++---- 39 files changed, 120 insertions(+), 105 deletions(-) rename {ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model => components-core/src/main/java/com/adyen/checkout/components/core}/AddressInputModel.kt (93%) rename {ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model => components-core/src/main/java/com/adyen/checkout/components/core}/LookupAddress.kt (94%) diff --git a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt index f7b0995eb9..9c00313617 100644 --- a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt +++ b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt @@ -14,6 +14,7 @@ import com.adyen.checkout.ach.internal.ui.model.ACHDirectDebitComponentParams import com.adyen.checkout.ach.internal.ui.model.ACHDirectDebitInputData import com.adyen.checkout.ach.internal.ui.model.ACHDirectDebitOutputData import com.adyen.checkout.ach.internal.util.ACHDirectDebitValidationUtils +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.Order import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod @@ -39,7 +40,6 @@ import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.ui.UIStateDelegate -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams @@ -134,7 +134,7 @@ internal class DefaultACHDirectDebitDelegate( private fun onInputDataChanged() { val outputData = createOutputData( countryOptions = outputData.addressState.countryOptions, - stateOptions = outputData.addressState.stateOptions + stateOptions = outputData.addressState.stateOptions, ) _outputDataFlow.tryEmit(outputData) updateComponentState(outputData) @@ -151,11 +151,11 @@ internal class DefaultACHDirectDebitDelegate( ): ACHDirectDebitOutputData { val updatedCountryOptions = AddressFormUtils.markAddressListItemSelected( countryOptions, - inputData.address.country + inputData.address.country, ) val updatedStateOptions = AddressFormUtils.markAddressListItemSelected( stateOptions, - inputData.address.stateOrProvince + inputData.address.stateOrProvince, ) val addressFormUIState = AddressFormUIState.fromAddressParams(componentParams.addressParams) @@ -169,11 +169,11 @@ internal class DefaultACHDirectDebitDelegate( addressFormUIState, updatedCountryOptions, updatedStateOptions, - false + false, ), addressUIState = addressFormUIState, shouldStorePaymentMethod = inputData.isStorePaymentMethodSwitchChecked, - showStorePaymentField = showStorePaymentField() + showStorePaymentField = showStorePaymentField(), ) } @@ -182,7 +182,7 @@ internal class DefaultACHDirectDebitDelegate( coroutineScope.launch { publicKeyRepository.fetchPublicKey( environment = componentParams.environment, - clientKey = componentParams.clientKey + clientKey = componentParams.clientKey, ).fold( onSuccess = { key -> Logger.d(TAG, "Public key fetched") @@ -192,7 +192,7 @@ internal class DefaultACHDirectDebitDelegate( onFailure = { e -> Logger.e(TAG, "Unable to fetch public key") exceptionChannel.trySend(ComponentException("Unable to fetch publicKey.", e)) - } + }, ) } } @@ -205,7 +205,7 @@ internal class DefaultACHDirectDebitDelegate( val countryOptions = AddressFormUtils.initializeCountryOptions( shopperLocale = componentParams.shopperLocale, addressParams = componentParams.addressParams, - countryList = countries + countryList = countries, ) countryOptions.firstOrNull { it.selected }?.let { inputData.address.country = it.code @@ -239,14 +239,14 @@ internal class DefaultACHDirectDebitDelegate( addressRepository.getStateList( shopperLocale = componentParams.shopperLocale, countryCode = countryCode, - coroutineScope = coroutineScope + coroutineScope = coroutineScope, ) } private fun requestCountryList() { addressRepository.getCountryList( shopperLocale = componentParams.shopperLocale, - coroutineScope = coroutineScope + coroutineScope = coroutineScope, ) } @@ -272,7 +272,7 @@ internal class DefaultACHDirectDebitDelegate( return ACHDirectDebitComponentState( data = PaymentComponentData(null, null, null), isInputValid = outputData.isValid, - isReady = publicKey != null + isReady = publicKey != null, ) } @@ -280,12 +280,12 @@ internal class DefaultACHDirectDebitDelegate( val encryptedBankAccountNumber = genericEncryptor.encryptField( fieldKeyToEncrypt = ENCRYPTION_KEY_FOR_BANK_ACCOUNT_NUMBER, fieldValueToEncrypt = outputData.bankAccountNumber.value, - publicKey = publicKey + publicKey = publicKey, ) val encryptedBankLocationId = genericEncryptor.encryptField( fieldKeyToEncrypt = ENCRYPTION_KEY_FOR_BANK_LOCATION_ID, fieldValueToEncrypt = outputData.bankLocationId.value, - publicKey = publicKey + publicKey = publicKey, ) val achPaymentMethod = ACHDirectDebitPaymentMethod( @@ -305,7 +305,7 @@ internal class DefaultACHDirectDebitDelegate( if (isAddressRequired(outputData.addressUIState)) { paymentComponentData.billingAddress = AddressFormUtils.makeAddressData( addressOutputData = outputData.addressState, - addressFormUIState = outputData.addressUIState + addressFormUIState = outputData.addressUIState, ) } @@ -315,7 +315,7 @@ internal class DefaultACHDirectDebitDelegate( return ACHDirectDebitComponentState( data = PaymentComponentData(null, null, null), isInputValid = false, - isReady = true + isReady = true, ) } } @@ -339,7 +339,7 @@ internal class DefaultACHDirectDebitDelegate( submitFlow = submitFlow, lifecycleOwner = lifecycleOwner, coroutineScope = coroutineScope, - callback = callback + callback = callback, ) } @@ -359,7 +359,7 @@ internal class DefaultACHDirectDebitDelegate( override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit( - state = state + state = state, ) } diff --git a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/StoredACHDirectDebitDelegate.kt b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/StoredACHDirectDebitDelegate.kt index fbb33c6980..77705d48c6 100644 --- a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/StoredACHDirectDebitDelegate.kt +++ b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/StoredACHDirectDebitDelegate.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.ach.ACHDirectDebitComponentState import com.adyen.checkout.ach.internal.ui.model.ACHDirectDebitComponentParams import com.adyen.checkout.ach.internal.ui.model.ACHDirectDebitInputData import com.adyen.checkout.ach.internal.ui.model.ACHDirectDebitOutputData +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethodTypes @@ -29,7 +30,6 @@ import com.adyen.checkout.core.internal.util.LogUtil import com.adyen.checkout.core.internal.util.Logger import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.ComponentViewType -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import kotlinx.coroutines.CoroutineScope @@ -127,7 +127,7 @@ internal class StoredACHDirectDebitDelegate( return ACHDirectDebitComponentState( data = paymentComponentData, isInputValid = true, - isReady = true + isReady = true, ) } @@ -163,7 +163,7 @@ internal class StoredACHDirectDebitDelegate( submitFlow = submitFlow, lifecycleOwner = lifecycleOwner, coroutineScope = coroutineScope, - callback = callback + callback = callback, ) } diff --git a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitInputData.kt b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitInputData.kt index af0702df85..eb11dcbf58 100644 --- a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitInputData.kt +++ b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitInputData.kt @@ -8,8 +8,8 @@ package com.adyen.checkout.ach.internal.ui.model +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.internal.ui.model.InputData -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel internal data class ACHDirectDebitInputData( var bankAccountNumber: String = "", diff --git a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt index 01c0f65997..4e883bacab 100644 --- a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt +++ b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt @@ -15,6 +15,7 @@ import com.adyen.checkout.ach.ACHDirectDebitConfiguration import com.adyen.checkout.ach.R import com.adyen.checkout.ach.achDirectDebit import com.adyen.checkout.ach.internal.ui.model.ACHDirectDebitComponentParamsMapper +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.CheckoutConfiguration import com.adyen.checkout.components.core.OrderRequest @@ -36,7 +37,6 @@ import com.adyen.checkout.ui.core.internal.data.api.AddressRepository import com.adyen.checkout.ui.core.internal.test.TestAddressRepository import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.AddressFormUtils diff --git a/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt b/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt index 4fc2d4355b..24d3377d8c 100644 --- a/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt +++ b/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt @@ -15,6 +15,7 @@ import com.adyen.checkout.boleto.internal.ui.model.BoletoComponentParams import com.adyen.checkout.boleto.internal.ui.model.BoletoInputData import com.adyen.checkout.boleto.internal.ui.model.BoletoOutputData import com.adyen.checkout.boleto.internal.util.BoletoValidationUtils +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod @@ -33,7 +34,6 @@ import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams @@ -127,7 +127,7 @@ internal class DefaultBoletoDelegate( val countryOptions = AddressFormUtils.initializeCountryOptions( shopperLocale = componentParams.shopperLocale, addressParams = componentParams.addressParams, - countryList = countries + countryList = countries, ) countryOptions.firstOrNull { it.selected }?.let { inputData.address.country = it.code @@ -141,7 +141,7 @@ internal class DefaultBoletoDelegate( private fun requestCountryList() { addressRepository.getCountryList( shopperLocale = componentParams.shopperLocale, - coroutineScope = coroutineScope + coroutineScope = coroutineScope, ) } @@ -149,7 +149,7 @@ internal class DefaultBoletoDelegate( addressRepository.getStateList( shopperLocale = componentParams.shopperLocale, countryCode = countryCode, - coroutineScope = coroutineScope + coroutineScope = coroutineScope, ) } @@ -167,7 +167,7 @@ internal class DefaultBoletoDelegate( private fun onInputDataChanged() { val outputData = createOutputData( countryOptions = outputData.addressState.countryOptions, - stateOptions = outputData.addressState.stateOptions + stateOptions = outputData.addressState.stateOptions, ) _outputDataFlow.tryEmit(outputData) updateComponentState(outputData) @@ -189,11 +189,11 @@ internal class DefaultBoletoDelegate( ): BoletoOutputData { val updatedCountryOptions = AddressFormUtils.markAddressListItemSelected( countryOptions, - inputData.address.country + inputData.address.country, ) val updatedStateOptions = AddressFormUtils.markAddressListItemSelected( stateOptions, - inputData.address.stateOrProvince + inputData.address.stateOrProvince, ) val addressFormUIState = AddressFormUIState.fromAddressParams(componentParams.addressParams) @@ -202,22 +202,22 @@ internal class DefaultBoletoDelegate( firstNameState = BoletoValidationUtils.validateFirstName(inputData.firstName), lastNameState = BoletoValidationUtils.validateLastName(inputData.lastName), socialSecurityNumberState = SocialSecurityNumberUtils.validateSocialSecurityNumber( - inputData.socialSecurityNumber + inputData.socialSecurityNumber, ), addressState = AddressValidationUtils.validateAddressInput( inputData.address, addressFormUIState, updatedCountryOptions, updatedStateOptions, - false + false, ), addressUIState = addressFormUIState, isEmailVisible = componentParams.isEmailVisible, isSendEmailSelected = inputData.isSendEmailSelected, shopperEmailState = BoletoValidationUtils.validateShopperEmail( inputData.isSendEmailSelected, - inputData.shopperEmail - ) + inputData.shopperEmail, + ), ) } @@ -241,8 +241,8 @@ internal class DefaultBoletoDelegate( socialSecurityNumber = outputData.socialSecurityNumberState.value, shopperName = ShopperName( firstName = outputData.firstNameState.value, - lastName = outputData.lastNameState.value - ) + lastName = outputData.lastNameState.value, + ), ) if (outputData.isSendEmailSelected) { paymentComponentData.shopperEmail = outputData.shopperEmailState.value @@ -250,7 +250,7 @@ internal class DefaultBoletoDelegate( if (AddressFormUtils.isAddressRequired(outputData.addressUIState)) { paymentComponentData.billingAddress = AddressFormUtils.makeAddressData( addressOutputData = outputData.addressState, - addressFormUIState = outputData.addressUIState + addressFormUIState = outputData.addressUIState, ) } val countriesList: List = outputData.addressState.countryOptions @@ -259,7 +259,7 @@ internal class DefaultBoletoDelegate( return BoletoComponentState( data = paymentComponentData, isInputValid = outputData.isValid, - isReady = countriesList.isNotEmpty() && statesList.isNotEmpty() + isReady = countriesList.isNotEmpty() && statesList.isNotEmpty(), ) } @@ -282,7 +282,7 @@ internal class DefaultBoletoDelegate( submitFlow = submitFlow, lifecycleOwner = lifecycleOwner, coroutineScope = coroutineScope, - callback = callback + callback = callback, ) } diff --git a/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/model/BoletoInputData.kt b/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/model/BoletoInputData.kt index 30c5c82260..8bf9d61091 100644 --- a/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/model/BoletoInputData.kt +++ b/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/model/BoletoInputData.kt @@ -8,8 +8,8 @@ package com.adyen.checkout.boleto.internal.ui.model +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.internal.ui.model.InputData -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel internal data class BoletoInputData( var firstName: String = "", diff --git a/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt b/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt index 1d7995e7bd..c632a6a7a5 100644 --- a/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt +++ b/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.boleto.BoletoComponentState import com.adyen.checkout.boleto.BoletoConfiguration import com.adyen.checkout.boleto.boleto import com.adyen.checkout.boleto.internal.ui.model.BoletoComponentParamsMapper +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.CheckoutConfiguration import com.adyen.checkout.components.core.Order @@ -26,7 +27,6 @@ import com.adyen.checkout.core.internal.util.Logger import com.adyen.checkout.test.extensions.test import com.adyen.checkout.ui.core.internal.test.TestAddressRepository import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel diff --git a/card/src/main/java/com/adyen/checkout/card/CardComponent.kt b/card/src/main/java/com/adyen/checkout/card/CardComponent.kt index 172d6f6853..93849af554 100644 --- a/card/src/main/java/com/adyen/checkout/card/CardComponent.kt +++ b/card/src/main/java/com/adyen/checkout/card/CardComponent.kt @@ -18,6 +18,7 @@ import com.adyen.checkout.action.core.internal.ui.GenericActionDelegate import com.adyen.checkout.card.internal.provider.CardComponentProvider import com.adyen.checkout.card.internal.ui.CardDelegate import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.ButtonComponent import com.adyen.checkout.components.core.internal.ComponentEventHandler @@ -30,7 +31,6 @@ import com.adyen.checkout.core.internal.util.Logger import com.adyen.checkout.ui.core.internal.ui.ButtonDelegate import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.ViewableComponent -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import com.adyen.checkout.ui.core.internal.util.mergeViewFlows import kotlinx.coroutines.flow.Flow diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index b71d4d4605..8cf6d78402 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -35,7 +35,9 @@ import com.adyen.checkout.card.internal.util.DetectedCardTypesUtils import com.adyen.checkout.card.internal.util.InstallmentUtils import com.adyen.checkout.card.internal.util.KcpValidationUtils import com.adyen.checkout.card.internal.util.toBinLookupData +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod @@ -66,14 +68,12 @@ import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import com.adyen.checkout.ui.core.internal.util.AddressFormUtils import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import com.adyen.checkout.ui.core.internal.util.SocialSecurityNumberUtils @@ -536,8 +536,8 @@ class DefaultCardDelegate( addressLookupCallback?.onQueryChanged(query) } - override fun onAddressLookupCompleted(id: String): Boolean { - return addressLookupCallback?.onLookupCompleted(id) ?: false + override fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean { + return addressLookupCallback?.onLookupCompleted(lookupAddress) ?: false } override fun handleBackPress(): Boolean { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt index 11f934745a..e7b275cf60 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt @@ -23,7 +23,9 @@ import com.adyen.checkout.card.internal.ui.model.ExpiryDate import com.adyen.checkout.card.internal.ui.model.InputFieldUIState import com.adyen.checkout.card.internal.ui.model.StoredCVCVisibility import com.adyen.checkout.card.internal.util.CardValidationUtils +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethodTypes @@ -52,12 +54,10 @@ import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import com.adyen.threeds2.ThreeDS2Service import kotlinx.coroutines.CoroutineScope @@ -324,7 +324,7 @@ internal class StoredCardDelegate( override fun onAddressQueryChanged(query: String) = Unit - override fun onAddressLookupCompleted(id: String) = false + override fun onAddressLookupCompleted(lookupAddress: LookupAddress) = false override fun handleBackPress(): Boolean { return if (_viewFlow.value == CardComponentViewType.AddressLookup) { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt index 7a21a2ea65..07ebd53e28 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt @@ -9,8 +9,8 @@ package com.adyen.checkout.card.internal.ui.model import androidx.annotation.RestrictTo import com.adyen.checkout.card.internal.ui.view.InstallmentModel +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.internal.ui.model.InputData -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt index 935114dc1c..578caa8ade 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt @@ -11,12 +11,12 @@ import androidx.annotation.RestrictTo import androidx.annotation.StringRes import com.adyen.checkout.card.internal.data.model.DetectedCardType import com.adyen.checkout.card.internal.ui.view.InstallmentModel +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.internal.ui.model.FieldState import com.adyen.checkout.components.core.internal.ui.model.OutputData import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class CardOutputData( diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index 77328b4504..55d777ac9e 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -40,6 +40,7 @@ import com.adyen.checkout.card.internal.ui.model.InstallmentsParamsMapper import com.adyen.checkout.card.internal.ui.view.InstallmentModel import com.adyen.checkout.card.internal.util.DetectedCardTypesUtils import com.adyen.checkout.card.internal.util.InstallmentUtils +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.CheckoutConfiguration import com.adyen.checkout.components.core.OrderRequest @@ -61,7 +62,6 @@ import com.adyen.checkout.ui.core.internal.data.api.AddressRepository import com.adyen.checkout.ui.core.internal.test.TestAddressRepository import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt index b3bed6aedc..9c2871725e 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt @@ -29,6 +29,7 @@ import com.adyen.checkout.card.internal.ui.model.ExpiryDate import com.adyen.checkout.card.internal.ui.model.InputFieldUIState import com.adyen.checkout.card.internal.ui.model.InstallmentsParamsMapper import com.adyen.checkout.card.internal.ui.view.InstallmentModel +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.CheckoutConfiguration import com.adyen.checkout.components.core.OrderRequest @@ -47,7 +48,6 @@ import com.adyen.checkout.cse.internal.test.TestCardEncryptor import com.adyen.checkout.test.TestDispatcherExtension import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressInputModel.kt b/components-core/src/main/java/com/adyen/checkout/components/core/AddressInputModel.kt similarity index 93% rename from ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressInputModel.kt rename to components-core/src/main/java/com/adyen/checkout/components/core/AddressInputModel.kt index 0c55f4b5d2..1838fe1b35 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressInputModel.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/AddressInputModel.kt @@ -1,12 +1,12 @@ /* - * Copyright (c) 2022 Adyen N.V. + * Copyright (c) 2023 Adyen N.V. * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by ozgur on 8/3/2022. + * Created by ozgur on 20/12/2023. */ -package com.adyen.checkout.ui.core.internal.ui.model +package com.adyen.checkout.components.core data class AddressInputModel( var postalCode: String = "", diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt b/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt index 2eb9c04f43..1030219cd9 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt @@ -12,5 +12,5 @@ interface AddressLookupCallback { fun onQueryChanged(query: String) - fun onLookupCompleted(id: String) = false + fun onLookupCompleted(lookupAddress: LookupAddress) = false } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LookupAddress.kt b/components-core/src/main/java/com/adyen/checkout/components/core/LookupAddress.kt similarity index 94% rename from ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LookupAddress.kt rename to components-core/src/main/java/com/adyen/checkout/components/core/LookupAddress.kt index a6f1a1f46b..c203d18fbb 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LookupAddress.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/LookupAddress.kt @@ -6,7 +6,7 @@ * Created by ozgur on 19/12/2023. */ -package com.adyen.checkout.ui.core.internal.ui.model +package com.adyen.checkout.components.core data class LookupAddress( val id: String, diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt index 4fb77639e4..6947884d24 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/BaseDropInServiceContract.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.dropin import android.os.Bundle import com.adyen.checkout.card.BinLookupData +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.core.exception.MethodNotImplementedException @@ -129,6 +130,11 @@ interface BaseDropInServiceContract { */ fun onAddressLookupQuery(query: String) = Unit - // TODO address lookup replace id with LookupAddress - fun onAddressLookupCompleted(id: String) = false + /** + * Set a callback that will be called when shopper chooses and address option that requires complete details to be + * provided. + * + * @param lookupAddress Address option selected by shopper. + */ + fun onAddressLookupCompleted(lookupAddress: LookupAddress) = false } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt index 0238a131dd..6bd787185e 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt @@ -9,10 +9,10 @@ package com.adyen.checkout.dropin import com.adyen.checkout.components.core.BalanceResult +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.OrderResponse import com.adyen.checkout.components.core.PaymentMethodsApiResponse import com.adyen.checkout.sessions.core.SessionPaymentResult -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import com.adyen.checkout.components.core.action.Action as ActionResponse sealed class BaseDropInServiceResult diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt index 55604d30c7..b973f4682e 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt @@ -18,6 +18,7 @@ import android.os.Bundle import android.os.IBinder import androidx.annotation.RestrictTo import com.adyen.checkout.card.BinLookupData +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.core.internal.util.LogUtil @@ -151,8 +152,8 @@ constructor() : Service(), CoroutineScope, BaseDropInServiceInterface, BaseDropI onAddressLookupQuery(query) } - final override fun onAddressLookupCompletion(id: String): Boolean { - return onAddressLookupCompleted(id) + final override fun onAddressLookupCompletion(lookupAddress: LookupAddress): Boolean { + return onAddressLookupCompleted(lookupAddress) } internal class DropInBinder(service: BaseDropInService) : Binder() { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInServiceInterfaces.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInServiceInterfaces.kt index 5eae7846b0..730e909c11 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInServiceInterfaces.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInServiceInterfaces.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.dropin.internal.service import com.adyen.checkout.card.BinLookupData import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.StoredPaymentMethod @@ -30,7 +31,7 @@ internal interface BaseDropInServiceInterface { fun onBinValueCalled(binValue: String) fun onBinLookupCalled(data: List) fun onAddressLookupQueryChanged(query: String) - fun onAddressLookupCompletion(id: String): Boolean + fun onAddressLookupCompletion(lookupAddress: LookupAddress): Boolean } internal interface SessionDropInServiceInterface : BaseDropInServiceInterface { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt index 6de6d0cb6a..93b16e5d86 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt @@ -15,6 +15,7 @@ import android.view.ViewGroup import androidx.lifecycle.viewModelScope import com.adyen.checkout.card.CardComponent import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.core.internal.util.LogUtil import com.adyen.checkout.core.internal.util.Logger import com.adyen.checkout.dropin.databinding.FragmentCardComponentBinding @@ -64,8 +65,8 @@ internal class CardComponentDialogFragment : BaseComponentDialogFragment(), Addr protocol.onAddressLookupQuery(query) } - override fun onLookupCompleted(id: String): Boolean { - return protocol.onAddressLookupCompletion(id) + override fun onLookupCompleted(lookupAddress: LookupAddress): Boolean { + return protocol.onAddressLookupCompletion(lookupAddress) } override fun onBackPressed(): Boolean { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt index 2adfbf9cda..ca7cb30a55 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt @@ -26,6 +26,7 @@ import com.adyen.checkout.card.BinLookupData import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.BalanceResult import com.adyen.checkout.components.core.CheckoutConfiguration +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.OrderResponse import com.adyen.checkout.components.core.PaymentComponentState @@ -706,8 +707,8 @@ internal class DropInActivity : dropInService?.onAddressLookupQueryChanged(query) } - override fun onAddressLookupCompletion(id: String): Boolean { - return dropInService?.onAddressLookupCompletion(id) ?: false + override fun onAddressLookupCompletion(lookupAddress: LookupAddress): Boolean { + return dropInService?.onAddressLookupCompletion(lookupAddress) ?: false } private fun showDialog(title: String, message: String, onDismiss: () -> Unit) { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInBottomSheetDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInBottomSheetDialogFragment.kt index 5407d79568..451c73d6dc 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInBottomSheetDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInBottomSheetDialogFragment.kt @@ -17,6 +17,7 @@ import android.widget.FrameLayout import androidx.fragment.app.activityViewModels import com.adyen.checkout.card.BinLookupData import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.StoredPaymentMethod @@ -58,7 +59,7 @@ internal abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragm dialog.setOnShowListener { val bottomSheet = (dialog as BottomSheetDialog).findViewById( - com.google.android.material.R.id.design_bottom_sheet + com.google.android.material.R.id.design_bottom_sheet, ) if (bottomSheet != null) { @@ -113,6 +114,6 @@ internal abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragm fun onBinValue(binValue: String) fun onBinLookup(data: List) fun onAddressLookupQuery(query: String) - fun onAddressLookupCompletion(id: String): Boolean + fun onAddressLookupCompletion(lookupAddress: LookupAddress): Boolean } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt index 89fa60a81a..874c3c9b03 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt @@ -14,6 +14,7 @@ import androidx.lifecycle.viewModelScope import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.BalanceResult import com.adyen.checkout.components.core.CheckoutConfiguration +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.OrderResponse import com.adyen.checkout.components.core.PaymentComponentData @@ -44,7 +45,6 @@ import com.adyen.checkout.giftcard.internal.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent import com.adyen.checkout.sessions.core.internal.data.model.SessionDetails import com.adyen.checkout.sessions.core.internal.data.model.mapToModel -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt index a8ced66dfa..7788f934a3 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt @@ -12,8 +12,10 @@ import android.util.Log import com.adyen.checkout.card.BinLookupData import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.BalanceResult +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.Order import com.adyen.checkout.components.core.OrderResponse import com.adyen.checkout.components.core.PaymentComponentData @@ -35,8 +37,6 @@ import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.extensions.toStringPretty import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview @@ -431,8 +431,8 @@ class ExampleAdvancedDropInService : DropInService() { addressLookupQueryFlow.tryEmit(query) } - override fun onAddressLookupCompleted(id: String): Boolean { - Log.d(TAG, "On address lookup query completion: $id") + override fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean { + Log.d(TAG, "On address lookup query completion: $lookupAddress") return false } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt index 2050ac667c..b19a4b8fe8 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt @@ -12,12 +12,12 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.adyen.checkout.card.CardComponent import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.example.databinding.ActivityCardBinding import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.ui.configuration.CheckoutConfigurationProvider import com.adyen.checkout.redirect.RedirectComponent -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import javax.inject.Inject @@ -149,9 +149,9 @@ class CardActivity : AppCompatActivity(), AddressLookupCallback { cardViewModel.onAddressLookupQueryChanged(query) } - override fun onLookupCompleted(id: String): Boolean { - Log.d(TAG, "on lookup completed $id") - cardViewModel.onAddressLookupCompleted(id) + override fun onLookupCompleted(lookupAddress: LookupAddress): Boolean { + Log.d(TAG, "on lookup completed $lookupAddress") + cardViewModel.onAddressLookupCompleted(lookupAddress) return true } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt index 202b39eed4..6e5a3978fd 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardEvent.kt @@ -8,8 +8,8 @@ package com.adyen.checkout.example.ui.card +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress internal sealed class CardEvent { diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 9066eddd53..3a394cc1ec 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -6,16 +6,16 @@ import androidx.lifecycle.viewModelScope import com.adyen.checkout.card.CardComponent import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.ComponentCallback import com.adyen.checkout.components.core.ComponentError +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview @@ -116,10 +116,10 @@ internal class CardViewModel @Inject constructor( } } - fun onAddressLookupCompleted(id: String) { + fun onAddressLookupCompleted(lookupAddress: LookupAddress) { viewModelScope.launch { delay(ADDRESS_LOOKUP_COMPLETION_DELAY) - _events.emit(CardEvent.AddressLookupResult(ADDRESS_LOOKUP_OPTIONS.first { it.id == id })) + _events.emit(CardEvent.AddressLookupResult(ADDRESS_LOOKUP_OPTIONS.first { it.id == lookupAddress.id })) } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt index cd4f6ca96a..0d60b03123 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverActivity.kt @@ -20,12 +20,12 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.adyen.checkout.card.CardComponent import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.example.databinding.ActivityCardBinding import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.ui.configuration.CheckoutConfigurationProvider import com.adyen.checkout.redirect.RedirectComponent -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import javax.inject.Inject @@ -104,7 +104,7 @@ class SessionsCardTakenOverActivity : AppCompatActivity(), AddressLookupCallback checkoutSession = sessionsCardComponentData.checkoutSession, paymentMethod = sessionsCardComponentData.paymentMethod, checkoutConfiguration = checkoutConfigurationProvider.checkoutConfig, - componentCallback = sessionsCardComponentData.callback + componentCallback = sessionsCardComponentData.callback, ) cardComponent.setOnRedirectListener { diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt index 942a0b00bf..e2891ad881 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt @@ -16,8 +16,10 @@ import com.adyen.checkout.card.CardBrand import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.card.CardType import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.CheckoutConfiguration import com.adyen.checkout.components.core.ComponentError +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.action.Action @@ -34,8 +36,6 @@ import com.adyen.checkout.sessions.core.CheckoutSessionResult import com.adyen.checkout.sessions.core.SessionComponentCallback import com.adyen.checkout.sessions.core.SessionModel import com.adyen.checkout.sessions.core.SessionPaymentResult -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressDelegate.kt index 89440253bf..44d83b4426 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressDelegate.kt @@ -9,7 +9,7 @@ package com.adyen.checkout.ui.core.internal.ui import androidx.annotation.RestrictTo -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import kotlinx.coroutines.flow.Flow diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt index 3b42dfb0f0..e748cb8a26 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt @@ -10,10 +10,10 @@ package com.adyen.checkout.ui.core.internal.ui import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow @@ -30,6 +30,6 @@ interface AddressLookupDelegate { fun updateAddressLookupOptions(options: List) fun setAddressLookupResult(lookupAddress: LookupAddress) fun onAddressQueryChanged(query: String) - fun onAddressLookupCompleted(id: String): Boolean + fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean fun updateAddressLookupInputData(update: AddressLookupInputData.() -> Unit) } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt index a71ea49479..80a966d524 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.LookupAddress @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) sealed class AddressLookupEvent { diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt index e64f23a771..2514554237 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.AddressInputModel @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class AddressLookupInputData( diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt index 1b0c499293..cdcc043a88 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt @@ -9,6 +9,8 @@ package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.AddressInputModel +import com.adyen.checkout.components.core.LookupAddress @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) sealed class AddressLookupState { diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt index 651200f1ee..815ab9af7e 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt @@ -14,14 +14,14 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.ui.core.databinding.AddressLookupOptionItemViewBinding -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress internal class AddressLookupOptionsAdapter( private val onItemClicked: (LookupAddress) -> Boolean ) : ListAdapter( - AddressLookupOptionDiffCallback + AddressLookupOptionDiffCallback, ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddressLookupOptionViewHolder { diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index d9e26eab3f..38c85ef30a 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -16,6 +16,7 @@ import android.view.View import android.widget.LinearLayout import androidx.annotation.RestrictTo import androidx.core.view.isVisible +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.internal.ui.ComponentDelegate import com.adyen.checkout.ui.core.R import com.adyen.checkout.ui.core.databinding.AddressLookupViewBinding @@ -23,7 +24,6 @@ import com.adyen.checkout.ui.core.internal.ui.AddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState -import com.adyen.checkout.ui.core.internal.ui.model.LookupAddress import com.adyen.checkout.ui.core.internal.util.hideError import com.adyen.checkout.ui.core.internal.util.setLocalizedHintFromStyle import kotlinx.coroutines.CoroutineScope @@ -40,7 +40,7 @@ class AddressLookupView @JvmOverloads constructor( LinearLayout( context, attrs, - defStyleAttr + defStyleAttr, ), ComponentView { @@ -91,7 +91,7 @@ class AddressLookupView @JvmOverloads constructor( private fun initLocalizedStrings(localizedContext: Context) { binding.textInputLayoutAddressLookupQuery.setLocalizedHintFromStyle( R.style.AdyenCheckout_AddressLookup_Query, - localizedContext + localizedContext, ) binding.addressFormInput.initLocalizedContext(localizedContext) } @@ -204,12 +204,12 @@ class AddressLookupView @JvmOverloads constructor( } private fun onAddressSelected(lookupAddress: LookupAddress): Boolean { - val isLoading = addressLookupDelegate.onAddressLookupCompleted(lookupAddress.id) + val isLoading = addressLookupDelegate.onAddressLookupCompleted(lookupAddress) addressLookupDelegate.addressLookupEventChannel.trySend( AddressLookupEvent.OptionSelected( lookupAddress, - isLoading - ) + isLoading, + ), ) clearQuery() return isLoading diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt index 6ef176f0dd..05599a4142 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressValidationUtils.kt @@ -9,12 +9,12 @@ package com.adyen.checkout.ui.core.internal.util import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.internal.ui.model.FieldState import com.adyen.checkout.components.core.internal.ui.model.Validation import com.adyen.checkout.ui.core.R import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.AddressSpecification -import com.adyen.checkout.ui.core.internal.ui.model.AddressInputModel import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData @@ -37,14 +37,14 @@ object AddressValidationUtils { addressInputModel, isOptional, countryOptions, - stateOptions + stateOptions, ) AddressFormUIState.POSTAL_CODE -> validatePostalCode( addressInputModel, isOptional, countryOptions, - stateOptions + stateOptions, ) else -> makeValidEmptyAddressOutput(addressInputModel) @@ -68,7 +68,7 @@ object AddressValidationUtils { country = FieldState(country, Validation.Valid), isOptional = isOptional, countryOptions = countryOptions, - stateOptions = stateOptions + stateOptions = stateOptions, ) } } @@ -91,7 +91,7 @@ object AddressValidationUtils { country = validateAddressField(country, spec.country.isRequired && !isOptional), isOptional = isOptional, countryOptions = countryOptions, - stateOptions = stateOptions + stateOptions = stateOptions, ) } } @@ -111,7 +111,7 @@ object AddressValidationUtils { country = FieldState(country, Validation.Valid), isOptional = true, countryOptions = emptyList(), - stateOptions = emptyList() + stateOptions = emptyList(), ) } } From 207854a3f37156d05e78243add4fb7b02cf2333c Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:14:27 +0100 Subject: [PATCH 111/255] Implement address lookup completion for drop-in COAND-730 --- .../com/adyen/checkout/dropin/DropInServiceResult.kt | 11 +++++++++++ .../dropin/internal/ui/CardComponentDialogFragment.kt | 4 ++++ .../checkout/dropin/internal/ui/DropInActivity.kt | 5 +++++ .../checkout/dropin/internal/ui/DropInViewModel.kt | 8 ++++++++ 4 files changed, 28 insertions(+) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt index 6bd787185e..a388826ee3 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInServiceResult.kt @@ -199,6 +199,17 @@ sealed class AddressLookupDropInServiceResult : BaseDropInServiceResult() { val options: List ) : AddressLookupDropInServiceResult() + /** + * Only applicable to address lookup flow. + * + * Send this to prefill the address after making an api call to fetch the complete address details. + * + * @param lookupAddress Complete address details. + */ + class LookupComplete( + val lookupAddress: LookupAddress + ) : AddressLookupDropInServiceResult() + /** * * Only applicable to address lookup flow. * diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt index 93b16e5d86..c8d7c02e61 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/CardComponentDialogFragment.kt @@ -59,6 +59,10 @@ internal class CardComponentDialogFragment : BaseComponentDialogFragment(), Addr dropInViewModel.addressLookupOptionsFlow.onEach { cardComponent.updateAddressLookupOptions(it) }.launchIn(dropInViewModel.viewModelScope) + + dropInViewModel.addressLookupCompleteFlow.onEach { + cardComponent.setAddressLookupResult(it) + }.launchIn(dropInViewModel.viewModelScope) } override fun onQueryChanged(query: String) { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt index ca7cb30a55..68c6eba556 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt @@ -437,6 +437,7 @@ internal class DropInActivity : private fun handleDropInServiceResult(dropInServiceResult: AddressLookupDropInServiceResult) { when (dropInServiceResult) { is AddressLookupDropInServiceResult.LookupResult -> handleAddressLookupOptionsUpdate(dropInServiceResult) + is AddressLookupDropInServiceResult.LookupComplete -> handleAddressLookupComplete(dropInServiceResult) is AddressLookupDropInServiceResult.Error -> handleErrorDropInServiceResult(dropInServiceResult) } } @@ -497,6 +498,10 @@ internal class DropInActivity : dropInViewModel.onAddressLookupOptions(lookupResult.options) } + private fun handleAddressLookupComplete(lookupResult: AddressLookupDropInServiceResult.LookupComplete) { + dropInViewModel.onAddressLookupComplete(lookupResult.lookupAddress) + } + private fun sendResult(result: String) { val resultIntent = Intent().putExtra(DropIn.RESULT_KEY, result) setResult(Activity.RESULT_OK, resultIntent) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt index 874c3c9b03..2b9e6b79d4 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt @@ -118,6 +118,9 @@ internal class DropInViewModel( private val _addressLookupOptionsFlow = bufferedChannel>() val addressLookupOptionsFlow: Flow> = _addressLookupOptionsFlow.receiveAsFlow() + private val _addressLookupCompleteFlow = bufferedChannel() + val addressLookupCompleteFlow: Flow = _addressLookupCompleteFlow.receiveAsFlow() + fun getPaymentMethods(): List { return paymentMethodsApiResponse.paymentMethods.orEmpty() } @@ -426,6 +429,11 @@ internal class DropInViewModel( viewModelScope.launch { _addressLookupOptionsFlow.send(options) } } + fun onAddressLookupComplete(lookupAddress: LookupAddress) { + Logger.d(TAG, "onAddressLookupComplete $lookupAddress") + viewModelScope.launch { _addressLookupCompleteFlow.send(lookupAddress) } + } + fun cancelDropIn() { currentOrder?.let { sendCancelOrderEvent(it, true) } sendEvent(DropInActivityEvent.CancelDropIn) From eec5880e031edebd051cfa12535cc86a3819b4f8 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:25:24 +0100 Subject: [PATCH 112/255] Fix country selection issue in address lookup COAND-730 --- .../adyen/checkout/card/internal/ui/DefaultCardDelegate.kt | 4 ++-- .../checkout/ui/core/internal/ui/view/AddressLookupView.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index 8cf6d78402..8063862b72 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -354,11 +354,11 @@ class DefaultCardDelegate( Logger.v(TAG, "createOutputData") val updatedCountryOptions = AddressFormUtils.markAddressListItemSelected( countryOptions, - inputData.address.country, + addressInputModel.country, ) val updatedStateOptions = AddressFormUtils.markAddressListItemSelected( stateOptions, - inputData.address.stateOrProvince, + addressInputModel.stateOrProvince, ) val isReliable = detectedCardTypes.any { it.isReliable } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 38c85ef30a..9a69bc57a1 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -89,6 +89,7 @@ class AddressLookupView @JvmOverloads constructor( } private fun initLocalizedStrings(localizedContext: Context) { + // TODO address lookup translations binding.textInputLayoutAddressLookupQuery.setLocalizedHintFromStyle( R.style.AdyenCheckout_AddressLookup_Query, localizedContext, From 764029c3598fce61e481a7c20b753ef88997e959 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:24:08 +0100 Subject: [PATCH 113/255] Create a model class for address lookup adapter to decouple it from merchant facing LookupAddress COAND-730 --- .../ui/view/BacsDirectDebitInputView.kt | 20 ++++---- .../card/internal/ui/DefaultCardDelegate.kt | 14 +++--- .../components/core/AddressLookupCallback.kt | 3 ++ .../checkout/components/core/LookupAddress.kt | 29 +---------- .../checkout/example/ui/card/CardActivity.kt | 5 ++ .../core/internal/ui/AddressLookupDelegate.kt | 4 +- .../internal/ui/model/AddressLookupState.kt | 4 +- .../ui/view/AddressLookupOptionsAdapter.kt | 49 +++++++++++++++---- .../internal/ui/view/AddressLookupView.kt | 3 +- 9 files changed, 73 insertions(+), 58 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/view/BacsDirectDebitInputView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/view/BacsDirectDebitInputView.kt index 56730eb014..fa5031611b 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/view/BacsDirectDebitInputView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/view/BacsDirectDebitInputView.kt @@ -45,7 +45,7 @@ internal class BacsDirectDebitInputView @JvmOverloads constructor( LinearLayout( context, attrs, - defStyleAttr + defStyleAttr, ), ComponentView { @@ -105,7 +105,7 @@ internal class BacsDirectDebitInputView @JvmOverloads constructor( binding.editTextBankAccountNumber.requestFocus() } binding.textInputLayoutBankAccountNumber.showError( - localizedContext.getString(bankAccountNumberValidation.reason) + localizedContext.getString(bankAccountNumberValidation.reason), ) } val sortCodeValidation = it.sortCodeState.validation @@ -144,23 +144,23 @@ internal class BacsDirectDebitInputView @JvmOverloads constructor( private fun initLocalizedStrings(localizedContext: Context) { binding.textInputLayoutHolderName.setLocalizedHintFromStyle( R.style.AdyenCheckout_Bacs_HolderNameInput, - localizedContext + localizedContext, ) binding.textInputLayoutBankAccountNumber.setLocalizedHintFromStyle( R.style.AdyenCheckout_Bacs_AccountNumberInput, - localizedContext + localizedContext, ) binding.textInputLayoutSortCode.setLocalizedHintFromStyle( R.style.AdyenCheckout_Bacs_SortCodeInput, - localizedContext + localizedContext, ) binding.textInputLayoutShopperEmail.setLocalizedHintFromStyle( R.style.AdyenCheckout_Bacs_ShopperEmailInput, - localizedContext + localizedContext, ) binding.switchConsentAccount.setLocalizedTextFromStyle( R.style.AdyenCheckout_Bacs_Switch_Account, - localizedContext + localizedContext, ) setAmountConsentSwitchText(bacsDelegate.componentParams) } @@ -206,7 +206,7 @@ internal class BacsDirectDebitInputView @JvmOverloads constructor( binding.textInputLayoutBankAccountNumber.hideError() } else if (bankAccountNumberValidation is Validation.Invalid) { binding.textInputLayoutBankAccountNumber.showError( - localizedContext.getString(bankAccountNumberValidation.reason) + localizedContext.getString(bankAccountNumberValidation.reason), ) } } @@ -261,14 +261,14 @@ internal class BacsDirectDebitInputView @JvmOverloads constructor( if (amount != null) { val formattedAmount = CurrencyUtils.formatAmount( amount, - componentParams.shopperLocale + componentParams.shopperLocale, ) binding.switchConsentAmount.text = localizedContext.getString(R.string.bacs_consent_amount_specified, formattedAmount) } else { binding.switchConsentAmount.setLocalizedTextFromStyle( R.style.AdyenCheckout_Bacs_Switch_Amount, - localizedContext + localizedContext, ) } } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index 8063862b72..1a7657a7bc 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -74,6 +74,7 @@ import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams +import com.adyen.checkout.ui.core.internal.ui.view.LookupOption import com.adyen.checkout.ui.core.internal.util.AddressFormUtils import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import com.adyen.checkout.ui.core.internal.util.SocialSecurityNumberUtils @@ -889,7 +890,9 @@ class DefaultCardDelegate( } else { AddressLookupState.SearchResult( inputData.addressLookupInputData.query, - event.addressLookupOptions, + event.addressLookupOptions.map { + LookupOption(lookupAddress = it, isLoading = false) + }, ) } } else { @@ -903,11 +906,10 @@ class DefaultCardDelegate( AddressLookupState.SearchResult( inputData.addressLookupInputData.query, addressLookupOptions.map { - if (it == event.lookupAddress) { - it.copy(isLoading = true) - } else { - it - } + LookupOption( + lookupAddress = it, + isLoading = it == event.lookupAddress, + ) }, ) } else { diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt b/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt index 1030219cd9..25769f1467 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/AddressLookupCallback.kt @@ -8,6 +8,9 @@ package com.adyen.checkout.components.core +/** + * TODO docs + */ interface AddressLookupCallback { fun onQueryChanged(query: String) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/LookupAddress.kt b/components-core/src/main/java/com/adyen/checkout/components/core/LookupAddress.kt index c203d18fbb..6b1c062214 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/LookupAddress.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/LookupAddress.kt @@ -10,30 +10,5 @@ package com.adyen.checkout.components.core data class LookupAddress( val id: String, - val address: AddressInputModel, - val isLoading: Boolean = false -) { - override fun toString(): String { - return listOf( - address.street, - address.houseNumberOrName, - address.apartmentSuite, - address.postalCode, - address.city, - address.stateOrProvince, - address.country - ).filter { it.isNotBlank() }.joinToString(" ") - } - - val title - get() = address.street.ifBlank { - toString() - } - - val subtitle - get() = if (address.street.isBlank()) { - "" - } else { - toString() - } -} + val address: AddressInputModel +) diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt index b19a4b8fe8..299ee2039a 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt @@ -155,6 +155,11 @@ class CardActivity : AppCompatActivity(), AddressLookupCallback { return true } + override fun onBackPressed() { + if (cardComponent?.handleBackPress() == true) return + super.onBackPressed() + } + override fun onDestroy() { super.onDestroy() cardComponent = null diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt index e748cb8a26..4cc84aa6ef 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt @@ -25,11 +25,11 @@ interface AddressLookupDelegate { val addressDelegate: AddressDelegate - fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) fun startAddressLookup() fun updateAddressLookupOptions(options: List) fun setAddressLookupResult(lookupAddress: LookupAddress) + fun updateAddressLookupInputData(update: AddressLookupInputData.() -> Unit) + fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) fun onAddressQueryChanged(query: String) fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean - fun updateAddressLookupInputData(update: AddressLookupInputData.() -> Unit) } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt index cdcc043a88..3040157375 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt @@ -10,13 +10,13 @@ package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.AddressInputModel -import com.adyen.checkout.components.core.LookupAddress +import com.adyen.checkout.ui.core.internal.ui.view.LookupOption @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) sealed class AddressLookupState { object Initial : AddressLookupState() object Loading : AddressLookupState() data class Form(val selectedAddress: AddressInputModel?) : AddressLookupState() - data class SearchResult(val query: String, val options: List) : AddressLookupState() + data class SearchResult(val query: String, val options: List) : AddressLookupState() object Error : AddressLookupState() } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt index 815ab9af7e..b00039cb94 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt @@ -20,7 +20,7 @@ import com.adyen.checkout.ui.core.databinding.AddressLookupOptionItemViewBinding internal class AddressLookupOptionsAdapter( private val onItemClicked: (LookupAddress) -> Boolean ) : - ListAdapter( + ListAdapter( AddressLookupOptionDiffCallback, ) { @@ -37,21 +37,50 @@ internal class AddressLookupOptionsAdapter( private val binding: AddressLookupOptionItemViewBinding, private val onItemClicked: (LookupAddress) -> Boolean ) : RecyclerView.ViewHolder(binding.root) { - fun bindItem(lookupAddress: LookupAddress) { + fun bindItem(lookupOption: LookupOption) { binding.root.setOnClickListener { - onItemClicked(lookupAddress) + onItemClicked(lookupOption.lookupAddress) } - binding.progressBar.isVisible = lookupAddress.isLoading - binding.textViewAddressHeader.text = lookupAddress.title - binding.textViewAddressDescription.text = lookupAddress.subtitle + binding.progressBar.isVisible = lookupOption.isLoading + binding.textViewAddressHeader.text = lookupOption.title + binding.textViewAddressDescription.text = lookupOption.subtitle } } - object AddressLookupOptionDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: LookupAddress, newItem: LookupAddress): Boolean = - oldItem.id == newItem.id + object AddressLookupOptionDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: LookupOption, newItem: LookupOption): Boolean = + oldItem.lookupAddress.id == newItem.lookupAddress.id - override fun areContentsTheSame(oldItem: LookupAddress, newItem: LookupAddress): Boolean = + override fun areContentsTheSame(oldItem: LookupOption, newItem: LookupOption): Boolean = oldItem == newItem } } + +data class LookupOption( + val lookupAddress: LookupAddress, + val isLoading: Boolean = false +) { + override fun toString(): String { + return listOf( + lookupAddress.address.street, + lookupAddress.address.houseNumberOrName, + lookupAddress.address.apartmentSuite, + lookupAddress.address.postalCode, + lookupAddress.address.city, + lookupAddress.address.stateOrProvince, + lookupAddress.address.country, + ).filter { it.isNotBlank() }.joinToString(" ") + } + + val title + get() = lookupAddress.address.street.ifBlank { + toString() + } + + val subtitle + get() = if (lookupAddress.address.street.isBlank()) { + "" + } else { + toString() + } +} diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 9a69bc57a1..4823789a5e 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -118,6 +118,7 @@ class AddressLookupView @JvmOverloads constructor( private fun initManualEntryErrorTextView() { binding.textViewManualEntryError.setOnClickListener { clearQuery() + // TODO use a delegate function that triggers this event from card delegate (implementation) addressLookupDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.Manual) } } @@ -197,7 +198,7 @@ class AddressLookupView @JvmOverloads constructor( binding.textInputLayoutAddressLookupQuery.hideError() } - private fun setAddressOptions(options: List) { + private fun setAddressOptions(options: List) { if (addressLookupOptionsAdapter == null) { initAddressOptions() } From 17abf50fb206746cee507f76e5ff90dbbdf65051 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:38:17 +0100 Subject: [PATCH 114/255] Move all address lookup events out of AddressLookupView COAND-730 --- .../card/internal/ui/DefaultCardDelegate.kt | 13 ++++++++++++- .../card/internal/ui/StoredCardDelegate.kt | 2 ++ .../core/internal/ui/AddressLookupDelegate.kt | 1 + .../ui/view/AddressLookupOptionsAdapter.kt | 4 ++-- .../core/internal/ui/view/AddressLookupView.kt | 17 ++++------------- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index 1a7657a7bc..22e084541f 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -538,7 +538,18 @@ class DefaultCardDelegate( } override fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean { - return addressLookupCallback?.onLookupCompleted(lookupAddress) ?: false + val isLoading = addressLookupCallback?.onLookupCompleted(lookupAddress) ?: false + addressLookupEventChannel.trySend( + AddressLookupEvent.OptionSelected( + lookupAddress, + isLoading, + ), + ) + return isLoading + } + + override fun onManualEntryModeSelected() { + addressLookupEventChannel.trySend(AddressLookupEvent.Manual) } override fun handleBackPress(): Boolean { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt index e7b275cf60..283109d6b8 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt @@ -326,6 +326,8 @@ internal class StoredCardDelegate( override fun onAddressLookupCompleted(lookupAddress: LookupAddress) = false + override fun onManualEntryModeSelected() = Unit + override fun handleBackPress(): Boolean { return if (_viewFlow.value == CardComponentViewType.AddressLookup) { _viewFlow.tryEmit(CardComponentViewType.StoredCardView) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt index 4cc84aa6ef..9bbd4e518a 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt @@ -32,4 +32,5 @@ interface AddressLookupDelegate { fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) fun onAddressQueryChanged(query: String) fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean + fun onManualEntryModeSelected() } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt index b00039cb94..44d447d810 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupOptionsAdapter.kt @@ -18,7 +18,7 @@ import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.ui.core.databinding.AddressLookupOptionItemViewBinding internal class AddressLookupOptionsAdapter( - private val onItemClicked: (LookupAddress) -> Boolean + private val onItemClicked: (LookupAddress) -> Unit ) : ListAdapter( AddressLookupOptionDiffCallback, @@ -35,7 +35,7 @@ internal class AddressLookupOptionsAdapter( internal class AddressLookupOptionViewHolder( private val binding: AddressLookupOptionItemViewBinding, - private val onItemClicked: (LookupAddress) -> Boolean + private val onItemClicked: (LookupAddress) -> Unit ) : RecyclerView.ViewHolder(binding.root) { fun bindItem(lookupOption: LookupOption) { binding.root.setOnClickListener { diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 4823789a5e..440eea5d1f 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -22,7 +22,6 @@ import com.adyen.checkout.ui.core.R import com.adyen.checkout.ui.core.databinding.AddressLookupViewBinding import com.adyen.checkout.ui.core.internal.ui.AddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.ComponentView -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.util.hideError import com.adyen.checkout.ui.core.internal.util.setLocalizedHintFromStyle @@ -118,15 +117,14 @@ class AddressLookupView @JvmOverloads constructor( private fun initManualEntryErrorTextView() { binding.textViewManualEntryError.setOnClickListener { clearQuery() - // TODO use a delegate function that triggers this event from card delegate (implementation) - addressLookupDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.Manual) + addressLookupDelegate.onManualEntryModeSelected() } } private fun initManualEntryInitialTextView() { binding.textViewManualEntryInitial.setOnClickListener { clearQuery() - addressLookupDelegate.addressLookupEventChannel.trySend(AddressLookupEvent.Manual) + addressLookupDelegate.onManualEntryModeSelected() } } @@ -205,16 +203,9 @@ class AddressLookupView @JvmOverloads constructor( addressLookupOptionsAdapter?.submitList(options) } - private fun onAddressSelected(lookupAddress: LookupAddress): Boolean { - val isLoading = addressLookupDelegate.onAddressLookupCompleted(lookupAddress) - addressLookupDelegate.addressLookupEventChannel.trySend( - AddressLookupEvent.OptionSelected( - lookupAddress, - isLoading, - ), - ) + private fun onAddressSelected(lookupAddress: LookupAddress) { + addressLookupDelegate.onAddressLookupCompleted(lookupAddress) clearQuery() - return isLoading } override fun getView(): View = this From 276bda3e19c7d00b07f9b00f7d662925799b08b7 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 22 Dec 2023 13:56:17 +0100 Subject: [PATCH 115/255] Extract address lookup code to DefaultAddressLookupDelegate COAND-730 --- .../provider/BcmcComponentProvider.kt | 3 + .../provider/CardComponentProvider.kt | 3 + .../checkout/card/internal/ui/CardDelegate.kt | 14 +- .../card/internal/ui/DefaultCardDelegate.kt | 139 +----------- .../card/internal/ui/StoredCardDelegate.kt | 20 -- .../internal/ui/DefaultCardDelegateTest.kt | 2 + .../core/internal/ui/AddressLookupDelegate.kt | 14 +- .../ui/DefaultAddressLookupDelegate.kt | 214 ++++++++++++++++++ .../ui/model/AddressLookupInputData.kt | 6 +- .../internal/ui/view/AddressLookupView.kt | 10 +- 10 files changed, 257 insertions(+), 168 deletions(-) create mode 100644 ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt diff --git a/bcmc/src/main/java/com/adyen/checkout/bcmc/internal/provider/BcmcComponentProvider.kt b/bcmc/src/main/java/com/adyen/checkout/bcmc/internal/provider/BcmcComponentProvider.kt index a7b404db8a..ee188977a9 100644 --- a/bcmc/src/main/java/com/adyen/checkout/bcmc/internal/provider/BcmcComponentProvider.kt +++ b/bcmc/src/main/java/com/adyen/checkout/bcmc/internal/provider/BcmcComponentProvider.kt @@ -58,6 +58,7 @@ import com.adyen.checkout.sessions.core.internal.provider.SessionPaymentComponen import com.adyen.checkout.sessions.core.internal.ui.model.SessionParamsFactory import com.adyen.checkout.ui.core.internal.data.api.AddressService import com.adyen.checkout.ui.core.internal.data.api.DefaultAddressRepository +import com.adyen.checkout.ui.core.internal.ui.DefaultAddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.SubmitHandler class BcmcComponentProvider @@ -134,6 +135,7 @@ constructor( cardEncryptor = cardEncryptor, genericEncryptor = genericEncryptor, submitHandler = SubmitHandler(savedStateHandle), + addressLookupDelegate = DefaultAddressLookupDelegate(), ) val genericActionDelegate = GenericActionComponentProvider(dropInOverrideParams).getDelegate( @@ -237,6 +239,7 @@ constructor( cardEncryptor = cardEncryptor, genericEncryptor = genericEncryptor, submitHandler = SubmitHandler(savedStateHandle), + addressLookupDelegate = DefaultAddressLookupDelegate(), ) val genericActionDelegate = GenericActionComponentProvider(dropInOverrideParams).getDelegate( diff --git a/card/src/main/java/com/adyen/checkout/card/internal/provider/CardComponentProvider.kt b/card/src/main/java/com/adyen/checkout/card/internal/provider/CardComponentProvider.kt index 6ac9d3e42d..58f4440428 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/provider/CardComponentProvider.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/provider/CardComponentProvider.kt @@ -62,6 +62,7 @@ import com.adyen.checkout.sessions.core.internal.provider.SessionStoredPaymentCo import com.adyen.checkout.sessions.core.internal.ui.model.SessionParamsFactory import com.adyen.checkout.ui.core.internal.data.api.AddressService import com.adyen.checkout.ui.core.internal.data.api.DefaultAddressRepository +import com.adyen.checkout.ui.core.internal.ui.DefaultAddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.SubmitHandler @Suppress("TooManyFunctions") @@ -159,6 +160,7 @@ constructor( cardEncryptor = cardEncryptor, genericEncryptor = genericEncryptor, submitHandler = SubmitHandler(savedStateHandle), + addressLookupDelegate = DefaultAddressLookupDelegate(), ) val genericActionDelegate = GenericActionComponentProvider(dropInOverrideParams).getDelegate( @@ -264,6 +266,7 @@ constructor( cardEncryptor = cardEncryptor, genericEncryptor = genericEncryptor, submitHandler = SubmitHandler(savedStateHandle), + addressLookupDelegate = DefaultAddressLookupDelegate(), ) val genericActionDelegate = GenericActionComponentProvider(dropInOverrideParams).getDelegate( diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt index 4c07c34ef0..152dae99c8 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardDelegate.kt @@ -13,10 +13,11 @@ import com.adyen.checkout.card.BinLookupData import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.card.internal.ui.model.CardInputData import com.adyen.checkout.card.internal.ui.model.CardOutputData +import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.internal.ui.PaymentComponentDelegate import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.ui.core.internal.ui.AddressDelegate -import com.adyen.checkout.ui.core.internal.ui.AddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.ButtonDelegate import com.adyen.checkout.ui.core.internal.ui.UIStateDelegate import com.adyen.checkout.ui.core.internal.ui.ViewProvidingDelegate @@ -29,8 +30,7 @@ interface CardDelegate : ViewProvidingDelegate, ButtonDelegate, UIStateDelegate, - AddressDelegate, - AddressLookupDelegate { + AddressDelegate { val outputData: CardOutputData @@ -48,5 +48,13 @@ interface CardDelegate : fun setOnBinLookupListener(listener: ((data: List) -> Unit)?) + fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) + + fun updateAddressLookupOptions(options: List) + + fun setAddressLookupResult(lookupAddress: LookupAddress) + fun handleBackPress(): Boolean + + fun startAddressLookup() } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index 22e084541f..f04c7a36d4 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -61,20 +61,17 @@ import com.adyen.checkout.cse.UnencryptedCard import com.adyen.checkout.cse.internal.BaseCardEncryptor import com.adyen.checkout.cse.internal.BaseGenericEncryptor import com.adyen.checkout.ui.core.internal.data.api.AddressRepository -import com.adyen.checkout.ui.core.internal.ui.AddressDelegate import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState +import com.adyen.checkout.ui.core.internal.ui.AddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.ButtonComponentViewType import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams -import com.adyen.checkout.ui.core.internal.ui.view.LookupOption import com.adyen.checkout.ui.core.internal.util.AddressFormUtils import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import com.adyen.checkout.ui.core.internal.util.SocialSecurityNumberUtils @@ -107,7 +104,8 @@ class DefaultCardDelegate( private val cardEncryptor: BaseCardEncryptor, private val genericEncryptor: BaseGenericEncryptor, private val submitHandler: SubmitHandler, -) : CardDelegate { + private val addressLookupDelegate: AddressLookupDelegate +) : CardDelegate, AddressLookupDelegate by addressLookupDelegate { private val inputData: CardInputData = CardInputData() @@ -125,12 +123,6 @@ class DefaultCardDelegate( }.stateIn(coroutineScope, SharingStarted.Lazily, outputData.addressState) } - override val addressLookupStateFlow: Flow by lazy { - outputDataFlow.map { - it.addressLookupState - }.stateIn(coroutineScope, SharingStarted.Lazily, outputData.addressLookupState) - } - override val outputData: CardOutputData get() = _outputDataFlow.value @@ -151,14 +143,8 @@ class DefaultCardDelegate( override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow - override val addressLookupEventChannel = bufferedChannel() - private val addressLookupEventFlow: Flow = addressLookupEventChannel.receiveAsFlow() - private var onBinValueListener: ((binValue: String) -> Unit)? = null private var onBinLookupListener: ((data: List) -> Unit)? = null - private var addressLookupCallback: AddressLookupCallback? = null - - override val addressDelegate: AddressDelegate = this private val addressInputModel: AddressInputModel get() = if (componentParams.addressParams is AddressParams.Lookup) { @@ -182,7 +168,6 @@ class DefaultCardDelegate( subscribeToStatesList() subscribeToCountryList() requestCountryList() - subscribeToAddressLookup() } } @@ -243,12 +228,6 @@ class DefaultCardDelegate( } } - override fun updateAddressLookupInputData(update: AddressLookupInputData.() -> Unit) { - updateInputData { - this.addressLookupInputData.update() - } - } - override fun setInteractionBlocked(isInteractionBlocked: Boolean) { submitHandler.setInteractionBlocked(isInteractionBlocked) } @@ -266,23 +245,6 @@ class DefaultCardDelegate( requestStateList(inputData.address.country) } - private fun subscribeToAddressLookup() { - addressLookupEventFlow - .onEach { addressLookupEvent -> - val addressLookupOptions = - if (addressLookupEvent is AddressLookupEvent.SearchResult) { - addressLookupEvent.addressLookupOptions - } else { - outputData.addressLookupOptions - } - updateOutputData( - addressLookupState = makeAddressLookupState(addressLookupOptions, addressLookupEvent), - addressLookupOptions = addressLookupOptions, - ) - } - .launchIn(coroutineScope) - } - private fun subscribeToDetectedCardTypes() { detectCardTypeRepository.detectedCardTypesFlow .onEach { detectedCardTypes -> @@ -316,6 +278,7 @@ class DefaultCardDelegate( inputData.address.country = it.code requestStateList(it.code) } + addressLookupDelegate.updateCountryOptions(countryOptions) updateOutputData(countryOptions = countryOptions) } .launchIn(coroutineScope) @@ -326,7 +289,9 @@ class DefaultCardDelegate( .distinctUntilChanged() .onEach { states -> Logger.d(TAG, "New states emitted - states: ${states.size}") - updateOutputData(stateOptions = AddressFormUtils.initializeStateOptions(states)) + val stateOptions = AddressFormUtils.initializeStateOptions(states) + updateOutputData(stateOptions = stateOptions) + addressLookupDelegate.updateStateOptions(stateOptions) } .launchIn(coroutineScope) } @@ -530,26 +495,7 @@ class DefaultCardDelegate( override fun startAddressLookup() { _viewFlow.tryEmit(CardComponentViewType.AddressLookup) - } - - override fun onAddressQueryChanged(query: String) { - addressLookupEventChannel.trySend(AddressLookupEvent.Query(query)) - addressLookupCallback?.onQueryChanged(query) - } - - override fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean { - val isLoading = addressLookupCallback?.onLookupCompleted(lookupAddress) ?: false - addressLookupEventChannel.trySend( - AddressLookupEvent.OptionSelected( - lookupAddress, - isLoading, - ), - ) - return isLoading - } - - override fun onManualEntryModeSelected() { - addressLookupEventChannel.trySend(AddressLookupEvent.Manual) + addressLookupDelegate.initialize(coroutineScope) } override fun handleBackPress(): Boolean { @@ -870,69 +816,6 @@ class DefaultCardDelegate( }?.cardBrand?.txVariant } - private fun makeAddressLookupState( - addressLookupOptions: List = outputData.addressLookupOptions, - event: AddressLookupEvent - ): AddressLookupState { - return when (event) { - is AddressLookupEvent.Query -> { - inputData.addressLookupInputData.query = event.query - AddressLookupState.Loading - } - - AddressLookupEvent.ClearQuery -> { - AddressLookupState.Initial - } - - AddressLookupEvent.Manual -> { - if (outputData.addressLookupState is AddressLookupState.Initial || - outputData.addressLookupState is AddressLookupState.Error - ) { - AddressLookupState.Form(null) - } else { - outputData.addressLookupState - } - } - - is AddressLookupEvent.SearchResult -> { - if (outputData.addressLookupState is AddressLookupState.Loading) { - if (event.addressLookupOptions.isEmpty()) { - AddressLookupState.Error - } else { - AddressLookupState.SearchResult( - inputData.addressLookupInputData.query, - event.addressLookupOptions.map { - LookupOption(lookupAddress = it, isLoading = false) - }, - ) - } - } else { - outputData.addressLookupState - } - } - - is AddressLookupEvent.OptionSelected -> { - if (outputData.addressLookupState is AddressLookupState.SearchResult) { - if (event.loading) { - AddressLookupState.SearchResult( - inputData.addressLookupInputData.query, - addressLookupOptions.map { - LookupOption( - lookupAddress = it, - isLoading = it == event.lookupAddress, - ) - }, - ) - } else { - AddressLookupState.Form(event.lookupAddress.address) - } - } else { - outputData.addressLookupState - } - } - } - } - override fun isConfirmationRequired(): Boolean = _viewFlow.value is ButtonComponentViewType override fun shouldShowSubmitButton(): Boolean = isConfirmationRequired() && componentParams.isSubmitButtonVisible @@ -946,16 +829,16 @@ class DefaultCardDelegate( } override fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) { - this.addressLookupCallback = addressLookupCallback + addressLookupDelegate.setAddressLookupCallback(addressLookupCallback) } override fun updateAddressLookupOptions(options: List) { - addressLookupEventChannel.trySend(AddressLookupEvent.SearchResult(options)) Logger.d(TAG, "update address lookup options $options") + addressLookupDelegate.updateAddressLookupOptions(options) } override fun setAddressLookupResult(lookupAddress: LookupAddress) { - addressLookupEventChannel.trySend(AddressLookupEvent.OptionSelected(lookupAddress, false)) + addressLookupDelegate.setAddressLookupResult(lookupAddress) } override fun onCleared() { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt index 283109d6b8..546f06c850 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt @@ -47,15 +47,12 @@ import com.adyen.checkout.cse.EncryptedCard import com.adyen.checkout.cse.EncryptionException import com.adyen.checkout.cse.UnencryptedCard import com.adyen.checkout.cse.internal.BaseCardEncryptor -import com.adyen.checkout.ui.core.internal.ui.AddressDelegate import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.ButtonComponentViewType import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils @@ -111,11 +108,6 @@ internal class StoredCardDelegate( override val addressOutputDataFlow: Flow get() = MutableStateFlow(_outputDataFlow.value.addressState) - override val addressDelegate: AddressDelegate = this - - override val addressLookupStateFlow: Flow - get() = MutableStateFlow(_outputDataFlow.value.addressLookupState) - private val _componentStateFlow = MutableStateFlow(createComponentState()) override val componentStateFlow: Flow = _componentStateFlow @@ -129,8 +121,6 @@ internal class StoredCardDelegate( override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow - override val addressLookupEventChannel = bufferedChannel() - override val outputData: CardOutputData get() = _outputDataFlow.value private var publicKey: String? = null @@ -322,12 +312,6 @@ internal class StoredCardDelegate( override fun startAddressLookup() = Unit - override fun onAddressQueryChanged(query: String) = Unit - - override fun onAddressLookupCompleted(lookupAddress: LookupAddress) = false - - override fun onManualEntryModeSelected() = Unit - override fun handleBackPress(): Boolean { return if (_viewFlow.value == CardComponentViewType.AddressLookup) { _viewFlow.tryEmit(CardComponentViewType.StoredCardView) @@ -438,10 +422,6 @@ internal class StoredCardDelegate( // no ops } - override fun updateAddressLookupInputData(update: AddressLookupInputData.() -> Unit) { - // no ops - } - // Bin doesn't change for stored cards override fun setOnBinValueListener(listener: ((binValue: String) -> Unit)?) = Unit diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index 55d777ac9e..219ebcfd7e 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -61,6 +61,7 @@ import com.adyen.checkout.test.TestDispatcherExtension import com.adyen.checkout.ui.core.internal.data.api.AddressRepository import com.adyen.checkout.ui.core.internal.test.TestAddressRepository import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState +import com.adyen.checkout.ui.core.internal.ui.DefaultAddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState @@ -1190,6 +1191,7 @@ internal class DefaultCardDelegateTest( genericEncryptor = genericEncryptor, analyticsRepository = analyticsRepository, submitHandler = submitHandler, + addressLookupDelegate = DefaultAddressLookupDelegate() ) } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt index 9bbd4e518a..0ef33b6327 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt @@ -11,26 +11,30 @@ package com.adyen.checkout.ui.core.internal.ui import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.AddressLookupCallback import com.adyen.checkout.components.core.LookupAddress +import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) interface AddressLookupDelegate { + val addressDelegate: AddressDelegate + val addressLookupStateFlow: Flow val addressLookupEventChannel: Channel - val addressDelegate: AddressDelegate - - fun startAddressLookup() + fun initialize(coroutineScope: CoroutineScope) fun updateAddressLookupOptions(options: List) fun setAddressLookupResult(lookupAddress: LookupAddress) - fun updateAddressLookupInputData(update: AddressLookupInputData.() -> Unit) fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) fun onAddressQueryChanged(query: String) fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean fun onManualEntryModeSelected() + + // FIXME eventually move all address related logic to this interface and make it the one and only AddressDelegate + fun updateCountryOptions(countryOptions: List) + fun updateStateOptions(stateOptions: List) } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt new file mode 100644 index 0000000000..3ef9c8986c --- /dev/null +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 22/12/2023. + */ + +package com.adyen.checkout.ui.core.internal.ui + +import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.AddressInputModel +import com.adyen.checkout.components.core.AddressLookupCallback +import com.adyen.checkout.components.core.LookupAddress +import com.adyen.checkout.components.core.internal.util.bufferedChannel +import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupEvent +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData +import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState +import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData +import com.adyen.checkout.ui.core.internal.ui.view.LookupOption +import com.adyen.checkout.ui.core.internal.util.AddressFormUtils +import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.receiveAsFlow + +@Suppress("TooManyFunctions") +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +class DefaultAddressLookupDelegate : + AddressLookupDelegate, + AddressDelegate { + + override val addressDelegate: AddressDelegate = this + + private var addressLookupCallback: AddressLookupCallback? = null + + private val addressLookupInputData = AddressLookupInputData() + + private val _addressLookupStateFlow = MutableStateFlow(AddressLookupState.Initial) + override val addressLookupStateFlow: Flow = _addressLookupStateFlow + + private var currentAddressLookupOptions: List = emptyList() + + private val currentAddressLookupState + get() = _addressLookupStateFlow.value + + override val addressLookupEventChannel = bufferedChannel() + private val addressLookupEventFlow: Flow = addressLookupEventChannel.receiveAsFlow() + + override val addressOutputData: AddressOutputData + get() = _addressOutputDataFlow.value + + private val _addressOutputDataFlow = MutableStateFlow( + AddressValidationUtils.validateAddressInput( + addressLookupInputData.selectedAddress, + AddressFormUIState.LOOKUP, + emptyList(), + emptyList(), + false, + ), + ) + override val addressOutputDataFlow: Flow = _addressOutputDataFlow + + private var countryOptions: List = emptyList() + private var stateOptions: List = emptyList() + + override fun initialize(coroutineScope: CoroutineScope) { + addressLookupEventFlow + .onEach { addressLookupEvent -> + val addressLookupOptions = + if (addressLookupEvent is AddressLookupEvent.SearchResult) { + addressLookupEvent.addressLookupOptions + } else { + currentAddressLookupOptions + } + _addressLookupStateFlow.emit( + makeAddressLookupState( + event = addressLookupEvent, + addressLookupOptions = addressLookupOptions, + ), + ) + } + .launchIn(coroutineScope) + } + + override fun onAddressQueryChanged(query: String) { + addressLookupEventChannel.trySend(AddressLookupEvent.Query(query)) + addressLookupCallback?.onQueryChanged(query) + } + + override fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean { + val isLoading = addressLookupCallback?.onLookupCompleted(lookupAddress) ?: false + addressLookupEventChannel.trySend( + AddressLookupEvent.OptionSelected( + lookupAddress, + isLoading, + ), + ) + return isLoading + } + + override fun onManualEntryModeSelected() { + addressLookupEventChannel.trySend(AddressLookupEvent.Manual) + } + + override fun updateAddressLookupOptions(options: List) { + addressLookupEventChannel.trySend(AddressLookupEvent.SearchResult(options)) + } + + override fun setAddressLookupResult(lookupAddress: LookupAddress) { + addressLookupEventChannel.trySend(AddressLookupEvent.OptionSelected(lookupAddress, false)) + } + + override fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) { + this.addressLookupCallback = addressLookupCallback + } + + private fun makeAddressLookupState( + event: AddressLookupEvent, + addressLookupOptions: List, + ): AddressLookupState { + return when (event) { + is AddressLookupEvent.Query -> { + addressLookupInputData.query = event.query + AddressLookupState.Loading + } + + AddressLookupEvent.ClearQuery -> { + AddressLookupState.Initial + } + + AddressLookupEvent.Manual -> { + if (currentAddressLookupState is AddressLookupState.Initial || + currentAddressLookupState is AddressLookupState.Error + ) { + AddressLookupState.Form(null) + } else { + currentAddressLookupState + } + } + + is AddressLookupEvent.SearchResult -> { + if (currentAddressLookupState is AddressLookupState.Loading) { + if (event.addressLookupOptions.isEmpty()) { + AddressLookupState.Error + } else { + currentAddressLookupOptions = event.addressLookupOptions + AddressLookupState.SearchResult( + addressLookupInputData.query, + event.addressLookupOptions.map { + LookupOption(lookupAddress = it, isLoading = false) + }, + ) + } + } else { + currentAddressLookupState + } + } + + is AddressLookupEvent.OptionSelected -> { + if (currentAddressLookupState is AddressLookupState.SearchResult) { + if (event.loading) { + AddressLookupState.SearchResult( + addressLookupInputData.query, + addressLookupOptions.map { + LookupOption( + lookupAddress = it, + isLoading = it == event.lookupAddress, + ) + }, + ) + } else { + AddressLookupState.Form(event.lookupAddress.address) + } + } else { + currentAddressLookupState + } + } + } + } + + override fun updateAddressInputData(update: AddressInputModel.() -> Unit) { + addressLookupInputData.selectedAddress.update() + countryOptions = AddressFormUtils.markAddressListItemSelected( + list = countryOptions, + code = addressLookupInputData.selectedAddress.country, + ) + stateOptions = AddressFormUtils.markAddressListItemSelected( + list = stateOptions, + code = addressLookupInputData.selectedAddress.stateOrProvince, + ) + _addressOutputDataFlow.tryEmit( + AddressValidationUtils.validateAddressInput( + addressInputModel = addressLookupInputData.selectedAddress, + addressFormUIState = AddressFormUIState.LOOKUP, + countryOptions = countryOptions, + stateOptions = stateOptions, + isOptional = false, + ), + ) + } + + override fun updateCountryOptions(countryOptions: List) { + this.countryOptions = countryOptions + } + + override fun updateStateOptions(stateOptions: List) { + this.stateOptions = stateOptions + } +} diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt index 2514554237..e61fe52196 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupInputData.kt @@ -15,8 +15,4 @@ import com.adyen.checkout.components.core.AddressInputModel data class AddressLookupInputData( var query: String = "", var selectedAddress: AddressInputModel = AddressInputModel() -) { - fun reset() { - query = "" - } -} +) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 440eea5d1f..4b8d307d30 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -64,10 +64,6 @@ class AddressLookupView @JvmOverloads constructor( this.localizedContext = localizedContext initLocalizedStrings(localizedContext) - addressLookupDelegate.updateAddressLookupInputData { - reset() - } - observeDelegate(delegate, coroutineScope) initAddressLookupQuery() @@ -164,11 +160,11 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryError.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false - addressLookupDelegate.updateAddressLookupInputData { + addressLookupDelegate.addressDelegate.updateAddressInputData { if (addressLookupState.selectedAddress == null) { - selectedAddress.resetAll() + this.resetAll() } else { - selectedAddress.set(addressLookupState.selectedAddress) + this.set(addressLookupState.selectedAddress) } } } From ca4069acad7f677b9d248051dd6f5d8ab3994847 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 22 Dec 2023 15:05:38 +0100 Subject: [PATCH 116/255] Initialize address lookup with the most recent address value from card component COAND-730 --- .../card/internal/ui/DefaultCardDelegate.kt | 31 ++--- .../card/internal/ui/StoredCardDelegate.kt | 3 - .../card/internal/ui/model/CardOutputData.kt | 4 - .../internal/ui/DefaultCardDelegateTest.kt | 5 +- .../internal/ui/StoredCardDelegateTest.kt | 3 - .../core/internal/ui/AddressLookupDelegate.kt | 5 +- .../ui/DefaultAddressLookupDelegate.kt | 122 ++++++++++-------- .../internal/ui/model/AddressLookupEvent.kt | 2 + .../internal/ui/view/AddressLookupView.kt | 2 +- 9 files changed, 91 insertions(+), 86 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index f04c7a36d4..c2119862fe 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -69,7 +69,6 @@ import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams import com.adyen.checkout.ui.core.internal.util.AddressFormUtils @@ -146,13 +145,6 @@ class DefaultCardDelegate( private var onBinValueListener: ((binValue: String) -> Unit)? = null private var onBinLookupListener: ((data: List) -> Unit)? = null - private val addressInputModel: AddressInputModel - get() = if (componentParams.addressParams is AddressParams.Lookup) { - inputData.addressLookupInputData.selectedAddress - } else { - inputData.address - } - override fun initialize(coroutineScope: CoroutineScope) { _coroutineScope = coroutineScope @@ -169,6 +161,12 @@ class DefaultCardDelegate( subscribeToCountryList() requestCountryList() } + addressLookupDelegate.addressLookupSubmitFlow + .onEach { + inputData.address = it + updateOutputData() + } + .launchIn(coroutineScope) } private fun setupAnalytics(coroutineScope: CoroutineScope) { @@ -300,11 +298,9 @@ class DefaultCardDelegate( detectedCardTypes: List = outputData.detectedCardTypes, countryOptions: List = outputData.addressState.countryOptions, stateOptions: List = outputData.addressState.stateOptions, - addressLookupOptions: List = outputData.addressLookupOptions, - addressLookupState: AddressLookupState = outputData.addressLookupState ) { val newOutputData = - createOutputData(detectedCardTypes, countryOptions, stateOptions, addressLookupOptions, addressLookupState) + createOutputData(detectedCardTypes, countryOptions, stateOptions) _outputDataFlow.tryEmit(newOutputData) updateComponentState(newOutputData) } @@ -314,17 +310,15 @@ class DefaultCardDelegate( detectedCardTypes: List = emptyList(), countryOptions: List = emptyList(), stateOptions: List = emptyList(), - addressLookupOptions: List = emptyList(), - addressLookupState: AddressLookupState = AddressLookupState.Initial ): CardOutputData { Logger.v(TAG, "createOutputData") val updatedCountryOptions = AddressFormUtils.markAddressListItemSelected( countryOptions, - addressInputModel.country, + inputData.address.country, ) val updatedStateOptions = AddressFormUtils.markAddressListItemSelected( stateOptions, - addressInputModel.stateOrProvince, + inputData.address.stateOrProvince, ) val isReliable = detectedCardTypes.any { it.isReliable } @@ -346,7 +340,7 @@ class DefaultCardDelegate( val addressFormUIState = AddressFormUIState.fromAddressParams(componentParams.addressParams) val addressState = validateAddress( - addressInputModel, + inputData.address, addressFormUIState, selectedOrFirstCardType, updatedCountryOptions, @@ -385,8 +379,6 @@ class DefaultCardDelegate( isDualBranded = isDualBrandedFlow(filteredDetectedCardTypes), kcpBirthDateOrTaxNumberHint = getKcpBirthDateOrTaxNumberHint(inputData.kcpBirthDateOrTaxNumber), isCardListVisible = isCardListVisible(getCardBrands(detectedCardTypes), filteredDetectedCardTypes), - addressLookupState = addressLookupState, - addressLookupOptions = addressLookupOptions, ) } @@ -487,6 +479,7 @@ class DefaultCardDelegate( override fun onSubmit() { val state = _componentStateFlow.value if (_viewFlow.value == CardComponentViewType.AddressLookup) { + addressLookupDelegate.submitAddress() _viewFlow.tryEmit(CardComponentViewType.DefaultCardView) } else { submitHandler.onSubmit(state = state) @@ -495,7 +488,7 @@ class DefaultCardDelegate( override fun startAddressLookup() { _viewFlow.tryEmit(CardComponentViewType.AddressLookup) - addressLookupDelegate.initialize(coroutineScope) + addressLookupDelegate.initialize(coroutineScope, inputData.address) } override fun handleBackPress(): Boolean { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt index 546f06c850..51a338dc9e 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt @@ -53,7 +53,6 @@ import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import com.adyen.threeds2.ThreeDS2Service @@ -236,8 +235,6 @@ internal class StoredCardDelegate( isDualBranded = false, kcpBirthDateOrTaxNumberHint = null, isCardListVisible = false, - addressLookupState = AddressLookupState.Initial, - addressLookupOptions = emptyList(), ) } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt index 578caa8ade..2808cf026b 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardOutputData.kt @@ -11,11 +11,9 @@ import androidx.annotation.RestrictTo import androidx.annotation.StringRes import com.adyen.checkout.card.internal.data.model.DetectedCardType import com.adyen.checkout.card.internal.ui.view.InstallmentModel -import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.internal.ui.model.FieldState import com.adyen.checkout.components.core.internal.ui.model.OutputData import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) @@ -44,8 +42,6 @@ data class CardOutputData( @StringRes val kcpBirthDateOrTaxNumberHint: Int?, val isCardListVisible: Boolean, - val addressLookupState: AddressLookupState, - val addressLookupOptions: List ) : OutputData { override val isValid: Boolean diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index 219ebcfd7e..0920831d05 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -64,7 +64,6 @@ import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.DefaultAddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams import com.adyen.checkout.ui.core.internal.util.AddressFormUtils @@ -1191,7 +1190,7 @@ internal class DefaultCardDelegateTest( genericEncryptor = genericEncryptor, analyticsRepository = analyticsRepository, submitHandler = submitHandler, - addressLookupDelegate = DefaultAddressLookupDelegate() + addressLookupDelegate = DefaultAddressLookupDelegate(), ) } @@ -1292,8 +1291,6 @@ internal class DefaultCardDelegateTest( isDualBranded = isDualBranded, kcpBirthDateOrTaxNumberHint = kcpBirthDateOrTaxNumberHint, isCardListVisible = isCardListVisible, - addressLookupState = AddressLookupState.Initial, - addressLookupOptions = emptyList(), // TODO address lookup test ) } diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt index 9c2871725e..d41f54abff 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt @@ -48,7 +48,6 @@ import com.adyen.checkout.cse.internal.test.TestCardEncryptor import com.adyen.checkout.test.TestDispatcherExtension import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.AddressValidationUtils import kotlinx.coroutines.CoroutineScope @@ -569,8 +568,6 @@ internal class StoredCardDelegateTest( isDualBranded = false, kcpBirthDateOrTaxNumberHint = null, isCardListVisible = isCardListVisible, - addressLookupState = AddressLookupState.Initial, - addressLookupOptions = emptyList(), // TODO address lookup test ) } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt index 0ef33b6327..e34e59c3a7 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressLookupDelegate.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.ui.core.internal.ui import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.AddressLookupCallback import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem @@ -25,14 +26,16 @@ interface AddressLookupDelegate { val addressLookupStateFlow: Flow val addressLookupEventChannel: Channel + val addressLookupSubmitFlow: Flow - fun initialize(coroutineScope: CoroutineScope) + fun initialize(coroutineScope: CoroutineScope, addressInputModel: AddressInputModel) fun updateAddressLookupOptions(options: List) fun setAddressLookupResult(lookupAddress: LookupAddress) fun setAddressLookupCallback(addressLookupCallback: AddressLookupCallback) fun onAddressQueryChanged(query: String) fun onAddressLookupCompleted(lookupAddress: LookupAddress): Boolean fun onManualEntryModeSelected() + fun submitAddress() // FIXME eventually move all address related logic to this interface and make it the one and only AddressDelegate fun updateCountryOptions(countryOptions: List) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt index 3ef9c8986c..224100d9b8 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt @@ -65,10 +65,13 @@ class DefaultAddressLookupDelegate : ) override val addressOutputDataFlow: Flow = _addressOutputDataFlow + private val submitAddressChannel = bufferedChannel() + override val addressLookupSubmitFlow: Flow = submitAddressChannel.receiveAsFlow() + private var countryOptions: List = emptyList() private var stateOptions: List = emptyList() - override fun initialize(coroutineScope: CoroutineScope) { + override fun initialize(coroutineScope: CoroutineScope, addressInputModel: AddressInputModel) { addressLookupEventFlow .onEach { addressLookupEvent -> val addressLookupOptions = @@ -85,6 +88,8 @@ class DefaultAddressLookupDelegate : ) } .launchIn(coroutineScope) + + addressLookupEventChannel.trySend(AddressLookupEvent.Initialize(addressInputModel)) } override fun onAddressQueryChanged(query: String) { @@ -107,6 +112,10 @@ class DefaultAddressLookupDelegate : addressLookupEventChannel.trySend(AddressLookupEvent.Manual) } + override fun submitAddress() { + submitAddressChannel.trySend(addressLookupInputData.selectedAddress) + } + override fun updateAddressLookupOptions(options: List) { addressLookupEventChannel.trySend(AddressLookupEvent.SearchResult(options)) } @@ -124,62 +133,73 @@ class DefaultAddressLookupDelegate : addressLookupOptions: List, ): AddressLookupState { return when (event) { - is AddressLookupEvent.Query -> { - addressLookupInputData.query = event.query - AddressLookupState.Loading - } + is AddressLookupEvent.Initialize -> handleInitializeEvent(event) + is AddressLookupEvent.Query -> handleQueryEvent(event) + AddressLookupEvent.ClearQuery -> AddressLookupState.Initial + AddressLookupEvent.Manual -> handleManualEvent() + is AddressLookupEvent.SearchResult -> handleSearchResultEvent(event) + is AddressLookupEvent.OptionSelected -> handleOptionSelectedEvent(event, addressLookupOptions) + } + } - AddressLookupEvent.ClearQuery -> { - AddressLookupState.Initial - } + private fun handleInitializeEvent(event: AddressLookupEvent.Initialize): AddressLookupState { + return if (event.address.isEmpty) { + AddressLookupState.Initial + } else { + AddressLookupState.Form(event.address) + } + } - AddressLookupEvent.Manual -> { - if (currentAddressLookupState is AddressLookupState.Initial || - currentAddressLookupState is AddressLookupState.Error - ) { - AddressLookupState.Form(null) - } else { - currentAddressLookupState - } - } + private fun handleQueryEvent(event: AddressLookupEvent.Query): AddressLookupState { + addressLookupInputData.query = event.query + return AddressLookupState.Loading + } - is AddressLookupEvent.SearchResult -> { - if (currentAddressLookupState is AddressLookupState.Loading) { - if (event.addressLookupOptions.isEmpty()) { - AddressLookupState.Error - } else { - currentAddressLookupOptions = event.addressLookupOptions - AddressLookupState.SearchResult( - addressLookupInputData.query, - event.addressLookupOptions.map { - LookupOption(lookupAddress = it, isLoading = false) - }, - ) - } - } else { - currentAddressLookupState - } + private fun handleManualEvent(): AddressLookupState { + return if (currentAddressLookupState is AddressLookupState.Initial || + currentAddressLookupState is AddressLookupState.Error + ) { + AddressLookupState.Form(null) + } else { + currentAddressLookupState + } + } + + private fun handleSearchResultEvent(event: AddressLookupEvent.SearchResult): AddressLookupState { + return if (currentAddressLookupState is AddressLookupState.Loading) { + if (event.addressLookupOptions.isEmpty()) { + AddressLookupState.Error + } else { + currentAddressLookupOptions = event.addressLookupOptions + AddressLookupState.SearchResult( + addressLookupInputData.query, + event.addressLookupOptions.map { + LookupOption(lookupAddress = it, isLoading = false) + }, + ) } + } else { + currentAddressLookupState + } + } - is AddressLookupEvent.OptionSelected -> { - if (currentAddressLookupState is AddressLookupState.SearchResult) { - if (event.loading) { - AddressLookupState.SearchResult( - addressLookupInputData.query, - addressLookupOptions.map { - LookupOption( - lookupAddress = it, - isLoading = it == event.lookupAddress, - ) - }, - ) - } else { - AddressLookupState.Form(event.lookupAddress.address) - } - } else { - currentAddressLookupState - } + private fun handleOptionSelectedEvent( + event: AddressLookupEvent.OptionSelected, + addressLookupOptions: List + ): AddressLookupState { + return if (currentAddressLookupState is AddressLookupState.SearchResult) { + if (event.loading) { + AddressLookupState.SearchResult( + addressLookupInputData.query, + addressLookupOptions.map { + LookupOption(lookupAddress = it, isLoading = it == event.lookupAddress) + }, + ) + } else { + AddressLookupState.Form(event.lookupAddress.address) } + } else { + currentAddressLookupState } } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt index 80a966d524..da301759ec 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt @@ -9,10 +9,12 @@ package com.adyen.checkout.ui.core.internal.ui.model import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.AddressInputModel import com.adyen.checkout.components.core.LookupAddress @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) sealed class AddressLookupEvent { + data class Initialize(val address: AddressInputModel) : AddressLookupEvent() data class Query(val query: String) : AddressLookupEvent() object Manual : AddressLookupEvent() object ClearQuery : AddressLookupEvent() diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 4b8d307d30..b7d0c7d20c 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -135,7 +135,7 @@ class AddressLookupView @JvmOverloads constructor( binding.progressBar.isVisible = false } - AddressLookupState.Initial -> { + is AddressLookupState.Initial -> { binding.recyclerViewAddressLookupOptions.isVisible = false binding.textViewManualEntryInitial.isVisible = true binding.textViewError.isVisible = false From 76ccc0a4648c5b46202f1b6b3d86f59b5875ad3b Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:35:41 +0100 Subject: [PATCH 117/255] Replace query edit text with search view COAND-730 --- .../internal/ui/view/AddressLookupView.kt | 38 ++++++++----------- .../drawable/address_lookup_search_border.xml | 16 ++++++++ .../main/res/layout/address_lookup_view.xml | 14 ++----- ui-core/src/main/res/values/colors.xml | 1 + ui-core/src/main/res/values/styles.xml | 7 +++- 5 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 ui-core/src/main/res/drawable/address_lookup_search_border.xml diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index b7d0c7d20c..75433b0170 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -9,11 +9,11 @@ package com.adyen.checkout.ui.core.internal.ui.view import android.content.Context -import android.text.Editable import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout +import android.widget.SearchView.OnQueryTextListener import androidx.annotation.RestrictTo import androidx.core.view.isVisible import com.adyen.checkout.components.core.LookupAddress @@ -23,8 +23,6 @@ import com.adyen.checkout.ui.core.databinding.AddressLookupViewBinding import com.adyen.checkout.ui.core.internal.ui.AddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState -import com.adyen.checkout.ui.core.internal.util.hideError -import com.adyen.checkout.ui.core.internal.util.setLocalizedHintFromStyle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -85,18 +83,22 @@ class AddressLookupView @JvmOverloads constructor( private fun initLocalizedStrings(localizedContext: Context) { // TODO address lookup translations - binding.textInputLayoutAddressLookupQuery.setLocalizedHintFromStyle( - R.style.AdyenCheckout_AddressLookup_Query, - localizedContext, - ) binding.addressFormInput.initLocalizedContext(localizedContext) } private fun initAddressLookupQuery() { - val addressLookupQueryEditText = binding.textInputLayoutAddressLookupQuery.editText as? AdyenTextInputEditText - addressLookupQueryEditText?.setOnChangeListener { - onQueryChanged(it) - } + binding.textInputLayoutAddressLookupQuerySearch.setOnQueryTextListener( + object : OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return true + } + + override fun onQueryTextChange(newText: String): Boolean { + onQueryChanged(newText) + return true + } + }, + ) } private fun initAddressFormInput(coroutineScope: CoroutineScope) { @@ -112,14 +114,12 @@ class AddressLookupView @JvmOverloads constructor( private fun initManualEntryErrorTextView() { binding.textViewManualEntryError.setOnClickListener { - clearQuery() addressLookupDelegate.onManualEntryModeSelected() } } private fun initManualEntryInitialTextView() { binding.textViewManualEntryInitial.setOnClickListener { - clearQuery() addressLookupDelegate.onManualEntryModeSelected() } } @@ -181,15 +181,8 @@ class AddressLookupView @JvmOverloads constructor( } } - private fun clearQuery() { - binding.editTextAddressLookupQuery.setOnChangeListener(null) - binding.editTextAddressLookupQuery.text = null - binding.editTextAddressLookupQuery.setOnChangeListener(::onQueryChanged) - } - - private fun onQueryChanged(editable: Editable) { - addressLookupDelegate.onAddressQueryChanged(editable.toString()) - binding.textInputLayoutAddressLookupQuery.hideError() + private fun onQueryChanged(query: String) { + addressLookupDelegate.onAddressQueryChanged(query) } private fun setAddressOptions(options: List) { @@ -201,7 +194,6 @@ class AddressLookupView @JvmOverloads constructor( private fun onAddressSelected(lookupAddress: LookupAddress) { addressLookupDelegate.onAddressLookupCompleted(lookupAddress) - clearQuery() } override fun getView(): View = this diff --git a/ui-core/src/main/res/drawable/address_lookup_search_border.xml b/ui-core/src/main/res/drawable/address_lookup_search_border.xml new file mode 100644 index 0000000000..4c6fd19b2b --- /dev/null +++ b/ui-core/src/main/res/drawable/address_lookup_search_border.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/ui-core/src/main/res/layout/address_lookup_view.xml b/ui-core/src/main/res/layout/address_lookup_view.xml index efa7e14cc8..65382159c9 100644 --- a/ui-core/src/main/res/layout/address_lookup_view.xml +++ b/ui-core/src/main/res/layout/address_lookup_view.xml @@ -14,17 +14,11 @@ android:orientation="vertical" tools:parentTag="android.widget.LinearLayout"> - - - - + android:layout_marginBottom="@dimen/standard_half_margin" /> #7F4A00 #FFEACC #0075FF + #73000000 diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index f1698d766b..af5e392d65 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -327,8 +327,11 @@ - From 9b5e36d3298517059ad80165fe2f1e165ad6b7f6 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 27 Dec 2023 15:14:25 +0100 Subject: [PATCH 118/255] Replace address lookup EditText in CardView with AutoCompleteTextView COAND-730 --- .../card/internal/ui/view/CardView.kt | 4 ++-- card/src/main/res/layout/card_view.xml | 20 +++++++++---------- card/src/main/res/values/styles.xml | 14 +++++++++++++ ui-core/src/main/res/values/styles.xml | 1 - 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt index c1bf6673ca..fdff7721b0 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt @@ -558,7 +558,7 @@ class CardView @JvmOverloads constructor( } private fun initAddressLookup() { - binding.textInputLayoutAddressLookup.setOnClickListener { + binding.autoCompleteTextViewAddressLookup.setOnClickListener { cardDelegate.startAddressLookup() } } @@ -703,7 +703,7 @@ class CardView @JvmOverloads constructor( } private fun updateAddressLookupInputText(addressOutputData: AddressOutputData) { - binding.editTextAddressLookup.setText(addressOutputData.toString()) + binding.autoCompleteTextViewAddressLookup.setText(addressOutputData.toString()) } private fun updateAddressHint(addressFormUIState: AddressFormUIState, isOptional: Boolean) { diff --git a/card/src/main/res/layout/card_view.xml b/card/src/main/res/layout/card_view.xml index ac2b740618..5b93e89b4f 100644 --- a/card/src/main/res/layout/card_view.xml +++ b/card/src/main/res/layout/card_view.xml @@ -152,19 +152,19 @@ + android:clickable="true" + android:focusable="true" + android:focusableInTouchMode="false"> + + - 16sp center_vertical + + + + + diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index af5e392d65..5b95da491a 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -334,7 +334,6 @@ false - From 136e132ae950c40c2232b505d1a5ca30dac4eddc Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 27 Dec 2023 15:44:41 +0100 Subject: [PATCH 119/255] Display submit address button only when it's AddressLookupState.Form COAND-730 --- .../checkout/card/internal/ui/CardViewProvider.kt | 7 ++----- .../checkout/card/internal/ui/DefaultCardDelegate.kt | 8 ++------ card/src/main/res/values/strings.xml | 3 --- .../ui/core/internal/ui/view/AddressLookupView.kt | 12 ++++++++++++ ui-core/src/main/res/layout/address_lookup_view.xml | 5 +++++ ui-core/src/main/res/values/strings.xml | 2 ++ ui-core/src/main/res/values/styles.xml | 6 ++++++ 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt index e895beff12..ab99c9dbe9 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/CardViewProvider.kt @@ -9,7 +9,6 @@ package com.adyen.checkout.card.internal.ui import android.content.Context -import com.adyen.checkout.card.R import com.adyen.checkout.card.internal.ui.view.CardView import com.adyen.checkout.card.internal.ui.view.StoredCardView import com.adyen.checkout.ui.core.internal.ui.AmountButtonComponentViewType @@ -34,7 +33,7 @@ internal object CardViewProvider : ViewProvider { } } -internal sealed class CardComponentViewType : ButtonComponentViewType { +internal sealed class CardComponentViewType : ComponentViewType { data object DefaultCardView : CardComponentViewType(), AmountButtonComponentViewType { override val buttonTextResId: Int = ButtonComponentViewType.DEFAULT_BUTTON_TEXT_RES_ID } @@ -43,9 +42,7 @@ internal sealed class CardComponentViewType : ButtonComponentViewType { override val buttonTextResId: Int = ButtonComponentViewType.DEFAULT_BUTTON_TEXT_RES_ID } - data object AddressLookup : CardComponentViewType() { - override val buttonTextResId: Int = R.string.checkout_address_lookup_button_text - } + data object AddressLookup : CardComponentViewType() override val viewProvider: ViewProvider = CardViewProvider } diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index c2119862fe..34672e782e 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -163,6 +163,7 @@ class DefaultCardDelegate( } addressLookupDelegate.addressLookupSubmitFlow .onEach { + _viewFlow.tryEmit(CardComponentViewType.DefaultCardView) inputData.address = it updateOutputData() } @@ -478,12 +479,7 @@ class DefaultCardDelegate( override fun onSubmit() { val state = _componentStateFlow.value - if (_viewFlow.value == CardComponentViewType.AddressLookup) { - addressLookupDelegate.submitAddress() - _viewFlow.tryEmit(CardComponentViewType.DefaultCardView) - } else { - submitHandler.onSubmit(state = state) - } + submitHandler.onSubmit(state = state) } override fun startAddressLookup() { diff --git a/card/src/main/res/values/strings.xml b/card/src/main/res/values/strings.xml index 423327ad52..29efdc76a4 100644 --- a/card/src/main/res/values/strings.xml +++ b/card/src/main/res/values/strings.xml @@ -40,7 +40,4 @@ CPF/CNPJ •••• %s - - - Use this address diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 75433b0170..cd34a9e4e4 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -69,6 +69,7 @@ class AddressLookupView @JvmOverloads constructor( initAddressOptions() initManualEntryErrorTextView() initManualEntryInitialTextView() + initSubmitAddressButton() } override fun highlightValidationErrors() { @@ -124,6 +125,12 @@ class AddressLookupView @JvmOverloads constructor( } } + private fun initSubmitAddressButton() { + binding.submitAddressButton.setOnClickListener { + addressLookupDelegate.submitAddress() + } + } + private fun outputDataChanged(addressLookupState: AddressLookupState) { when (addressLookupState) { AddressLookupState.Error -> { @@ -133,6 +140,7 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryError.isVisible = true binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = false } is AddressLookupState.Initial -> { @@ -142,6 +150,7 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryError.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = false } AddressLookupState.Loading -> { @@ -151,6 +160,7 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryError.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = true + binding.submitAddressButton.isVisible = false } is AddressLookupState.Form -> { @@ -160,6 +170,7 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryError.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = true addressLookupDelegate.addressDelegate.updateAddressInputData { if (addressLookupState.selectedAddress == null) { this.resetAll() @@ -176,6 +187,7 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryError.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = false setAddressOptions(addressLookupState.options) } } diff --git a/ui-core/src/main/res/layout/address_lookup_view.xml b/ui-core/src/main/res/layout/address_lookup_view.xml index 65382159c9..e0a51c78a4 100644 --- a/ui-core/src/main/res/layout/address_lookup_view.xml +++ b/ui-core/src/main/res/layout/address_lookup_view.xml @@ -70,4 +70,9 @@ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:listitem="@layout/address_lookup_option_item_view" tools:visibility="visible" /> + + diff --git a/ui-core/src/main/res/values/strings.xml b/ui-core/src/main/res/values/strings.xml index 547183ddb5..a54c5c7c89 100644 --- a/ui-core/src/main/res/values/strings.xml +++ b/ui-core/src/main/res/values/strings.xml @@ -43,6 +43,8 @@ Province or Territory (optional) City / Town (optional) + + Use this address %1$s (%2$s) diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index 5b95da491a..d779e8f305 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -350,4 +350,10 @@ 0.38 center_vertical + + From 990542fd301591c01e236ca3b02ebe076b12d69a Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 27 Dec 2023 16:08:40 +0100 Subject: [PATCH 120/255] Validate address in address lookup COAND-730 --- .../ui/DefaultAddressLookupDelegate.kt | 17 ++- .../internal/ui/model/AddressLookupEvent.kt | 1 + .../internal/ui/model/AddressLookupState.kt | 1 + .../internal/ui/view/AddressLookupView.kt | 122 ++++++++++-------- 4 files changed, 88 insertions(+), 53 deletions(-) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt index 224100d9b8..e1c3c905e0 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt @@ -113,7 +113,11 @@ class DefaultAddressLookupDelegate : } override fun submitAddress() { - submitAddressChannel.trySend(addressLookupInputData.selectedAddress) + if (addressDelegate.addressOutputData.isValid) { + submitAddressChannel.trySend(addressLookupInputData.selectedAddress) + } else { + addressLookupEventChannel.trySend(AddressLookupEvent.InvalidUI) + } } override fun updateAddressLookupOptions(options: List) { @@ -139,6 +143,7 @@ class DefaultAddressLookupDelegate : AddressLookupEvent.Manual -> handleManualEvent() is AddressLookupEvent.SearchResult -> handleSearchResultEvent(event) is AddressLookupEvent.OptionSelected -> handleOptionSelectedEvent(event, addressLookupOptions) + is AddressLookupEvent.InvalidUI -> handleInvalidUIEvent() } } @@ -203,6 +208,16 @@ class DefaultAddressLookupDelegate : } } + private fun handleInvalidUIEvent(): AddressLookupState { + return if (currentAddressLookupState is AddressLookupState.Form || + currentAddressLookupState is AddressLookupState.SearchResult + ) { + AddressLookupState.InvalidUI + } else { + currentAddressLookupState + } + } + override fun updateAddressInputData(update: AddressInputModel.() -> Unit) { addressLookupInputData.selectedAddress.update() countryOptions = AddressFormUtils.markAddressListItemSelected( diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt index da301759ec..cd79444d60 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupEvent.kt @@ -20,4 +20,5 @@ sealed class AddressLookupEvent { object ClearQuery : AddressLookupEvent() data class SearchResult(val addressLookupOptions: List) : AddressLookupEvent() data class OptionSelected(val lookupAddress: LookupAddress, val loading: Boolean) : AddressLookupEvent() + object InvalidUI : AddressLookupEvent() } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt index 3040157375..937df2c581 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt @@ -19,4 +19,5 @@ sealed class AddressLookupState { data class Form(val selectedAddress: AddressInputModel?) : AddressLookupState() data class SearchResult(val query: String, val options: List) : AddressLookupState() object Error : AddressLookupState() + object InvalidUI : AddressLookupState() } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index cd34a9e4e4..08899e4bda 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -133,66 +133,84 @@ class AddressLookupView @JvmOverloads constructor( private fun outputDataChanged(addressLookupState: AddressLookupState) { when (addressLookupState) { - AddressLookupState.Error -> { - binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = false - binding.textViewError.isVisible = true - binding.textViewManualEntryError.isVisible = true - binding.addressFormInput.isVisible = false - binding.progressBar.isVisible = false - binding.submitAddressButton.isVisible = false - } + AddressLookupState.Error -> handleErrorState() + is AddressLookupState.Initial -> handleInitialState() + AddressLookupState.Loading -> handleLoadingState() + is AddressLookupState.Form -> handleFormState(addressLookupState) + is AddressLookupState.SearchResult -> handleSearchResultState(addressLookupState) + AddressLookupState.InvalidUI -> handleInvalidUIState() + } + } - is AddressLookupState.Initial -> { - binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = true - binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false - binding.addressFormInput.isVisible = false - binding.progressBar.isVisible = false - binding.submitAddressButton.isVisible = false - } + private fun handleErrorState() { + binding.recyclerViewAddressLookupOptions.isVisible = false + binding.textViewManualEntryInitial.isVisible = false + binding.textViewError.isVisible = true + binding.textViewManualEntryError.isVisible = true + binding.addressFormInput.isVisible = false + binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = false + } - AddressLookupState.Loading -> { - binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = false - binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false - binding.addressFormInput.isVisible = false - binding.progressBar.isVisible = true - binding.submitAddressButton.isVisible = false - } + private fun handleInitialState() { + binding.recyclerViewAddressLookupOptions.isVisible = false + binding.textViewManualEntryInitial.isVisible = true + binding.textViewError.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.addressFormInput.isVisible = false + binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = false + } - is AddressLookupState.Form -> { - binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = false - binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false - binding.addressFormInput.isVisible = true - binding.progressBar.isVisible = false - binding.submitAddressButton.isVisible = true - addressLookupDelegate.addressDelegate.updateAddressInputData { - if (addressLookupState.selectedAddress == null) { - this.resetAll() - } else { - this.set(addressLookupState.selectedAddress) - } - } - } + private fun handleLoadingState() { + binding.recyclerViewAddressLookupOptions.isVisible = false + binding.textViewManualEntryInitial.isVisible = false + binding.textViewError.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.addressFormInput.isVisible = false + binding.progressBar.isVisible = true + binding.submitAddressButton.isVisible = false + } - is AddressLookupState.SearchResult -> { - binding.recyclerViewAddressLookupOptions.isVisible = true - binding.textViewManualEntryInitial.isVisible = false - binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false - binding.addressFormInput.isVisible = false - binding.progressBar.isVisible = false - binding.submitAddressButton.isVisible = false - setAddressOptions(addressLookupState.options) + private fun handleFormState(addressLookupState: AddressLookupState.Form) { + binding.recyclerViewAddressLookupOptions.isVisible = false + binding.textViewManualEntryInitial.isVisible = false + binding.textViewError.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.addressFormInput.isVisible = true + binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = true + addressLookupDelegate.addressDelegate.updateAddressInputData { + if (addressLookupState.selectedAddress == null) { + this.resetAll() + } else { + this.set(addressLookupState.selectedAddress) } } } + private fun handleSearchResultState(addressLookupState: AddressLookupState.SearchResult) { + binding.recyclerViewAddressLookupOptions.isVisible = true + binding.textViewManualEntryInitial.isVisible = false + binding.textViewError.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.addressFormInput.isVisible = false + binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = false + setAddressOptions(addressLookupState.options) + } + + private fun handleInvalidUIState() { + binding.recyclerViewAddressLookupOptions.isVisible = false + binding.textViewManualEntryInitial.isVisible = false + binding.textViewError.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.addressFormInput.isVisible = true + binding.progressBar.isVisible = false + binding.submitAddressButton.isVisible = true + highlightValidationErrors() + } + private fun onQueryChanged(query: String) { addressLookupDelegate.onAddressQueryChanged(query) } From d06e6ba87e2b2408b1d68bb136cf3c65ab2c7cda Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 28 Dec 2023 11:50:49 +0100 Subject: [PATCH 121/255] Fix prefilling form issue on address option selection COAND-730 --- .../core/internal/ui/AddressSpecification.kt | 2 +- .../core/internal/ui/view/AddressFormInput.kt | 56 +++++++++---------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressSpecification.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressSpecification.kt index 7a5b36f765..0fbe3415c5 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressSpecification.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/AddressSpecification.kt @@ -223,7 +223,7 @@ enum class AddressSpecification( companion object { fun fromString(countryCode: String?): AddressSpecification { - return values().firstOrNull { it.name == countryCode } ?: DEFAULT + return entries.firstOrNull { it.name == countryCode } ?: DEFAULT } } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt index aa9c6e988c..5b977e64dc 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt @@ -22,7 +22,6 @@ import com.adyen.checkout.ui.core.internal.ui.AddressDelegate import com.adyen.checkout.ui.core.internal.ui.AddressSpecification import com.adyen.checkout.ui.core.internal.ui.SimpleTextListAdapter import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem -import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.util.hideError import com.adyen.checkout.ui.core.internal.util.setLocalizedHintFromStyle import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle @@ -136,7 +135,6 @@ class AddressFormInput @JvmOverloads constructor( delegate.addressOutputDataFlow.onEach { addressOutputData -> updateCountries(addressOutputData.countryOptions) updateStates(addressOutputData.stateOptions) - updateInputFields(addressOutputData) }.launchIn(coroutineScope) } @@ -209,10 +207,11 @@ class AddressFormInput @JvmOverloads constructor( } private fun updateCountries(countryList: List) { + val currentSelected = countryAdapter.getItem { it.selected } countryAdapter.setItems(countryList) val selectedCountry = countryList.firstOrNull { it.selected } val selectedSpecification = AddressSpecification.fromString(selectedCountry?.code) - if (selectedSpecification != currentSpec) { + if (selectedSpecification != currentSpec || currentSelected != selectedCountry) { currentSpec = selectedSpecification autoCompleteTextViewCountry.setText(selectedCountry?.name) populateFormFields(selectedSpecification) @@ -253,58 +252,60 @@ class AddressFormInput @JvmOverloads constructor( initCountryInput(addressSpecification.country.styleResId) initStreetInput( styleResId = addressSpecification.street.getStyleResId( - isOptional = delegate.addressOutputData.isOptional - ) + isOptional = delegate.addressOutputData.isOptional, + ), ) initHouseNumberInput( styleResId = addressSpecification.houseNumber.getStyleResId( - isOptional = delegate.addressOutputData.isOptional - ) + isOptional = delegate.addressOutputData.isOptional, + ), ) initApartmentSuiteInput( styleResId = addressSpecification.apartmentSuite.getStyleResId( - isOptional = delegate.addressOutputData.isOptional - ) + isOptional = delegate.addressOutputData.isOptional, + ), ) initPostalCodeInput( styleResId = addressSpecification.postalCode.getStyleResId( - isOptional = delegate.addressOutputData.isOptional - ) + isOptional = delegate.addressOutputData.isOptional, + ), ) initCityInput( styleResId = addressSpecification.city.getStyleResId( - isOptional = delegate.addressOutputData.isOptional - ) + isOptional = delegate.addressOutputData.isOptional, + ), ) initProvinceTerritoryInput( styleResId = addressSpecification.stateProvince.getStyleResId( - isOptional = delegate.addressOutputData.isOptional - ) + isOptional = delegate.addressOutputData.isOptional, + ), ) initStatesInput( styleResId = addressSpecification.stateProvince.getStyleResId( - isOptional = delegate.addressOutputData.isOptional - ) + isOptional = delegate.addressOutputData.isOptional, + ), ) } private fun initHeader() { textViewHeader.setLocalizedTextFromStyle( R.style.AdyenCheckout_AddressForm_HeaderTextAppearance, - localizedContext + localizedContext, ) } private fun initCountryInput(styleResId: Int) { textInputLayoutCountry?.setLocalizedHintFromStyle( styleResId, - localizedContext + localizedContext, ) + autoCompleteTextViewCountry.setText(delegate.addressOutputData.countryOptions.firstOrNull { it.selected }?.name) } private fun initStreetInput(styleResId: Int?) { styleResId?.let { textInputLayoutStreet?.setLocalizedHintFromStyle(it, localizedContext) } editTextStreet?.apply { + setText(delegate.addressOutputData.street.value) setOnChangeListener { delegate.updateAddressInputData { street = it.toString() } textInputLayoutStreet?.hideError() @@ -323,6 +324,7 @@ class AddressFormInput @JvmOverloads constructor( private fun initHouseNumberInput(styleResId: Int?) { styleResId?.let { textInputLayoutHouseNumber?.setLocalizedHintFromStyle(it, localizedContext) } editTextHouseNumber?.apply { + setText(delegate.addressOutputData.houseNumberOrName.value) setOnChangeListener { delegate.updateAddressInputData { houseNumberOrName = it.toString() } textInputLayoutHouseNumber?.hideError() @@ -341,6 +343,7 @@ class AddressFormInput @JvmOverloads constructor( private fun initApartmentSuiteInput(styleResId: Int?) { styleResId?.let { textInputLayoutApartmentSuite?.setLocalizedHintFromStyle(it, localizedContext) } editTextApartmentSuite?.apply { + setText(delegate.addressOutputData.apartmentSuite.value) setOnChangeListener { delegate.updateAddressInputData { apartmentSuite = it.toString() } } @@ -358,6 +361,7 @@ class AddressFormInput @JvmOverloads constructor( private fun initPostalCodeInput(styleResId: Int?) { styleResId?.let { textInputLayoutPostalCode?.setLocalizedHintFromStyle(it, localizedContext) } editTextPostalCode?.apply { + setText(delegate.addressOutputData.postalCode.value) setOnChangeListener { delegate.updateAddressInputData { postalCode = it.toString() } textInputLayoutPostalCode?.hideError() @@ -376,6 +380,7 @@ class AddressFormInput @JvmOverloads constructor( private fun initCityInput(styleResId: Int?) { styleResId?.let { textInputLayoutCity?.setLocalizedHintFromStyle(it, localizedContext) } editTextCity?.apply { + setText(delegate.addressOutputData.city.value) setOnChangeListener { delegate.updateAddressInputData { city = it.toString() } textInputLayoutCity?.hideError() @@ -394,6 +399,7 @@ class AddressFormInput @JvmOverloads constructor( private fun initProvinceTerritoryInput(styleResId: Int?) { styleResId?.let { textInputLayoutProvinceTerritory?.setLocalizedHintFromStyle(it, localizedContext) } editTextProvinceTerritory?.apply { + setText(delegate.addressOutputData.stateOrProvince.value) setOnChangeListener { delegate.updateAddressInputData { stateOrProvince = it.toString() } textInputLayoutProvinceTerritory?.hideError() @@ -412,6 +418,7 @@ class AddressFormInput @JvmOverloads constructor( private fun initStatesInput(styleResId: Int?) { styleResId?.let { textInputLayoutState?.setLocalizedHintFromStyle(it, localizedContext) } autoCompleteTextViewState?.apply { + setText(statesAdapter.getItem { it.selected }?.name) inputType = 0 setAdapter(statesAdapter) onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> @@ -457,15 +464,4 @@ class AddressFormInput @JvmOverloads constructor( val statesStyleResId = spec.stateProvince.getStyleResId(isOptional) statesStyleResId?.let { textInputLayoutState?.setLocalizedHintFromStyle(it, localizedContext) } } - - private fun updateInputFields(addressOutputData: AddressOutputData) { - autoCompleteTextViewCountry.setText(addressOutputData.countryOptions.firstOrNull { it.selected }?.name) - editTextStreet?.setText(delegate.addressOutputData.street.value) - editTextHouseNumber?.setText(delegate.addressOutputData.houseNumberOrName.value) - editTextApartmentSuite?.setText(delegate.addressOutputData.apartmentSuite.value) - editTextPostalCode?.setText(delegate.addressOutputData.postalCode.value) - editTextCity?.setText(delegate.addressOutputData.city.value) - editTextProvinceTerritory?.setText(delegate.addressOutputData.stateOrProvince.value) - autoCompleteTextViewState?.setText(statesAdapter.getItem { it.selected }?.name) - } } From 330adc887d5cf444e2576d25dfdd7a1241077ec1 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:10:29 +0100 Subject: [PATCH 122/255] Make manual entry TextView a Button COAND-730 --- .../internal/ui/view/AddressLookupView.kt | 37 ++++++++----------- .../main/res/layout/address_lookup_view.xml | 20 ++++++---- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 08899e4bda..178132b773 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -67,8 +67,7 @@ class AddressLookupView @JvmOverloads constructor( initAddressLookupQuery() initAddressFormInput(coroutineScope) initAddressOptions() - initManualEntryErrorTextView() - initManualEntryInitialTextView() + initManualEntryButton() initSubmitAddressButton() } @@ -113,14 +112,8 @@ class AddressLookupView @JvmOverloads constructor( } } - private fun initManualEntryErrorTextView() { - binding.textViewManualEntryError.setOnClickListener { - addressLookupDelegate.onManualEntryModeSelected() - } - } - - private fun initManualEntryInitialTextView() { - binding.textViewManualEntryInitial.setOnClickListener { + private fun initManualEntryButton() { + binding.buttonManualEntry.setOnClickListener { addressLookupDelegate.onManualEntryModeSelected() } } @@ -144,9 +137,9 @@ class AddressLookupView @JvmOverloads constructor( private fun handleErrorState() { binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = false + binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = true - binding.textViewManualEntryError.isVisible = true + binding.buttonManualEntry.isVisible = true binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = false @@ -154,9 +147,9 @@ class AddressLookupView @JvmOverloads constructor( private fun handleInitialState() { binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = true + binding.textViewInitialDisclaimer.isVisible = true binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false + binding.buttonManualEntry.isVisible = true binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = false @@ -164,9 +157,9 @@ class AddressLookupView @JvmOverloads constructor( private fun handleLoadingState() { binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = false + binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false + binding.buttonManualEntry.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = true binding.submitAddressButton.isVisible = false @@ -174,9 +167,9 @@ class AddressLookupView @JvmOverloads constructor( private fun handleFormState(addressLookupState: AddressLookupState.Form) { binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = false + binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false + binding.buttonManualEntry.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = true @@ -191,9 +184,9 @@ class AddressLookupView @JvmOverloads constructor( private fun handleSearchResultState(addressLookupState: AddressLookupState.SearchResult) { binding.recyclerViewAddressLookupOptions.isVisible = true - binding.textViewManualEntryInitial.isVisible = false + binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false + binding.buttonManualEntry.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = false @@ -202,9 +195,9 @@ class AddressLookupView @JvmOverloads constructor( private fun handleInvalidUIState() { binding.recyclerViewAddressLookupOptions.isVisible = false - binding.textViewManualEntryInitial.isVisible = false + binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.textViewManualEntryError.isVisible = false + binding.buttonManualEntry.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = true diff --git a/ui-core/src/main/res/layout/address_lookup_view.xml b/ui-core/src/main/res/layout/address_lookup_view.xml index e0a51c78a4..d151154964 100644 --- a/ui-core/src/main/res/layout/address_lookup_view.xml +++ b/ui-core/src/main/res/layout/address_lookup_view.xml @@ -30,6 +30,7 @@ + android:text="You can always enter your address manually" /> - + android:text="Enter address manually" + android:visibility="gone" /> Date: Tue, 2 Jan 2024 10:41:51 +0100 Subject: [PATCH 123/255] Add address lookup translations COAND-730 --- .../card/internal/ui/view/CardView.kt | 4 ++ card/src/main/res/values/styles.xml | 2 +- .../ui/DefaultAddressLookupDelegate.kt | 2 +- .../internal/ui/model/AddressLookupState.kt | 2 +- .../internal/ui/view/AddressLookupView.kt | 58 +++++++++++++++---- .../main/res/layout/address_lookup_view.xml | 22 ++++--- .../main/res/template/values/strings.xml.tt | 5 ++ ui-core/src/main/res/values-ar/strings.xml | 7 +++ .../src/main/res/values-cs-rCZ/strings.xml | 7 +++ .../src/main/res/values-da-rDK/strings.xml | 9 ++- .../src/main/res/values-de-rDE/strings.xml | 9 ++- .../src/main/res/values-el-rGR/strings.xml | 7 +++ .../src/main/res/values-es-rES/strings.xml | 7 +++ .../src/main/res/values-fi-rFI/strings.xml | 7 +++ .../src/main/res/values-fr-rFR/strings.xml | 7 +++ .../src/main/res/values-hr-rHR/strings.xml | 7 +++ .../src/main/res/values-hu-rHU/strings.xml | 7 +++ .../src/main/res/values-it-rIT/strings.xml | 7 +++ .../src/main/res/values-ja-rJP/strings.xml | 7 +++ .../src/main/res/values-ko-rKR/strings.xml | 7 +++ .../src/main/res/values-nb-rNO/strings.xml | 9 ++- .../src/main/res/values-nl-rNL/strings.xml | 7 +++ .../src/main/res/values-pl-rPL/strings.xml | 7 +++ .../src/main/res/values-pt-rBR/strings.xml | 7 +++ .../src/main/res/values-pt-rPT/strings.xml | 7 +++ .../src/main/res/values-ro-rRO/strings.xml | 7 +++ .../src/main/res/values-ru-rRU/strings.xml | 7 +++ .../src/main/res/values-sk-rSK/strings.xml | 7 +++ .../src/main/res/values-sl-rSI/strings.xml | 9 ++- .../src/main/res/values-sv-rSE/strings.xml | 7 +++ .../src/main/res/values-zh-rCN/strings.xml | 7 +++ .../src/main/res/values-zh-rTW/strings.xml | 7 +++ ui-core/src/main/res/values/strings.xml | 7 ++- ui-core/src/main/res/values/styles.xml | 28 ++++++++- 34 files changed, 283 insertions(+), 30 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt index fdff7721b0..28003a457a 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/view/CardView.kt @@ -145,6 +145,10 @@ class CardView @JvmOverloads constructor( R.style.AdyenCheckout_PostalCodeInput, localizedContext ) + binding.textInputLayoutAddressLookup.setLocalizedHintFromStyle( + R.style.AdyenCheckout_Card_AddressLookup_DropdownTextInputEditText, + localizedContext + ) binding.textInputLayoutSocialSecurityNumber.setLocalizedHintFromStyle( R.style.AdyenCheckout_Card_SocialSecurityNumberInput, localizedContext diff --git a/card/src/main/res/values/styles.xml b/card/src/main/res/values/styles.xml index 748ea05d3d..45b6ef47ff 100644 --- a/card/src/main/res/values/styles.xml +++ b/card/src/main/res/values/styles.xml @@ -97,7 +97,6 @@ none - diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt index e1c3c905e0..da295eb92e 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt @@ -173,7 +173,7 @@ class DefaultAddressLookupDelegate : private fun handleSearchResultEvent(event: AddressLookupEvent.SearchResult): AddressLookupState { return if (currentAddressLookupState is AddressLookupState.Loading) { if (event.addressLookupOptions.isEmpty()) { - AddressLookupState.Error + AddressLookupState.Error(addressLookupInputData.query) } else { currentAddressLookupOptions = event.addressLookupOptions AddressLookupState.SearchResult( diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt index 937df2c581..799a657b31 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/AddressLookupState.kt @@ -18,6 +18,6 @@ sealed class AddressLookupState { object Loading : AddressLookupState() data class Form(val selectedAddress: AddressInputModel?) : AddressLookupState() data class SearchResult(val query: String, val options: List) : AddressLookupState() - object Error : AddressLookupState() + data class Error(val query: String) : AddressLookupState() object InvalidUI : AddressLookupState() } diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 178132b773..01a0a58436 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -23,6 +23,8 @@ import com.adyen.checkout.ui.core.databinding.AddressLookupViewBinding import com.adyen.checkout.ui.core.internal.ui.AddressLookupDelegate import com.adyen.checkout.ui.core.internal.ui.ComponentView import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupState +import com.adyen.checkout.ui.core.internal.util.formatStringWithHyperlink +import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -67,7 +69,7 @@ class AddressLookupView @JvmOverloads constructor( initAddressLookupQuery() initAddressFormInput(coroutineScope) initAddressOptions() - initManualEntryButton() + initManualEntryTextViews() initSubmitAddressButton() } @@ -82,8 +84,27 @@ class AddressLookupView @JvmOverloads constructor( } private fun initLocalizedStrings(localizedContext: Context) { - // TODO address lookup translations binding.addressFormInput.initLocalizedContext(localizedContext) + + binding.textViewInitialDisclaimer.setLocalizedTextFromStyle( + styleResId = R.style.AdyenCheckout_AddressLookup_InitialDisclaimer_Title, + localizedContext = localizedContext, + ) + + binding.textViewManualEntryInitial.text = + localizedContext.getString(R.string.checkout_address_lookup_initial_description) + .formatStringWithHyperlink("#") + + binding.textViewError.setLocalizedTextFromStyle( + styleResId = R.style.AdyenCheckout_AddressLookup_Empty_Title, + localizedContext = localizedContext, + ) + + binding.textViewManualEntryError.setLocalizedTextFromStyle( + styleResId = R.style.AdyenCheckout_AddressLookup_Empty_Description, + localizedContext = localizedContext, + formatHyperLink = true, + ) } private fun initAddressLookupQuery() { @@ -112,8 +133,12 @@ class AddressLookupView @JvmOverloads constructor( } } - private fun initManualEntryButton() { - binding.buttonManualEntry.setOnClickListener { + private fun initManualEntryTextViews() { + binding.textViewManualEntryError.setOnClickListener { + addressLookupDelegate.onManualEntryModeSelected() + } + + binding.textViewManualEntryInitial.setOnClickListener { addressLookupDelegate.onManualEntryModeSelected() } } @@ -126,7 +151,7 @@ class AddressLookupView @JvmOverloads constructor( private fun outputDataChanged(addressLookupState: AddressLookupState) { when (addressLookupState) { - AddressLookupState.Error -> handleErrorState() + is AddressLookupState.Error -> handleErrorState(addressLookupState) is AddressLookupState.Initial -> handleInitialState() AddressLookupState.Loading -> handleLoadingState() is AddressLookupState.Form -> handleFormState(addressLookupState) @@ -135,21 +160,26 @@ class AddressLookupView @JvmOverloads constructor( } } - private fun handleErrorState() { + private fun handleErrorState(addressLookupState: AddressLookupState.Error) { binding.recyclerViewAddressLookupOptions.isVisible = false binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = true - binding.buttonManualEntry.isVisible = true + binding.textViewManualEntryError.isVisible = true + binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = false + binding.textViewManualEntryError.text = + localizedContext.getString(R.string.checkout_address_lookup_empty_description, addressLookupState.query) + .formatStringWithHyperlink("#") } private fun handleInitialState() { binding.recyclerViewAddressLookupOptions.isVisible = false binding.textViewInitialDisclaimer.isVisible = true binding.textViewError.isVisible = false - binding.buttonManualEntry.isVisible = true + binding.textViewManualEntryError.isVisible = false + binding.textViewManualEntryInitial.isVisible = true binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = false @@ -159,7 +189,8 @@ class AddressLookupView @JvmOverloads constructor( binding.recyclerViewAddressLookupOptions.isVisible = false binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.buttonManualEntry.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = true binding.submitAddressButton.isVisible = false @@ -169,7 +200,8 @@ class AddressLookupView @JvmOverloads constructor( binding.recyclerViewAddressLookupOptions.isVisible = false binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.buttonManualEntry.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = true @@ -186,7 +218,8 @@ class AddressLookupView @JvmOverloads constructor( binding.recyclerViewAddressLookupOptions.isVisible = true binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.buttonManualEntry.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = false @@ -197,7 +230,8 @@ class AddressLookupView @JvmOverloads constructor( binding.recyclerViewAddressLookupOptions.isVisible = false binding.textViewInitialDisclaimer.isVisible = false binding.textViewError.isVisible = false - binding.buttonManualEntry.isVisible = false + binding.textViewManualEntryError.isVisible = false + binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false binding.submitAddressButton.isVisible = true diff --git a/ui-core/src/main/res/layout/address_lookup_view.xml b/ui-core/src/main/res/layout/address_lookup_view.xml index d151154964..4dacd1fb06 100644 --- a/ui-core/src/main/res/layout/address_lookup_view.xml +++ b/ui-core/src/main/res/layout/address_lookup_view.xml @@ -35,7 +35,16 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:gravity="center" - android:text="No results found." + android:text="@string/checkout_address_lookup_empty" + android:visibility="gone" /> + + - + android:text="@string/checkout_address_lookup_initial" /> - + %%provinceOrTerritory.optional%% %%cityTown.optional%% + %%address.lookup.search.placeholder%% + %%address.lookup.search.empty.title%% + %%address.lookup.search.empty.subtitle%% + %%address.lookup.search.empty.title.noResults%% + %%address.lookup.search.empty.subtitle.noResults%% %1$s (%2$s) diff --git a/ui-core/src/main/res/values-ar/strings.xml b/ui-core/src/main/res/values-ar/strings.xml index 2156c8b7d8..551ebba4f1 100644 --- a/ui-core/src/main/res/values-ar/strings.xml +++ b/ui-core/src/main/res/values-ar/strings.xml @@ -42,4 +42,11 @@ الرمز البريدي (اختياري) المقاطعة أو الإقليم (اختياري) المدينة / البلدة (اختياري) + + ابحث عن عنوانك + لا تستطيع البحث عن عنوانك؟ + يمكنك دائمًا #إدخال عنوانك يدويًا# + لم يتم العثور على نتائج + لم يتطابق \'%s\' مع أي شيء، حاول مرة أخرى أو استخدم #إدخال العنوان يدويًا# + diff --git a/ui-core/src/main/res/values-cs-rCZ/strings.xml b/ui-core/src/main/res/values-cs-rCZ/strings.xml index 9808cc86a0..98185402bd 100644 --- a/ui-core/src/main/res/values-cs-rCZ/strings.xml +++ b/ui-core/src/main/res/values-cs-rCZ/strings.xml @@ -42,4 +42,11 @@ PSČ (nepovinné) Provincie nebo teritorium Město (nepovinné) + + Vyhledat vaši adresu + Nedaří se vám vyhledat vaši adresu? + Vždy můžete #zadat svou adresu ručně# + Nebyly nalezeny žádné výsledky + „%s“ se s ničím neshoduje, zkuste to znovu nebo použijte #ruční zadání adresy# + diff --git a/ui-core/src/main/res/values-da-rDK/strings.xml b/ui-core/src/main/res/values-da-rDK/strings.xml index 05b1af5f84..415640e68a 100644 --- a/ui-core/src/main/res/values-da-rDK/strings.xml +++ b/ui-core/src/main/res/values-da-rDK/strings.xml @@ -12,7 +12,7 @@ Bekræft forhåndsgodkendelse En betalingsproces er stadig aktiv - Afventer fuldførelse … + Afventer fuldførelse… Annuller Ugyldig indtastning @@ -42,4 +42,11 @@ Postnummer (valgfrit) Provins eller territorium (valgfrit) By (valgfrit) + + Søg på din adresse + Kan du ikke søge på din adresse? + Du kan altid #indtaste din adresse manuelt# + Ingen resultater fundet + Fandt ikke noget match for \'%s\'. Prøv igen eller #indtast adresse manuelt#. + diff --git a/ui-core/src/main/res/values-de-rDE/strings.xml b/ui-core/src/main/res/values-de-rDE/strings.xml index 5301321678..95eac2e030 100644 --- a/ui-core/src/main/res/values-de-rDE/strings.xml +++ b/ui-core/src/main/res/values-de-rDE/strings.xml @@ -12,7 +12,7 @@ Vorautorisierung bestätigen Ein Bezahlvorgang ist noch aktiv - Abschluss abwarten … + Abschluss abwarten… Abbrechen Ungültige Eingabe @@ -42,4 +42,11 @@ PLZ (optional) Provinz oder Territorium (optional) Ort (optional) + + Suchen Sie Ihre Adresse + Sie können Ihre Adresse nicht suchen? + Sie können Ihre Adresse jederzeit manuell #eingeben# + Keine Ergebnisse gefunden + \'%s\' stimmt nicht mit irgendetwas überein, versuchen Sie es erneut oder verwenden Sie #manual address entry# + diff --git a/ui-core/src/main/res/values-el-rGR/strings.xml b/ui-core/src/main/res/values-el-rGR/strings.xml index 52458d7287..57dbed7380 100644 --- a/ui-core/src/main/res/values-el-rGR/strings.xml +++ b/ui-core/src/main/res/values-el-rGR/strings.xml @@ -42,4 +42,11 @@ Ταχυδρομικός κωδικός (προαιρετικό) Επαρχία ή περιοχή (προαιρετικό) Πόλη / Δήμος (προαιρετικό) + + Αναζητήστε τη διεύθυνσή σας + Δεν μπορείτε να κάνετε αναζήτηση της διεύθυνσής σας; + Μπορείτε πάντα να #εισαγάγετε τη διεύθυνσή σας μη αυτόματα# + Δεν βρέθηκαν αποτελέσματα + Το \'%s\' δεν ταιριάζει με τίποτα. Προσπαθήστε ξανά ή χρησιμοποιήστε #μη αυτόματη εισαγωγή διεύθυνσης# + diff --git a/ui-core/src/main/res/values-es-rES/strings.xml b/ui-core/src/main/res/values-es-rES/strings.xml index 6e81195c7c..a0673af9f8 100644 --- a/ui-core/src/main/res/values-es-rES/strings.xml +++ b/ui-core/src/main/res/values-es-rES/strings.xml @@ -42,4 +42,11 @@ Código postal (opcional) Provincia o territorio (opcional) Ciudad/población (opcional) + + Busque su dirección + ¿No puede buscar su dirección? + También puede #introducir su dirección manualmente# + No se han encontrado resultados + "%s" no ha coincidido con nada, inténtelo de nuevo o #introduzca su dirección manualmente# + diff --git a/ui-core/src/main/res/values-fi-rFI/strings.xml b/ui-core/src/main/res/values-fi-rFI/strings.xml index f5f5631d2c..85a4be5217 100644 --- a/ui-core/src/main/res/values-fi-rFI/strings.xml +++ b/ui-core/src/main/res/values-fi-rFI/strings.xml @@ -42,4 +42,11 @@ Postinumero (valinnainen) Maakunta tai alue (valinnainen) Kaupunki / taajama (valinnainen) + + Hae osoitteesi + Eikö osoitetta löydy? + Voit myös #syöttää osoitteen manuaalisesti# + Tuloksia ei löytynyt + \'%s\' ei tuottanut tuloksia. Yritä uudelleen tai käytä #manuaalista osoitteen syöttöä# + diff --git a/ui-core/src/main/res/values-fr-rFR/strings.xml b/ui-core/src/main/res/values-fr-rFR/strings.xml index d73479c09a..2b3031ddc2 100644 --- a/ui-core/src/main/res/values-fr-rFR/strings.xml +++ b/ui-core/src/main/res/values-fr-rFR/strings.xml @@ -42,4 +42,11 @@ Code postal (facultatif) Province ou territoire (facultatif) Ville (facultatif) + + Rechercher votre adresse + Vous ne pouvez pas rechercher votre adresse ? + Vous pouvez toujours #saisir votre adresse manuellement# + Aucun résultat trouvé + Aucune correspondance pour \'%s\', réessayez ou #saisissez votre adresse manuellement# + diff --git a/ui-core/src/main/res/values-hr-rHR/strings.xml b/ui-core/src/main/res/values-hr-rHR/strings.xml index 1836d32082..c3eb24ba74 100644 --- a/ui-core/src/main/res/values-hr-rHR/strings.xml +++ b/ui-core/src/main/res/values-hr-rHR/strings.xml @@ -42,4 +42,11 @@ Poštanski broj (neobavezno) Pokrajina ili teritorij (neobavezno) Grad (neobavezno) + + Pretraživanje vaše adrese + Ne možete pretražiti svoju adresu? + Uvijek možete #ručno unijeti svoju adresu# + Nisu pronađeni rezultati + \'%s\' nije se podudarao s ničime, pokušajte ponovno ili upotrijebite #ručni unos adrese# + diff --git a/ui-core/src/main/res/values-hu-rHU/strings.xml b/ui-core/src/main/res/values-hu-rHU/strings.xml index 5c5d0c51ee..747d89bb29 100644 --- a/ui-core/src/main/res/values-hu-rHU/strings.xml +++ b/ui-core/src/main/res/values-hu-rHU/strings.xml @@ -42,4 +42,11 @@ Irányítószám (nem kötelező) Tartomány vagy terület (nem kötelező) Város (nem kötelező) + + Keresse meg a címét + Nem tudja megkeresni a címét? + Mindig #beírhatja manuálisan a címét# + Nincs találat + A keresett „%s„ kifejezésre nincs találat, próbálkozzon újra, vagy #írja be manuálisan a címet# + diff --git a/ui-core/src/main/res/values-it-rIT/strings.xml b/ui-core/src/main/res/values-it-rIT/strings.xml index 57d82831b4..de69413792 100644 --- a/ui-core/src/main/res/values-it-rIT/strings.xml +++ b/ui-core/src/main/res/values-it-rIT/strings.xml @@ -42,4 +42,11 @@ CAP (facoltativo) Provincia o territorio (facoltativo) Città (facoltativo) + + Cerca il tuo indirizzo + Non riesci a cercare il tuo indirizzo? + Puoi sempre #immettere il tuo indirizzo #manualmente + Nessun risultato trovato + %s non corrisponde a nulla, riprova o usa #inserimento indirizzo manuale# + diff --git a/ui-core/src/main/res/values-ja-rJP/strings.xml b/ui-core/src/main/res/values-ja-rJP/strings.xml index 1f3bedc33a..17db583d85 100644 --- a/ui-core/src/main/res/values-ja-rJP/strings.xml +++ b/ui-core/src/main/res/values-ja-rJP/strings.xml @@ -42,4 +42,11 @@ 郵便番号 (任意) 州または準州 (任意) 市区町村 (任意) + + 住所を検索してください + 住所を検索できませんか? + いつでも手動で#住所を入力#できます + 結果が見つかりませんでした + 「%s」との一致はありませんでした。もう一度試すか、#手動でアドレスを入力#してください + diff --git a/ui-core/src/main/res/values-ko-rKR/strings.xml b/ui-core/src/main/res/values-ko-rKR/strings.xml index 77f0147750..d24be133ac 100644 --- a/ui-core/src/main/res/values-ko-rKR/strings.xml +++ b/ui-core/src/main/res/values-ko-rKR/strings.xml @@ -42,4 +42,11 @@ 우편 번호(선택 사항) 도(선택 사항) 시/구(선택 사항) + + 주소 검색 + 주소를 검색할 수 없나요? + 언제든지 #수동으로 주소를 입력할 수 있습니다#. + 결과를 찾을 수 없습니다. + \'%s\'와(과) 일치하는 항목이 없습니다. 다시 시도하거나 #수동 주소 입력#을 사용하세요. + diff --git a/ui-core/src/main/res/values-nb-rNO/strings.xml b/ui-core/src/main/res/values-nb-rNO/strings.xml index 8de3a1c2e9..4f5cdb5c58 100644 --- a/ui-core/src/main/res/values-nb-rNO/strings.xml +++ b/ui-core/src/main/res/values-nb-rNO/strings.xml @@ -12,7 +12,7 @@ Bekreft forhåndsgodkjenning Det er en betalingsprosess som fortsatt er aktiv - Venter på fullførelse … + Venter på fullførelse… Avbryt Ugyldige inndata @@ -42,4 +42,11 @@ Postnummer (valgfritt) Provins eller territorium (valgfritt) By (valgfritt) + + Søk på adressen din + Kan du ikke søke på adressen din? + Du kan alltids #skrive inn adressen din manuelt# + Fant ingen resultater + Fikk ingen treff på «%s». Prøv igjen eller #skriv inn adressen manuelt# + diff --git a/ui-core/src/main/res/values-nl-rNL/strings.xml b/ui-core/src/main/res/values-nl-rNL/strings.xml index 25545be1ac..3dd2126c56 100644 --- a/ui-core/src/main/res/values-nl-rNL/strings.xml +++ b/ui-core/src/main/res/values-nl-rNL/strings.xml @@ -42,4 +42,11 @@ Postcode (optioneel) Provincie of territorium (optioneel) Stad (optioneel) + + Zoek uw adres + Werd uw adres niet gevonden? + U kunt #uw adres handmatig invoeren# + Geen resultaten gevonden + Geen resulaten gevonden voor \'%s\', probeer het opnieuw of gebruik #adres handmatig invoeren# + diff --git a/ui-core/src/main/res/values-pl-rPL/strings.xml b/ui-core/src/main/res/values-pl-rPL/strings.xml index 023bf43643..676e42900c 100644 --- a/ui-core/src/main/res/values-pl-rPL/strings.xml +++ b/ui-core/src/main/res/values-pl-rPL/strings.xml @@ -42,4 +42,11 @@ Kod pocztowy (opcjonalnie) Region lub terytorium (opcjonalnie) Miejscowość (opcjonalnie) + + Znajdź swój adres + Nie możesz znaleźć swojego adresu? + Zawsze możesz #wprowadzić swój adres ręcznie# + Nie znaleziono żadnych wyników + Nie znaleziono żadnych dopasowań dla \'%s\', spróbuj ponownie lub #wprowadź adres ręcznie# + diff --git a/ui-core/src/main/res/values-pt-rBR/strings.xml b/ui-core/src/main/res/values-pt-rBR/strings.xml index b75b5b5fb9..17fa2e288e 100644 --- a/ui-core/src/main/res/values-pt-rBR/strings.xml +++ b/ui-core/src/main/res/values-pt-rBR/strings.xml @@ -42,4 +42,11 @@ Código postal (opcional) Província ou território (opcional) Cidade (opcional) + + Pesquise seu endereço + Não consegue pesquisar seu endereço? + Você pode #inserir seu endereço manualmente# + Nenhum resultado encontrado + A pesquisa de \'%s\' não obteve resultados. Tente novamente ou use #inserir endereço manualmente# + diff --git a/ui-core/src/main/res/values-pt-rPT/strings.xml b/ui-core/src/main/res/values-pt-rPT/strings.xml index 3a6cd14f2f..6790dd941b 100644 --- a/ui-core/src/main/res/values-pt-rPT/strings.xml +++ b/ui-core/src/main/res/values-pt-rPT/strings.xml @@ -42,4 +42,11 @@ Código postal (opcional) Província ou Território (opcional) Cidade/cidade (opcional) + + Pesquise o seu endereço + Não consegue pesquisar o seu endereço? + Pode sempre #inserir o seu endereço manualmente# + Nenhum resultado encontrado + \'%s\' não devolveu resultados, tente novamente ou use #inserção manual do endereço# + diff --git a/ui-core/src/main/res/values-ro-rRO/strings.xml b/ui-core/src/main/res/values-ro-rRO/strings.xml index 5446b2cc55..8411037ded 100644 --- a/ui-core/src/main/res/values-ro-rRO/strings.xml +++ b/ui-core/src/main/res/values-ro-rRO/strings.xml @@ -42,4 +42,11 @@ Cod poștal (opțional) Provincie sau teritoriu (opțional) Oraș/localitate (opțional) + + Căutați adresa dvs. + Nu vă puteți căuta adresa? + Puteți oricând să #completați adresa dvs. manual# + Nu s-au găsit rezultate + \'%s\' nu s-a potrivit cu nimic, încercați din nou sau folosiți #completarea manuală a adresei# + diff --git a/ui-core/src/main/res/values-ru-rRU/strings.xml b/ui-core/src/main/res/values-ru-rRU/strings.xml index 9f7cebc1e0..b4c083b738 100644 --- a/ui-core/src/main/res/values-ru-rRU/strings.xml +++ b/ui-core/src/main/res/values-ru-rRU/strings.xml @@ -42,4 +42,11 @@ Почтовый индекс (необязательно) Область или территория (необязательно) Город (необязательно) + + Поиск по адресу + Не можете найти адрес? + Можно #ввести адрес вручную# + Результаты не найдены + Не найдено соответствий «%s». Повторите попытку или используйте #ручной ввод адреса# + diff --git a/ui-core/src/main/res/values-sk-rSK/strings.xml b/ui-core/src/main/res/values-sk-rSK/strings.xml index d9fe85bb2a..88e604c2f3 100644 --- a/ui-core/src/main/res/values-sk-rSK/strings.xml +++ b/ui-core/src/main/res/values-sk-rSK/strings.xml @@ -42,4 +42,11 @@ PSČ (nepovinné) Okres alebo územie (voliteľné) Mesto/obec (nepovinné) + + Vyhľadajte svoju adresu + Nemôžete vyhľadať svoju adresu? + Vždy môžete #zadať svoju adresu ručne# + Nenašli sa žiadne výsledky + \'%s\' sa s ničím nezhoduje, skúste to znova alebo použite #ručné zadanie adresy# + diff --git a/ui-core/src/main/res/values-sl-rSI/strings.xml b/ui-core/src/main/res/values-sl-rSI/strings.xml index 3f5654744c..b014350cd4 100644 --- a/ui-core/src/main/res/values-sl-rSI/strings.xml +++ b/ui-core/src/main/res/values-sl-rSI/strings.xml @@ -12,7 +12,7 @@ Potrdi predhodno odobritev Postopek plačila je še vedno aktiven - Čakanje na dokončanje … + Čakanje na dokončanje… Prekliči Neveljaven vnos @@ -42,4 +42,11 @@ Poštna številka (neobvezno) Območje ali ozemlje (neobvezno) Mesto (neobvezno) + + Poiščite svoj naslov + Ne morete iskati svojega naslova? + Vedno lahko #ročno vnesete svoj naslov# + Nobenega rezultata ni bilo mogoče najti + »%s« se ni ujemalo z ničemer, poskusite znova ali uporabite #ročni vnos naslova# + diff --git a/ui-core/src/main/res/values-sv-rSE/strings.xml b/ui-core/src/main/res/values-sv-rSE/strings.xml index 69caa3d0d8..8124766f72 100644 --- a/ui-core/src/main/res/values-sv-rSE/strings.xml +++ b/ui-core/src/main/res/values-sv-rSE/strings.xml @@ -42,4 +42,11 @@ Postnummer (valfritt) Provins eller territorium (valfritt) Ort (valfritt) + + Sök upp din adress + Kan du inte söka efter din adress? + Du kan alltid #ange din adress manuellt# + Inga resultat hittades + Det finns inga matchningar för ”%s”. Försök igen eller använd #manuell adressinmatning# + diff --git a/ui-core/src/main/res/values-zh-rCN/strings.xml b/ui-core/src/main/res/values-zh-rCN/strings.xml index f35ca1d9cf..9ad883046c 100644 --- a/ui-core/src/main/res/values-zh-rCN/strings.xml +++ b/ui-core/src/main/res/values-zh-rCN/strings.xml @@ -42,4 +42,11 @@ 邮政编码(可选) 省或地区(可选) 市 / 镇(可选) + + 搜索地址 + 无法搜索地址? + 您随时可以#手动输入地址# + 未找到任何结果 + “%s”无匹配内容,请重试或者使用#手动地址条目# + diff --git a/ui-core/src/main/res/values-zh-rTW/strings.xml b/ui-core/src/main/res/values-zh-rTW/strings.xml index 57c14d5adf..6de5e5179f 100644 --- a/ui-core/src/main/res/values-zh-rTW/strings.xml +++ b/ui-core/src/main/res/values-zh-rTW/strings.xml @@ -42,4 +42,11 @@ 郵遞區號(選用) 省或地區(選用) 市/鎮(選用) + + 搜尋您的地址 + 無法搜尋您的地址? + 可以隨時#手動輸入您的地址# + 找不到任何結果 + 「%s」不符合任何搜尋內容,請再試一次或#手動輸入地址# + diff --git a/ui-core/src/main/res/values/strings.xml b/ui-core/src/main/res/values/strings.xml index a54c5c7c89..fbb433ea1f 100644 --- a/ui-core/src/main/res/values/strings.xml +++ b/ui-core/src/main/res/values/strings.xml @@ -43,8 +43,11 @@ Province or Territory (optional) City / Town (optional) - - Use this address + Search your address + Can\'t search your address? + You can always #enter your address manually# + No results found + \'%s\' did not match with anything, try again or use #manual address entry# %1$s (%2$s) diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index d779e8f305..3e8b5d1228 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -330,7 +330,7 @@ @@ -354,6 +354,30 @@ + + + + + + + + From f9124c1ca5a94061d5e189e6a446656859e8b434 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:45:20 +0100 Subject: [PATCH 124/255] Trigger ClearQuery event on empty query in address lookup COAND-730 --- .../ui/core/internal/ui/DefaultAddressLookupDelegate.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt index da295eb92e..2fcec0d6fe 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt @@ -93,7 +93,11 @@ class DefaultAddressLookupDelegate : } override fun onAddressQueryChanged(query: String) { - addressLookupEventChannel.trySend(AddressLookupEvent.Query(query)) + if (query.isEmpty()) { + addressLookupEventChannel.trySend(AddressLookupEvent.ClearQuery) + } else { + addressLookupEventChannel.trySend(AddressLookupEvent.Query(query)) + } addressLookupCallback?.onQueryChanged(query) } From 99f457df6b3677000b5b59248e0471d6213954fc Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 2 Jan 2024 11:47:25 +0100 Subject: [PATCH 125/255] Set default state to AddressLookupState.Form when there's an initial address COAND-730 --- .../adyen/checkout/example/ui/card/CardViewModel.kt | 2 +- .../core/internal/ui/DefaultAddressLookupDelegate.kt | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 3a394cc1ec..8906a7e429 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -58,7 +58,7 @@ internal class CardViewModel @Inject constructor( .filterNotNull() .debounce(ADDRESS_LOOKUP_QUERY_DEBOUNCE_DURATION) .onEach { query -> - val options = if (query == "empty" || query.isEmpty()) { + val options = if (query == "empty") { emptyList() } else { ADDRESS_LOOKUP_OPTIONS diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt index 2fcec0d6fe..4e36e68d2e 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt @@ -143,7 +143,7 @@ class DefaultAddressLookupDelegate : return when (event) { is AddressLookupEvent.Initialize -> handleInitializeEvent(event) is AddressLookupEvent.Query -> handleQueryEvent(event) - AddressLookupEvent.ClearQuery -> AddressLookupState.Initial + AddressLookupEvent.ClearQuery -> handleClearQueryEvent() AddressLookupEvent.Manual -> handleManualEvent() is AddressLookupEvent.SearchResult -> handleSearchResultEvent(event) is AddressLookupEvent.OptionSelected -> handleOptionSelectedEvent(event, addressLookupOptions) @@ -164,6 +164,14 @@ class DefaultAddressLookupDelegate : return AddressLookupState.Loading } + private fun handleClearQueryEvent(): AddressLookupState { + return if (!addressLookupInputData.selectedAddress.isEmpty) { + AddressLookupState.Form(addressLookupInputData.selectedAddress) + } else { + AddressLookupState.Initial + } + } + private fun handleManualEvent(): AddressLookupState { return if (currentAddressLookupState is AddressLookupState.Initial || currentAddressLookupState is AddressLookupState.Error From ba21d32e8d0ba8a8e70ccae65c6080106a6ad565 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 2 Jan 2024 13:40:04 +0100 Subject: [PATCH 126/255] Adjust margins of AddressLookupView COAND-730 --- .../checkout/ui/core/internal/ui/view/AddressLookupView.kt | 2 +- ui-core/src/main/res/layout/address_lookup_view.xml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 01a0a58436..18b5a01c1c 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -54,7 +54,7 @@ class AddressLookupView @JvmOverloads constructor( init { orientation = VERTICAL val padding = resources.getDimension(R.dimen.standard_margin).toInt() - setPadding(padding, padding, padding, 0) + setPadding(padding, padding, padding, padding) } override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { diff --git a/ui-core/src/main/res/layout/address_lookup_view.xml b/ui-core/src/main/res/layout/address_lookup_view.xml index 4dacd1fb06..e893ce93b8 100644 --- a/ui-core/src/main/res/layout/address_lookup_view.xml +++ b/ui-core/src/main/res/layout/address_lookup_view.xml @@ -18,7 +18,7 @@ android:id="@+id/textInputLayout_addressLookupQuerySearch" style="@style/AdyenCheckout.AddressLookup.Query" android:layout_width="match_parent" - android:layout_marginBottom="@dimen/standard_half_margin" /> + android:layout_marginBottom="@dimen/standard_margin" /> @@ -53,6 +54,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" + android:layout_marginBottom="@dimen/standard_half_margin" android:gravity="center" android:text="@string/checkout_address_lookup_initial" /> From 2a50262f5cc52894f03b1e4ba59f11b15bc9aaf2 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 2 Jan 2024 13:46:25 +0100 Subject: [PATCH 127/255] Add an arrow to indicate search address field leads to another screen COAND-730 --- card/src/main/res/layout/card_view.xml | 1 + .../main/res/drawable/address_lookup_search_input_arrow.xml | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 ui-core/src/main/res/drawable/address_lookup_search_input_arrow.xml diff --git a/card/src/main/res/layout/card_view.xml b/card/src/main/res/layout/card_view.xml index 5b93e89b4f..c7f97d09c7 100644 --- a/card/src/main/res/layout/card_view.xml +++ b/card/src/main/res/layout/card_view.xml @@ -162,6 +162,7 @@ diff --git a/ui-core/src/main/res/drawable/address_lookup_search_input_arrow.xml b/ui-core/src/main/res/drawable/address_lookup_search_input_arrow.xml new file mode 100644 index 0000000000..c8e71a95ba --- /dev/null +++ b/ui-core/src/main/res/drawable/address_lookup_search_input_arrow.xml @@ -0,0 +1,6 @@ + + + From f98a12b93cd0a4c8ac7fd368542fdb77ce71e867 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 2 Jan 2024 15:23:34 +0100 Subject: [PATCH 128/255] Display manual entry option together with search result COAND-730 --- .../ui/DefaultAddressLookupDelegate.kt | 3 ++- .../internal/ui/view/AddressLookupView.kt | 20 ++++++++++++++++-- .../main/res/layout/address_lookup_view.xml | 21 ++++++++++++++++++- ui-core/src/main/res/values/styles.xml | 9 +++++++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt index 4e36e68d2e..9fca6584e5 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/DefaultAddressLookupDelegate.kt @@ -174,7 +174,8 @@ class DefaultAddressLookupDelegate : private fun handleManualEvent(): AddressLookupState { return if (currentAddressLookupState is AddressLookupState.Initial || - currentAddressLookupState is AddressLookupState.Error + currentAddressLookupState is AddressLookupState.Error || + currentAddressLookupState is AddressLookupState.SearchResult ) { AddressLookupState.Form(null) } else { diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt index 18b5a01c1c..8ab52a3568 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressLookupView.kt @@ -69,7 +69,7 @@ class AddressLookupView @JvmOverloads constructor( initAddressLookupQuery() initAddressFormInput(coroutineScope) initAddressOptions() - initManualEntryTextViews() + initManualEntryFields() initSubmitAddressButton() } @@ -133,7 +133,7 @@ class AddressLookupView @JvmOverloads constructor( } } - private fun initManualEntryTextViews() { + private fun initManualEntryFields() { binding.textViewManualEntryError.setOnClickListener { addressLookupDelegate.onManualEntryModeSelected() } @@ -141,6 +141,10 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryInitial.setOnClickListener { addressLookupDelegate.onManualEntryModeSelected() } + + binding.buttonManualEntry.setOnClickListener { + addressLookupDelegate.onManualEntryModeSelected() + } } private fun initSubmitAddressButton() { @@ -168,6 +172,8 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false + binding.buttonManualEntry.isVisible = false + binding.divider.isVisible = false binding.submitAddressButton.isVisible = false binding.textViewManualEntryError.text = localizedContext.getString(R.string.checkout_address_lookup_empty_description, addressLookupState.query) @@ -182,6 +188,8 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryInitial.isVisible = true binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false + binding.buttonManualEntry.isVisible = false + binding.divider.isVisible = false binding.submitAddressButton.isVisible = false } @@ -193,6 +201,8 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = true + binding.buttonManualEntry.isVisible = false + binding.divider.isVisible = false binding.submitAddressButton.isVisible = false } @@ -204,6 +214,8 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false + binding.buttonManualEntry.isVisible = false + binding.divider.isVisible = false binding.submitAddressButton.isVisible = true addressLookupDelegate.addressDelegate.updateAddressInputData { if (addressLookupState.selectedAddress == null) { @@ -222,6 +234,8 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = false binding.progressBar.isVisible = false + binding.buttonManualEntry.isVisible = true + binding.divider.isVisible = true binding.submitAddressButton.isVisible = false setAddressOptions(addressLookupState.options) } @@ -234,6 +248,8 @@ class AddressLookupView @JvmOverloads constructor( binding.textViewManualEntryInitial.isVisible = false binding.addressFormInput.isVisible = true binding.progressBar.isVisible = false + binding.buttonManualEntry.isVisible = false + binding.divider.isVisible = false binding.submitAddressButton.isVisible = true highlightValidationErrors() } diff --git a/ui-core/src/main/res/layout/address_lookup_view.xml b/ui-core/src/main/res/layout/address_lookup_view.xml index e893ce93b8..f2415d540c 100644 --- a/ui-core/src/main/res/layout/address_lookup_view.xml +++ b/ui-core/src/main/res/layout/address_lookup_view.xml @@ -76,6 +76,25 @@ android:focusableInTouchMode="true" android:visibility="gone" /> +