From 71208ad7b59d451fb6836dd9f41fa20f5173a6b5 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 15 Nov 2021 09:45:56 +0100 Subject: [PATCH 001/102] Add icon for example app settings --- .../src/main/res/drawable/ic_settings.xml | 20 +++++++++++++++++++ example-app/src/main/res/menu/main_menu.xml | 14 +++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 example-app/src/main/res/drawable/ic_settings.xml diff --git a/example-app/src/main/res/drawable/ic_settings.xml b/example-app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 0000000000..fdfec3546c --- /dev/null +++ b/example-app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/example-app/src/main/res/menu/main_menu.xml b/example-app/src/main/res/menu/main_menu.xml index de9008a043..53605eca2c 100644 --- a/example-app/src/main/res/menu/main_menu.xml +++ b/example-app/src/main/res/menu/main_menu.xml @@ -1,5 +1,4 @@ - - - + - + \ No newline at end of file From 874c7cd7995fd1119731368638dd9fc732168c18 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 15 Nov 2021 14:07:35 +0100 Subject: [PATCH 002/102] Check all PRs even if they don't target develop --- .github/workflows/check_pr.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check_pr.yml b/.github/workflows/check_pr.yml index 0eb5b73299..ecce951562 100644 --- a/.github/workflows/check_pr.yml +++ b/.github/workflows/check_pr.yml @@ -3,7 +3,8 @@ name: Check PR # Every PR should be checked for static analysis on: pull_request: - branches: [ develop ] + branches-ignore: + - 'master' types: [ opened, synchronize, reopened ] jobs: From d6d40311c88e94239f42f02fd5351d8b68af4903 Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 9 Sep 2021 11:14:55 +0200 Subject: [PATCH 003/102] Creating new gift card module --- drop-in/build.gradle | 1 + giftcard/build.gradle | 59 +++++++++++++++++++ giftcard/consumer-rules.pro | 0 giftcard/proguard-rules.pro | 21 +++++++ giftcard/src/main/AndroidManifest.xml | 10 ++++ .../src/main/res/layout/giftcard_view.xml | 16 +++++ .../main/res/template/values/strings.xml.tt | 11 ++++ .../src/main/res/values-pt-rBR/strings.xml | 11 ++++ giftcard/src/main/res/values/colors.xml | 10 ++++ giftcard/src/main/res/values/dimens.xml | 11 ++++ giftcard/src/main/res/values/strings.xml | 10 ++++ giftcard/src/main/res/values/styles.xml | 12 ++++ settings.gradle | 1 + 13 files changed, 173 insertions(+) create mode 100644 giftcard/build.gradle create mode 100644 giftcard/consumer-rules.pro create mode 100644 giftcard/proguard-rules.pro create mode 100644 giftcard/src/main/AndroidManifest.xml create mode 100644 giftcard/src/main/res/layout/giftcard_view.xml create mode 100644 giftcard/src/main/res/template/values/strings.xml.tt create mode 100644 giftcard/src/main/res/values-pt-rBR/strings.xml create mode 100644 giftcard/src/main/res/values/colors.xml create mode 100644 giftcard/src/main/res/values/dimens.xml create mode 100644 giftcard/src/main/res/values/strings.xml create mode 100644 giftcard/src/main/res/values/styles.xml diff --git a/drop-in/build.gradle b/drop-in/build.gradle index 065ff80619..da7f0044fe 100644 --- a/drop-in/build.gradle +++ b/drop-in/build.gradle @@ -59,6 +59,7 @@ dependencies { api project(':dotpay') api project(':entercash') api project(':eps') + api project(':giftcard') api project(':googlepay') api project(':ideal') api project(':mbway') diff --git a/giftcard/build.gradle b/giftcard/build.gradle new file mode 100644 index 0000000000..ae2e55eba3 --- /dev/null +++ b/giftcard/build.gradle @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 9/9/2021. + */ + +plugins { + id 'com.android.library' + id 'kotlin-android' +} + +ext.mavenArtifactId = "giftcard" +ext.mavenArtifactName = "Adyen checkout Gift Card component" +ext.mavenArtifactDescription = "Adyen checkout Gift Card component client for Adyen's Checkout API." + +apply from: "${rootDir}/config/gradle/sharedTasks.gradle" + +android { + compileSdkVersion compile_sdk_version + + defaultConfig { + minSdkVersion min_sdk_version + targetSdkVersion target_sdk_version + versionCode version_code + versionName version_name + + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + consumerProguardFiles "consumer-rules.pro" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + + buildFeatures { + viewBinding true + } +} + +dependencies { + // Checkout + api project(':components-core') + api project(':ui-core') + + // Dependencies + implementation "com.google.android.material:material:$material_version" + + //Tests + testImplementation "junit:junit:$junit_version" + androidTestImplementation "androidx.test.ext:junit:$test_ext_version" + androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" +} diff --git a/giftcard/consumer-rules.pro b/giftcard/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/giftcard/proguard-rules.pro b/giftcard/proguard-rules.pro new file mode 100644 index 0000000000..f1b424510d --- /dev/null +++ b/giftcard/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/giftcard/src/main/AndroidManifest.xml b/giftcard/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..cb3241b04a --- /dev/null +++ b/giftcard/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + diff --git a/giftcard/src/main/res/layout/giftcard_view.xml b/giftcard/src/main/res/layout/giftcard_view.xml new file mode 100644 index 0000000000..f5984f1e04 --- /dev/null +++ b/giftcard/src/main/res/layout/giftcard_view.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/giftcard/src/main/res/template/values/strings.xml.tt b/giftcard/src/main/res/template/values/strings.xml.tt new file mode 100644 index 0000000000..ba12b29a22 --- /dev/null +++ b/giftcard/src/main/res/template/values/strings.xml.tt @@ -0,0 +1,11 @@ + + + + + diff --git a/giftcard/src/main/res/values-pt-rBR/strings.xml b/giftcard/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000..ad75faae8c --- /dev/null +++ b/giftcard/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/giftcard/src/main/res/values/colors.xml b/giftcard/src/main/res/values/colors.xml new file mode 100644 index 0000000000..240616675d --- /dev/null +++ b/giftcard/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/giftcard/src/main/res/values/dimens.xml b/giftcard/src/main/res/values/dimens.xml new file mode 100644 index 0000000000..ad75faae8c --- /dev/null +++ b/giftcard/src/main/res/values/dimens.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/giftcard/src/main/res/values/strings.xml b/giftcard/src/main/res/values/strings.xml new file mode 100644 index 0000000000..240616675d --- /dev/null +++ b/giftcard/src/main/res/values/strings.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/giftcard/src/main/res/values/styles.xml b/giftcard/src/main/res/values/styles.xml new file mode 100644 index 0000000000..f7d661e29c --- /dev/null +++ b/giftcard/src/main/res/values/styles.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardNumberUtilsTest.kt b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardNumberUtilsTest.kt new file mode 100644 index 0000000000..967d8eb269 --- /dev/null +++ b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardNumberUtilsTest.kt @@ -0,0 +1,58 @@ +package com.adyen.checkout.giftcard + +import com.adyen.checkout.giftcard.util.GiftCardNumberUtils +import org.junit.Assert.assertEquals +import org.junit.Test + +class GiftCardNumberUtilsTest { + + @Test + fun formatEmptyInput() { + assertEquals("", GiftCardNumberUtils.formatInput("")) + } + + @Test + fun format3DigitInput() { + assertEquals("123", GiftCardNumberUtils.formatInput("123")) + } + + @Test + fun format4DigitInput() { + assertEquals("1234", GiftCardNumberUtils.formatInput("1234")) + } + + @Test + fun format5DigitInput() { + assertEquals("1234 5", GiftCardNumberUtils.formatInput("12345")) + } + + @Test + fun format7DigitInput() { + assertEquals("1234 567", GiftCardNumberUtils.formatInput("1234567")) + } + + @Test + fun format8DigitInput() { + assertEquals("1234 5678", GiftCardNumberUtils.formatInput("12345678")) + } + + @Test + fun format9DigitInput() { + assertEquals("1234 5678 9", GiftCardNumberUtils.formatInput("123456789")) + } + + @Test + fun format16DigitInput() { + assertEquals("1234 5678 4321 9876", GiftCardNumberUtils.formatInput("1234567843219876")) + } + + @Test + fun format19DigitInput() { + assertEquals("1234 5678 4321 9876 000", GiftCardNumberUtils.formatInput("1234567843219876000")) + } + + @Test + fun formatAlphanumericInputWithSpaces() { + assertEquals("1247 8453 3", GiftCardNumberUtils.formatInput("hioj rfg1247fds gd8453 h3h")) + } +} From 6d4161aa0fea2b85aef49c512908f5bb8f8e47ea Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 13 Sep 2021 15:32:39 +0200 Subject: [PATCH 006/102] Adding component and configuration --- .../request/GiftCardPaymentMethod.java | 106 ++++++++++++++ .../request/PaymentMethodDetails.java | 2 + .../components/util/PaymentMethodTypes.java | 2 +- .../dropin/ComponentParsingProvider.kt | 9 ++ .../checkout/giftcard/GiftCardComponent.kt | 61 ++++++++ .../giftcard/GiftCardConfiguration.kt | 70 +++++++++ .../checkout/giftcard/GiftCardInputData.kt | 16 ++ .../checkout/giftcard/GiftCardOutputData.kt | 24 +++ .../adyen/checkout/giftcard/GiftCardView.kt | 137 ++++++++++++++++++ .../giftcard/GiftCardNumberUtilsTest.kt | 2 +- 10 files changed, 427 insertions(+), 2 deletions(-) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/payments/request/GiftCardPaymentMethod.java create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardConfiguration.kt create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardInputData.kt create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardOutputData.kt create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/GiftCardPaymentMethod.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/GiftCardPaymentMethod.java new file mode 100644 index 0000000000..b390577575 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/GiftCardPaymentMethod.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by caiof on 11/8/2020. + */ + +package com.adyen.checkout.components.model.payments.request; + +import android.os.Parcel; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.adyen.checkout.components.util.PaymentMethodTypes; +import com.adyen.checkout.core.exception.ModelSerializationException; +import com.adyen.checkout.core.model.JsonUtils; + +import org.json.JSONException; +import org.json.JSONObject; + +@SuppressWarnings({"AbbreviationAsWordInName", "MemberName", "PMD.DataClass"}) +public class GiftCardPaymentMethod extends PaymentMethodDetails { + + @NonNull + public static final Creator CREATOR = new Creator<>(GiftCardPaymentMethod.class); + + public static final String PAYMENT_METHOD_TYPE = PaymentMethodTypes.GIFTCARD; + + private static final String ENCRYPTED_CARD_NUMBER = "encryptedCardNumber"; + private static final String ENCRYPTED_SECURITY_CODE = "encryptedSecurityCode"; + private static final String BRAND = "brand"; + + @NonNull + public static final Serializer SERIALIZER = new Serializer() { + + @NonNull + @Override + public JSONObject serialize(@NonNull GiftCardPaymentMethod modelObject) { + final JSONObject jsonObject = new JSONObject(); + try { + // getting parameters from parent class + jsonObject.putOpt(PaymentMethodDetails.TYPE, modelObject.getType()); + + jsonObject.putOpt(ENCRYPTED_CARD_NUMBER, modelObject.getEncryptedCardNumber()); + jsonObject.putOpt(ENCRYPTED_SECURITY_CODE, modelObject.getEncryptedSecurityCode()); + jsonObject.putOpt(BRAND, modelObject.getBrand()); + } catch (JSONException e) { + throw new ModelSerializationException(GooglePayPaymentMethod.class, e); + } + return jsonObject; + } + + @NonNull + @Override + public GiftCardPaymentMethod deserialize(@NonNull JSONObject jsonObject) { + final GiftCardPaymentMethod giftcardPaymentMethod = new GiftCardPaymentMethod(); + + // getting parameters from parent class + giftcardPaymentMethod.setType(jsonObject.optString(PaymentMethodDetails.TYPE, null)); + + giftcardPaymentMethod.setEncryptedCardNumber(jsonObject.optString(ENCRYPTED_CARD_NUMBER, null)); + giftcardPaymentMethod.setEncryptedSecurityCode(jsonObject.optString(ENCRYPTED_SECURITY_CODE, null)); + giftcardPaymentMethod.setBrand(jsonObject.optString(BRAND)); + + return giftcardPaymentMethod; + } + }; + + private String encryptedCardNumber; + private String encryptedSecurityCode; + private String brand; + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + JsonUtils.writeToParcel(dest, SERIALIZER.serialize(this)); + } + + @Nullable + public String getEncryptedCardNumber() { + return encryptedCardNumber; + } + + public void setEncryptedCardNumber(@Nullable String encryptedCardNumber) { + this.encryptedCardNumber = encryptedCardNumber; + } + + @Nullable + public String getEncryptedSecurityCode() { + return encryptedSecurityCode; + } + + public void setEncryptedSecurityCode(@Nullable String encryptedSecurityCode) { + this.encryptedSecurityCode = encryptedSecurityCode; + } + + @Nullable + public String getBrand() { + return brand; + } + + public void setBrand(@Nullable String brand) { + this.brand = brand; + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java index a846969d71..8c4aabe21c 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java @@ -81,6 +81,8 @@ static Serializer getChildSerializer(@NonNull St return OpenBankingPaymentMethod.SERIALIZER; case EntercashPaymentMethod.PAYMENT_METHOD_TYPE: return EntercashPaymentMethod.SERIALIZER; + case GiftCardPaymentMethod.PAYMENT_METHOD_TYPE: + return GiftCardPaymentMethod.SERIALIZER; //Intentional fallthrough of the new and legacy google pay txVariants case PaymentMethodTypes.GOOGLE_PAY: case PaymentMethodTypes.GOOGLE_PAY_LEGACY: diff --git a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java index a89e4eaa3f..a65b6dc87a 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java +++ b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java @@ -39,7 +39,6 @@ public final class PaymentMethodTypes { public static final String BCMC = "bcmc"; public static final String MB_WAY = "mbway"; public static final String BLIK = "blik"; - // TODO: not supported yet but needed in PaymentMethodAdapter, add to SUPPORTED_PAYMENT_METHODS when supported public static final String GIFTCARD = "giftcard"; // Payment methods that do not need a payment component, but only an action component @@ -99,6 +98,7 @@ public final class PaymentMethodTypes { DOTPAY, ENTERCASH, EPS, + GIFTCARD, GOOGLE_PAY, GOOGLE_PAY_LEGACY, IDEAL, diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt index 4015b1992d..ed0c5af500 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt @@ -56,6 +56,9 @@ import com.adyen.checkout.entercash.EntercashRecyclerView import com.adyen.checkout.eps.EPSComponent import com.adyen.checkout.eps.EPSConfiguration import com.adyen.checkout.eps.EPSRecyclerView +import com.adyen.checkout.giftcard.GiftCardComponent +import com.adyen.checkout.giftcard.GiftCardConfiguration +import com.adyen.checkout.giftcard.GiftCardView import com.adyen.checkout.googlepay.GooglePayComponent import com.adyen.checkout.googlepay.GooglePayConfiguration import com.adyen.checkout.googlepay.GooglePayProvider @@ -103,6 +106,7 @@ internal fun getDefaultConfigForPaymentMethod( PaymentMethodTypes.DOTPAY -> DotpayConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.ENTERCASH -> EntercashConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.EPS -> EPSConfiguration.Builder(shopperLocale, environment, clientKey) + PaymentMethodTypes.GIFTCARD -> GiftCardConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.GOOGLE_PAY, PaymentMethodTypes.GOOGLE_PAY_LEGACY -> { GooglePayConfiguration.Builder(shopperLocale, environment, clientKey).apply { @@ -245,6 +249,10 @@ internal fun getComponentFor( val epsConfig: EPSConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.EPS) EPSComponent.PROVIDER.get(fragment, paymentMethod, epsConfig) } + PaymentMethodTypes.GIFTCARD -> { + val giftcardConfiguration: GiftCardConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.GIFTCARD, context) + GiftCardComponent.PROVIDER.get(fragment, paymentMethod, giftcardConfiguration) + } PaymentMethodTypes.GOOGLE_PAY -> { val googlePayConfiguration: GooglePayConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.GOOGLE_PAY) GooglePayComponent.PROVIDER.get(fragment, paymentMethod, googlePayConfiguration) @@ -314,6 +322,7 @@ internal fun getViewFor( PaymentMethodTypes.DOTPAY -> DotpayRecyclerView(context) PaymentMethodTypes.ENTERCASH -> EntercashRecyclerView(context) PaymentMethodTypes.EPS -> EPSRecyclerView(context) + PaymentMethodTypes.GIFTCARD -> GiftCardView(context) PaymentMethodTypes.IDEAL -> IdealRecyclerView(context) PaymentMethodTypes.MB_WAY -> MBWayView(context) PaymentMethodTypes.MOLPAY_THAILAND, diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt new file mode 100644 index 0000000000..29c0cfb756 --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 13/9/2021. + */ +package com.adyen.checkout.giftcard + +import com.adyen.checkout.components.GenericComponentState +import com.adyen.checkout.components.PaymentComponentProvider +import com.adyen.checkout.components.base.BasePaymentComponent +import com.adyen.checkout.components.base.GenericPaymentComponentProvider +import com.adyen.checkout.components.base.GenericPaymentMethodDelegate +import com.adyen.checkout.components.model.payments.request.GiftCardPaymentMethod +import com.adyen.checkout.components.model.payments.request.PaymentComponentData +import com.adyen.checkout.components.util.PaymentMethodTypes +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger + +private val TAG = LogUtil.getTag() + +private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.GIFTCARD) + +/** + * Component should not be instantiated directly. Instead use the PROVIDER object. + * + * @param paymentMethodDelegate [GenericPaymentMethodDelegate] + * @param configuration [GiftCardConfiguration] + */ +class GiftCardComponent(paymentMethodDelegate: GenericPaymentMethodDelegate, configuration: GiftCardConfiguration) : + BasePaymentComponent>(paymentMethodDelegate, configuration) { + + companion object { + @JvmStatic + val PROVIDER: PaymentComponentProvider = + GenericPaymentComponentProvider(GiftCardComponent::class.java) + } + + override fun onInputDataChanged(inputData: GiftCardInputData): GiftCardOutputData { + Logger.v(TAG, "onInputDataChanged") + return GiftCardOutputData(cardNumber = inputData.cardNumber, pin = inputData.pin) + } + + override fun createComponentState(): GenericComponentState { + val paymentComponentData = PaymentComponentData() + val paymentMethod = GiftCardPaymentMethod().apply { + type = GiftCardPaymentMethod.PAYMENT_METHOD_TYPE + } + + val giftcardOutputData = outputData + if (giftcardOutputData != null) { + // TODO encrypt and set up paymentMethod + } + paymentComponentData.paymentMethod = paymentMethod + return GenericComponentState(paymentComponentData, giftcardOutputData?.isValid == true, true) + } + + override fun getSupportedPaymentMethodTypes(): Array = PAYMENT_METHOD_TYPES +} diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardConfiguration.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardConfiguration.kt new file mode 100644 index 0000000000..b2fcee9b84 --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardConfiguration.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 9/9/2021. + */ +package com.adyen.checkout.giftcard + +import android.content.Context +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.base.BaseConfigurationBuilder +import com.adyen.checkout.components.base.Configuration +import com.adyen.checkout.core.api.Environment +import java.util.* + +class GiftCardConfiguration : Configuration { + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel?): GiftCardConfiguration? { + if (source == null) return null + return GiftCardConfiguration(source) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + internal constructor(builder: Builder) : super(builder.builderShopperLocale, builder.builderEnvironment, builder.builderClientKey) + internal constructor(parcel: Parcel) : super(parcel) + + /** + * Builder to create a [GiftCardConfiguration]. + */ + class Builder : BaseConfigurationBuilder { + /** + * Constructor for Builder with default values. + * + * @param context A context + * @param clientKey Your Client Key used for network calls from the SDK to Adyen. + */ + constructor(context: Context, clientKey: String) : super(context, clientKey) + + /** + * Builder with required parameters. + * + * @param shopperLocale The Locale of the shopper. + * @param environment The [Environment] to be used for network calls to Adyen. + * @param clientKey Your Client Key used for network calls from the SDK to Adyen. + */ + constructor(shopperLocale: Locale, environment: Environment, clientKey: String) : super(shopperLocale, environment, clientKey) + + override fun setShopperLocale(builderShopperLocale: Locale): Builder { + return super.setShopperLocale(builderShopperLocale) as Builder + } + + override fun setEnvironment(builderEnvironment: Environment): Builder { + return super.setEnvironment(builderEnvironment) as Builder + } + + override fun buildInternal(): GiftCardConfiguration { + return GiftCardConfiguration(this) + } + } +} diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardInputData.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardInputData.kt new file mode 100644 index 0000000000..81b9808249 --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardInputData.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 9/9/2021. + */ + +package com.adyen.checkout.giftcard + +import com.adyen.checkout.components.base.InputData + +data class GiftCardInputData( + var cardNumber: String = "", + var pin: String = "" +) : InputData diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardOutputData.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardOutputData.kt new file mode 100644 index 0000000000..537c232505 --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardOutputData.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 9/9/2021. + */ + +package com.adyen.checkout.giftcard + +import com.adyen.checkout.components.base.OutputData +import com.adyen.checkout.components.ui.FieldState +import com.adyen.checkout.giftcard.util.GiftCardNumberUtils +import com.adyen.checkout.giftcard.util.GiftCardPinUtils + +class GiftCardOutputData(cardNumber: String, pin: String) : OutputData { + + val giftcardNumberFieldState: FieldState = GiftCardNumberUtils.validateInputField(cardNumber) + val giftcardPinFieldState: FieldState = GiftCardPinUtils.validateInputField(pin) + + override fun isValid(): Boolean { + return giftcardNumberFieldState.validation.isValid() && giftcardPinFieldState.validation.isValid() + } +} diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt new file mode 100644 index 0000000000..318c278070 --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 13/9/2021. + */ + +package com.adyen.checkout.giftcard + +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 androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.Observer +import com.adyen.checkout.components.GenericComponentState +import com.adyen.checkout.components.model.payments.request.GiftCardPaymentMethod +import com.adyen.checkout.components.ui.Validation +import com.adyen.checkout.components.ui.view.AdyenLinearLayout +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.giftcard.databinding.GiftcardViewBinding + +private val TAG = LogUtil.getTag() + +class GiftCardView : + AdyenLinearLayout, GiftCardComponent>, + Observer { + + private val binding: GiftcardViewBinding = GiftcardViewBinding.inflate(LayoutInflater.from(context), this) + + private var giftCardInputData = GiftCardInputData() + + constructor(context: Context) : super(context) { + init() + } + + constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { + init() + } + + constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) { + init() + } + + private fun init() { + orientation = VERTICAL + val padding = resources.getDimension(R.dimen.standard_margin).toInt() + setPadding(padding, padding, padding, 0) + } + + override fun initLocalizedStrings(localizedContext: Context) { + val myAttrs = intArrayOf(android.R.attr.hint) + + // Card Number + var typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_GiftCard_GiftCardNumberInput, myAttrs) + binding.textInputLayoutGiftcardNumber.hint = typedArray.getString(0) + typedArray.recycle() + + // PIN + typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_GiftCard_GiftCardPinInput, myAttrs) + binding.textInputLayoutGiftcardPin.hint = typedArray.getString(0) + typedArray.recycle() + } + + override fun initView() { + binding.editTextGiftcardNumber.setOnChangeListener { + giftCardInputData.cardNumber = binding.editTextGiftcardNumber.rawValue + notifyInputDataChanged() + binding.textInputLayoutGiftcardNumber.error = null + } + binding.editTextGiftcardNumber.onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean -> + val cardNumberValidation = component.outputData?.giftcardNumberFieldState?.validation + if (hasFocus) { + binding.textInputLayoutGiftcardNumber.error = null + } else if (cardNumberValidation != null && cardNumberValidation is Validation.Invalid) { + binding.textInputLayoutGiftcardNumber.error = mLocalizedContext.getString(cardNumberValidation.reason) + } + } + binding.editTextGiftcardPin.setOnChangeListener { editable: Editable -> + giftCardInputData.pin = editable.toString() + notifyInputDataChanged() + binding.textInputLayoutGiftcardPin.error = null + } + binding.editTextGiftcardPin.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> + val pinValidation = component.outputData?.giftcardPinFieldState?.validation + if (hasFocus) { + binding.textInputLayoutGiftcardPin.error = null + } else if (pinValidation != null && pinValidation is Validation.Invalid) { + binding.textInputLayoutGiftcardPin.error = mLocalizedContext.getString(pinValidation.reason) + } + } + notifyInputDataChanged() + } + + override fun observeComponentChanges(lifecycleOwner: LifecycleOwner) { + component.observeOutputData(lifecycleOwner, this) + } + + override fun onComponentAttached() { + // nothing to impl + } + + override fun onChanged(giftCardOutputData: GiftCardOutputData?) { + Logger.v(TAG, "GiftCardOutputData changed") + } + + override fun isConfirmationRequired(): Boolean { + return true + } + + override fun highlightValidationErrors() { + Logger.d(TAG, "highlightValidationErrors") + val outputData = component.outputData ?: return + var isErrorFocused = false + val cardNumberValidation = outputData.giftcardNumberFieldState.validation + if (cardNumberValidation is Validation.Invalid) { + isErrorFocused = true + binding.textInputLayoutGiftcardNumber.requestFocus() + binding.textInputLayoutGiftcardNumber.error = mLocalizedContext.getString(cardNumberValidation.reason) + } + val pinValidation = outputData.giftcardPinFieldState.validation + if (pinValidation is Validation.Invalid) { + if (!isErrorFocused) { + binding.textInputLayoutGiftcardPin.requestFocus() + } + binding.textInputLayoutGiftcardPin.error = mLocalizedContext.getString(pinValidation.reason) + } + } + + private fun notifyInputDataChanged() { + component.inputDataChanged(giftCardInputData) + } +} diff --git a/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardNumberUtilsTest.kt b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardNumberUtilsTest.kt index 967d8eb269..9d9147bfd5 100644 --- a/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardNumberUtilsTest.kt +++ b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardNumberUtilsTest.kt @@ -53,6 +53,6 @@ class GiftCardNumberUtilsTest { @Test fun formatAlphanumericInputWithSpaces() { - assertEquals("1247 8453 3", GiftCardNumberUtils.formatInput("hioj rfg1247fds gd8453 h3h")) + assertEquals("hioj rfg1 247f dsgd 8453 h3h", GiftCardNumberUtils.formatInput("hioj rfg1247fds gd8453 h3h")) } } From 3c634ed10c47f9617ea68531e1a371491b977f9f Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 13 Sep 2021 16:53:39 +0200 Subject: [PATCH 007/102] Include brand in the payment method object --- .../com/adyen/checkout/giftcard/GiftCardComponent.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt index 29c0cfb756..850e9ccf47 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt @@ -28,7 +28,10 @@ private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.GIFTCARD) * @param paymentMethodDelegate [GenericPaymentMethodDelegate] * @param configuration [GiftCardConfiguration] */ -class GiftCardComponent(paymentMethodDelegate: GenericPaymentMethodDelegate, configuration: GiftCardConfiguration) : +class GiftCardComponent( + private val paymentMethodDelegate: GenericPaymentMethodDelegate, + configuration: GiftCardConfiguration +) : BasePaymentComponent>(paymentMethodDelegate, configuration) { @@ -51,7 +54,9 @@ class GiftCardComponent(paymentMethodDelegate: GenericPaymentMethodDelegate, con val giftcardOutputData = outputData if (giftcardOutputData != null) { - // TODO encrypt and set up paymentMethod + paymentMethod.encryptedCardNumber = giftcardOutputData.giftcardNumberFieldState.value + paymentMethod.encryptedSecurityCode = giftcardOutputData.giftcardPinFieldState.value + paymentMethod.brand = paymentMethodDelegate.paymentMethod.brand } paymentComponentData.paymentMethod = paymentMethod return GenericComponentState(paymentComponentData, giftcardOutputData?.isValid == true, true) From 251b976e31686a57a92703c4bbcf66cf47c45d63 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 13 Sep 2021 17:01:46 +0200 Subject: [PATCH 008/102] Move public key repository to components-core --- bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponent.kt | 2 +- .../java/com/adyen/checkout/bcmc/BcmcComponentProvider.kt | 2 +- .../java/com/adyen/checkout/card/CardComponentProvider.kt | 2 +- card/src/main/java/com/adyen/checkout/card/CardDelegate.kt | 2 +- card/src/main/java/com/adyen/checkout/card/NewCardDelegate.kt | 2 +- .../main/java/com/adyen/checkout/card/StoredCardDelegate.kt | 2 +- .../com/adyen/checkout/components}/api/PublicKeyConnection.kt | 2 +- .../checkout/components}/repository/PublicKeyRepository.kt | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) rename {card/src/main/java/com/adyen/checkout/card => components-core/src/main/java/com/adyen/checkout/components}/api/PublicKeyConnection.kt (96%) rename {card/src/main/java/com/adyen/checkout/card => components-core/src/main/java/com/adyen/checkout/components}/repository/PublicKeyRepository.kt (91%) diff --git a/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponent.kt b/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponent.kt index bbed9a47ea..d1475c7e38 100644 --- a/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponent.kt +++ b/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponent.kt @@ -13,13 +13,13 @@ import com.adyen.checkout.card.CardValidationMapper import com.adyen.checkout.card.CardValidationUtils import com.adyen.checkout.card.data.CardType import com.adyen.checkout.card.data.ExpiryDate -import com.adyen.checkout.card.repository.PublicKeyRepository import com.adyen.checkout.components.GenericComponentState import com.adyen.checkout.components.PaymentComponentProvider import com.adyen.checkout.components.base.BasePaymentComponent import com.adyen.checkout.components.base.GenericPaymentMethodDelegate import com.adyen.checkout.components.model.payments.request.CardPaymentMethod import com.adyen.checkout.components.model.payments.request.PaymentComponentData +import com.adyen.checkout.components.repository.PublicKeyRepository import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException diff --git a/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponentProvider.kt b/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponentProvider.kt index 4e74964a79..6b5177a560 100644 --- a/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponentProvider.kt +++ b/bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponentProvider.kt @@ -12,11 +12,11 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStoreOwner import androidx.savedstate.SavedStateRegistryOwner import com.adyen.checkout.card.CardValidationMapper -import com.adyen.checkout.card.repository.PublicKeyRepository import com.adyen.checkout.components.PaymentComponentProvider import com.adyen.checkout.components.base.GenericPaymentMethodDelegate import com.adyen.checkout.components.base.lifecycle.viewModelFactory import com.adyen.checkout.components.model.paymentmethods.PaymentMethod +import com.adyen.checkout.components.repository.PublicKeyRepository class BcmcComponentProvider : PaymentComponentProvider { override fun get( diff --git a/card/src/main/java/com/adyen/checkout/card/CardComponentProvider.kt b/card/src/main/java/com/adyen/checkout/card/CardComponentProvider.kt index 8ab574bcd0..f7f5686deb 100644 --- a/card/src/main/java/com/adyen/checkout/card/CardComponentProvider.kt +++ b/card/src/main/java/com/adyen/checkout/card/CardComponentProvider.kt @@ -13,11 +13,11 @@ import androidx.lifecycle.ViewModelStoreOwner import androidx.savedstate.SavedStateRegistryOwner import com.adyen.checkout.card.data.CardType import com.adyen.checkout.card.repository.BinLookupRepository -import com.adyen.checkout.card.repository.PublicKeyRepository import com.adyen.checkout.components.StoredPaymentComponentProvider import com.adyen.checkout.components.base.lifecycle.viewModelFactory import com.adyen.checkout.components.model.paymentmethods.PaymentMethod import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod +import com.adyen.checkout.components.repository.PublicKeyRepository import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger diff --git a/card/src/main/java/com/adyen/checkout/card/CardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/CardDelegate.kt index 4766fe4ce4..fd4175ddbd 100644 --- a/card/src/main/java/com/adyen/checkout/card/CardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/CardDelegate.kt @@ -12,8 +12,8 @@ import com.adyen.checkout.card.api.model.Brand import com.adyen.checkout.card.data.CardType import com.adyen.checkout.card.data.DetectedCardType import com.adyen.checkout.card.data.ExpiryDate -import com.adyen.checkout.card.repository.PublicKeyRepository import com.adyen.checkout.components.base.PaymentMethodDelegate +import com.adyen.checkout.components.repository.PublicKeyRepository import com.adyen.checkout.components.ui.FieldState import kotlinx.coroutines.CoroutineScope diff --git a/card/src/main/java/com/adyen/checkout/card/NewCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/NewCardDelegate.kt index 2908653c5f..ce27a37877 100644 --- a/card/src/main/java/com/adyen/checkout/card/NewCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/NewCardDelegate.kt @@ -13,9 +13,9 @@ import com.adyen.checkout.card.data.CardType import com.adyen.checkout.card.data.DetectedCardType import com.adyen.checkout.card.data.ExpiryDate import com.adyen.checkout.card.repository.BinLookupRepository -import com.adyen.checkout.card.repository.PublicKeyRepository import com.adyen.checkout.components.base.AddressVisibility import com.adyen.checkout.components.model.paymentmethods.PaymentMethod +import com.adyen.checkout.components.repository.PublicKeyRepository import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.util.PaymentMethodTypes diff --git a/card/src/main/java/com/adyen/checkout/card/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/StoredCardDelegate.kt index 9e2fbdc99d..ee6155a641 100644 --- a/card/src/main/java/com/adyen/checkout/card/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/StoredCardDelegate.kt @@ -12,8 +12,8 @@ import com.adyen.checkout.card.api.model.Brand import com.adyen.checkout.card.data.CardType import com.adyen.checkout.card.data.DetectedCardType import com.adyen.checkout.card.data.ExpiryDate -import com.adyen.checkout.card.repository.PublicKeyRepository import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod +import com.adyen.checkout.components.repository.PublicKeyRepository import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.util.PaymentMethodTypes diff --git a/card/src/main/java/com/adyen/checkout/card/api/PublicKeyConnection.kt b/components-core/src/main/java/com/adyen/checkout/components/api/PublicKeyConnection.kt similarity index 96% rename from card/src/main/java/com/adyen/checkout/card/api/PublicKeyConnection.kt rename to components-core/src/main/java/com/adyen/checkout/components/api/PublicKeyConnection.kt index 7c5f7951c5..7a7d712594 100644 --- a/card/src/main/java/com/adyen/checkout/card/api/PublicKeyConnection.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/api/PublicKeyConnection.kt @@ -6,7 +6,7 @@ * Created by caiof on 5/1/2021. */ -package com.adyen.checkout.card.api +package com.adyen.checkout.components.api import com.adyen.checkout.core.api.Connection import com.adyen.checkout.core.api.Environment diff --git a/card/src/main/java/com/adyen/checkout/card/repository/PublicKeyRepository.kt b/components-core/src/main/java/com/adyen/checkout/components/repository/PublicKeyRepository.kt similarity index 91% rename from card/src/main/java/com/adyen/checkout/card/repository/PublicKeyRepository.kt rename to components-core/src/main/java/com/adyen/checkout/components/repository/PublicKeyRepository.kt index 5b8189a7a1..81ce2db4b3 100644 --- a/card/src/main/java/com/adyen/checkout/card/repository/PublicKeyRepository.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/repository/PublicKeyRepository.kt @@ -6,9 +6,9 @@ * Created by josephj on 22/2/2021. */ -package com.adyen.checkout.card.repository +package com.adyen.checkout.components.repository -import com.adyen.checkout.card.api.PublicKeyConnection +import com.adyen.checkout.components.api.PublicKeyConnection import com.adyen.checkout.components.api.suspendedCall import com.adyen.checkout.core.api.Environment import com.adyen.checkout.core.exception.CheckoutException From 889c305c35ecedbe9b69192556e16fb51fb89461 Mon Sep 17 00:00:00 2001 From: jreij Date: Tue, 14 Sep 2021 17:25:12 +0200 Subject: [PATCH 009/102] Encrypt card number and cvc --- giftcard/build.gradle | 1 + .../checkout/giftcard/GiftCardComponent.kt | 69 +++++++++++++++---- .../giftcard/GiftCardComponentProvider.kt | 34 +++++++++ 3 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt diff --git a/giftcard/build.gradle b/giftcard/build.gradle index ae2e55eba3..6325610367 100644 --- a/giftcard/build.gradle +++ b/giftcard/build.gradle @@ -48,6 +48,7 @@ dependencies { // Checkout api project(':components-core') api project(':ui-core') + api project(':cse') // Dependencies implementation "com.google.android.material:material:$material_version" diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt index 850e9ccf47..4afafd94a3 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt @@ -7,16 +7,23 @@ */ package com.adyen.checkout.giftcard +import androidx.lifecycle.viewModelScope import com.adyen.checkout.components.GenericComponentState import com.adyen.checkout.components.PaymentComponentProvider import com.adyen.checkout.components.base.BasePaymentComponent -import com.adyen.checkout.components.base.GenericPaymentComponentProvider import com.adyen.checkout.components.base.GenericPaymentMethodDelegate import com.adyen.checkout.components.model.payments.request.GiftCardPaymentMethod import com.adyen.checkout.components.model.payments.request.PaymentComponentData +import com.adyen.checkout.components.repository.PublicKeyRepository import com.adyen.checkout.components.util.PaymentMethodTypes +import com.adyen.checkout.core.exception.CheckoutException +import com.adyen.checkout.core.exception.ComponentException import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.cse.CardEncrypter +import com.adyen.checkout.cse.UnencryptedCard +import com.adyen.checkout.cse.exception.EncryptionException +import kotlinx.coroutines.launch private val TAG = LogUtil.getTag() @@ -30,15 +37,35 @@ private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.GIFTCARD) */ class GiftCardComponent( private val paymentMethodDelegate: GenericPaymentMethodDelegate, - configuration: GiftCardConfiguration + configuration: GiftCardConfiguration, + private val publicKeyRepository: PublicKeyRepository ) : BasePaymentComponent>(paymentMethodDelegate, configuration) { companion object { @JvmStatic - val PROVIDER: PaymentComponentProvider = - GenericPaymentComponentProvider(GiftCardComponent::class.java) + val PROVIDER: PaymentComponentProvider = GiftCardComponentProvider() + } + + private var publicKey: String? = null + + init { + viewModelScope.launch { + try { + publicKey = fetchPublicKey() + notifyStateChanged() + } catch (e: CheckoutException) { + notifyException(ComponentException("Unable to fetch publicKey.", e)) + } + } + } + + private suspend fun fetchPublicKey(): String { + return publicKeyRepository.fetchPublicKey( + environment = configuration.environment, + clientKey = configuration.clientKey + ) } override fun onInputDataChanged(inputData: GiftCardInputData): GiftCardOutputData { @@ -47,19 +74,35 @@ class GiftCardComponent( } override fun createComponentState(): GenericComponentState { + val unencryptedCardBuilder = UnencryptedCard.Builder() + val outputData = outputData val paymentComponentData = PaymentComponentData() - val paymentMethod = GiftCardPaymentMethod().apply { - type = GiftCardPaymentMethod.PAYMENT_METHOD_TYPE + + val publicKey = publicKey + + // If data is not valid we just return empty object, encryption would fail and we don't pass unencrypted data. + if (outputData?.isValid != true || publicKey == null) { + val isInputValid = outputData?.isValid ?: false + val isReady = publicKey != null + return GenericComponentState(paymentComponentData, isInputValid, isReady) + } + val encryptedCard = try { + unencryptedCardBuilder.setNumber(outputData.giftcardNumberFieldState.value) + unencryptedCardBuilder.setCvc(outputData.giftcardPinFieldState.value) + CardEncrypter.encryptFields(unencryptedCardBuilder.build(), publicKey) + } catch (e: EncryptionException) { + notifyException(e) + return GenericComponentState(paymentComponentData, false, true) } - val giftcardOutputData = outputData - if (giftcardOutputData != null) { - paymentMethod.encryptedCardNumber = giftcardOutputData.giftcardNumberFieldState.value - paymentMethod.encryptedSecurityCode = giftcardOutputData.giftcardPinFieldState.value - paymentMethod.brand = paymentMethodDelegate.paymentMethod.brand + val giftCardPaymentMethod = GiftCardPaymentMethod().apply { + type = GiftCardPaymentMethod.PAYMENT_METHOD_TYPE + encryptedCardNumber = encryptedCard.encryptedCardNumber + encryptedSecurityCode = encryptedCard.encryptedSecurityCode + brand = paymentMethodDelegate.paymentMethod.brand } - paymentComponentData.paymentMethod = paymentMethod - return GenericComponentState(paymentComponentData, giftcardOutputData?.isValid == true, true) + paymentComponentData.paymentMethod = giftCardPaymentMethod + return GenericComponentState(paymentComponentData, true, true) } override fun getSupportedPaymentMethodTypes(): Array = PAYMENT_METHOD_TYPES diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt new file mode 100644 index 0000000000..2522f5c479 --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 13/9/2021. + */ +package com.adyen.checkout.giftcard + +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelStoreOwner +import com.adyen.checkout.components.PaymentComponentProvider +import com.adyen.checkout.components.base.GenericPaymentMethodDelegate +import com.adyen.checkout.components.base.lifecycle.viewModelFactory +import com.adyen.checkout.components.model.paymentmethods.PaymentMethod +import com.adyen.checkout.components.repository.PublicKeyRepository + +class GiftCardComponentProvider : PaymentComponentProvider { + override operator fun get( + viewModelStoreOwner: ViewModelStoreOwner, + paymentMethod: PaymentMethod, + configuration: GiftCardConfiguration + ): GiftCardComponent { + val publicKeyRepository = PublicKeyRepository() + val giftCardFactory = viewModelFactory { + GiftCardComponent( + GenericPaymentMethodDelegate(paymentMethod), + configuration, + publicKeyRepository + ) + } + return ViewModelProvider(viewModelStoreOwner, giftCardFactory).get(GiftCardComponent::class.java) + } +} From f5cc613b4fc891e650bd00e1469ffbf35fec3627 Mon Sep 17 00:00:00 2001 From: jreij Date: Tue, 14 Sep 2021 17:36:30 +0200 Subject: [PATCH 010/102] Remove validation in UnencryptedCard.build() --- .../adyen/checkout/cse/UnencryptedCard.java | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/cse/src/main/java/com/adyen/checkout/cse/UnencryptedCard.java b/cse/src/main/java/com/adyen/checkout/cse/UnencryptedCard.java index 93c78d66a8..ac8a78f96f 100644 --- a/cse/src/main/java/com/adyen/checkout/cse/UnencryptedCard.java +++ b/cse/src/main/java/com/adyen/checkout/cse/UnencryptedCard.java @@ -180,25 +180,12 @@ public Builder setGenerationTime(@NonNull Date generationTime) { } /** - * Performs some simple checks on the given {@link UnencryptedCard} object and builds it. + * Builds the given {@link UnencryptedCard} object. * - * @return The valid {@link UnencryptedCard} object. - * @throws NullPointerException If any mandatory field is null. - * @throws IllegalStateException If any field is in an illegal state. + * @return The {@link UnencryptedCard} object. */ @NonNull public UnencryptedCard build() throws NullPointerException, IllegalStateException { - require(mNumber == null || mNumber.matches("[0-9]{8,19}"), - "number must be null or have 8 to 19 digits (inclusive)."); - require(mCardHolderName == null || mCardHolderName.length() > 0, - "cardHolderName must be null or not empty."); - require(mCvc == null || mCvc.matches("[0-9]{3,4}"), - "cvc must be null or have 3 to 4 digits."); - require(mExpiryMonth == null || mExpiryMonth.matches("0?[1-9]|1[0-2]"), - "expiryMonth must be null or between 1 and 12."); - require(mExpiryYear == null || mExpiryYear.matches("20\\d{2}"), - "expiryYear must be in the second millennium and first century."); - return new UnencryptedCard(mNumber, mExpiryMonth, mExpiryYear, mCvc, mCardHolderName, mGenerationTime); } @@ -209,11 +196,5 @@ private String removeWhiteSpaces(String string) { private String trimAndRemoveMultipleWhiteSpaces(String string) { return string != null ? string.trim().replaceAll("\\s{2,}", " ") : null; } - - private void require(boolean condition, String message) throws IllegalStateException { - if (!condition) { - throw new IllegalStateException(message); - } - } } } From 21bea6d6e351820160faa0181246165811516583 Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 15 Sep 2021 14:51:13 +0200 Subject: [PATCH 011/102] Move redeem string resource to drop-in module --- drop-in/src/main/res/template/values/strings.xml.tt | 1 + drop-in/src/main/res/values-cs-rCZ/strings.xml | 1 + drop-in/src/main/res/values-da-rDK/strings.xml | 1 + drop-in/src/main/res/values-de-rDE/strings.xml | 1 + drop-in/src/main/res/values-el-rGR/strings.xml | 1 + drop-in/src/main/res/values-es-rES/strings.xml | 1 + drop-in/src/main/res/values-fi-rFI/strings.xml | 1 + drop-in/src/main/res/values-fr-rFR/strings.xml | 1 + drop-in/src/main/res/values-hr-rHR/strings.xml | 1 + drop-in/src/main/res/values-hu-rHU/strings.xml | 1 + drop-in/src/main/res/values-it-rIT/strings.xml | 1 + drop-in/src/main/res/values-ja-rJP/strings.xml | 1 + drop-in/src/main/res/values-ko-rKR/strings.xml | 1 + drop-in/src/main/res/values-nb-rNO/strings.xml | 1 + drop-in/src/main/res/values-nl-rNL/strings.xml | 1 + drop-in/src/main/res/values-pl-rPL/strings.xml | 1 + drop-in/src/main/res/values-pt-rBR/strings.xml | 1 + drop-in/src/main/res/values-ro-rRO/strings.xml | 1 + drop-in/src/main/res/values-ru-rRU/strings.xml | 1 + drop-in/src/main/res/values-sk-rSK/strings.xml | 1 + drop-in/src/main/res/values-sl-rSI/strings.xml | 1 + drop-in/src/main/res/values-sv-rSE/strings.xml | 1 + drop-in/src/main/res/values-zh-rCN/strings.xml | 1 + drop-in/src/main/res/values-zh-rTW/strings.xml | 1 + drop-in/src/main/res/values/strings.xml | 1 + giftcard/src/main/res/template/values/strings.xml.tt | 1 - giftcard/src/main/res/values-cs-rCZ/strings.xml | 1 - giftcard/src/main/res/values-da-rDK/strings.xml | 1 - giftcard/src/main/res/values-de-rDE/strings.xml | 1 - giftcard/src/main/res/values-el-rGR/strings.xml | 1 - giftcard/src/main/res/values-es-rES/strings.xml | 1 - giftcard/src/main/res/values-fi-rFI/strings.xml | 1 - giftcard/src/main/res/values-fr-rFR/strings.xml | 1 - giftcard/src/main/res/values-hr-rHR/strings.xml | 1 - giftcard/src/main/res/values-hu-rHU/strings.xml | 1 - giftcard/src/main/res/values-it-rIT/strings.xml | 1 - giftcard/src/main/res/values-ja-rJP/strings.xml | 1 - giftcard/src/main/res/values-ko-rKR/strings.xml | 1 - giftcard/src/main/res/values-nb-rNO/strings.xml | 1 - giftcard/src/main/res/values-nl-rNL/strings.xml | 1 - giftcard/src/main/res/values-pl-rPL/strings.xml | 1 - giftcard/src/main/res/values-pt-rBR/strings.xml | 1 - giftcard/src/main/res/values-ro-rRO/strings.xml | 1 - giftcard/src/main/res/values-ru-rRU/strings.xml | 1 - giftcard/src/main/res/values-sk-rSK/strings.xml | 1 - giftcard/src/main/res/values-sl-rSI/strings.xml | 1 - giftcard/src/main/res/values-sv-rSE/strings.xml | 1 - giftcard/src/main/res/values-zh-rCN/strings.xml | 1 - giftcard/src/main/res/values-zh-rTW/strings.xml | 1 - giftcard/src/main/res/values/strings.xml | 1 - 50 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drop-in/src/main/res/template/values/strings.xml.tt b/drop-in/src/main/res/template/values/strings.xml.tt index 5b7eda3696..89afe2124b 100644 --- a/drop-in/src/main/res/template/values/strings.xml.tt +++ b/drop-in/src/main/res/template/values/strings.xml.tt @@ -21,4 +21,5 @@ %%continue%% %%preselectedPaymentMethod.changeButton.accessibilityLabel%% Credit Card + %%applyGiftcard%% diff --git a/drop-in/src/main/res/values-cs-rCZ/strings.xml b/drop-in/src/main/res/values-cs-rCZ/strings.xml index ddb5668e54..6930e1b49d 100644 --- a/drop-in/src/main/res/values-cs-rCZ/strings.xml +++ b/drop-in/src/main/res/values-cs-rCZ/strings.xml @@ -21,4 +21,5 @@ Pokračovat Změnit způsob platby Credit Card + Uplatnit \ No newline at end of file diff --git a/drop-in/src/main/res/values-da-rDK/strings.xml b/drop-in/src/main/res/values-da-rDK/strings.xml index 1576e1fc25..e6c0529778 100644 --- a/drop-in/src/main/res/values-da-rDK/strings.xml +++ b/drop-in/src/main/res/values-da-rDK/strings.xml @@ -21,4 +21,5 @@ Fortsæt Skift betalingsmåde Credit Card + Indløs \ No newline at end of file diff --git a/drop-in/src/main/res/values-de-rDE/strings.xml b/drop-in/src/main/res/values-de-rDE/strings.xml index 834a35f07c..d67d20f3db 100644 --- a/drop-in/src/main/res/values-de-rDE/strings.xml +++ b/drop-in/src/main/res/values-de-rDE/strings.xml @@ -21,4 +21,5 @@ Weiter Zahlungsmethode wechseln Credit Card + Einlösen \ No newline at end of file diff --git a/drop-in/src/main/res/values-el-rGR/strings.xml b/drop-in/src/main/res/values-el-rGR/strings.xml index 2eb14b9571..e5c64cddb2 100644 --- a/drop-in/src/main/res/values-el-rGR/strings.xml +++ b/drop-in/src/main/res/values-el-rGR/strings.xml @@ -21,4 +21,5 @@ Συνέχεια Αλλαγή τρόπου πληρωμής Credit Card + Εξαργύρωση \ No newline at end of file diff --git a/drop-in/src/main/res/values-es-rES/strings.xml b/drop-in/src/main/res/values-es-rES/strings.xml index eec7b74ef4..6aa1cdc856 100644 --- a/drop-in/src/main/res/values-es-rES/strings.xml +++ b/drop-in/src/main/res/values-es-rES/strings.xml @@ -21,4 +21,5 @@ Continuar Cambiar método de pago Credit Card + Canjear \ No newline at end of file diff --git a/drop-in/src/main/res/values-fi-rFI/strings.xml b/drop-in/src/main/res/values-fi-rFI/strings.xml index 8e3bb22caa..72a79e7ae7 100644 --- a/drop-in/src/main/res/values-fi-rFI/strings.xml +++ b/drop-in/src/main/res/values-fi-rFI/strings.xml @@ -21,4 +21,5 @@ Jatka Muuta maksutapaa Credit Card + Lunasta \ No newline at end of file diff --git a/drop-in/src/main/res/values-fr-rFR/strings.xml b/drop-in/src/main/res/values-fr-rFR/strings.xml index 3308941b99..0784aa0632 100644 --- a/drop-in/src/main/res/values-fr-rFR/strings.xml +++ b/drop-in/src/main/res/values-fr-rFR/strings.xml @@ -21,4 +21,5 @@ Continuer Changer de moyen de paiement Credit Card + Utiliser \ No newline at end of file diff --git a/drop-in/src/main/res/values-hr-rHR/strings.xml b/drop-in/src/main/res/values-hr-rHR/strings.xml index 7633e14f77..6ed71180a9 100644 --- a/drop-in/src/main/res/values-hr-rHR/strings.xml +++ b/drop-in/src/main/res/values-hr-rHR/strings.xml @@ -21,4 +21,5 @@ Nastavi Promijeni način plaćanja Credit Card + Iskoristite \ No newline at end of file diff --git a/drop-in/src/main/res/values-hu-rHU/strings.xml b/drop-in/src/main/res/values-hu-rHU/strings.xml index 8a49f10d2f..f9602b61e1 100644 --- a/drop-in/src/main/res/values-hu-rHU/strings.xml +++ b/drop-in/src/main/res/values-hu-rHU/strings.xml @@ -21,4 +21,5 @@ Folytatás Fizetési mód módosítása Credit Card + Beváltás \ No newline at end of file diff --git a/drop-in/src/main/res/values-it-rIT/strings.xml b/drop-in/src/main/res/values-it-rIT/strings.xml index 1618d440da..cadbb0a1a1 100644 --- a/drop-in/src/main/res/values-it-rIT/strings.xml +++ b/drop-in/src/main/res/values-it-rIT/strings.xml @@ -21,4 +21,5 @@ Continua Cambia metodo di pagamento Credit Card + Riscatta \ No newline at end of file diff --git a/drop-in/src/main/res/values-ja-rJP/strings.xml b/drop-in/src/main/res/values-ja-rJP/strings.xml index 42f841c387..ba23ec91fd 100644 --- a/drop-in/src/main/res/values-ja-rJP/strings.xml +++ b/drop-in/src/main/res/values-ja-rJP/strings.xml @@ -21,4 +21,5 @@ 続ける お支払方法を変更する Credit Card + 利用する \ No newline at end of file diff --git a/drop-in/src/main/res/values-ko-rKR/strings.xml b/drop-in/src/main/res/values-ko-rKR/strings.xml index ada259ff88..242f833023 100644 --- a/drop-in/src/main/res/values-ko-rKR/strings.xml +++ b/drop-in/src/main/res/values-ko-rKR/strings.xml @@ -21,4 +21,5 @@ 계속 결제 수단 변경 Credit Card + 기프트 카드로 결제 \ No newline at end of file diff --git a/drop-in/src/main/res/values-nb-rNO/strings.xml b/drop-in/src/main/res/values-nb-rNO/strings.xml index 4bfb2466d0..d92b1cfb9b 100644 --- a/drop-in/src/main/res/values-nb-rNO/strings.xml +++ b/drop-in/src/main/res/values-nb-rNO/strings.xml @@ -21,4 +21,5 @@ Fortsett Endre betalingsmetode Credit Card + Løs inn \ No newline at end of file diff --git a/drop-in/src/main/res/values-nl-rNL/strings.xml b/drop-in/src/main/res/values-nl-rNL/strings.xml index 3a508e77ff..5285ffd02a 100644 --- a/drop-in/src/main/res/values-nl-rNL/strings.xml +++ b/drop-in/src/main/res/values-nl-rNL/strings.xml @@ -21,4 +21,5 @@ Doorgaan Betalingsmethode wijzigen Credit Card + Inwisselen \ No newline at end of file diff --git a/drop-in/src/main/res/values-pl-rPL/strings.xml b/drop-in/src/main/res/values-pl-rPL/strings.xml index 532a8edad6..8fba97714d 100644 --- a/drop-in/src/main/res/values-pl-rPL/strings.xml +++ b/drop-in/src/main/res/values-pl-rPL/strings.xml @@ -21,4 +21,5 @@ Kontynuuj Zmień metodę płatności Credit Card + Wykorzystaj \ No newline at end of file diff --git a/drop-in/src/main/res/values-pt-rBR/strings.xml b/drop-in/src/main/res/values-pt-rBR/strings.xml index 390df52d63..2d338130ee 100644 --- a/drop-in/src/main/res/values-pt-rBR/strings.xml +++ b/drop-in/src/main/res/values-pt-rBR/strings.xml @@ -21,4 +21,5 @@ Continuar Alterar método de pagamento Credit Card + Resgatar \ No newline at end of file diff --git a/drop-in/src/main/res/values-ro-rRO/strings.xml b/drop-in/src/main/res/values-ro-rRO/strings.xml index da783f4966..cb12ecf445 100644 --- a/drop-in/src/main/res/values-ro-rRO/strings.xml +++ b/drop-in/src/main/res/values-ro-rRO/strings.xml @@ -21,4 +21,5 @@ Continuare Schimbare metodă de plată Credit Card + Valorificare \ No newline at end of file diff --git a/drop-in/src/main/res/values-ru-rRU/strings.xml b/drop-in/src/main/res/values-ru-rRU/strings.xml index 9ee22c9f4c..70673b9a7e 100644 --- a/drop-in/src/main/res/values-ru-rRU/strings.xml +++ b/drop-in/src/main/res/values-ru-rRU/strings.xml @@ -21,4 +21,5 @@ Продолжить Изменить способ оплаты Credit Card + Использовать \ No newline at end of file diff --git a/drop-in/src/main/res/values-sk-rSK/strings.xml b/drop-in/src/main/res/values-sk-rSK/strings.xml index 5eed8d430d..31de2f0557 100644 --- a/drop-in/src/main/res/values-sk-rSK/strings.xml +++ b/drop-in/src/main/res/values-sk-rSK/strings.xml @@ -21,4 +21,5 @@ Pokračovať Zmeniť spôsob platby Credit Card + Uplatniť \ No newline at end of file diff --git a/drop-in/src/main/res/values-sl-rSI/strings.xml b/drop-in/src/main/res/values-sl-rSI/strings.xml index 432f0a1a60..a2819127c0 100644 --- a/drop-in/src/main/res/values-sl-rSI/strings.xml +++ b/drop-in/src/main/res/values-sl-rSI/strings.xml @@ -21,4 +21,5 @@ Nadaljuj Spremeni način plačila Credit Card + Unovči \ No newline at end of file diff --git a/drop-in/src/main/res/values-sv-rSE/strings.xml b/drop-in/src/main/res/values-sv-rSE/strings.xml index 9ad156a352..f5cc0b4bdd 100644 --- a/drop-in/src/main/res/values-sv-rSE/strings.xml +++ b/drop-in/src/main/res/values-sv-rSE/strings.xml @@ -21,4 +21,5 @@ Fortsätt Ändra betalningssätt Credit Card + Lös in \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rCN/strings.xml b/drop-in/src/main/res/values-zh-rCN/strings.xml index a5ca7ac950..a42372f03b 100644 --- a/drop-in/src/main/res/values-zh-rCN/strings.xml +++ b/drop-in/src/main/res/values-zh-rCN/strings.xml @@ -21,4 +21,5 @@ 继续 更改支付方式 Credit Card + 兑换 \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rTW/strings.xml b/drop-in/src/main/res/values-zh-rTW/strings.xml index 3bbc18db80..9be1d615e0 100644 --- a/drop-in/src/main/res/values-zh-rTW/strings.xml +++ b/drop-in/src/main/res/values-zh-rTW/strings.xml @@ -21,4 +21,5 @@ 繼續 變更付款方式 Credit Card + 兌換 \ No newline at end of file diff --git a/drop-in/src/main/res/values/strings.xml b/drop-in/src/main/res/values/strings.xml index e8c49d22f4..3a6f5d8f9d 100644 --- a/drop-in/src/main/res/values/strings.xml +++ b/drop-in/src/main/res/values/strings.xml @@ -21,4 +21,5 @@ Continue Change Payment Method Credit Card + Redeem \ No newline at end of file diff --git a/giftcard/src/main/res/template/values/strings.xml.tt b/giftcard/src/main/res/template/values/strings.xml.tt index 200724893f..ec3ba8d83e 100644 --- a/giftcard/src/main/res/template/values/strings.xml.tt +++ b/giftcard/src/main/res/template/values/strings.xml.tt @@ -8,7 +8,6 @@ --> - %%applyGiftcard%% %%creditCard.numberField.title%% %%creditCard.pin.title%% %%creditCard.numberField.invalid%% diff --git a/giftcard/src/main/res/values-cs-rCZ/strings.xml b/giftcard/src/main/res/values-cs-rCZ/strings.xml index 6801946ea0..5292921f53 100644 --- a/giftcard/src/main/res/values-cs-rCZ/strings.xml +++ b/giftcard/src/main/res/values-cs-rCZ/strings.xml @@ -8,7 +8,6 @@ --> - Uplatnit Číslo karty Pin Neplatné číslo karty diff --git a/giftcard/src/main/res/values-da-rDK/strings.xml b/giftcard/src/main/res/values-da-rDK/strings.xml index 4d2ee26275..825c382d74 100644 --- a/giftcard/src/main/res/values-da-rDK/strings.xml +++ b/giftcard/src/main/res/values-da-rDK/strings.xml @@ -8,7 +8,6 @@ --> - Indløs Kortnummer Pinkode Ugyldigt kortnummer diff --git a/giftcard/src/main/res/values-de-rDE/strings.xml b/giftcard/src/main/res/values-de-rDE/strings.xml index e7c5c55290..0995d59e66 100644 --- a/giftcard/src/main/res/values-de-rDE/strings.xml +++ b/giftcard/src/main/res/values-de-rDE/strings.xml @@ -8,7 +8,6 @@ --> - Einlösen Kartennummer PIN Ungültige Kartennummer diff --git a/giftcard/src/main/res/values-el-rGR/strings.xml b/giftcard/src/main/res/values-el-rGR/strings.xml index f982d2dac0..66fd364da8 100644 --- a/giftcard/src/main/res/values-el-rGR/strings.xml +++ b/giftcard/src/main/res/values-el-rGR/strings.xml @@ -8,7 +8,6 @@ --> - Εξαργύρωση Αριθμός κάρτας Κωδικός PIN Μη έγκυρος αριθμός κάρτας diff --git a/giftcard/src/main/res/values-es-rES/strings.xml b/giftcard/src/main/res/values-es-rES/strings.xml index 48c3fff5bc..97dde7df4d 100644 --- a/giftcard/src/main/res/values-es-rES/strings.xml +++ b/giftcard/src/main/res/values-es-rES/strings.xml @@ -8,7 +8,6 @@ --> - Canjear Número de tarjeta PIN Número de tarjeta no válido diff --git a/giftcard/src/main/res/values-fi-rFI/strings.xml b/giftcard/src/main/res/values-fi-rFI/strings.xml index 1dc52aa26b..eacdf3b01a 100644 --- a/giftcard/src/main/res/values-fi-rFI/strings.xml +++ b/giftcard/src/main/res/values-fi-rFI/strings.xml @@ -8,7 +8,6 @@ --> - Lunasta Kortin numero Pin-tunnus Väärä kortin numero diff --git a/giftcard/src/main/res/values-fr-rFR/strings.xml b/giftcard/src/main/res/values-fr-rFR/strings.xml index ad5ae85640..a5ec1ed8bd 100644 --- a/giftcard/src/main/res/values-fr-rFR/strings.xml +++ b/giftcard/src/main/res/values-fr-rFR/strings.xml @@ -8,7 +8,6 @@ --> - Utiliser Numéro de la carte PIN Numéro de carte non valide diff --git a/giftcard/src/main/res/values-hr-rHR/strings.xml b/giftcard/src/main/res/values-hr-rHR/strings.xml index edbca9db50..ee3282c745 100644 --- a/giftcard/src/main/res/values-hr-rHR/strings.xml +++ b/giftcard/src/main/res/values-hr-rHR/strings.xml @@ -8,7 +8,6 @@ --> - Iskoristite Broj kartice Pin Nevažeći broj kartice diff --git a/giftcard/src/main/res/values-hu-rHU/strings.xml b/giftcard/src/main/res/values-hu-rHU/strings.xml index af11912cb3..8ca7848223 100644 --- a/giftcard/src/main/res/values-hu-rHU/strings.xml +++ b/giftcard/src/main/res/values-hu-rHU/strings.xml @@ -8,7 +8,6 @@ --> - Beváltás Kártyaszám PIN-kód Érvénytelen kártyaszám diff --git a/giftcard/src/main/res/values-it-rIT/strings.xml b/giftcard/src/main/res/values-it-rIT/strings.xml index 60b986bef1..33f1a4499e 100644 --- a/giftcard/src/main/res/values-it-rIT/strings.xml +++ b/giftcard/src/main/res/values-it-rIT/strings.xml @@ -8,7 +8,6 @@ --> - Riscatta Numero carta Pin Numero carta non valido diff --git a/giftcard/src/main/res/values-ja-rJP/strings.xml b/giftcard/src/main/res/values-ja-rJP/strings.xml index 4d836ba44c..5d63f76ed0 100644 --- a/giftcard/src/main/res/values-ja-rJP/strings.xml +++ b/giftcard/src/main/res/values-ja-rJP/strings.xml @@ -8,7 +8,6 @@ --> - 利用する カード番号 PIN カード番号が無効です diff --git a/giftcard/src/main/res/values-ko-rKR/strings.xml b/giftcard/src/main/res/values-ko-rKR/strings.xml index 4c527fce7e..3c68fe9855 100644 --- a/giftcard/src/main/res/values-ko-rKR/strings.xml +++ b/giftcard/src/main/res/values-ko-rKR/strings.xml @@ -8,7 +8,6 @@ --> - 기프트 카드로 결제 카드 번호 비밀번호 유효하지 않은 카드 번호 diff --git a/giftcard/src/main/res/values-nb-rNO/strings.xml b/giftcard/src/main/res/values-nb-rNO/strings.xml index 96944ce1e0..7564626a92 100644 --- a/giftcard/src/main/res/values-nb-rNO/strings.xml +++ b/giftcard/src/main/res/values-nb-rNO/strings.xml @@ -8,7 +8,6 @@ --> - Løs inn Kortnummer PIN Ugyldig kortnummer diff --git a/giftcard/src/main/res/values-nl-rNL/strings.xml b/giftcard/src/main/res/values-nl-rNL/strings.xml index eae4dd68a2..d3c4618cef 100644 --- a/giftcard/src/main/res/values-nl-rNL/strings.xml +++ b/giftcard/src/main/res/values-nl-rNL/strings.xml @@ -8,7 +8,6 @@ --> - Inwisselen Kaartnummer PIN Ongeldig kaartnummer diff --git a/giftcard/src/main/res/values-pl-rPL/strings.xml b/giftcard/src/main/res/values-pl-rPL/strings.xml index c0e6c4a6e3..b9dc56e3ee 100644 --- a/giftcard/src/main/res/values-pl-rPL/strings.xml +++ b/giftcard/src/main/res/values-pl-rPL/strings.xml @@ -8,7 +8,6 @@ --> - Wykorzystaj Numer karty PIN Nieprawidłowy numer karty diff --git a/giftcard/src/main/res/values-pt-rBR/strings.xml b/giftcard/src/main/res/values-pt-rBR/strings.xml index b7b743a897..ba3ec22536 100644 --- a/giftcard/src/main/res/values-pt-rBR/strings.xml +++ b/giftcard/src/main/res/values-pt-rBR/strings.xml @@ -8,7 +8,6 @@ --> - Resgatar Número do cartão Pin Número de cartão inválido diff --git a/giftcard/src/main/res/values-ro-rRO/strings.xml b/giftcard/src/main/res/values-ro-rRO/strings.xml index a4c28b36a3..0522d110c8 100644 --- a/giftcard/src/main/res/values-ro-rRO/strings.xml +++ b/giftcard/src/main/res/values-ro-rRO/strings.xml @@ -8,7 +8,6 @@ --> - Valorificare Număr card PIN Număr de card incorect diff --git a/giftcard/src/main/res/values-ru-rRU/strings.xml b/giftcard/src/main/res/values-ru-rRU/strings.xml index 2d67401722..5e8b6a0e1b 100644 --- a/giftcard/src/main/res/values-ru-rRU/strings.xml +++ b/giftcard/src/main/res/values-ru-rRU/strings.xml @@ -8,7 +8,6 @@ --> - Использовать Номер карты PIN-код Недействительный номер карты diff --git a/giftcard/src/main/res/values-sk-rSK/strings.xml b/giftcard/src/main/res/values-sk-rSK/strings.xml index 478af61902..3a290aa20e 100644 --- a/giftcard/src/main/res/values-sk-rSK/strings.xml +++ b/giftcard/src/main/res/values-sk-rSK/strings.xml @@ -8,7 +8,6 @@ --> - Uplatniť Číslo karty Kód PIN Neplatné číslo karty diff --git a/giftcard/src/main/res/values-sl-rSI/strings.xml b/giftcard/src/main/res/values-sl-rSI/strings.xml index 6bba95fe5f..a48f4eaa96 100644 --- a/giftcard/src/main/res/values-sl-rSI/strings.xml +++ b/giftcard/src/main/res/values-sl-rSI/strings.xml @@ -8,7 +8,6 @@ --> - Unovči Številka kartice PIN Neveljavna številka kartice diff --git a/giftcard/src/main/res/values-sv-rSE/strings.xml b/giftcard/src/main/res/values-sv-rSE/strings.xml index 77d177dc61..3ca7b80ea4 100644 --- a/giftcard/src/main/res/values-sv-rSE/strings.xml +++ b/giftcard/src/main/res/values-sv-rSE/strings.xml @@ -8,7 +8,6 @@ --> - Lös in Kortnummer PIN-kod Ogiltigt kortnummer diff --git a/giftcard/src/main/res/values-zh-rCN/strings.xml b/giftcard/src/main/res/values-zh-rCN/strings.xml index c4a5d858e4..617bff8905 100644 --- a/giftcard/src/main/res/values-zh-rCN/strings.xml +++ b/giftcard/src/main/res/values-zh-rCN/strings.xml @@ -8,7 +8,6 @@ --> - 兑换 卡号 Pin 无效的卡号 diff --git a/giftcard/src/main/res/values-zh-rTW/strings.xml b/giftcard/src/main/res/values-zh-rTW/strings.xml index 0008198f87..125498f8eb 100644 --- a/giftcard/src/main/res/values-zh-rTW/strings.xml +++ b/giftcard/src/main/res/values-zh-rTW/strings.xml @@ -8,7 +8,6 @@ --> - 兌換 信用卡號碼 數字密碼 信用卡號碼無效 diff --git a/giftcard/src/main/res/values/strings.xml b/giftcard/src/main/res/values/strings.xml index 80aa643694..a6f1f2f1b2 100644 --- a/giftcard/src/main/res/values/strings.xml +++ b/giftcard/src/main/res/values/strings.xml @@ -8,7 +8,6 @@ --> - Redeem Card number Pin Invalid card number From 02a578bc22deaa1a2d419bc440b2dc74e7190d15 Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 22 Sep 2021 12:55:14 +0200 Subject: [PATCH 012/102] Adding fragment for gift card component --- .../ui/base/BaseComponentDialogFragment.kt | 2 +- .../GiftCardComponentDialogFragment.kt | 107 ++++++++++++++++++ .../layout/fragment_giftcard_component.xml | 58 ++++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt create mode 100644 drop-in/src/main/res/layout/fragment_giftcard_component.xml diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt index c383fcacb5..aa4116d668 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt @@ -153,7 +153,7 @@ abstract class BaseComponentDialogFragment : DropInBottomSheetDialogFragment(), protocol.terminateDropIn() } - private fun startPayment() { + open fun startPayment() { val componentState = component.state try { if (componentState != null) { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt new file mode 100644 index 0000000000..99ea48b4dc --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 15/9/2021. + */ + +package com.adyen.checkout.dropin.ui.component + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import com.adyen.checkout.components.ComponentError +import com.adyen.checkout.components.ComponentView +import com.adyen.checkout.components.PaymentComponent +import com.adyen.checkout.components.PaymentComponentState +import com.adyen.checkout.components.ViewableComponent +import com.adyen.checkout.components.base.Configuration +import com.adyen.checkout.components.base.OutputData +import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails +import com.adyen.checkout.core.exception.CheckoutException +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.dropin.databinding.FragmentGiftcardComponentBinding +import com.adyen.checkout.dropin.getViewFor +import com.adyen.checkout.dropin.ui.base.BaseComponentDialogFragment +import com.google.android.material.bottomsheet.BottomSheetBehavior + +class GiftCardComponentDialogFragment : BaseComponentDialogFragment() { + + private lateinit var componentView: ComponentView> + private lateinit var binding: FragmentGiftcardComponentBinding + + companion object : BaseCompanion(GiftCardComponentDialogFragment::class.java) { + private val TAG = LogUtil.getTag() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + binding = FragmentGiftcardComponentBinding.inflate(inflater, container, false) + return binding.root + } + + override fun setPaymentPendingInitialization(pending: Boolean) { + if (!componentView.isConfirmationRequired) return + binding.redeemButton.isVisible = !pending + if (pending) binding.progressBar.show() + else binding.progressBar.hide() + } + + override fun highlightValidationErrors() { + componentView.highlightValidationErrors() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Logger.d(TAG, "onViewCreated") + binding.header.text = paymentMethod.name + + try { + componentView = getViewFor(requireContext(), paymentMethod.type!!) + attachComponent(component, componentView) + } catch (e: CheckoutException) { + handleError(ComponentError(e)) + } + } + + override fun onChanged(paymentComponentState: PaymentComponentState?) { + componentDialogViewModel.componentStateChanged(component.state, componentView.isConfirmationRequired) + } + + private fun attachComponent( + component: PaymentComponent, Configuration>, + componentView: ComponentView> + ) { + component.observe(viewLifecycleOwner, this) + component.observeErrors(viewLifecycleOwner, createErrorHandlerObserver()) + binding.componentContainer.addView(componentView as View) + componentView.attach(component as ViewableComponent<*, *, *>, viewLifecycleOwner) + + if (componentView.isConfirmationRequired) { + binding.redeemButton.setOnClickListener { componentDialogViewModel.payButtonClicked() } + setInitViewState(BottomSheetBehavior.STATE_EXPANDED) + (componentView as View).requestFocus() + } else { + binding.redeemButton.visibility = View.GONE + } + } + + override fun startPayment() { + val componentState = component.state + try { + if (componentState != null) { + if (componentState.isValid) { + // request balance + } else { + throw CheckoutException("PaymentComponentState is not valid.") + } + } else { + throw CheckoutException("PaymentComponentState is null.") + } + } catch (e: CheckoutException) { + handleError(ComponentError(e)) + } + } +} diff --git a/drop-in/src/main/res/layout/fragment_giftcard_component.xml b/drop-in/src/main/res/layout/fragment_giftcard_component.xml new file mode 100644 index 0000000000..684c471475 --- /dev/null +++ b/drop-in/src/main/res/layout/fragment_giftcard_component.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 3c52c8f313ccfc6f2b9f3b5a43eb2f1caa8d55f5 Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 22 Sep 2021 12:58:32 +0200 Subject: [PATCH 013/102] Adding request balance functionality to drop-in --- .../checkout/dropin/service/BalanceResult.kt | 14 +++++++ .../checkout/dropin/service/DropInService.kt | 30 +++++++++++++- .../checkout/dropin/ui/DropInActivity.kt | 41 +++++++++++++++++++ .../base/DropInBottomSheetDialogFragment.kt | 1 + .../GiftCardComponentDialogFragment.kt | 2 +- 5 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt new file mode 100644 index 0000000000..cf99dad697 --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 16/9/2021. + */ + +package com.adyen.checkout.dropin.service + +data class BalanceResult( + val balance: String, + val transactionLimit: String? +) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt index 72c96cd9ca..69bf4d7ebb 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt @@ -21,14 +21,15 @@ import androidx.lifecycle.Observer import com.adyen.checkout.components.ActionComponentData import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.payments.request.PaymentComponentData +import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger +import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import org.json.JSONObject -import kotlin.coroutines.CoroutineContext private val TAG = LogUtil.getTag() @@ -51,6 +52,7 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface private val binder = DropInBinder() private val resultLiveData: MutableLiveData = MutableLiveData() + private val balanceLiveData: MutableLiveData = MutableLiveData() override fun onBind(intent: Intent?): IBinder { Logger.d(TAG, "onBind") @@ -261,8 +263,30 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface throw NotImplementedError("Neither makeDetailsCall nor onDetailsCallRequested is implemented") } + override fun requestBalanceCall(paymentMethodData: PaymentMethodDetails) { + Logger.d(TAG, "requestBalanceCall") + val json = PaymentMethodDetails.SERIALIZER.serialize(paymentMethodData) + checkBalance(paymentMethodData, json) + } + + // TODO docs + open fun checkBalance(paymentMethodData: PaymentMethodDetails, paymentMethodJson: JSONObject) { + throw NotImplementedError("Method checkBalance is not implemented") + } + + // TODO docs + protected fun onBalanceChecked(balanceJson: String, transactionLimitJson: String?) { + // send response back to activity + Logger.d(TAG, "onBalanceChecked called") + balanceLiveData.postValue(BalanceResult(balanceJson, transactionLimitJson)) + } + override fun observeResult(owner: LifecycleOwner, observer: Observer) { - this.resultLiveData.observe(owner, observer) + resultLiveData.observe(owner, observer) + } + + override fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) { + balanceLiveData.observe(owner, observer) } internal inner class DropInBinder : Binder() { @@ -291,4 +315,6 @@ internal interface DropInServiceInterface { fun observeResult(owner: LifecycleOwner, observer: Observer) fun requestPaymentsCall(paymentComponentState: PaymentComponentState<*>) fun requestDetailsCall(actionComponentData: ActionComponentData) + fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) + fun requestBalanceCall(paymentMethodData: PaymentMethodDetails) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index e496e9cc51..654559aa07 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -29,6 +29,7 @@ import com.adyen.checkout.components.analytics.AnalyticsDispatcher import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.PaymentMethod import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod +import com.adyen.checkout.components.model.payments.Amount import com.adyen.checkout.components.model.payments.response.Action import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException @@ -39,6 +40,7 @@ import com.adyen.checkout.dropin.DropIn import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.DropInPrefs import com.adyen.checkout.dropin.R +import com.adyen.checkout.dropin.service.BalanceResult import com.adyen.checkout.dropin.service.DropInService import com.adyen.checkout.dropin.service.DropInServiceInterface import com.adyen.checkout.dropin.service.DropInServiceResult @@ -46,6 +48,7 @@ import com.adyen.checkout.dropin.ui.action.ActionComponentDialogFragment import com.adyen.checkout.dropin.ui.base.DropInBottomSheetDialogFragment import com.adyen.checkout.dropin.ui.component.CardComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GenericComponentDialogFragment +import com.adyen.checkout.dropin.ui.component.GiftCardComponentDialogFragment import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListDialogFragment import com.adyen.checkout.dropin.ui.stored.PreselectedStoredPaymentMethodFragment import com.adyen.checkout.googlepay.GooglePayComponent @@ -97,6 +100,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot // these queues exist for when a call is requested before the service is bound private var paymentDataQueue: PaymentComponentState<*>? = null private var actionDataQueue: ActionComponentData? = null + private var balanceDataQueue: PaymentComponentState<*>? = null private val serviceConnection = object : ServiceConnection { @@ -105,6 +109,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot val dropInBinder = binder as? DropInService.DropInBinder ?: return dropInService = dropInBinder.getService() dropInService?.observeResult(this@DropInActivity) { handleDropInServiceResult(it) } + dropInService?.observeBalanceResult(this@DropInActivity) { handleBalanceResult(it) } paymentDataQueue?.let { Logger.d(TAG, "Sending queued payment request") @@ -117,6 +122,11 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot requestDetailsCall(it) actionDataQueue = null } + balanceDataQueue?.let { + Logger.d(TAG, "Sending queued action request") + requestBalanceCall(it) + balanceDataQueue = null + } } override fun onServiceDisconnected(className: ComponentName) { @@ -339,6 +349,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot hideAllScreens() val dialogFragment = when (paymentMethod.type) { PaymentMethodTypes.SCHEME -> CardComponentDialogFragment + PaymentMethodTypes.GIFTCARD -> GiftCardComponentDialogFragment else -> GenericComponentDialogFragment }.newInstance(paymentMethod, dropInViewModel.dropInConfiguration) @@ -367,6 +378,23 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot googlePayComponent.startGooglePayScreen(this, GOOGLE_PAY_REQUEST_CODE) } + override fun requestBalanceCall(paymentComponentState: PaymentComponentState<*>) { + Logger.d(TAG, "requestCheckBalanceCall") + val paymentMethod = paymentComponentState.data.paymentMethod + if (paymentMethod == null) { + Logger.e(TAG, "requestBalanceCall - paymentMethod is null") + return + } + if (dropInService == null) { + Logger.e(TAG, "requestBalanceCall - service is disconnected") + balanceDataQueue = paymentComponentState + return + } + isWaitingResult = true + setLoading(true) + dropInService?.requestBalanceCall(paymentMethod) + } + private fun handleDropInServiceResult(dropInServiceResult: DropInServiceResult) { Logger.d(TAG, "handleDropInServiceResult - ${dropInServiceResult::class.simpleName}") dropInViewModel.isWaitingResult = false @@ -478,6 +506,19 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } } + private fun handleBalanceResult(balanceResult: BalanceResult) { + Logger.d(TAG, "handleBalanceResult - balance: ${balanceResult.balance} - transactionLimit: ${balanceResult.transactionLimit}") + isWaitingResult = false + // TODO move this somewhere else later? + setLoading(false) + val balance = Amount.SERIALIZER.deserialize(JSONObject(balanceResult.balance)) + val transactionLimit = + if (balanceResult.transactionLimit == null) null + else Amount.SERIALIZER.deserialize(JSONObject(balanceResult.transactionLimit)) + balance + // TODO handle balance and transactionLimit + } + companion object { fun createIntent( context: Context, diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt index 23834e8cc7..87e10d54ef 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt @@ -98,5 +98,6 @@ abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragment() { fun showError(errorMessage: String, reason: String, terminate: Boolean) fun terminateDropIn() fun startGooglePay(paymentMethod: PaymentMethod, googlePayConfiguration: GooglePayConfiguration) + fun requestBalanceCall(paymentComponentState: PaymentComponentState<*>) } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt index 99ea48b4dc..a61bcce71c 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt @@ -93,7 +93,7 @@ class GiftCardComponentDialogFragment : BaseComponentDialogFragment() { try { if (componentState != null) { if (componentState.isValid) { - // request balance + protocol.requestBalanceCall(componentState) } else { throw CheckoutException("PaymentComponentState is not valid.") } From 0bd0ec6dc45eef899e7c20c4251517ce0ed94290 Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 22 Sep 2021 12:58:44 +0200 Subject: [PATCH 014/102] Adding request balance functionality to example app --- .../example/data/api/CheckoutApiService.kt | 4 ++ .../paymentMethods/PaymentsRepository.kt | 7 +++ .../service/ExampleAsyncDropInService.kt | 38 +++++++++++++++ .../checkout/example/service/RequestUtils.kt | 46 +++++++++++-------- .../checkout/example/ui/main/MainActivity.kt | 4 +- 5 files changed, 78 insertions(+), 21 deletions(-) diff --git a/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt b/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt index bce273464c..461a2f6068 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt @@ -51,4 +51,8 @@ interface CheckoutApiService { @Headers(BuildConfig.API_KEY_HEADER_NAME + ":" + BuildConfig.CHECKOUT_API_KEY) @POST("payments/details") fun detailsAsync(@Body detailsRequest: RequestBody): Deferred> + + @Headers(BuildConfig.API_KEY_HEADER_NAME + ":" + BuildConfig.CHECKOUT_API_KEY) + @POST("paymentMethods/balance") + fun checkBalanceAsync(@Body balanceRequest: RequestBody): Deferred> } diff --git a/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt b/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt index 48b8d4560e..95b1e9b5d4 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt @@ -22,6 +22,7 @@ interface PaymentsRepository { suspend fun paymentsRequestAsync(paymentsRequest: RequestBody): ResponseBody? fun detailsRequest(paymentsRequest: RequestBody): Call suspend fun detailsRequestAsync(paymentsRequest: RequestBody): ResponseBody? + suspend fun balanceRequestAsync(balanceRequest: RequestBody): ResponseBody? } class PaymentsRepositoryImpl(private val checkoutApiService: CheckoutApiService) : PaymentsRepository, BaseRepository() { @@ -51,4 +52,10 @@ class PaymentsRepositoryImpl(private val checkoutApiService: CheckoutApiService) call = { checkoutApiService.detailsAsync(paymentsRequest).await() } ) } + + override suspend fun balanceRequestAsync(balanceRequest: RequestBody): ResponseBody? { + return safeApiCall( + call = { checkoutApiService.checkBalanceAsync(balanceRequest).await() } + ) + } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index dabd855069..71631fc7d0 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -11,8 +11,10 @@ package com.adyen.checkout.example.service import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.components.ActionComponentData import com.adyen.checkout.components.PaymentComponentState +import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.core.model.getStringOrNull import com.adyen.checkout.core.model.toStringPretty import com.adyen.checkout.dropin.service.DropInService import com.adyen.checkout.dropin.service.DropInServiceResult @@ -117,4 +119,40 @@ class ExampleAsyncDropInService : DropInService() { DropInServiceResult.Error(reason = "IOException") } } + + override fun checkBalance(paymentMethodData: PaymentMethodDetails, paymentMethodJson: JSONObject) { + launch(Dispatchers.IO) { + Logger.d(TAG, "checkBalance") + + Logger.v(TAG, "paymentMethods/balance/ - ${paymentMethodJson.toStringPretty()}") + + val paymentRequest = createBalanceRequest( + paymentMethodJson, + keyValueStorage.getMerchantAccount() + ) + + val requestBody = paymentRequest.toString().toRequestBody(CONTENT_TYPE) + val response = paymentsRepository.balanceRequestAsync(requestBody) + + handleBalanceResponse(response) + } + } + + @Suppress("NestedBlockDepth") + private fun handleBalanceResponse(response: ResponseBody?) { + if (response != null) { + val jsonResponse = JSONObject(response.string()) + val resultCode = jsonResponse.getStringOrNull("resultCode") + val balance = jsonResponse.getStringOrNull("balance") + val transactionLimit = jsonResponse.getStringOrNull("transactionLimit") + when { + resultCode == "Success" && balance != null -> onBalanceChecked(balance, transactionLimit) + resultCode == "NotEnoughBalance" -> sendResult(DropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false)) + else -> sendResult(DropInServiceResult.Error(reason = resultCode, dismissDropIn = false)) + } + } else { + Logger.e(TAG, "FAILED") + sendResult(DropInServiceResult.Error(reason = "IOException")) + } + } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt index 7c8d457e88..264bb684d4 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt @@ -28,26 +28,34 @@ fun createPaymentRequest( threeDSAuthenticationOnly: Boolean = false ): JSONObject { - val request = JSONObject(paymentComponentData.toString()) + return JSONObject(paymentComponentData.toString()).apply { + put("shopperReference", shopperReference) + put("amount", JSONObject(Gson().toJson(amount))) + put("merchantAccount", merchantAccount) + put("returnUrl", redirectUrl) + put("countryCode", countryCode) + put("shopperIP", "142.12.31.22") + put("reference", "android-test-components_${System.currentTimeMillis()}") + put("channel", "android") + put("additionalData", JSONObject(Gson().toJson(additionalData))) + put("lineItems", JSONArray(Gson().toJson(listOf(Item())))) + put("threeDSAuthenticationOnly", threeDSAuthenticationOnly) - request.put("shopperReference", shopperReference) - request.put("amount", JSONObject(Gson().toJson(amount))) - request.put("merchantAccount", merchantAccount) - request.put("returnUrl", redirectUrl) - request.put("countryCode", countryCode) - request.put("shopperIP", "142.12.31.22") - request.put("reference", "android-test-components_${System.currentTimeMillis()}") - request.put("channel", "android") - request.put("additionalData", JSONObject(Gson().toJson(additionalData))) - request.put("lineItems", JSONArray(Gson().toJson(listOf(Item())))) - request.put("threeDSAuthenticationOnly", threeDSAuthenticationOnly) - - if (force3DS2Challenge) { - val threeDS2RequestData = JSONObject() - threeDS2RequestData.put("deviceChannel", "app") - threeDS2RequestData.put("challengeIndicator", "requestChallenge") - request.put("threeDS2RequestData", threeDS2RequestData) + if (force3DS2Challenge) { + val threeDS2RequestData = JSONObject() + threeDS2RequestData.put("deviceChannel", "app") + threeDS2RequestData.put("challengeIndicator", "requestChallenge") + put("threeDS2RequestData", threeDS2RequestData) + } } +} - return request +fun createBalanceRequest( + paymentComponentData: JSONObject, + merchantAccount: String, +): JSONObject { + return JSONObject().apply { + put("paymentMethod", paymentComponentData) + put("merchantAccount", merchantAccount) + } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt index 5a2ef182b8..7b5e32f15e 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt @@ -33,7 +33,7 @@ import com.adyen.checkout.example.R import com.adyen.checkout.example.data.api.CheckoutApiService import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.databinding.ActivityMainBinding -import com.adyen.checkout.example.service.ExampleDropInService +import com.adyen.checkout.example.service.ExampleAsyncDropInService import com.adyen.checkout.example.ui.configuration.ConfigurationActivity import com.adyen.checkout.googlepay.GooglePayConfiguration import java.util.Locale @@ -166,7 +166,7 @@ class MainActivity : AppCompatActivity(), DropInCallback { val dropInConfigurationBuilder = DropInConfiguration.Builder( this@MainActivity, - ExampleDropInService::class.java, + ExampleAsyncDropInService::class.java, BuildConfig.CLIENT_KEY ) .setEnvironment(Environment.TEST) From 45294f3d588f741fcc7217a8a346ce7cf8964009 Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 22 Sep 2021 12:59:03 +0200 Subject: [PATCH 015/102] Adding GiftCardBalanceUtils and tests --- .../giftcard/util/GiftCardBalanceUtils.kt | 59 +++++ .../giftcard/GiftCardBalanceUtilsTest.kt | 206 ++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt create mode 100644 giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt new file mode 100644 index 0000000000..9776c01b7a --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 20/9/2021. + */ + +package com.adyen.checkout.giftcard.util + +import com.adyen.checkout.components.model.payments.Amount +import kotlin.math.min + +// TODO docs +object GiftCardBalanceUtils { + + // TODO docs + fun checkBalance(balance: Amount, transactionLimit: Amount?, amountToBePaid: Amount): GiftCardBalanceResult { + return when { + amountToBePaid.isEmpty || amountToBePaid.value <= 0 -> GiftCardBalanceResult.ZeroAmountToBePaid + balance.isEmpty || balance.value <= 0 -> GiftCardBalanceResult.ZeroBalance + amountToBePaid.currency != balance.currency -> GiftCardBalanceResult.NonMatchingCurrencies + transactionLimit != null && amountToBePaid.currency != transactionLimit.currency -> GiftCardBalanceResult.NonMatchingCurrencies + else -> calculateRemainingAmount(balance, transactionLimit, amountToBePaid) + } + } + + private fun calculateRemainingAmount(balance: Amount, transactionLimit: Amount?, amountToBePaid: Amount): GiftCardBalanceResult { + val maxPayableAmount = + if (transactionLimit == null || transactionLimit.isEmpty) balance.value + else min(balance.value, transactionLimit.value) + + val paidCurrency = amountToBePaid.currency + val actualPaidAmount = min(maxPayableAmount, amountToBePaid.value) + + val amountPaid = Amount().apply { + currency = paidCurrency + value = actualPaidAmount + } + val remainingBalance = Amount().apply { + currency = paidCurrency + value = balance.value - actualPaidAmount + } + + return if (maxPayableAmount >= amountToBePaid.value) { + GiftCardBalanceResult.FullPayment(amountPaid = amountPaid, remainingBalance = remainingBalance) + } else { + GiftCardBalanceResult.PartialPayment(amountPaid = amountPaid, remainingBalance = remainingBalance) + } + } +} + +sealed class GiftCardBalanceResult { + class FullPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceResult() + class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceResult() + object NonMatchingCurrencies : GiftCardBalanceResult() + object ZeroAmountToBePaid : GiftCardBalanceResult() + object ZeroBalance : GiftCardBalanceResult() +} diff --git a/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt new file mode 100644 index 0000000000..dd2b30486c --- /dev/null +++ b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt @@ -0,0 +1,206 @@ +package com.adyen.checkout.giftcard + +import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.giftcard.util.GiftCardBalanceResult +import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils +import org.junit.Assert.assertEquals +import org.junit.Test + +class GiftCardBalanceUtilsTest { + + @Test + fun checkBalance_LargerTransactionLimit_ExpectFullPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = createAmount(1000), + amountToBePaid = createAmount(10) + ) + + assert(result is GiftCardBalanceResult.FullPayment) + require(result is GiftCardBalanceResult.FullPayment) + assertEquals(10, result.amountPaid.value) + assertEquals(90, result.remainingBalance.value) + } + + @Test + fun checkBalance_LargerBalance_ExpectFullPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(1000), + transactionLimit = createAmount(100), + amountToBePaid = createAmount(10) + ) + + assert(result is GiftCardBalanceResult.FullPayment) + require(result is GiftCardBalanceResult.FullPayment) + assertEquals(10, result.amountPaid.value) + assertEquals(990, result.remainingBalance.value) + } + + @Test + fun checkBalance_NullTransactionLimit_ExpectFullPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = null, + amountToBePaid = createAmount(10) + ) + + assert(result is GiftCardBalanceResult.FullPayment) + require(result is GiftCardBalanceResult.FullPayment) + assertEquals(10, result.amountPaid.value) + assertEquals(90, result.remainingBalance.value) + } + + @Test + fun checkBalance_ZeroRemainingBalance_ExpectFullPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = createAmount(100), + amountToBePaid = createAmount(100) + ) + + assert(result is GiftCardBalanceResult.FullPayment) + require(result is GiftCardBalanceResult.FullPayment) + assertEquals(100, result.amountPaid.value) + assertEquals(0, result.remainingBalance.value) + } + + @Test + fun checkBalance_LargerTransactionLimit_ExpectPartialPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = createAmount(200), + amountToBePaid = createAmount(1000) + ) + + assert(result is GiftCardBalanceResult.PartialPayment) + require(result is GiftCardBalanceResult.PartialPayment) + assertEquals(100, result.amountPaid.value) + assertEquals(0, result.remainingBalance.value) + } + + @Test + fun checkBalance_LargerBalance_ExpectPartialPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(200), + transactionLimit = createAmount(100), + amountToBePaid = createAmount(1000) + ) + + assert(result is GiftCardBalanceResult.PartialPayment) + require(result is GiftCardBalanceResult.PartialPayment) + assertEquals(100, result.amountPaid.value) + assertEquals(100, result.remainingBalance.value) + } + + @Test + fun checkBalance_NullTransactionLimit_ExpectPartialPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = null, + amountToBePaid = createAmount(1000) + ) + + assert(result is GiftCardBalanceResult.PartialPayment) + require(result is GiftCardBalanceResult.PartialPayment) + assertEquals(100, result.amountPaid.value) + assertEquals(0, result.remainingBalance.value) + } + + @Test + fun checkBalance_ZeroRemainingBalance_ExpectPartialPayment() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = createAmount(100), + amountToBePaid = createAmount(200) + ) + + assert(result is GiftCardBalanceResult.PartialPayment) + require(result is GiftCardBalanceResult.PartialPayment) + assertEquals(100, result.amountPaid.value) + assertEquals(0, result.remainingBalance.value) + } + + @Test + fun checkBalance_BalanceUSD_ExpectNonMatchingCurrencies() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100, "USD"), + transactionLimit = createAmount(500), + amountToBePaid = createAmount(200) + ) + + assert(result is GiftCardBalanceResult.NonMatchingCurrencies) + } + + @Test + fun checkBalance_TransactionLimitUSD_ExpectNonMatchingCurrencies() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = createAmount(500, "USD"), + amountToBePaid = createAmount(200) + ) + + assert(result is GiftCardBalanceResult.NonMatchingCurrencies) + } + + @Test + fun checkBalance_AmountUSD_ExpectNonMatchingCurrencies() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = null, + amountToBePaid = createAmount(200, "USD") + ) + + assert(result is GiftCardBalanceResult.NonMatchingCurrencies) + } + + @Test + fun checkBalance_EmptyAmount_ExpectZeroAmountToBePaid() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = createAmount(10), + amountToBePaid = Amount.EMPTY + ) + + assert(result is GiftCardBalanceResult.ZeroAmountToBePaid) + } + + @Test + fun checkBalance_ZeroAmount_ExpectZeroAmountToBePaid() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(100), + transactionLimit = createAmount(10), + amountToBePaid = createAmount(0) + ) + + assert(result is GiftCardBalanceResult.ZeroAmountToBePaid) + } + + @Test + fun checkBalance_EmptyBalance_ExpectZeroBalance() { + val result = GiftCardBalanceUtils.checkBalance( + balance = Amount.EMPTY, + transactionLimit = createAmount(10), + amountToBePaid = createAmount(100) + ) + + assert(result is GiftCardBalanceResult.ZeroBalance) + } + + @Test + fun checkBalance_ZeroBalance_ExpectZeroBalance() { + val result = GiftCardBalanceUtils.checkBalance( + balance = createAmount(0), + transactionLimit = createAmount(10), + amountToBePaid = createAmount(100) + ) + + assert(result is GiftCardBalanceResult.ZeroBalance) + } + + private fun createAmount(value: Int, currency: String = "EUR"): Amount { + return Amount().apply { + this.value = value + this.currency = currency + } + } +} From 71935e1bc25fa134e7dc99ab5c7ae16010923e98 Mon Sep 17 00:00:00 2001 From: jreij Date: Tue, 28 Sep 2021 16:25:28 +0200 Subject: [PATCH 016/102] Adding balance error message strings --- drop-in/src/main/res/template/values/strings.xml.tt | 2 ++ drop-in/src/main/res/values-cs-rCZ/strings.xml | 2 ++ drop-in/src/main/res/values-da-rDK/strings.xml | 2 ++ drop-in/src/main/res/values-de-rDE/strings.xml | 2 ++ drop-in/src/main/res/values-el-rGR/strings.xml | 2 ++ drop-in/src/main/res/values-es-rES/strings.xml | 2 ++ drop-in/src/main/res/values-fi-rFI/strings.xml | 2 ++ drop-in/src/main/res/values-fr-rFR/strings.xml | 2 ++ drop-in/src/main/res/values-hr-rHR/strings.xml | 2 ++ drop-in/src/main/res/values-hu-rHU/strings.xml | 2 ++ drop-in/src/main/res/values-it-rIT/strings.xml | 2 ++ drop-in/src/main/res/values-ja-rJP/strings.xml | 2 ++ drop-in/src/main/res/values-ko-rKR/strings.xml | 2 ++ drop-in/src/main/res/values-nb-rNO/strings.xml | 2 ++ drop-in/src/main/res/values-nl-rNL/strings.xml | 2 ++ drop-in/src/main/res/values-pl-rPL/strings.xml | 2 ++ drop-in/src/main/res/values-pt-rBR/strings.xml | 2 ++ drop-in/src/main/res/values-ro-rRO/strings.xml | 2 ++ drop-in/src/main/res/values-ru-rRU/strings.xml | 2 ++ drop-in/src/main/res/values-sk-rSK/strings.xml | 2 ++ drop-in/src/main/res/values-sl-rSI/strings.xml | 2 ++ drop-in/src/main/res/values-sv-rSE/strings.xml | 2 ++ drop-in/src/main/res/values-zh-rCN/strings.xml | 2 ++ drop-in/src/main/res/values-zh-rTW/strings.xml | 2 ++ drop-in/src/main/res/values/strings.xml | 2 ++ 25 files changed, 50 insertions(+) diff --git a/drop-in/src/main/res/template/values/strings.xml.tt b/drop-in/src/main/res/template/values/strings.xml.tt index 89afe2124b..ccbf243cd6 100644 --- a/drop-in/src/main/res/template/values/strings.xml.tt +++ b/drop-in/src/main/res/template/values/strings.xml.tt @@ -22,4 +22,6 @@ %%preselectedPaymentMethod.changeButton.accessibilityLabel%% Credit Card %%applyGiftcard%% + %%error.giftcard.no-balance%% + %%error.giftcard.currency-error%% diff --git a/drop-in/src/main/res/values-cs-rCZ/strings.xml b/drop-in/src/main/res/values-cs-rCZ/strings.xml index 6930e1b49d..c52e3e1ba8 100644 --- a/drop-in/src/main/res/values-cs-rCZ/strings.xml +++ b/drop-in/src/main/res/values-cs-rCZ/strings.xml @@ -22,4 +22,6 @@ Změnit způsob platby Credit Card Uplatnit + Na dárkové kartě je nulový zůstatek + Dárkové karty jsou platné jenom v měně, ve které byly vystavené \ No newline at end of file diff --git a/drop-in/src/main/res/values-da-rDK/strings.xml b/drop-in/src/main/res/values-da-rDK/strings.xml index e6c0529778..47097f5c06 100644 --- a/drop-in/src/main/res/values-da-rDK/strings.xml +++ b/drop-in/src/main/res/values-da-rDK/strings.xml @@ -22,4 +22,6 @@ Skift betalingsmåde Credit Card Indløs + Saldoen på gavekortet er 0 + Gavekort er kun gyldige i udstedelsesvalutaen \ No newline at end of file diff --git a/drop-in/src/main/res/values-de-rDE/strings.xml b/drop-in/src/main/res/values-de-rDE/strings.xml index d67d20f3db..2920ebb40a 100644 --- a/drop-in/src/main/res/values-de-rDE/strings.xml +++ b/drop-in/src/main/res/values-de-rDE/strings.xml @@ -22,4 +22,6 @@ Zahlungsmethode wechseln Credit Card Einlösen + Auf dieser Geschenkkarte ist kein Guthaben vorhanden + Geschenkkarten sind nur in der Währung gültig, in der sie ausgestellt wurden \ No newline at end of file diff --git a/drop-in/src/main/res/values-el-rGR/strings.xml b/drop-in/src/main/res/values-el-rGR/strings.xml index e5c64cddb2..e2017440b8 100644 --- a/drop-in/src/main/res/values-el-rGR/strings.xml +++ b/drop-in/src/main/res/values-el-rGR/strings.xml @@ -22,4 +22,6 @@ Αλλαγή τρόπου πληρωμής Credit Card Εξαργύρωση + Η συγκεκριμένη δωροκάρτα έχει μηδενικό υπόλοιπο + Οι δωροκάρτες ισχύουν μόνο για το νόμισμα στο οποίο εκδόθηκαν \ No newline at end of file diff --git a/drop-in/src/main/res/values-es-rES/strings.xml b/drop-in/src/main/res/values-es-rES/strings.xml index 6aa1cdc856..110806dad8 100644 --- a/drop-in/src/main/res/values-es-rES/strings.xml +++ b/drop-in/src/main/res/values-es-rES/strings.xml @@ -22,4 +22,6 @@ Cambiar método de pago Credit Card Canjear + Esta tarjeta regalo no tiene saldo + Las tarjetas regalo solo son válidas en la moneda en que fueron emitidas \ No newline at end of file diff --git a/drop-in/src/main/res/values-fi-rFI/strings.xml b/drop-in/src/main/res/values-fi-rFI/strings.xml index 72a79e7ae7..df67206eeb 100644 --- a/drop-in/src/main/res/values-fi-rFI/strings.xml +++ b/drop-in/src/main/res/values-fi-rFI/strings.xml @@ -22,4 +22,6 @@ Muuta maksutapaa Credit Card Lunasta + Lahjakortin saldo on nolla + Gift cards are only valid in the currency they were issued in \ No newline at end of file diff --git a/drop-in/src/main/res/values-fr-rFR/strings.xml b/drop-in/src/main/res/values-fr-rFR/strings.xml index 0784aa0632..b4587ba26d 100644 --- a/drop-in/src/main/res/values-fr-rFR/strings.xml +++ b/drop-in/src/main/res/values-fr-rFR/strings.xml @@ -22,4 +22,6 @@ Changer de moyen de paiement Credit Card Utiliser + Aucun solde n\'est disponible sur cette carte cadeau + Les cartes cadeaux sont valables uniquement dans la devise dans laquelle elles ont été émises \ No newline at end of file diff --git a/drop-in/src/main/res/values-hr-rHR/strings.xml b/drop-in/src/main/res/values-hr-rHR/strings.xml index 6ed71180a9..95d88c917b 100644 --- a/drop-in/src/main/res/values-hr-rHR/strings.xml +++ b/drop-in/src/main/res/values-hr-rHR/strings.xml @@ -22,4 +22,6 @@ Promijeni način plaćanja Credit Card Iskoristite + Stanje na ovoj poklon-kartici iznosi nula + Poklon-kartice vrijede samo u valuti u kojoj su izdane \ No newline at end of file diff --git a/drop-in/src/main/res/values-hu-rHU/strings.xml b/drop-in/src/main/res/values-hu-rHU/strings.xml index f9602b61e1..0645eb1088 100644 --- a/drop-in/src/main/res/values-hu-rHU/strings.xml +++ b/drop-in/src/main/res/values-hu-rHU/strings.xml @@ -22,4 +22,6 @@ Fizetési mód módosítása Credit Card Beváltás + Az ajándékkártya egyenlege nulla + Az ajándékkártyák csak abban a pénznemben érvényesek, amelyre kiállították azokat \ No newline at end of file diff --git a/drop-in/src/main/res/values-it-rIT/strings.xml b/drop-in/src/main/res/values-it-rIT/strings.xml index cadbb0a1a1..e6b1c54116 100644 --- a/drop-in/src/main/res/values-it-rIT/strings.xml +++ b/drop-in/src/main/res/values-it-rIT/strings.xml @@ -22,4 +22,6 @@ Cambia metodo di pagamento Credit Card Riscatta + Questo buono regalo ha un saldo pari a zero + I buono regalo sono validi solo nella valuta in cui sono state emessi \ No newline at end of file diff --git a/drop-in/src/main/res/values-ja-rJP/strings.xml b/drop-in/src/main/res/values-ja-rJP/strings.xml index ba23ec91fd..5ecd6d6091 100644 --- a/drop-in/src/main/res/values-ja-rJP/strings.xml +++ b/drop-in/src/main/res/values-ja-rJP/strings.xml @@ -22,4 +22,6 @@ お支払方法を変更する Credit Card 利用する + このギフトカードの残高はゼロです + ギフトカードは、発行された通貨でのみ有効です。 \ No newline at end of file diff --git a/drop-in/src/main/res/values-ko-rKR/strings.xml b/drop-in/src/main/res/values-ko-rKR/strings.xml index 242f833023..7987ddfb35 100644 --- a/drop-in/src/main/res/values-ko-rKR/strings.xml +++ b/drop-in/src/main/res/values-ko-rKR/strings.xml @@ -22,4 +22,6 @@ 결제 수단 변경 Credit Card 기프트 카드로 결제 + 이 기프트 카드에는 잔액이 없습니다 + 기프트 카드는 발급된 통화로만 사용하실 수 있습니다 \ No newline at end of file diff --git a/drop-in/src/main/res/values-nb-rNO/strings.xml b/drop-in/src/main/res/values-nb-rNO/strings.xml index d92b1cfb9b..3aeb72db4c 100644 --- a/drop-in/src/main/res/values-nb-rNO/strings.xml +++ b/drop-in/src/main/res/values-nb-rNO/strings.xml @@ -22,4 +22,6 @@ Endre betalingsmetode Credit Card Løs inn + Dette gavekortet har en saldo på null + Gavekort er kun gyldige i den valutaen de ble utstedt i \ No newline at end of file diff --git a/drop-in/src/main/res/values-nl-rNL/strings.xml b/drop-in/src/main/res/values-nl-rNL/strings.xml index 5285ffd02a..fa241aecc2 100644 --- a/drop-in/src/main/res/values-nl-rNL/strings.xml +++ b/drop-in/src/main/res/values-nl-rNL/strings.xml @@ -22,4 +22,6 @@ Betalingsmethode wijzigen Credit Card Inwisselen + Deze cadeaukaart heeft geen saldo + Cadeaukaarten zijn alleen geldig in de valuta waarin ze zijn uitgegeven \ No newline at end of file diff --git a/drop-in/src/main/res/values-pl-rPL/strings.xml b/drop-in/src/main/res/values-pl-rPL/strings.xml index 8fba97714d..95ed1f3f20 100644 --- a/drop-in/src/main/res/values-pl-rPL/strings.xml +++ b/drop-in/src/main/res/values-pl-rPL/strings.xml @@ -22,4 +22,6 @@ Zmień metodę płatności Credit Card Wykorzystaj + Saldo karty podarunkowej jest puste + Karty podarunkowe są ważne tylko w walucie, w której zostały wydane \ No newline at end of file diff --git a/drop-in/src/main/res/values-pt-rBR/strings.xml b/drop-in/src/main/res/values-pt-rBR/strings.xml index 2d338130ee..7947254a31 100644 --- a/drop-in/src/main/res/values-pt-rBR/strings.xml +++ b/drop-in/src/main/res/values-pt-rBR/strings.xml @@ -22,4 +22,6 @@ Alterar método de pagamento Credit Card Resgatar + Este vale-presente tem saldo zero + Os vales-presente são válidos somente na moeda em que foram emitidos \ No newline at end of file diff --git a/drop-in/src/main/res/values-ro-rRO/strings.xml b/drop-in/src/main/res/values-ro-rRO/strings.xml index cb12ecf445..4ddbe2b45d 100644 --- a/drop-in/src/main/res/values-ro-rRO/strings.xml +++ b/drop-in/src/main/res/values-ro-rRO/strings.xml @@ -22,4 +22,6 @@ Schimbare metodă de plată Credit Card Valorificare + Acest card cadou are soldul zero + Cardurile cadou sunt valabile numai în moneda în care au fost emise \ No newline at end of file diff --git a/drop-in/src/main/res/values-ru-rRU/strings.xml b/drop-in/src/main/res/values-ru-rRU/strings.xml index 70673b9a7e..b220c4b727 100644 --- a/drop-in/src/main/res/values-ru-rRU/strings.xml +++ b/drop-in/src/main/res/values-ru-rRU/strings.xml @@ -22,4 +22,6 @@ Изменить способ оплаты Credit Card Использовать + На этой подарочной карте нет средств + Принимаются только подарочные карты соответствующей валюты \ No newline at end of file diff --git a/drop-in/src/main/res/values-sk-rSK/strings.xml b/drop-in/src/main/res/values-sk-rSK/strings.xml index 31de2f0557..617afbed8f 100644 --- a/drop-in/src/main/res/values-sk-rSK/strings.xml +++ b/drop-in/src/main/res/values-sk-rSK/strings.xml @@ -22,4 +22,6 @@ Zmeniť spôsob platby Credit Card Uplatniť + Táto darčeková karta má nulový zostatok + Darčekové karty sú platné iba v mene, v ktorej boli vydané \ No newline at end of file diff --git a/drop-in/src/main/res/values-sl-rSI/strings.xml b/drop-in/src/main/res/values-sl-rSI/strings.xml index a2819127c0..464e515e20 100644 --- a/drop-in/src/main/res/values-sl-rSI/strings.xml +++ b/drop-in/src/main/res/values-sl-rSI/strings.xml @@ -22,4 +22,6 @@ Spremeni način plačila Credit Card Unovči + Na tej darilni kartici ni sredstev + Darilne kartice so veljavne samo za valuto, za katero so bile izdane \ No newline at end of file diff --git a/drop-in/src/main/res/values-sv-rSE/strings.xml b/drop-in/src/main/res/values-sv-rSE/strings.xml index f5cc0b4bdd..919dc89d45 100644 --- a/drop-in/src/main/res/values-sv-rSE/strings.xml +++ b/drop-in/src/main/res/values-sv-rSE/strings.xml @@ -22,4 +22,6 @@ Ändra betalningssätt Credit Card Lös in + Saldot för detta presentkort är noll + Presentkort är endast giltiga i den valuta som de utfärdades i \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rCN/strings.xml b/drop-in/src/main/res/values-zh-rCN/strings.xml index a42372f03b..6b8ef1b4bd 100644 --- a/drop-in/src/main/res/values-zh-rCN/strings.xml +++ b/drop-in/src/main/res/values-zh-rCN/strings.xml @@ -22,4 +22,6 @@ 更改支付方式 Credit Card 兑换 + 礼品卡余额为零 + 礼品卡仅以其发行的货币为有效货币 \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rTW/strings.xml b/drop-in/src/main/res/values-zh-rTW/strings.xml index 9be1d615e0..9ddb1308d2 100644 --- a/drop-in/src/main/res/values-zh-rTW/strings.xml +++ b/drop-in/src/main/res/values-zh-rTW/strings.xml @@ -22,4 +22,6 @@ 變更付款方式 Credit Card 兌換 + 此禮品卡的餘額為零 + 禮品卡只能以其簽發時所使用的貨幣進行結算 \ No newline at end of file diff --git a/drop-in/src/main/res/values/strings.xml b/drop-in/src/main/res/values/strings.xml index 3a6f5d8f9d..2211acfbdd 100644 --- a/drop-in/src/main/res/values/strings.xml +++ b/drop-in/src/main/res/values/strings.xml @@ -22,4 +22,6 @@ Change Payment Method Credit Card Redeem + This gift card has zero balance + Gift cards are only valid in the currency they were issued in \ No newline at end of file From ea9d9090d9cff3e6e3d2c9827855783ad270d539 Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 30 Sep 2021 11:50:09 +0200 Subject: [PATCH 017/102] Handle balance result --- .../checkout/dropin/ui/DropInActivity.kt | 23 +++++++--- .../checkout/dropin/ui/DropInViewModel.kt | 46 +++++++++++++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 654559aa07..deddb0be83 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -29,7 +29,6 @@ import com.adyen.checkout.components.analytics.AnalyticsDispatcher import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.PaymentMethod import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod -import com.adyen.checkout.components.model.payments.Amount import com.adyen.checkout.components.model.payments.response.Action import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException @@ -509,14 +508,24 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleBalanceResult(balanceResult: BalanceResult) { Logger.d(TAG, "handleBalanceResult - balance: ${balanceResult.balance} - transactionLimit: ${balanceResult.transactionLimit}") isWaitingResult = false + val result = dropInViewModel.handleBalanceResult(balanceResult) + when (result) { + is GiftCardResult.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) + is GiftCardResult.FullPayment -> handleGiftCardFullPayment(result) + is GiftCardResult.PartialPayment -> handleGiftCardPartialPayment(result) + } + } + + private fun handleGiftCardFullPayment(fullPayment: GiftCardResult.FullPayment) { + // TODO move this somewhere else later? + setLoading(false) + // TODO handle full payment + } + + private fun handleGiftCardPartialPayment(partialPayment: GiftCardResult.PartialPayment) { // TODO move this somewhere else later? setLoading(false) - val balance = Amount.SERIALIZER.deserialize(JSONObject(balanceResult.balance)) - val transactionLimit = - if (balanceResult.transactionLimit == null) null - else Amount.SERIALIZER.deserialize(JSONObject(balanceResult.transactionLimit)) - balance - // TODO handle balance and transactionLimit + // TODO handle partial payment } companion object { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 475a14eeee..962acc42b2 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -9,16 +9,23 @@ package com.adyen.checkout.dropin.ui import android.content.Intent +import androidx.annotation.StringRes import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod +import com.adyen.checkout.components.model.payments.Amount import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.DropInConfiguration +import com.adyen.checkout.dropin.R +import com.adyen.checkout.dropin.service.BalanceResult +import com.adyen.checkout.giftcard.util.GiftCardBalanceResult +import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent +import org.json.JSONObject private val TAG = LogUtil.getTag() @@ -72,6 +79,39 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return noStored && singlePm && paymentMethodHasComponent && dropInConfiguration.skipListWhenSinglePaymentMethod } + fun handleBalanceResult(balanceResult: BalanceResult): GiftCardResult { + Logger.d(TAG, "handleBalanceResult - balance: ${balanceResult.balance} - transactionLimit: ${balanceResult.transactionLimit}") + val balance = Amount.SERIALIZER.deserialize(JSONObject(balanceResult.balance)) + val transactionLimit = + if (balanceResult.transactionLimit == null) null + else Amount.SERIALIZER.deserialize(JSONObject(balanceResult.transactionLimit)) + val giftCardBalanceResult = GiftCardBalanceUtils.checkBalance( + balance = balance, + transactionLimit = transactionLimit, + amountToBePaid = dropInConfiguration.amount + ) + return when (giftCardBalanceResult) { + is GiftCardBalanceResult.ZeroBalance -> { + Logger.i(TAG, "handleBalanceResult - Gift Card has zero balance") + GiftCardResult.Error(R.string.checkout_giftcard_error_zero_balance, "Gift Card has zero balance", false) + } + is GiftCardBalanceResult.NonMatchingCurrencies -> { + Logger.e(TAG, "handleBalanceResult - Gift Card currency mismatch") + GiftCardResult.Error(R.string.checkout_giftcard_error_currency, "Gift Card currency mismatch", false) + } + is GiftCardBalanceResult.ZeroAmountToBePaid -> { + Logger.e(TAG, "handleBalanceResult - You must set an amount in DropInConfiguration.Builder to enable gift card payments") + GiftCardResult.Error(R.string.payment_failed, "Drop-in amount is not set", true) + } + is GiftCardBalanceResult.FullPayment -> { + GiftCardResult.FullPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) + } + is GiftCardBalanceResult.PartialPayment -> { + GiftCardResult.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) + } + } + } + companion object { fun putIntentExtras( intent: Intent, @@ -87,3 +127,9 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode } } } + +sealed class GiftCardResult { + class FullPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardResult() + class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardResult() + class Error(@StringRes val errorMessage: Int, val reason: String, val terminateDropIn: Boolean) : GiftCardResult() +} From b7dba6b8e3e0f52b05bc55fe06c7d4e325738cc6 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 15 Oct 2021 10:32:24 +0200 Subject: [PATCH 018/102] Remove unnecessary duplicate startPayment override --- .../ui/base/BaseComponentDialogFragment.kt | 8 ++++++-- .../GiftCardComponentDialogFragment.kt | 17 ++--------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt index aa4116d668..1ab76086e8 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/BaseComponentDialogFragment.kt @@ -153,12 +153,12 @@ abstract class BaseComponentDialogFragment : DropInBottomSheetDialogFragment(), protocol.terminateDropIn() } - open fun startPayment() { + private fun startPayment() { val componentState = component.state try { if (componentState != null) { if (componentState.isValid) { - protocol.requestPaymentsCall(componentState) + requestProtocolCall(componentState) } else { throw CheckoutException("PaymentComponentState are not valid.") } @@ -170,6 +170,10 @@ abstract class BaseComponentDialogFragment : DropInBottomSheetDialogFragment(), } } + open fun requestProtocolCall(componentState: PaymentComponentState) { + protocol.requestPaymentsCall(componentState) + } + protected fun createErrorHandlerObserver(): Observer { return Observer { if (it != null) { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt index a61bcce71c..4d8ce23daa 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt @@ -88,20 +88,7 @@ class GiftCardComponentDialogFragment : BaseComponentDialogFragment() { } } - override fun startPayment() { - val componentState = component.state - try { - if (componentState != null) { - if (componentState.isValid) { - protocol.requestBalanceCall(componentState) - } else { - throw CheckoutException("PaymentComponentState is not valid.") - } - } else { - throw CheckoutException("PaymentComponentState is null.") - } - } catch (e: CheckoutException) { - handleError(ComponentError(e)) - } + override fun requestProtocolCall(componentState: PaymentComponentState) { + protocol.requestBalanceCall(componentState) } } From 4c281c6df08efe89fbbb87180c98994ca2301871 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 15 Oct 2021 11:29:13 +0200 Subject: [PATCH 019/102] Change BalanceResult into a ModelObject and deserialize it inside DropInViewModel --- .../model/payments/response/BalanceResult.kt | 54 +++++++++++++++++++ .../checkout/dropin/service/BalanceResult.kt | 14 ----- .../checkout/dropin/service/DropInService.kt | 10 ++-- .../checkout/dropin/ui/DropInActivity.kt | 7 ++- .../checkout/dropin/ui/DropInViewModel.kt | 17 ++++-- .../service/ExampleAsyncDropInService.kt | 11 ++-- 6 files changed, 80 insertions(+), 33 deletions(-) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt delete mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt new file mode 100644 index 0000000000..9d3562564f --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 15/10/2021. + */ +package com.adyen.checkout.components.model.payments.response + +import android.os.Parcel +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.model.JsonUtils.writeToParcel +import com.adyen.checkout.core.model.ModelObject +import org.json.JSONException +import org.json.JSONObject + +data class BalanceResult( + val balance: String, + val transactionLimit: String? +) : ModelObject() { + + override fun writeToParcel(dest: Parcel, flags: Int) { + writeToParcel(dest, SERIALIZER.serialize(this)) + } + + companion object { + private const val BALANCE = "balance" + private const val TRANSACTION_LIMIT = "transactionLimit" + + @JvmField + val CREATOR = Creator(BalanceResult::class.java) + + @JvmField + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: BalanceResult): JSONObject { + return JSONObject().apply { + try { + putOpt(BALANCE, modelObject.balance) + putOpt(TRANSACTION_LIMIT, modelObject.transactionLimit) + } catch (e: JSONException) { + throw ModelSerializationException(BalanceResult::class.java, e) + } + } + } + + override fun deserialize(jsonObject: JSONObject): BalanceResult { + return BalanceResult( + balance = jsonObject.optString(BALANCE, null), + transactionLimit = jsonObject.optString(TRANSACTION_LIMIT, null) + ) + } + } + } +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt deleted file mode 100644 index cf99dad697..0000000000 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/BalanceResult.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - * - * Created by josephj on 16/9/2021. - */ - -package com.adyen.checkout.dropin.service - -data class BalanceResult( - val balance: String, - val transactionLimit: String? -) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt index 69bf4d7ebb..26db083ac2 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt @@ -52,7 +52,7 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface private val binder = DropInBinder() private val resultLiveData: MutableLiveData = MutableLiveData() - private val balanceLiveData: MutableLiveData = MutableLiveData() + private val balanceLiveData: MutableLiveData = MutableLiveData() override fun onBind(intent: Intent?): IBinder { Logger.d(TAG, "onBind") @@ -275,17 +275,17 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface } // TODO docs - protected fun onBalanceChecked(balanceJson: String, transactionLimitJson: String?) { + protected fun onBalanceChecked(balanceJson: String) { // send response back to activity Logger.d(TAG, "onBalanceChecked called") - balanceLiveData.postValue(BalanceResult(balanceJson, transactionLimitJson)) + balanceLiveData.postValue(balanceJson) } override fun observeResult(owner: LifecycleOwner, observer: Observer) { resultLiveData.observe(owner, observer) } - override fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) { + override fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) { balanceLiveData.observe(owner, observer) } @@ -315,6 +315,6 @@ internal interface DropInServiceInterface { fun observeResult(owner: LifecycleOwner, observer: Observer) fun requestPaymentsCall(paymentComponentState: PaymentComponentState<*>) fun requestDetailsCall(actionComponentData: ActionComponentData) - fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) + fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) fun requestBalanceCall(paymentMethodData: PaymentMethodDetails) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index deddb0be83..7e77b2f72c 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -39,7 +39,6 @@ import com.adyen.checkout.dropin.DropIn import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.DropInPrefs import com.adyen.checkout.dropin.R -import com.adyen.checkout.dropin.service.BalanceResult import com.adyen.checkout.dropin.service.DropInService import com.adyen.checkout.dropin.service.DropInServiceInterface import com.adyen.checkout.dropin.service.DropInServiceResult @@ -505,10 +504,10 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } } - private fun handleBalanceResult(balanceResult: BalanceResult) { - Logger.d(TAG, "handleBalanceResult - balance: ${balanceResult.balance} - transactionLimit: ${balanceResult.transactionLimit}") + private fun handleBalanceResult(balanceJson: String) { + Logger.d(TAG, "handleBalanceResult") isWaitingResult = false - val result = dropInViewModel.handleBalanceResult(balanceResult) + val result = dropInViewModel.handleBalanceResult(balanceJson) when (result) { is GiftCardResult.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) is GiftCardResult.FullPayment -> handleGiftCardFullPayment(result) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 962acc42b2..fa3427b532 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -15,16 +15,17 @@ import androidx.lifecycle.ViewModel import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.components.model.payments.response.BalanceResult import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.R -import com.adyen.checkout.dropin.service.BalanceResult import com.adyen.checkout.giftcard.util.GiftCardBalanceResult import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent +import org.json.JSONException import org.json.JSONObject private val TAG = LogUtil.getTag() @@ -79,12 +80,20 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return noStored && singlePm && paymentMethodHasComponent && dropInConfiguration.skipListWhenSinglePaymentMethod } - fun handleBalanceResult(balanceResult: BalanceResult): GiftCardResult { + fun handleBalanceResult(balanceJson: String): GiftCardResult { + val balanceJSONObject = try { + JSONObject(balanceJson) + } catch (e: JSONException) { + throw CheckoutException("Provided balance is not a JSON object") + } + val balanceResult = BalanceResult.SERIALIZER.deserialize(balanceJSONObject) Logger.d(TAG, "handleBalanceResult - balance: ${balanceResult.balance} - transactionLimit: ${balanceResult.transactionLimit}") + val balance = Amount.SERIALIZER.deserialize(JSONObject(balanceResult.balance)) + val transactionLimitString = balanceResult.transactionLimit val transactionLimit = - if (balanceResult.transactionLimit == null) null - else Amount.SERIALIZER.deserialize(JSONObject(balanceResult.transactionLimit)) + if (transactionLimitString == null) null + else Amount.SERIALIZER.deserialize(JSONObject(transactionLimitString)) val giftCardBalanceResult = GiftCardBalanceUtils.checkBalance( balance = balance, transactionLimit = transactionLimit, diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index 71631fc7d0..a376619a69 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -141,13 +141,12 @@ class ExampleAsyncDropInService : DropInService() { @Suppress("NestedBlockDepth") private fun handleBalanceResponse(response: ResponseBody?) { if (response != null) { - val jsonResponse = JSONObject(response.string()) + val balanceJson = response.string() + val jsonResponse = JSONObject(balanceJson) val resultCode = jsonResponse.getStringOrNull("resultCode") - val balance = jsonResponse.getStringOrNull("balance") - val transactionLimit = jsonResponse.getStringOrNull("transactionLimit") - when { - resultCode == "Success" && balance != null -> onBalanceChecked(balance, transactionLimit) - resultCode == "NotEnoughBalance" -> sendResult(DropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false)) + when (resultCode) { + "Success" -> onBalanceChecked(balanceJson) + "NotEnoughBalance" -> sendResult(DropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false)) else -> sendResult(DropInServiceResult.Error(reason = resultCode, dismissDropIn = false)) } } else { From 129ec4b6600173156fbcf8bde2de6c64c7951eec Mon Sep 17 00:00:00 2001 From: jreij Date: Tue, 26 Oct 2021 11:03:57 +0200 Subject: [PATCH 020/102] Updating gift card component with rebased changes --- .../dropin/ComponentParsingProvider.kt | 2 +- .../checkout/dropin/ui/DropInActivity.kt | 4 ++-- .../checkout/giftcard/GiftCardComponent.kt | 4 +++- .../giftcard/GiftCardComponentProvider.kt | 19 ++++++++++++++++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt index ed0c5af500..3e2c4fb1a4 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt @@ -250,7 +250,7 @@ internal fun getComponentFor( EPSComponent.PROVIDER.get(fragment, paymentMethod, epsConfig) } PaymentMethodTypes.GIFTCARD -> { - val giftcardConfiguration: GiftCardConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.GIFTCARD, context) + val giftcardConfiguration: GiftCardConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.GIFTCARD) GiftCardComponent.PROVIDER.get(fragment, paymentMethod, giftcardConfiguration) } PaymentMethodTypes.GOOGLE_PAY -> { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 7e77b2f72c..61879fbb52 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -388,7 +388,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot balanceDataQueue = paymentComponentState return } - isWaitingResult = true + dropInViewModel.isWaitingResult = true setLoading(true) dropInService?.requestBalanceCall(paymentMethod) } @@ -506,7 +506,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleBalanceResult(balanceJson: String) { Logger.d(TAG, "handleBalanceResult") - isWaitingResult = false + dropInViewModel.isWaitingResult = false val result = dropInViewModel.handleBalanceResult(balanceJson) when (result) { is GiftCardResult.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt index 4afafd94a3..68d9b8b2be 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt @@ -7,6 +7,7 @@ */ package com.adyen.checkout.giftcard +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.adyen.checkout.components.GenericComponentState import com.adyen.checkout.components.PaymentComponentProvider @@ -36,12 +37,13 @@ private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.GIFTCARD) * @param configuration [GiftCardConfiguration] */ class GiftCardComponent( + savedStateHandle: SavedStateHandle, private val paymentMethodDelegate: GenericPaymentMethodDelegate, configuration: GiftCardConfiguration, private val publicKeyRepository: PublicKeyRepository ) : BasePaymentComponent>(paymentMethodDelegate, configuration) { + GenericComponentState>(savedStateHandle, paymentMethodDelegate, configuration) { companion object { @JvmStatic diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt index 2522f5c479..731ba39793 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentProvider.kt @@ -7,8 +7,10 @@ */ package com.adyen.checkout.giftcard +import android.os.Bundle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStoreOwner +import androidx.savedstate.SavedStateRegistryOwner import com.adyen.checkout.components.PaymentComponentProvider import com.adyen.checkout.components.base.GenericPaymentMethodDelegate import com.adyen.checkout.components.base.lifecycle.viewModelFactory @@ -16,14 +18,25 @@ import com.adyen.checkout.components.model.paymentmethods.PaymentMethod import com.adyen.checkout.components.repository.PublicKeyRepository class GiftCardComponentProvider : PaymentComponentProvider { - override operator fun get( - viewModelStoreOwner: ViewModelStoreOwner, + override fun get( + owner: T, paymentMethod: PaymentMethod, configuration: GiftCardConfiguration + ): GiftCardComponent where T : SavedStateRegistryOwner, T : ViewModelStoreOwner { + return get(owner, owner, paymentMethod, configuration, null) + } + + override fun get( + savedStateRegistryOwner: SavedStateRegistryOwner, + viewModelStoreOwner: ViewModelStoreOwner, + paymentMethod: PaymentMethod, + configuration: GiftCardConfiguration, + defaultArgs: Bundle? ): GiftCardComponent { val publicKeyRepository = PublicKeyRepository() - val giftCardFactory = viewModelFactory { + val giftCardFactory = viewModelFactory(savedStateRegistryOwner, defaultArgs) { savedStateHandle -> GiftCardComponent( + savedStateHandle, GenericPaymentMethodDelegate(paymentMethod), configuration, publicKeyRepository From 05ba71b6d0084541c8f47b7a87d72799d54dd3f6 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 1 Oct 2021 11:49:34 +0200 Subject: [PATCH 021/102] Make PaymentMethodAdapter click callback optional --- .../ui/paymentmethods/PaymentMethodAdapter.kt | 13 +++++++++---- .../PaymentMethodListDialogFragment.kt | 19 +++++++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt index 06aef8c556..5dc1d34cb9 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt @@ -26,10 +26,15 @@ import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Compani @SuppressWarnings("TooManyFunctions") class PaymentMethodAdapter( private val paymentMethods: List, - private val imageLoader: ImageLoader, - private val onPaymentMethodSelectedCallback: OnPaymentMethodSelectedCallback + private val imageLoader: ImageLoader ) : RecyclerView.Adapter() { + private var onPaymentMethodSelectedCallback: OnPaymentMethodSelectedCallback? = null + + fun setPaymentMethodSelectedCallback(onPaymentMethodSelectedCallback: OnPaymentMethodSelectedCallback) { + this.onPaymentMethodSelectedCallback = onPaymentMethodSelectedCallback + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { return when (viewType) { PAYMENT_METHODS_HEADER -> HeaderVH(getView(parent, R.layout.payment_methods_list_header)) @@ -114,11 +119,11 @@ class PaymentMethodAdapter( } private fun onStoredPaymentMethodClick(storedPaymentMethodModel: StoredPaymentMethodModel) { - onPaymentMethodSelectedCallback.onStoredPaymentMethodSelected(storedPaymentMethodModel) + onPaymentMethodSelectedCallback?.onStoredPaymentMethodSelected(storedPaymentMethodModel) } private fun onPaymentMethodClick(paymentMethod: PaymentMethodModel) { - onPaymentMethodSelectedCallback.onPaymentMethodSelected(paymentMethod) + onPaymentMethodSelectedCallback?.onPaymentMethodSelected(paymentMethod) } private fun getView(parent: ViewGroup, id: Int): View { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt index 3aa427c3fb..b58ab220e5 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt @@ -61,21 +61,20 @@ class PaymentMethodListDialogFragment : DropInBottomSheetDialogFragment(), Payme private fun addObserver(recyclerView: RecyclerView) { paymentMethodsListViewModel.paymentMethodsLiveData.observe( viewLifecycleOwner, - { + { paymentMethods -> Logger.d(TAG, "paymentMethods changed") - if (it == null) { + if (paymentMethods == null) { throw CheckoutException("List of PaymentMethodModel is null.") } - // We expect the list of payment methods to be updated only once, so we just set the adapter - paymentMethodAdapter = PaymentMethodAdapter( - it, - ImageLoader.getInstance( - requireContext(), - dropInViewModel.dropInConfiguration.environment - ), - this + val imageLoader = ImageLoader.getInstance( + requireContext(), + dropInViewModel.dropInConfiguration.environment ) + + // We expect the list of payment methods to be updated only once, so we just set the adapter + paymentMethodAdapter = PaymentMethodAdapter(paymentMethods, imageLoader) + paymentMethodAdapter.setPaymentMethodSelectedCallback(this) recyclerView.layoutManager = LinearLayoutManager(requireContext()) recyclerView.adapter = paymentMethodAdapter } From a6863be1a3bde89b471507c4e214cd03490a853c Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 11 Nov 2021 11:34:51 +0100 Subject: [PATCH 022/102] Add todo for DropInService live data --- .../main/java/com/adyen/checkout/dropin/service/DropInService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt index 26db083ac2..5a2828a463 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt @@ -51,6 +51,7 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface private val binder = DropInBinder() + // TODO change LiveData into channel/flow to support single events? private val resultLiveData: MutableLiveData = MutableLiveData() private val balanceLiveData: MutableLiveData = MutableLiveData() From bf0313cc9febebc07cff8cf3993155a436a37ca7 Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 11 Nov 2021 14:55:28 +0100 Subject: [PATCH 023/102] Cache gift card object in DropInViewModel --- .../checkout/dropin/ui/DropInActivity.kt | 24 ++++----- .../checkout/dropin/ui/DropInViewModel.kt | 44 +++++++++++----- .../base/DropInBottomSheetDialogFragment.kt | 3 +- .../GiftCardComponentDialogFragment.kt | 4 ++ .../ui/giftcard/GiftCardBalanceUIState.kt | 18 +++++++ .../checkout/giftcard/GiftCardComponent.kt | 34 ++++++++++--- .../giftcard/GiftCardComponentState.kt | 50 +++++++++++++++++++ .../adyen/checkout/giftcard/GiftCardView.kt | 4 +- 8 files changed, 144 insertions(+), 37 deletions(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt create mode 100644 giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentState.kt diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 61879fbb52..6c88d57744 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -47,8 +47,10 @@ import com.adyen.checkout.dropin.ui.base.DropInBottomSheetDialogFragment import com.adyen.checkout.dropin.ui.component.CardComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GenericComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GiftCardComponentDialogFragment +import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceUIState import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListDialogFragment import com.adyen.checkout.dropin.ui.stored.PreselectedStoredPaymentMethodFragment +import com.adyen.checkout.giftcard.GiftCardComponentState import com.adyen.checkout.googlepay.GooglePayComponent import com.adyen.checkout.googlepay.GooglePayComponentState import com.adyen.checkout.googlepay.GooglePayConfiguration @@ -98,7 +100,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot // these queues exist for when a call is requested before the service is bound private var paymentDataQueue: PaymentComponentState<*>? = null private var actionDataQueue: ActionComponentData? = null - private var balanceDataQueue: PaymentComponentState<*>? = null + private var balanceDataQueue: GiftCardComponentState? = null private val serviceConnection = object : ServiceConnection { @@ -376,16 +378,12 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot googlePayComponent.startGooglePayScreen(this, GOOGLE_PAY_REQUEST_CODE) } - override fun requestBalanceCall(paymentComponentState: PaymentComponentState<*>) { + override fun requestBalanceCall(giftCardComponentState: GiftCardComponentState) { Logger.d(TAG, "requestCheckBalanceCall") - val paymentMethod = paymentComponentState.data.paymentMethod - if (paymentMethod == null) { - Logger.e(TAG, "requestBalanceCall - paymentMethod is null") - return - } + val paymentMethod = dropInViewModel.onBalanceCallRequested(giftCardComponentState) ?: return if (dropInService == null) { Logger.e(TAG, "requestBalanceCall - service is disconnected") - balanceDataQueue = paymentComponentState + balanceDataQueue = giftCardComponentState return } dropInViewModel.isWaitingResult = true @@ -509,19 +507,19 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot dropInViewModel.isWaitingResult = false val result = dropInViewModel.handleBalanceResult(balanceJson) when (result) { - is GiftCardResult.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) - is GiftCardResult.FullPayment -> handleGiftCardFullPayment(result) - is GiftCardResult.PartialPayment -> handleGiftCardPartialPayment(result) + is GiftCardBalanceUIState.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) + is GiftCardBalanceUIState.FullPayment -> handleGiftCardFullPayment(result) + is GiftCardBalanceUIState.PartialPayment -> handleGiftCardPartialPayment(result) } } - private fun handleGiftCardFullPayment(fullPayment: GiftCardResult.FullPayment) { + private fun handleGiftCardFullPayment(fullPayment: GiftCardBalanceUIState.FullPayment) { // TODO move this somewhere else later? setLoading(false) // TODO handle full payment } - private fun handleGiftCardPartialPayment(partialPayment: GiftCardResult.PartialPayment) { + private fun handleGiftCardPartialPayment(partialPayment: GiftCardBalanceUIState.PartialPayment) { // TODO move this somewhere else later? setLoading(false) // TODO handle partial payment diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index fa3427b532..79e6cf8e35 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -9,12 +9,12 @@ package com.adyen.checkout.dropin.ui import android.content.Intent -import androidx.annotation.StringRes import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.components.model.payments.response.BalanceResult import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException @@ -22,6 +22,8 @@ import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.R +import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceUIState +import com.adyen.checkout.giftcard.GiftCardComponentState import com.adyen.checkout.giftcard.util.GiftCardBalanceResult import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent @@ -34,6 +36,7 @@ private const val PAYMENT_METHODS_RESPONSE_KEY = "PAYMENT_METHODS_RESPONSE_KEY" private const val DROP_IN_CONFIGURATION_KEY = "DROP_IN_CONFIGURATION_KEY" private const val DROP_IN_RESULT_INTENT_KEY = "DROP_IN_RESULT_INTENT_KEY" private const val IS_WAITING_FOR_RESULT_KEY = "IS_WAITING_FOR_RESULT_KEY" +private const val CACHED_GIFT_CARD = "CACHED_GIFT_CARD" class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { @@ -49,6 +52,14 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode savedStateHandle[IS_WAITING_FOR_RESULT_KEY] = value } + private var cachedGiftCardComponentState: GiftCardComponentState? + get() { + return savedStateHandle.get(CACHED_GIFT_CARD) + } + set(value) { + savedStateHandle[CACHED_GIFT_CARD] = value + } + private fun getStateValueOrFail(key: String): T { val value: T? = savedStateHandle[key] if (value == null) { @@ -80,7 +91,20 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return noStored && singlePm && paymentMethodHasComponent && dropInConfiguration.skipListWhenSinglePaymentMethod } - fun handleBalanceResult(balanceJson: String): GiftCardResult { + /** + * @return the payment method details required to request the balance, or null if invalid + */ + fun onBalanceCallRequested(giftCardComponentState: GiftCardComponentState): PaymentMethodDetails? { + val paymentMethod = giftCardComponentState.data.paymentMethod + if (paymentMethod == null) { + Logger.e(TAG, "onBalanceCallRequested - paymentMethod is null") + return null + } + cachedGiftCardComponentState = giftCardComponentState + return paymentMethod + } + + fun handleBalanceResult(balanceJson: String): GiftCardBalanceUIState { val balanceJSONObject = try { JSONObject(balanceJson) } catch (e: JSONException) { @@ -102,21 +126,21 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return when (giftCardBalanceResult) { is GiftCardBalanceResult.ZeroBalance -> { Logger.i(TAG, "handleBalanceResult - Gift Card has zero balance") - GiftCardResult.Error(R.string.checkout_giftcard_error_zero_balance, "Gift Card has zero balance", false) + GiftCardBalanceUIState.Error(R.string.checkout_giftcard_error_zero_balance, "Gift Card has zero balance", false) } is GiftCardBalanceResult.NonMatchingCurrencies -> { Logger.e(TAG, "handleBalanceResult - Gift Card currency mismatch") - GiftCardResult.Error(R.string.checkout_giftcard_error_currency, "Gift Card currency mismatch", false) + GiftCardBalanceUIState.Error(R.string.checkout_giftcard_error_currency, "Gift Card currency mismatch", false) } is GiftCardBalanceResult.ZeroAmountToBePaid -> { Logger.e(TAG, "handleBalanceResult - You must set an amount in DropInConfiguration.Builder to enable gift card payments") - GiftCardResult.Error(R.string.payment_failed, "Drop-in amount is not set", true) + GiftCardBalanceUIState.Error(R.string.payment_failed, "Drop-in amount is not set", true) } is GiftCardBalanceResult.FullPayment -> { - GiftCardResult.FullPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) + GiftCardBalanceUIState.FullPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) } is GiftCardBalanceResult.PartialPayment -> { - GiftCardResult.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) + GiftCardBalanceUIState.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) } } } @@ -136,9 +160,3 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode } } } - -sealed class GiftCardResult { - class FullPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardResult() - class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardResult() - class Error(@StringRes val errorMessage: Int, val reason: String, val terminateDropIn: Boolean) : GiftCardResult() -} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt index 87e10d54ef..e81070b38c 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt @@ -22,6 +22,7 @@ import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.R import com.adyen.checkout.dropin.ui.DropInViewModel +import com.adyen.checkout.giftcard.GiftCardComponentState import com.adyen.checkout.googlepay.GooglePayConfiguration import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog @@ -98,6 +99,6 @@ abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragment() { fun showError(errorMessage: String, reason: String, terminate: Boolean) fun terminateDropIn() fun startGooglePay(paymentMethod: PaymentMethod, googlePayConfiguration: GooglePayConfiguration) - fun requestBalanceCall(paymentComponentState: PaymentComponentState<*>) + fun requestBalanceCall(giftCardComponentState: GiftCardComponentState) } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt index 4d8ce23daa..9f7c195ed5 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GiftCardComponentDialogFragment.kt @@ -27,6 +27,7 @@ import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.databinding.FragmentGiftcardComponentBinding import com.adyen.checkout.dropin.getViewFor import com.adyen.checkout.dropin.ui.base.BaseComponentDialogFragment +import com.adyen.checkout.giftcard.GiftCardComponentState import com.google.android.material.bottomsheet.BottomSheetBehavior class GiftCardComponentDialogFragment : BaseComponentDialogFragment() { @@ -89,6 +90,9 @@ class GiftCardComponentDialogFragment : BaseComponentDialogFragment() { } override fun requestProtocolCall(componentState: PaymentComponentState) { + if (componentState !is GiftCardComponentState) { + throw CheckoutException("Unsupported payment method, not a gift card: $componentState") + } protocol.requestBalanceCall(componentState) } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt new file mode 100644 index 0000000000..2b69338140 --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 11/11/2021. + */ + +package com.adyen.checkout.dropin.ui.giftcard + +import androidx.annotation.StringRes +import com.adyen.checkout.components.model.payments.Amount + +sealed class GiftCardBalanceUIState { + class FullPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceUIState() + class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceUIState() + class Error(@StringRes val errorMessage: Int, val reason: String, val terminateDropIn: Boolean) : GiftCardBalanceUIState() +} diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt index 68d9b8b2be..2b83a3d05a 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt @@ -9,7 +9,6 @@ package com.adyen.checkout.giftcard import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope -import com.adyen.checkout.components.GenericComponentState import com.adyen.checkout.components.PaymentComponentProvider import com.adyen.checkout.components.base.BasePaymentComponent import com.adyen.checkout.components.base.GenericPaymentMethodDelegate @@ -30,6 +29,8 @@ private val TAG = LogUtil.getTag() private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.GIFTCARD) +private const val LAST_FOUR_LENGTH = 4 + /** * Component should not be instantiated directly. Instead use the PROVIDER object. * @@ -42,8 +43,11 @@ class GiftCardComponent( configuration: GiftCardConfiguration, private val publicKeyRepository: PublicKeyRepository ) : - BasePaymentComponent>(savedStateHandle, paymentMethodDelegate, configuration) { + BasePaymentComponent( + savedStateHandle, + paymentMethodDelegate, + configuration + ) { companion object { @JvmStatic @@ -75,7 +79,7 @@ class GiftCardComponent( return GiftCardOutputData(cardNumber = inputData.cardNumber, pin = inputData.pin) } - override fun createComponentState(): GenericComponentState { + override fun createComponentState(): GiftCardComponentState { val unencryptedCardBuilder = UnencryptedCard.Builder() val outputData = outputData val paymentComponentData = PaymentComponentData() @@ -86,7 +90,12 @@ class GiftCardComponent( if (outputData?.isValid != true || publicKey == null) { val isInputValid = outputData?.isValid ?: false val isReady = publicKey != null - return GenericComponentState(paymentComponentData, isInputValid, isReady) + return GiftCardComponentState( + paymentComponentData = paymentComponentData, + isInputValid = isInputValid, + isReady = isReady, + lastFourDigits = null + ) } val encryptedCard = try { unencryptedCardBuilder.setNumber(outputData.giftcardNumberFieldState.value) @@ -94,7 +103,12 @@ class GiftCardComponent( CardEncrypter.encryptFields(unencryptedCardBuilder.build(), publicKey) } catch (e: EncryptionException) { notifyException(e) - return GenericComponentState(paymentComponentData, false, true) + return GiftCardComponentState( + paymentComponentData = paymentComponentData, + isInputValid = false, + isReady = true, + lastFourDigits = null + ) } val giftCardPaymentMethod = GiftCardPaymentMethod().apply { @@ -104,7 +118,13 @@ class GiftCardComponent( brand = paymentMethodDelegate.paymentMethod.brand } paymentComponentData.paymentMethod = giftCardPaymentMethod - return GenericComponentState(paymentComponentData, true, true) + val lastFour = outputData.giftcardNumberFieldState.value.takeLast(LAST_FOUR_LENGTH) + return GiftCardComponentState( + paymentComponentData = paymentComponentData, + isInputValid = true, + isReady = true, + lastFourDigits = lastFour + ) } override fun getSupportedPaymentMethodTypes(): Array = PAYMENT_METHOD_TYPES diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentState.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentState.kt new file mode 100644 index 0000000000..bdc0e6076d --- /dev/null +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponentState.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 11/11/2021. + */ +package com.adyen.checkout.giftcard + +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.PaymentComponentState +import com.adyen.checkout.components.model.payments.request.GiftCardPaymentMethod +import com.adyen.checkout.components.model.payments.request.PaymentComponentData +import com.adyen.checkout.core.util.ParcelUtils + +/** + * PaymentComponentState for GiftCardComponent with additional data. + */ +class GiftCardComponentState( + paymentComponentData: PaymentComponentData, + isInputValid: Boolean, + isReady: Boolean, + val lastFourDigits: String? +) : PaymentComponentState(paymentComponentData, isInputValid, isReady), Parcelable { + + private constructor(parcel: Parcel) : this( + paymentComponentData = parcel.readParcelable(PaymentComponentData::class.java.classLoader)!!, + isInputValid = ParcelUtils.readBoolean(parcel), + isReady = ParcelUtils.readBoolean(parcel), + lastFourDigits = parcel.readString() + ) + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeParcelable(data, flags) + ParcelUtils.writeBoolean(dest, isInputValid) + ParcelUtils.writeBoolean(dest, isReady) + dest.writeString(lastFourDigits) + } + + override fun describeContents() = Parcelable.CONTENTS_FILE_DESCRIPTOR + + companion object { + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = GiftCardComponentState(source) + override fun newArray(size: Int) = arrayOfNulls(size) + } + } +} diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt index 318c278070..1123d0db2a 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardView.kt @@ -16,8 +16,6 @@ import android.view.View import android.view.View.OnFocusChangeListener import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer -import com.adyen.checkout.components.GenericComponentState -import com.adyen.checkout.components.model.payments.request.GiftCardPaymentMethod import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.core.log.LogUtil @@ -27,7 +25,7 @@ import com.adyen.checkout.giftcard.databinding.GiftcardViewBinding private val TAG = LogUtil.getTag() class GiftCardView : - AdyenLinearLayout, GiftCardComponent>, + AdyenLinearLayout, Observer { private val binding: GiftcardViewBinding = GiftcardViewBinding.inflate(LayoutInflater.from(context), this) From 94251d31e78af8c38ca7a5b3ce652fa14a913b41 Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 11 Nov 2021 15:24:35 +0100 Subject: [PATCH 024/102] Update strings --- drop-in/src/main/res/template/values/strings.xml.tt | 1 + drop-in/src/main/res/values-cs-rCZ/strings.xml | 1 + drop-in/src/main/res/values-da-rDK/strings.xml | 1 + drop-in/src/main/res/values-de-rDE/strings.xml | 1 + drop-in/src/main/res/values-el-rGR/strings.xml | 1 + drop-in/src/main/res/values-es-rES/strings.xml | 1 + drop-in/src/main/res/values-fi-rFI/strings.xml | 1 + drop-in/src/main/res/values-fr-rFR/strings.xml | 1 + drop-in/src/main/res/values-hr-rHR/strings.xml | 1 + drop-in/src/main/res/values-hu-rHU/strings.xml | 1 + drop-in/src/main/res/values-it-rIT/strings.xml | 1 + drop-in/src/main/res/values-ja-rJP/strings.xml | 1 + drop-in/src/main/res/values-ko-rKR/strings.xml | 1 + drop-in/src/main/res/values-nb-rNO/strings.xml | 1 + drop-in/src/main/res/values-nl-rNL/strings.xml | 1 + drop-in/src/main/res/values-pl-rPL/strings.xml | 1 + drop-in/src/main/res/values-pt-rBR/strings.xml | 1 + drop-in/src/main/res/values-ro-rRO/strings.xml | 1 + drop-in/src/main/res/values-ru-rRU/strings.xml | 1 + drop-in/src/main/res/values-sk-rSK/strings.xml | 1 + drop-in/src/main/res/values-sl-rSI/strings.xml | 1 + drop-in/src/main/res/values-sv-rSE/strings.xml | 1 + drop-in/src/main/res/values-zh-rCN/strings.xml | 1 + drop-in/src/main/res/values-zh-rTW/strings.xml | 1 + drop-in/src/main/res/values/strings.xml | 1 + 25 files changed, 25 insertions(+) diff --git a/drop-in/src/main/res/template/values/strings.xml.tt b/drop-in/src/main/res/template/values/strings.xml.tt index ccbf243cd6..7ec3787582 100644 --- a/drop-in/src/main/res/template/values/strings.xml.tt +++ b/drop-in/src/main/res/template/values/strings.xml.tt @@ -24,4 +24,5 @@ %%applyGiftcard%% %%error.giftcard.no-balance%% %%error.giftcard.currency-error%% + %%partialPayment.remainingBalance%% diff --git a/drop-in/src/main/res/values-cs-rCZ/strings.xml b/drop-in/src/main/res/values-cs-rCZ/strings.xml index c52e3e1ba8..291c765c3b 100644 --- a/drop-in/src/main/res/values-cs-rCZ/strings.xml +++ b/drop-in/src/main/res/values-cs-rCZ/strings.xml @@ -24,4 +24,5 @@ Uplatnit Na dárkové kartě je nulový zůstatek Dárkové karty jsou platné jenom v měně, ve které byly vystavené + Zbývající zůstatek bude %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-da-rDK/strings.xml b/drop-in/src/main/res/values-da-rDK/strings.xml index 47097f5c06..f30d22f242 100644 --- a/drop-in/src/main/res/values-da-rDK/strings.xml +++ b/drop-in/src/main/res/values-da-rDK/strings.xml @@ -24,4 +24,5 @@ Indløs Saldoen på gavekortet er 0 Gavekort er kun gyldige i udstedelsesvalutaen + Restbeløbet vil være %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-de-rDE/strings.xml b/drop-in/src/main/res/values-de-rDE/strings.xml index 2920ebb40a..df5ea552c0 100644 --- a/drop-in/src/main/res/values-de-rDE/strings.xml +++ b/drop-in/src/main/res/values-de-rDE/strings.xml @@ -24,4 +24,5 @@ Einlösen Auf dieser Geschenkkarte ist kein Guthaben vorhanden Geschenkkarten sind nur in der Währung gültig, in der sie ausgestellt wurden + Es verbleibt ein Restbetrag von %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-el-rGR/strings.xml b/drop-in/src/main/res/values-el-rGR/strings.xml index e2017440b8..bcfa0b1886 100644 --- a/drop-in/src/main/res/values-el-rGR/strings.xml +++ b/drop-in/src/main/res/values-el-rGR/strings.xml @@ -24,4 +24,5 @@ Εξαργύρωση Η συγκεκριμένη δωροκάρτα έχει μηδενικό υπόλοιπο Οι δωροκάρτες ισχύουν μόνο για το νόμισμα στο οποίο εκδόθηκαν + Το υπόλοιπο θα είναι %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-es-rES/strings.xml b/drop-in/src/main/res/values-es-rES/strings.xml index 110806dad8..01bfc5d171 100644 --- a/drop-in/src/main/res/values-es-rES/strings.xml +++ b/drop-in/src/main/res/values-es-rES/strings.xml @@ -24,4 +24,5 @@ Canjear Esta tarjeta regalo no tiene saldo Las tarjetas regalo solo son válidas en la moneda en que fueron emitidas + El saldo restante será %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-fi-rFI/strings.xml b/drop-in/src/main/res/values-fi-rFI/strings.xml index df67206eeb..bd44c2f892 100644 --- a/drop-in/src/main/res/values-fi-rFI/strings.xml +++ b/drop-in/src/main/res/values-fi-rFI/strings.xml @@ -24,4 +24,5 @@ Lunasta Lahjakortin saldo on nolla Gift cards are only valid in the currency they were issued in + Jäljellä oleva saldo on %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-fr-rFR/strings.xml b/drop-in/src/main/res/values-fr-rFR/strings.xml index b4587ba26d..dc7caceed7 100644 --- a/drop-in/src/main/res/values-fr-rFR/strings.xml +++ b/drop-in/src/main/res/values-fr-rFR/strings.xml @@ -24,4 +24,5 @@ Utiliser Aucun solde n\'est disponible sur cette carte cadeau Les cartes cadeaux sont valables uniquement dans la devise dans laquelle elles ont été émises + Le solde restant sera de %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-hr-rHR/strings.xml b/drop-in/src/main/res/values-hr-rHR/strings.xml index 95d88c917b..45eb0990be 100644 --- a/drop-in/src/main/res/values-hr-rHR/strings.xml +++ b/drop-in/src/main/res/values-hr-rHR/strings.xml @@ -24,4 +24,5 @@ Iskoristite Stanje na ovoj poklon-kartici iznosi nula Poklon-kartice vrijede samo u valuti u kojoj su izdane + Preostalo stanje na računu iznosit će %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-hu-rHU/strings.xml b/drop-in/src/main/res/values-hu-rHU/strings.xml index 0645eb1088..14ca014770 100644 --- a/drop-in/src/main/res/values-hu-rHU/strings.xml +++ b/drop-in/src/main/res/values-hu-rHU/strings.xml @@ -24,4 +24,5 @@ Beváltás Az ajándékkártya egyenlege nulla Az ajándékkártyák csak abban a pénznemben érvényesek, amelyre kiállították azokat + A fennmaradó egyenleg %s lesz \ No newline at end of file diff --git a/drop-in/src/main/res/values-it-rIT/strings.xml b/drop-in/src/main/res/values-it-rIT/strings.xml index e6b1c54116..5970bc450c 100644 --- a/drop-in/src/main/res/values-it-rIT/strings.xml +++ b/drop-in/src/main/res/values-it-rIT/strings.xml @@ -24,4 +24,5 @@ Riscatta Questo buono regalo ha un saldo pari a zero I buono regalo sono validi solo nella valuta in cui sono state emessi + Il saldo rimanente sarà di %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-ja-rJP/strings.xml b/drop-in/src/main/res/values-ja-rJP/strings.xml index 5ecd6d6091..3361edcb9c 100644 --- a/drop-in/src/main/res/values-ja-rJP/strings.xml +++ b/drop-in/src/main/res/values-ja-rJP/strings.xml @@ -24,4 +24,5 @@ 利用する このギフトカードの残高はゼロです ギフトカードは、発行された通貨でのみ有効です。 + 残りの残高は%sになります \ No newline at end of file diff --git a/drop-in/src/main/res/values-ko-rKR/strings.xml b/drop-in/src/main/res/values-ko-rKR/strings.xml index 7987ddfb35..571360b41c 100644 --- a/drop-in/src/main/res/values-ko-rKR/strings.xml +++ b/drop-in/src/main/res/values-ko-rKR/strings.xml @@ -24,4 +24,5 @@ 기프트 카드로 결제 이 기프트 카드에는 잔액이 없습니다 기프트 카드는 발급된 통화로만 사용하실 수 있습니다 + 남은 잔액은 %s입니다 \ No newline at end of file diff --git a/drop-in/src/main/res/values-nb-rNO/strings.xml b/drop-in/src/main/res/values-nb-rNO/strings.xml index 3aeb72db4c..c6bcf37d56 100644 --- a/drop-in/src/main/res/values-nb-rNO/strings.xml +++ b/drop-in/src/main/res/values-nb-rNO/strings.xml @@ -24,4 +24,5 @@ Løs inn Dette gavekortet har en saldo på null Gavekort er kun gyldige i den valutaen de ble utstedt i + Gjenværende saldo vil være %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-nl-rNL/strings.xml b/drop-in/src/main/res/values-nl-rNL/strings.xml index fa241aecc2..ced9f8f450 100644 --- a/drop-in/src/main/res/values-nl-rNL/strings.xml +++ b/drop-in/src/main/res/values-nl-rNL/strings.xml @@ -24,4 +24,5 @@ Inwisselen Deze cadeaukaart heeft geen saldo Cadeaukaarten zijn alleen geldig in de valuta waarin ze zijn uitgegeven + Het resterende saldo is %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-pl-rPL/strings.xml b/drop-in/src/main/res/values-pl-rPL/strings.xml index 95ed1f3f20..da03662cf7 100644 --- a/drop-in/src/main/res/values-pl-rPL/strings.xml +++ b/drop-in/src/main/res/values-pl-rPL/strings.xml @@ -24,4 +24,5 @@ Wykorzystaj Saldo karty podarunkowej jest puste Karty podarunkowe są ważne tylko w walucie, w której zostały wydane + Pozostałe saldo wynosi %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-pt-rBR/strings.xml b/drop-in/src/main/res/values-pt-rBR/strings.xml index 7947254a31..217d23d4ba 100644 --- a/drop-in/src/main/res/values-pt-rBR/strings.xml +++ b/drop-in/src/main/res/values-pt-rBR/strings.xml @@ -24,4 +24,5 @@ Resgatar Este vale-presente tem saldo zero Os vales-presente são válidos somente na moeda em que foram emitidos + O saldo restante será %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-ro-rRO/strings.xml b/drop-in/src/main/res/values-ro-rRO/strings.xml index 4ddbe2b45d..0bd2e1686f 100644 --- a/drop-in/src/main/res/values-ro-rRO/strings.xml +++ b/drop-in/src/main/res/values-ro-rRO/strings.xml @@ -24,4 +24,5 @@ Valorificare Acest card cadou are soldul zero Cardurile cadou sunt valabile numai în moneda în care au fost emise + Soldul rămas va fi de %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-ru-rRU/strings.xml b/drop-in/src/main/res/values-ru-rRU/strings.xml index b220c4b727..e9e027550c 100644 --- a/drop-in/src/main/res/values-ru-rRU/strings.xml +++ b/drop-in/src/main/res/values-ru-rRU/strings.xml @@ -24,4 +24,5 @@ Использовать На этой подарочной карте нет средств Принимаются только подарочные карты соответствующей валюты + Остаток на балансе составит %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-sk-rSK/strings.xml b/drop-in/src/main/res/values-sk-rSK/strings.xml index 617afbed8f..54eca8d694 100644 --- a/drop-in/src/main/res/values-sk-rSK/strings.xml +++ b/drop-in/src/main/res/values-sk-rSK/strings.xml @@ -24,4 +24,5 @@ Uplatniť Táto darčeková karta má nulový zostatok Darčekové karty sú platné iba v mene, v ktorej boli vydané + Zvyšný zostatok bude %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-sl-rSI/strings.xml b/drop-in/src/main/res/values-sl-rSI/strings.xml index 464e515e20..88aad46c8f 100644 --- a/drop-in/src/main/res/values-sl-rSI/strings.xml +++ b/drop-in/src/main/res/values-sl-rSI/strings.xml @@ -24,4 +24,5 @@ Unovči Na tej darilni kartici ni sredstev Darilne kartice so veljavne samo za valuto, za katero so bile izdane + Preostalo stanje bo %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-sv-rSE/strings.xml b/drop-in/src/main/res/values-sv-rSE/strings.xml index 919dc89d45..6436c90d2c 100644 --- a/drop-in/src/main/res/values-sv-rSE/strings.xml +++ b/drop-in/src/main/res/values-sv-rSE/strings.xml @@ -24,4 +24,5 @@ Lös in Saldot för detta presentkort är noll Presentkort är endast giltiga i den valuta som de utfärdades i + Återstående saldo blir %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rCN/strings.xml b/drop-in/src/main/res/values-zh-rCN/strings.xml index 6b8ef1b4bd..60ec5770f7 100644 --- a/drop-in/src/main/res/values-zh-rCN/strings.xml +++ b/drop-in/src/main/res/values-zh-rCN/strings.xml @@ -24,4 +24,5 @@ 兑换 礼品卡余额为零 礼品卡仅以其发行的货币为有效货币 + 剩余额度为 %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rTW/strings.xml b/drop-in/src/main/res/values-zh-rTW/strings.xml index 9ddb1308d2..2343d72d33 100644 --- a/drop-in/src/main/res/values-zh-rTW/strings.xml +++ b/drop-in/src/main/res/values-zh-rTW/strings.xml @@ -24,4 +24,5 @@ 兌換 此禮品卡的餘額為零 禮品卡只能以其簽發時所使用的貨幣進行結算 + 餘額將為 %s \ No newline at end of file diff --git a/drop-in/src/main/res/values/strings.xml b/drop-in/src/main/res/values/strings.xml index 2211acfbdd..096bdb48c0 100644 --- a/drop-in/src/main/res/values/strings.xml +++ b/drop-in/src/main/res/values/strings.xml @@ -24,4 +24,5 @@ Redeem This gift card has zero balance Gift cards are only valid in the currency they were issued in + Remaining balance will be %s \ No newline at end of file From 1cfbca5e2b4bc3a34da1c210a019dd14922802ae Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 11 Nov 2021 16:09:35 +0100 Subject: [PATCH 025/102] Adding fragment for gift card payment confirmation --- .../checkout/dropin/ui/DropInActivity.kt | 15 ++- .../checkout/dropin/ui/DropInViewModel.kt | 19 ++- .../ui/giftcard/GiftCardBalanceUIState.kt | 2 +- .../GiftCardPaymentConfirmationData.kt | 49 +++++++ ...ftCardPaymentConfirmationDialogFragment.kt | 124 ++++++++++++++++++ .../GiftCardPaymentMethodModel.kt | 16 +++ .../ui/paymentmethods/PaymentMethodAdapter.kt | 24 ++++ .../paymentmethods/PaymentMethodListItem.kt | 1 + ...ragment_gift_card_payment_confirmation.xml | 63 +++++++++ .../layout/fragment_stored_payment_method.xml | 2 - drop-in/src/main/res/values/styles.xml | 7 + ui-core/src/main/res/values/styles.xml | 6 +- 12 files changed, 321 insertions(+), 7 deletions(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt create mode 100644 drop-in/src/main/res/layout/fragment_gift_card_payment_confirmation.xml diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 6c88d57744..2d3b6b936a 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -48,6 +48,8 @@ import com.adyen.checkout.dropin.ui.component.CardComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GenericComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GiftCardComponentDialogFragment import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceUIState +import com.adyen.checkout.dropin.ui.giftcard.GiftCardPaymentConfirmationData +import com.adyen.checkout.dropin.ui.giftcard.GiftCardPaymentConfirmationDialogFragment import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListDialogFragment import com.adyen.checkout.dropin.ui.stored.PreselectedStoredPaymentMethodFragment import com.adyen.checkout.giftcard.GiftCardComponentState @@ -66,6 +68,7 @@ private const val PAYMENT_METHODS_LIST_FRAGMENT_TAG = "PAYMENT_METHODS_LIST_FRAG private const val COMPONENT_FRAGMENT_TAG = "COMPONENT_DIALOG_FRAGMENT" private const val ACTION_FRAGMENT_TAG = "ACTION_DIALOG_FRAGMENT" private const val LOADING_FRAGMENT_TAG = "LOADING_DIALOG_FRAGMENT" +private const val GIFT_CARD_PAYMENT_CONFIRMATION_FRAGMENT_TAG = "GIFT_CARD_PAYMENT_CONFIRMATION_FRAGMENT" private const val GOOGLE_PAY_REQUEST_CODE = 1 @@ -182,7 +185,8 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot return getFragmentByTag(PRESELECTED_PAYMENT_METHOD_FRAGMENT_TAG) == null && getFragmentByTag(PAYMENT_METHODS_LIST_FRAGMENT_TAG) == null && getFragmentByTag(COMPONENT_FRAGMENT_TAG) == null && - getFragmentByTag(ACTION_FRAGMENT_TAG) == null + getFragmentByTag(ACTION_FRAGMENT_TAG) == null && + getFragmentByTag(GIFT_CARD_PAYMENT_CONFIRMATION_FRAGMENT_TAG) == null } private fun createLocalizedContext(baseContext: Context?): Context? { @@ -361,6 +365,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot hideFragmentDialog(PAYMENT_METHODS_LIST_FRAGMENT_TAG) hideFragmentDialog(COMPONENT_FRAGMENT_TAG) hideFragmentDialog(ACTION_FRAGMENT_TAG) + hideFragmentDialog(GIFT_CARD_PAYMENT_CONFIRMATION_FRAGMENT_TAG) } override fun terminateDropIn() { @@ -516,9 +521,17 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleGiftCardFullPayment(fullPayment: GiftCardBalanceUIState.FullPayment) { // TODO move this somewhere else later? setLoading(false) + showGiftCardPaymentConfirmationDialog(fullPayment.data) // TODO handle full payment } + private fun showGiftCardPaymentConfirmationDialog(data: GiftCardPaymentConfirmationData) { + Logger.d(TAG, "showGiftCardPaymentConfirmationDialog") + hideAllScreens() + GiftCardPaymentConfirmationDialogFragment.newInstance(data) + .show(supportFragmentManager, GIFT_CARD_PAYMENT_CONFIRMATION_FRAGMENT_TAG) + } + private fun handleGiftCardPartialPayment(partialPayment: GiftCardBalanceUIState.PartialPayment) { // TODO move this somewhere else later? setLoading(false) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 79e6cf8e35..49d4379413 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.R import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceUIState +import com.adyen.checkout.dropin.ui.giftcard.GiftCardPaymentConfirmationData import com.adyen.checkout.giftcard.GiftCardComponentState import com.adyen.checkout.giftcard.util.GiftCardBalanceResult import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils @@ -123,6 +124,7 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode transactionLimit = transactionLimit, amountToBePaid = dropInConfiguration.amount ) + val cachedGiftCardComponentState = cachedGiftCardComponentState ?: throw CheckoutException("Failed to retrieved cached gift card object") return when (giftCardBalanceResult) { is GiftCardBalanceResult.ZeroBalance -> { Logger.i(TAG, "handleBalanceResult - Gift Card has zero balance") @@ -137,7 +139,9 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode GiftCardBalanceUIState.Error(R.string.payment_failed, "Drop-in amount is not set", true) } is GiftCardBalanceResult.FullPayment -> { - GiftCardBalanceUIState.FullPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) + GiftCardBalanceUIState.FullPayment( + createGiftCardPaymentConfirmationData(giftCardBalanceResult, cachedGiftCardComponentState) + ) } is GiftCardBalanceResult.PartialPayment -> { GiftCardBalanceUIState.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) @@ -145,6 +149,19 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode } } + private fun createGiftCardPaymentConfirmationData( + giftCardBalanceResult: GiftCardBalanceResult.FullPayment, + giftCardComponentState: GiftCardComponentState + ): GiftCardPaymentConfirmationData { + return GiftCardPaymentConfirmationData( + amountPaid = giftCardBalanceResult.amountPaid, + remainingBalance = giftCardBalanceResult.remainingBalance, + shopperLocale = dropInConfiguration.shopperLocale, + brand = giftCardComponentState.data.paymentMethod?.brand.orEmpty(), + lastFourDigits = giftCardComponentState.lastFourDigits.orEmpty() + ) + } + companion object { fun putIntentExtras( intent: Intent, diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt index 2b69338140..ded2c13abe 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt @@ -12,7 +12,7 @@ import androidx.annotation.StringRes import com.adyen.checkout.components.model.payments.Amount sealed class GiftCardBalanceUIState { - class FullPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceUIState() + class FullPayment(val data: GiftCardPaymentConfirmationData) : GiftCardBalanceUIState() class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceUIState() class Error(@StringRes val errorMessage: Int, val reason: String, val terminateDropIn: Boolean) : GiftCardBalanceUIState() } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt new file mode 100644 index 0000000000..6667452124 --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 11/11/2021. + */ + +package com.adyen.checkout.dropin.ui.giftcard + +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.model.payments.Amount +import java.util.Locale + +data class GiftCardPaymentConfirmationData( + val amountPaid: Amount, + val remainingBalance: Amount, + val shopperLocale: Locale, + val brand: String, + val lastFourDigits: String +) : Parcelable { + private constructor(parcel: Parcel) : this( + amountPaid = parcel.readParcelable(Amount::class.java.classLoader)!!, + remainingBalance = parcel.readParcelable(Amount::class.java.classLoader)!!, + shopperLocale = parcel.readSerializable() as Locale, + brand = parcel.readString().orEmpty(), + lastFourDigits = parcel.readString().orEmpty() + ) + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeParcelable(amountPaid, flags) + dest.writeParcelable(remainingBalance, flags) + dest.writeSerializable(shopperLocale) + dest.writeString(brand) + dest.writeString(lastFourDigits) + } + + override fun describeContents() = Parcelable.CONTENTS_FILE_DESCRIPTOR + + + companion object { + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = GiftCardPaymentConfirmationData(source) + override fun newArray(size: Int) = arrayOfNulls(size) + } + } +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt new file mode 100644 index 0000000000..fde077ec8a --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 1/10/2021. + */ + +package com.adyen.checkout.dropin.ui.giftcard + +import android.content.Context +import android.content.DialogInterface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import com.adyen.checkout.components.api.ImageLoader +import com.adyen.checkout.components.util.CurrencyUtils +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.dropin.R +import com.adyen.checkout.dropin.databinding.FragmentGiftCardPaymentConfirmationBinding +import com.adyen.checkout.dropin.ui.base.DropInBottomSheetDialogFragment +import com.adyen.checkout.dropin.ui.paymentmethods.GiftCardPaymentMethodModel +import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodAdapter + +class GiftCardPaymentConfirmationDialogFragment : DropInBottomSheetDialogFragment() { + + private lateinit var binding: FragmentGiftCardPaymentConfirmationBinding + private lateinit var paymentMethodAdapter: PaymentMethodAdapter + + private lateinit var giftCardPaymentConfirmationData: GiftCardPaymentConfirmationData + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + giftCardPaymentConfirmationData = arguments?.getParcelable(GIFT_CARD_DATA) + ?: throw IllegalArgumentException("Gift card data not found") + } + + override fun onAttach(context: Context) { + super.onAttach(context) + Logger.d(TAG, "onAttach") + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + Logger.d(TAG, "onCreateView") + binding = FragmentGiftCardPaymentConfirmationBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val amountToPay = CurrencyUtils.formatAmount( + giftCardPaymentConfirmationData.amountPaid, + giftCardPaymentConfirmationData.shopperLocale + ) + binding.payButton.text = String.format(resources.getString(R.string.pay_button_with_value), amountToPay) + + val remainingBalance = CurrencyUtils.formatAmount( + giftCardPaymentConfirmationData.remainingBalance, + giftCardPaymentConfirmationData.shopperLocale + ) + binding.textViewRemainingBalance.text = + String.format(resources.getString(R.string.checkout_giftcard_remaining_balance_text), remainingBalance) + + binding.changePaymentMethodButton.setOnClickListener { + performBackAction() + } + + initRecyclerView() + } + + private fun initRecyclerView() { + val paymentMethods = listOf( + GiftCardPaymentMethodModel( + imageId = giftCardPaymentConfirmationData.brand, + lastFour = giftCardPaymentConfirmationData.lastFourDigits + ) + ) + + val imageLoader = ImageLoader.getInstance( + requireContext(), + dropInViewModel.dropInConfiguration.environment + ) + + paymentMethodAdapter = PaymentMethodAdapter(paymentMethods, imageLoader) + binding.recyclerViewGiftCards.layoutManager = LinearLayoutManager(requireContext()) + binding.recyclerViewGiftCards.adapter = paymentMethodAdapter + } + + override fun onCancel(dialog: DialogInterface) { + super.onCancel(dialog) + Logger.d(TAG, "onCancel") + protocol.terminateDropIn() + } + + override fun onBackPressed(): Boolean { + return performBackAction() + } + + private fun performBackAction(): Boolean { + if (dropInViewModel.shouldSkipToSinglePaymentMethod()) { + protocol.terminateDropIn() + } else { + protocol.showPaymentMethodsDialog() + } + return true + } + + companion object { + private val TAG = LogUtil.getTag() + private const val GIFT_CARD_DATA = "GIFT_CARD_DATA" + + @JvmStatic + fun newInstance(data: GiftCardPaymentConfirmationData) = + GiftCardPaymentConfirmationDialogFragment().apply { + arguments = Bundle().apply { + putParcelable(GIFT_CARD_DATA, data) + } + } + } +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt new file mode 100644 index 0000000000..871fb78f69 --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 11/11/2021. + */ + +package com.adyen.checkout.dropin.ui.paymentmethods + +data class GiftCardPaymentMethodModel( + val imageId: String, + val lastFour: String +) : PaymentMethodListItem { + override fun getViewType(): Int = PaymentMethodListItem.GIFT_CARD_PAYMENT_METHOD +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt index 5dc1d34cb9..2ca4bf0ac4 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt @@ -19,6 +19,7 @@ import com.adyen.checkout.components.util.DateUtils import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.dropin.R +import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.GIFT_CARD_PAYMENT_METHOD import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.PAYMENT_METHOD import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.PAYMENT_METHODS_HEADER import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.STORED_PAYMENT_METHOD @@ -40,6 +41,7 @@ class PaymentMethodAdapter( PAYMENT_METHODS_HEADER -> HeaderVH(getView(parent, R.layout.payment_methods_list_header)) STORED_PAYMENT_METHOD -> StoredPaymentMethodVH(getView(parent, R.layout.payment_methods_list_item)) PAYMENT_METHOD -> PaymentMethodVH(getView(parent, R.layout.payment_methods_list_item)) + GIFT_CARD_PAYMENT_METHOD -> GiftCardPaymentMethodVH(getView(parent, R.layout.payment_methods_list_item)) else -> throw CheckoutException("Unexpected viewType on onCreateViewHolder - $viewType") } } @@ -53,6 +55,7 @@ class PaymentMethodAdapter( is HeaderVH -> bindHeader(holder, position) is StoredPaymentMethodVH -> bindStoredPaymentMethod(holder, position) is PaymentMethodVH -> bindPaymentMethod(holder, position) + is GiftCardPaymentMethodVH -> bindGiftCardPaymentMethod(holder, position) } } @@ -102,6 +105,17 @@ class PaymentMethodAdapter( } } + private fun bindGiftCardPaymentMethod(holder: GiftCardPaymentMethodVH, position: Int) { + val giftCardPaymentMethod = getGiftCardPaymentMethodAt(position) + + val context = holder.itemView.context + holder.text.text = context.getString(R.string.card_number_4digit, giftCardPaymentMethod.lastFour) + imageLoader.load(giftCardPaymentMethod.imageId, holder.logo) + holder.detail.visibility = View.GONE + + holder.itemView.setOnClickListener(null) + } + override fun getItemCount(): Int { return paymentMethods.size } @@ -118,6 +132,10 @@ class PaymentMethodAdapter( return paymentMethods[position] as PaymentMethodModel } + private fun getGiftCardPaymentMethodAt(position: Int): GiftCardPaymentMethodModel { + return paymentMethods[position] as GiftCardPaymentMethodModel + } + private fun onStoredPaymentMethodClick(storedPaymentMethodModel: StoredPaymentMethodModel) { onPaymentMethodSelectedCallback?.onStoredPaymentMethodSelected(storedPaymentMethodModel) } @@ -151,6 +169,12 @@ class PaymentMethodAdapter( internal val logo: RoundCornerImageView = rootView.findViewById(R.id.imageView_logo) } + class GiftCardPaymentMethodVH(rootView: View) : BaseViewHolder(rootView) { + internal val text: TextView = rootView.findViewById(R.id.textView_text) + internal val detail: TextView = rootView.findViewById(R.id.textView_detail) + internal val logo: RoundCornerImageView = rootView.findViewById(R.id.imageView_logo) + } + class HeaderVH(rootView: View) : BaseViewHolder(rootView) { internal val title: TextView = rootView.findViewById(R.id.payment_method_header) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt index 368c6a7c26..25dbcf7fda 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt @@ -17,5 +17,6 @@ interface PaymentMethodListItem { const val PAYMENT_METHODS_HEADER = 1 const val STORED_PAYMENT_METHOD = 2 const val PAYMENT_METHOD = 3 + const val GIFT_CARD_PAYMENT_METHOD = 4 } } diff --git a/drop-in/src/main/res/layout/fragment_gift_card_payment_confirmation.xml b/drop-in/src/main/res/layout/fragment_gift_card_payment_confirmation.xml new file mode 100644 index 0000000000..97f40ed069 --- /dev/null +++ b/drop-in/src/main/res/layout/fragment_gift_card_payment_confirmation.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drop-in/src/main/res/layout/fragment_stored_payment_method.xml b/drop-in/src/main/res/layout/fragment_stored_payment_method.xml index 185480078c..4e8b2fb2ec 100644 --- a/drop-in/src/main/res/layout/fragment_stored_payment_method.xml +++ b/drop-in/src/main/res/layout/fragment_stored_payment_method.xml @@ -53,7 +53,5 @@ android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/AdyenCheckout.SecondaryFlatButton" - android:layout_marginStart="@dimen/standard_margin" - android:layout_marginEnd="@dimen/standard_margin" android:text="@string/change_payment_method" /> \ No newline at end of file diff --git a/drop-in/src/main/res/values/styles.xml b/drop-in/src/main/res/values/styles.xml index 14cf402ca7..5b76dec7e2 100644 --- a/drop-in/src/main/res/values/styles.xml +++ b/drop-in/src/main/res/values/styles.xml @@ -50,5 +50,12 @@ 0dp + \ No newline at end of file diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index 91added8a7..0544e55c9b 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -130,8 +130,8 @@ @@ -143,6 +143,8 @@ \ No newline at end of file From f0b1da0d872c93ac78e9b91a9ef6d918d50c1397 Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 11 Nov 2021 16:59:57 +0100 Subject: [PATCH 026/102] Make payment from GiftCardPaymentConfirmationDialogFragment --- .../java/com/adyen/checkout/dropin/ui/DropInActivity.kt | 8 ++++---- .../java/com/adyen/checkout/dropin/ui/DropInViewModel.kt | 4 ++-- .../giftcard/GiftCardPaymentConfirmationDialogFragment.kt | 7 +++++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 2d3b6b936a..1f7d531ce6 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -508,9 +508,10 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } private fun handleBalanceResult(balanceJson: String) { - Logger.d(TAG, "handleBalanceResult") + Logger.v(TAG, "handleBalanceResult") dropInViewModel.isWaitingResult = false val result = dropInViewModel.handleBalanceResult(balanceJson) + Logger.d(TAG, "handleBalanceResult: ${result::class.java.simpleName}") when (result) { is GiftCardBalanceUIState.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) is GiftCardBalanceUIState.FullPayment -> handleGiftCardFullPayment(result) @@ -519,10 +520,9 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } private fun handleGiftCardFullPayment(fullPayment: GiftCardBalanceUIState.FullPayment) { - // TODO move this somewhere else later? + Logger.d(TAG, "handleGiftCardFullPayment") setLoading(false) showGiftCardPaymentConfirmationDialog(fullPayment.data) - // TODO handle full payment } private fun showGiftCardPaymentConfirmationDialog(data: GiftCardPaymentConfirmationData) { @@ -533,7 +533,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } private fun handleGiftCardPartialPayment(partialPayment: GiftCardBalanceUIState.PartialPayment) { - // TODO move this somewhere else later? + Logger.d(TAG, "handleGiftCardPartialPayment") setLoading(false) // TODO handle partial payment } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 49d4379413..7bf65a7fd8 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -53,11 +53,11 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode savedStateHandle[IS_WAITING_FOR_RESULT_KEY] = value } - private var cachedGiftCardComponentState: GiftCardComponentState? + var cachedGiftCardComponentState: GiftCardComponentState? get() { return savedStateHandle.get(CACHED_GIFT_CARD) } - set(value) { + private set(value) { savedStateHandle[CACHED_GIFT_CARD] = value } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt index fde077ec8a..e82a51dad8 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt @@ -17,6 +17,7 @@ import android.view.ViewGroup import androidx.recyclerview.widget.LinearLayoutManager import com.adyen.checkout.components.api.ImageLoader import com.adyen.checkout.components.util.CurrencyUtils +import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.R @@ -70,6 +71,12 @@ class GiftCardPaymentConfirmationDialogFragment : DropInBottomSheetDialogFragmen } initRecyclerView() + + binding.payButton.setOnClickListener { + val paymentComponentState = dropInViewModel.cachedGiftCardComponentState + ?: throw CheckoutException("Lost reference to cached GiftCardComponentState") + protocol.requestPaymentsCall(paymentComponentState) + } } private fun initRecyclerView() { From 01248161daddb0b177891f52a445bff90fd72b8b Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 11 Nov 2021 17:02:58 +0100 Subject: [PATCH 027/102] Improve gift card balance class names --- .../checkout/dropin/ui/DropInActivity.kt | 12 ++--- .../checkout/dropin/ui/DropInViewModel.kt | 32 ++++++------- ...nceUIState.kt => GiftCardBalanceResult.kt} | 8 ++-- .../giftcard/util/GiftCardBalanceUtils.kt | 28 +++++------ .../giftcard/GiftCardBalanceUtilsTest.kt | 48 +++++++++---------- 5 files changed, 64 insertions(+), 64 deletions(-) rename drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/{GiftCardBalanceUIState.kt => GiftCardBalanceResult.kt} (75%) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 1f7d531ce6..b403e7b78a 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -47,7 +47,7 @@ import com.adyen.checkout.dropin.ui.base.DropInBottomSheetDialogFragment import com.adyen.checkout.dropin.ui.component.CardComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GenericComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GiftCardComponentDialogFragment -import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceUIState +import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceResult import com.adyen.checkout.dropin.ui.giftcard.GiftCardPaymentConfirmationData import com.adyen.checkout.dropin.ui.giftcard.GiftCardPaymentConfirmationDialogFragment import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListDialogFragment @@ -513,13 +513,13 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot val result = dropInViewModel.handleBalanceResult(balanceJson) Logger.d(TAG, "handleBalanceResult: ${result::class.java.simpleName}") when (result) { - is GiftCardBalanceUIState.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) - is GiftCardBalanceUIState.FullPayment -> handleGiftCardFullPayment(result) - is GiftCardBalanceUIState.PartialPayment -> handleGiftCardPartialPayment(result) + is GiftCardBalanceResult.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) + is GiftCardBalanceResult.FullPayment -> handleGiftCardFullPayment(result) + is GiftCardBalanceResult.PartialPayment -> handleGiftCardPartialPayment(result) } } - private fun handleGiftCardFullPayment(fullPayment: GiftCardBalanceUIState.FullPayment) { + private fun handleGiftCardFullPayment(fullPayment: GiftCardBalanceResult.FullPayment) { Logger.d(TAG, "handleGiftCardFullPayment") setLoading(false) showGiftCardPaymentConfirmationDialog(fullPayment.data) @@ -532,7 +532,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot .show(supportFragmentManager, GIFT_CARD_PAYMENT_CONFIRMATION_FRAGMENT_TAG) } - private fun handleGiftCardPartialPayment(partialPayment: GiftCardBalanceUIState.PartialPayment) { + private fun handleGiftCardPartialPayment(partialPayment: GiftCardBalanceResult.PartialPayment) { Logger.d(TAG, "handleGiftCardPartialPayment") setLoading(false) // TODO handle partial payment diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 7bf65a7fd8..5e477919ba 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -22,10 +22,10 @@ import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.R -import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceUIState +import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceResult import com.adyen.checkout.dropin.ui.giftcard.GiftCardPaymentConfirmationData import com.adyen.checkout.giftcard.GiftCardComponentState -import com.adyen.checkout.giftcard.util.GiftCardBalanceResult +import com.adyen.checkout.giftcard.util.GiftCardBalanceStatus import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent import org.json.JSONException @@ -105,7 +105,7 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return paymentMethod } - fun handleBalanceResult(balanceJson: String): GiftCardBalanceUIState { + fun handleBalanceResult(balanceJson: String): GiftCardBalanceResult { val balanceJSONObject = try { JSONObject(balanceJson) } catch (e: JSONException) { @@ -126,36 +126,36 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode ) val cachedGiftCardComponentState = cachedGiftCardComponentState ?: throw CheckoutException("Failed to retrieved cached gift card object") return when (giftCardBalanceResult) { - is GiftCardBalanceResult.ZeroBalance -> { + is GiftCardBalanceStatus.ZeroBalance -> { Logger.i(TAG, "handleBalanceResult - Gift Card has zero balance") - GiftCardBalanceUIState.Error(R.string.checkout_giftcard_error_zero_balance, "Gift Card has zero balance", false) + GiftCardBalanceResult.Error(R.string.checkout_giftcard_error_zero_balance, "Gift Card has zero balance", false) } - is GiftCardBalanceResult.NonMatchingCurrencies -> { + is GiftCardBalanceStatus.NonMatchingCurrencies -> { Logger.e(TAG, "handleBalanceResult - Gift Card currency mismatch") - GiftCardBalanceUIState.Error(R.string.checkout_giftcard_error_currency, "Gift Card currency mismatch", false) + GiftCardBalanceResult.Error(R.string.checkout_giftcard_error_currency, "Gift Card currency mismatch", false) } - is GiftCardBalanceResult.ZeroAmountToBePaid -> { + is GiftCardBalanceStatus.ZeroAmountToBePaid -> { Logger.e(TAG, "handleBalanceResult - You must set an amount in DropInConfiguration.Builder to enable gift card payments") - GiftCardBalanceUIState.Error(R.string.payment_failed, "Drop-in amount is not set", true) + GiftCardBalanceResult.Error(R.string.payment_failed, "Drop-in amount is not set", true) } - is GiftCardBalanceResult.FullPayment -> { - GiftCardBalanceUIState.FullPayment( + is GiftCardBalanceStatus.FullPayment -> { + GiftCardBalanceResult.FullPayment( createGiftCardPaymentConfirmationData(giftCardBalanceResult, cachedGiftCardComponentState) ) } - is GiftCardBalanceResult.PartialPayment -> { - GiftCardBalanceUIState.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) + is GiftCardBalanceStatus.PartialPayment -> { + GiftCardBalanceResult.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) } } } private fun createGiftCardPaymentConfirmationData( - giftCardBalanceResult: GiftCardBalanceResult.FullPayment, + giftCardBalanceStatus: GiftCardBalanceStatus.FullPayment, giftCardComponentState: GiftCardComponentState ): GiftCardPaymentConfirmationData { return GiftCardPaymentConfirmationData( - amountPaid = giftCardBalanceResult.amountPaid, - remainingBalance = giftCardBalanceResult.remainingBalance, + amountPaid = giftCardBalanceStatus.amountPaid, + remainingBalance = giftCardBalanceStatus.remainingBalance, shopperLocale = dropInConfiguration.shopperLocale, brand = giftCardComponentState.data.paymentMethod?.brand.orEmpty(), lastFourDigits = giftCardComponentState.lastFourDigits.orEmpty() diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceResult.kt similarity index 75% rename from drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt rename to drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceResult.kt index ded2c13abe..c54b623e9e 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceUIState.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceResult.kt @@ -11,8 +11,8 @@ package com.adyen.checkout.dropin.ui.giftcard import androidx.annotation.StringRes import com.adyen.checkout.components.model.payments.Amount -sealed class GiftCardBalanceUIState { - class FullPayment(val data: GiftCardPaymentConfirmationData) : GiftCardBalanceUIState() - class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceUIState() - class Error(@StringRes val errorMessage: Int, val reason: String, val terminateDropIn: Boolean) : GiftCardBalanceUIState() +sealed class GiftCardBalanceResult { + class FullPayment(val data: GiftCardPaymentConfirmationData) : GiftCardBalanceResult() + class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceResult() + class Error(@StringRes val errorMessage: Int, val reason: String, val terminateDropIn: Boolean) : GiftCardBalanceResult() } diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt index 9776c01b7a..46666af8d4 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/util/GiftCardBalanceUtils.kt @@ -15,17 +15,17 @@ import kotlin.math.min object GiftCardBalanceUtils { // TODO docs - fun checkBalance(balance: Amount, transactionLimit: Amount?, amountToBePaid: Amount): GiftCardBalanceResult { + fun checkBalance(balance: Amount, transactionLimit: Amount?, amountToBePaid: Amount): GiftCardBalanceStatus { return when { - amountToBePaid.isEmpty || amountToBePaid.value <= 0 -> GiftCardBalanceResult.ZeroAmountToBePaid - balance.isEmpty || balance.value <= 0 -> GiftCardBalanceResult.ZeroBalance - amountToBePaid.currency != balance.currency -> GiftCardBalanceResult.NonMatchingCurrencies - transactionLimit != null && amountToBePaid.currency != transactionLimit.currency -> GiftCardBalanceResult.NonMatchingCurrencies + amountToBePaid.isEmpty || amountToBePaid.value <= 0 -> GiftCardBalanceStatus.ZeroAmountToBePaid + balance.isEmpty || balance.value <= 0 -> GiftCardBalanceStatus.ZeroBalance + amountToBePaid.currency != balance.currency -> GiftCardBalanceStatus.NonMatchingCurrencies + transactionLimit != null && amountToBePaid.currency != transactionLimit.currency -> GiftCardBalanceStatus.NonMatchingCurrencies else -> calculateRemainingAmount(balance, transactionLimit, amountToBePaid) } } - private fun calculateRemainingAmount(balance: Amount, transactionLimit: Amount?, amountToBePaid: Amount): GiftCardBalanceResult { + private fun calculateRemainingAmount(balance: Amount, transactionLimit: Amount?, amountToBePaid: Amount): GiftCardBalanceStatus { val maxPayableAmount = if (transactionLimit == null || transactionLimit.isEmpty) balance.value else min(balance.value, transactionLimit.value) @@ -43,17 +43,17 @@ object GiftCardBalanceUtils { } return if (maxPayableAmount >= amountToBePaid.value) { - GiftCardBalanceResult.FullPayment(amountPaid = amountPaid, remainingBalance = remainingBalance) + GiftCardBalanceStatus.FullPayment(amountPaid = amountPaid, remainingBalance = remainingBalance) } else { - GiftCardBalanceResult.PartialPayment(amountPaid = amountPaid, remainingBalance = remainingBalance) + GiftCardBalanceStatus.PartialPayment(amountPaid = amountPaid, remainingBalance = remainingBalance) } } } -sealed class GiftCardBalanceResult { - class FullPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceResult() - class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceResult() - object NonMatchingCurrencies : GiftCardBalanceResult() - object ZeroAmountToBePaid : GiftCardBalanceResult() - object ZeroBalance : GiftCardBalanceResult() +sealed class GiftCardBalanceStatus { + class FullPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceStatus() + class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceStatus() + object NonMatchingCurrencies : GiftCardBalanceStatus() + object ZeroAmountToBePaid : GiftCardBalanceStatus() + object ZeroBalance : GiftCardBalanceStatus() } diff --git a/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt index dd2b30486c..b544695e8b 100644 --- a/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt +++ b/giftcard/src/test/java/com/adyen/checkout/giftcard/GiftCardBalanceUtilsTest.kt @@ -1,7 +1,7 @@ package com.adyen.checkout.giftcard import com.adyen.checkout.components.model.payments.Amount -import com.adyen.checkout.giftcard.util.GiftCardBalanceResult +import com.adyen.checkout.giftcard.util.GiftCardBalanceStatus import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import org.junit.Assert.assertEquals import org.junit.Test @@ -16,8 +16,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(10) ) - assert(result is GiftCardBalanceResult.FullPayment) - require(result is GiftCardBalanceResult.FullPayment) + assert(result is GiftCardBalanceStatus.FullPayment) + require(result is GiftCardBalanceStatus.FullPayment) assertEquals(10, result.amountPaid.value) assertEquals(90, result.remainingBalance.value) } @@ -30,8 +30,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(10) ) - assert(result is GiftCardBalanceResult.FullPayment) - require(result is GiftCardBalanceResult.FullPayment) + assert(result is GiftCardBalanceStatus.FullPayment) + require(result is GiftCardBalanceStatus.FullPayment) assertEquals(10, result.amountPaid.value) assertEquals(990, result.remainingBalance.value) } @@ -44,8 +44,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(10) ) - assert(result is GiftCardBalanceResult.FullPayment) - require(result is GiftCardBalanceResult.FullPayment) + assert(result is GiftCardBalanceStatus.FullPayment) + require(result is GiftCardBalanceStatus.FullPayment) assertEquals(10, result.amountPaid.value) assertEquals(90, result.remainingBalance.value) } @@ -58,8 +58,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(100) ) - assert(result is GiftCardBalanceResult.FullPayment) - require(result is GiftCardBalanceResult.FullPayment) + assert(result is GiftCardBalanceStatus.FullPayment) + require(result is GiftCardBalanceStatus.FullPayment) assertEquals(100, result.amountPaid.value) assertEquals(0, result.remainingBalance.value) } @@ -72,8 +72,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(1000) ) - assert(result is GiftCardBalanceResult.PartialPayment) - require(result is GiftCardBalanceResult.PartialPayment) + assert(result is GiftCardBalanceStatus.PartialPayment) + require(result is GiftCardBalanceStatus.PartialPayment) assertEquals(100, result.amountPaid.value) assertEquals(0, result.remainingBalance.value) } @@ -86,8 +86,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(1000) ) - assert(result is GiftCardBalanceResult.PartialPayment) - require(result is GiftCardBalanceResult.PartialPayment) + assert(result is GiftCardBalanceStatus.PartialPayment) + require(result is GiftCardBalanceStatus.PartialPayment) assertEquals(100, result.amountPaid.value) assertEquals(100, result.remainingBalance.value) } @@ -100,8 +100,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(1000) ) - assert(result is GiftCardBalanceResult.PartialPayment) - require(result is GiftCardBalanceResult.PartialPayment) + assert(result is GiftCardBalanceStatus.PartialPayment) + require(result is GiftCardBalanceStatus.PartialPayment) assertEquals(100, result.amountPaid.value) assertEquals(0, result.remainingBalance.value) } @@ -114,8 +114,8 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(200) ) - assert(result is GiftCardBalanceResult.PartialPayment) - require(result is GiftCardBalanceResult.PartialPayment) + assert(result is GiftCardBalanceStatus.PartialPayment) + require(result is GiftCardBalanceStatus.PartialPayment) assertEquals(100, result.amountPaid.value) assertEquals(0, result.remainingBalance.value) } @@ -128,7 +128,7 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(200) ) - assert(result is GiftCardBalanceResult.NonMatchingCurrencies) + assert(result is GiftCardBalanceStatus.NonMatchingCurrencies) } @Test @@ -139,7 +139,7 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(200) ) - assert(result is GiftCardBalanceResult.NonMatchingCurrencies) + assert(result is GiftCardBalanceStatus.NonMatchingCurrencies) } @Test @@ -150,7 +150,7 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(200, "USD") ) - assert(result is GiftCardBalanceResult.NonMatchingCurrencies) + assert(result is GiftCardBalanceStatus.NonMatchingCurrencies) } @Test @@ -161,7 +161,7 @@ class GiftCardBalanceUtilsTest { amountToBePaid = Amount.EMPTY ) - assert(result is GiftCardBalanceResult.ZeroAmountToBePaid) + assert(result is GiftCardBalanceStatus.ZeroAmountToBePaid) } @Test @@ -172,7 +172,7 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(0) ) - assert(result is GiftCardBalanceResult.ZeroAmountToBePaid) + assert(result is GiftCardBalanceStatus.ZeroAmountToBePaid) } @Test @@ -183,7 +183,7 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(100) ) - assert(result is GiftCardBalanceResult.ZeroBalance) + assert(result is GiftCardBalanceStatus.ZeroBalance) } @Test @@ -194,7 +194,7 @@ class GiftCardBalanceUtilsTest { amountToBePaid = createAmount(100) ) - assert(result is GiftCardBalanceResult.ZeroBalance) + assert(result is GiftCardBalanceStatus.ZeroBalance) } private fun createAmount(value: Int, currency: String = "EUR"): Amount { From a12f032cd795bf17f9c1ac3edad5582aa915739a Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 15 Nov 2021 11:54:11 +0100 Subject: [PATCH 028/102] Merge returning balance in DropInService with DropInServiceResult --- .../checkout/dropin/service/DropInService.kt | 13 ------------- .../dropin/service/DropInServiceResult.kt | 8 ++++++++ .../adyen/checkout/dropin/ui/DropInActivity.kt | 5 +++-- .../service/ExampleAsyncDropInService.kt | 18 ++++++++---------- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt index 5a2828a463..2462ee91a7 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt @@ -53,7 +53,6 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface // TODO change LiveData into channel/flow to support single events? private val resultLiveData: MutableLiveData = MutableLiveData() - private val balanceLiveData: MutableLiveData = MutableLiveData() override fun onBind(intent: Intent?): IBinder { Logger.d(TAG, "onBind") @@ -275,21 +274,10 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface throw NotImplementedError("Method checkBalance is not implemented") } - // TODO docs - protected fun onBalanceChecked(balanceJson: String) { - // send response back to activity - Logger.d(TAG, "onBalanceChecked called") - balanceLiveData.postValue(balanceJson) - } - override fun observeResult(owner: LifecycleOwner, observer: Observer) { resultLiveData.observe(owner, observer) } - override fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) { - balanceLiveData.observe(owner, observer) - } - internal inner class DropInBinder : Binder() { fun getService(): DropInServiceInterface = this@DropInService } @@ -316,6 +304,5 @@ internal interface DropInServiceInterface { fun observeResult(owner: LifecycleOwner, observer: Observer) fun requestPaymentsCall(paymentComponentState: PaymentComponentState<*>) fun requestDetailsCall(actionComponentData: ActionComponentData) - fun observeBalanceResult(owner: LifecycleOwner, observer: Observer) fun requestBalanceCall(paymentMethodData: PaymentMethodDetails) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt index 97c3823e5e..f6000a4bbc 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt @@ -31,4 +31,12 @@ sealed class DropInServiceResult { * in an Alert Dialog, otherwise a generic error message will be shown. */ class Error(val errorMessage: String? = null, val reason: String? = null, val dismissDropIn: Boolean = false) : DropInServiceResult() + + /** + * Only applicable for gift card flow. + * + * A call to fetch a gift card balance was successful and returned with a + * [com.adyen.checkout.components.model.payments.response.BalanceResult] that needs to be handled. + */ + class Balance(val balanceJSON: String) : DropInServiceResult() } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index b403e7b78a..4f12dbc750 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -112,7 +112,6 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot val dropInBinder = binder as? DropInService.DropInBinder ?: return dropInService = dropInBinder.getService() dropInService?.observeResult(this@DropInActivity) { handleDropInServiceResult(it) } - dropInService?.observeBalanceResult(this@DropInActivity) { handleBalanceResult(it) } paymentDataQueue?.let { Logger.d(TAG, "Sending queued payment request") @@ -407,6 +406,9 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot val action = Action.SERIALIZER.deserialize(JSONObject(dropInServiceResult.actionJSON)) actionHandler.handleAction(this, action, ::sendResult) } + is DropInServiceResult.Balance -> { + handleBalanceResult(dropInServiceResult.balanceJSON) + } is DropInServiceResult.Error -> { Logger.d(TAG, "handleDropInServiceResult ERROR - reason: ${dropInServiceResult.reason}") val reason = dropInServiceResult.reason ?: "Unspecified reason" @@ -509,7 +511,6 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleBalanceResult(balanceJson: String) { Logger.v(TAG, "handleBalanceResult") - dropInViewModel.isWaitingResult = false val result = dropInViewModel.handleBalanceResult(balanceJson) Logger.d(TAG, "handleBalanceResult: ${result::class.java.simpleName}") when (result) { diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index a376619a69..09946a9670 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -98,7 +98,6 @@ class ExampleAsyncDropInService : DropInService() { } } - @Suppress("NestedBlockDepth") private fun handleResponse(response: ResponseBody?): DropInServiceResult { return if (response != null) { val detailsResponse = JSONObject(response.string()) @@ -133,25 +132,24 @@ class ExampleAsyncDropInService : DropInService() { val requestBody = paymentRequest.toString().toRequestBody(CONTENT_TYPE) val response = paymentsRepository.balanceRequestAsync(requestBody) - - handleBalanceResponse(response) + val result = handleBalanceResponse(response) + sendResult(result) } } - @Suppress("NestedBlockDepth") - private fun handleBalanceResponse(response: ResponseBody?) { - if (response != null) { + private fun handleBalanceResponse(response: ResponseBody?): DropInServiceResult { + return if (response != null) { val balanceJson = response.string() val jsonResponse = JSONObject(balanceJson) val resultCode = jsonResponse.getStringOrNull("resultCode") when (resultCode) { - "Success" -> onBalanceChecked(balanceJson) - "NotEnoughBalance" -> sendResult(DropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false)) - else -> sendResult(DropInServiceResult.Error(reason = resultCode, dismissDropIn = false)) + "Success" -> DropInServiceResult.Balance(balanceJson) + "NotEnoughBalance" -> DropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false) + else -> DropInServiceResult.Error(reason = resultCode, dismissDropIn = false) } } else { Logger.e(TAG, "FAILED") - sendResult(DropInServiceResult.Error(reason = "IOException")) + DropInServiceResult.Error(reason = "IOException") } } } From 0dddab0b090630731e5d561201f668dde9517dd0 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 15 Nov 2021 13:32:37 +0100 Subject: [PATCH 029/102] Code checks --- .../dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt | 1 - .../main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt index 6667452124..44e738d3c4 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationData.kt @@ -38,7 +38,6 @@ data class GiftCardPaymentConfirmationData( override fun describeContents() = Parcelable.CONTENTS_FILE_DESCRIPTOR - companion object { @JvmField val CREATOR = object : Parcelable.Creator { diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt index 2b83a3d05a..36a873bca5 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/GiftCardComponent.kt @@ -79,6 +79,7 @@ class GiftCardComponent( return GiftCardOutputData(cardNumber = inputData.cardNumber, pin = inputData.pin) } + @Suppress("ReturnCount") override fun createComponentState(): GiftCardComponentState { val unencryptedCardBuilder = UnencryptedCard.Builder() val outputData = outputData From 4f96accac4e57ad107901a618699d3c6cc2b067f Mon Sep 17 00:00:00 2001 From: jreij Date: Tue, 16 Nov 2021 16:47:28 +0100 Subject: [PATCH 030/102] Split DropInServiceResult into multiple classes for each flow --- .../checkout/dropin/service/DropInService.kt | 16 ++++-- .../dropin/service/DropInServiceResult.kt | 31 +++++++++-- .../checkout/dropin/ui/DropInActivity.kt | 53 ++++++++++++------- .../service/ExampleAsyncDropInService.kt | 13 ++--- 4 files changed, 79 insertions(+), 34 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt index 2462ee91a7..e2d4427eec 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt @@ -52,7 +52,7 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface private val binder = DropInBinder() // TODO change LiveData into channel/flow to support single events? - private val resultLiveData: MutableLiveData = MutableLiveData() + private val mResultLiveData: MutableLiveData = MutableLiveData() override fun onBind(intent: Intent?): IBinder { Logger.d(TAG, "onBind") @@ -202,7 +202,13 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface protected fun sendResult(result: DropInServiceResult) { // send response back to activity Logger.d(TAG, "dispatching DropInServiceResult") - resultLiveData.postValue(result) + mResultLiveData.postValue(result) + } + + protected fun sendBalanceResult(result: BalanceDropInServiceResult) { + // send response back to activity + Logger.d(TAG, "dispatching DropInServiceResult") + mResultLiveData.postValue(result) } /** @@ -274,8 +280,8 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface throw NotImplementedError("Method checkBalance is not implemented") } - override fun observeResult(owner: LifecycleOwner, observer: Observer) { - resultLiveData.observe(owner, observer) + override fun observeResult(owner: LifecycleOwner, observer: Observer) { + mResultLiveData.observe(owner, observer) } internal inner class DropInBinder : Binder() { @@ -301,7 +307,7 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface } internal interface DropInServiceInterface { - fun observeResult(owner: LifecycleOwner, observer: Observer) + fun observeResult(owner: LifecycleOwner, observer: Observer) fun requestPaymentsCall(paymentComponentState: PaymentComponentState<*>) fun requestDetailsCall(actionComponentData: ActionComponentData) fun requestBalanceCall(paymentMethodData: PaymentMethodDetails) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt index f6000a4bbc..42accc985d 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt @@ -8,10 +8,18 @@ package com.adyen.checkout.dropin.service +sealed class BaseDropInServiceResult + +internal interface DropInServiceResultError { + val errorMessage: String? + val reason: String? + val dismissDropIn: Boolean +} + /** * The result from a server call request on the [DropInService] */ -sealed class DropInServiceResult { +sealed class DropInServiceResult : BaseDropInServiceResult() { /** * Call was successful and payment is finished. This does not necessarily mean that the @@ -30,7 +38,14 @@ sealed class DropInServiceResult { * Call failed with an error. Can have the localized error message which will be shown * in an Alert Dialog, otherwise a generic error message will be shown. */ - class Error(val errorMessage: String? = null, val reason: String? = null, val dismissDropIn: Boolean = false) : DropInServiceResult() + class Error( + override val errorMessage: String? = null, + override val reason: String? = null, + override val dismissDropIn: Boolean = false + ) : DropInServiceResult(), DropInServiceResultError +} + +sealed class BalanceDropInServiceResult : BaseDropInServiceResult() { /** * Only applicable for gift card flow. @@ -38,5 +53,15 @@ sealed class DropInServiceResult { * A call to fetch a gift card balance was successful and returned with a * [com.adyen.checkout.components.model.payments.response.BalanceResult] that needs to be handled. */ - class Balance(val balanceJSON: String) : DropInServiceResult() + class Balance(val balanceJSON: String) : BalanceDropInServiceResult() + + /** + * Call failed with an error. Can have the localized error message which will be shown + * in an Alert Dialog, otherwise a generic error message will be shown. + */ + class Error( + override val errorMessage: String? = null, + override val reason: String? = null, + override val dismissDropIn: Boolean = false + ) : BalanceDropInServiceResult(), DropInServiceResultError } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 4f12dbc750..f1ed7d0a2c 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -39,9 +39,12 @@ import com.adyen.checkout.dropin.DropIn import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.DropInPrefs import com.adyen.checkout.dropin.R +import com.adyen.checkout.dropin.service.BalanceDropInServiceResult +import com.adyen.checkout.dropin.service.BaseDropInServiceResult import com.adyen.checkout.dropin.service.DropInService import com.adyen.checkout.dropin.service.DropInServiceInterface import com.adyen.checkout.dropin.service.DropInServiceResult +import com.adyen.checkout.dropin.service.DropInServiceResultError import com.adyen.checkout.dropin.ui.action.ActionComponentDialogFragment import com.adyen.checkout.dropin.ui.base.DropInBottomSheetDialogFragment import com.adyen.checkout.dropin.ui.component.CardComponentDialogFragment @@ -395,32 +398,42 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot dropInService?.requestBalanceCall(paymentMethod) } - private fun handleDropInServiceResult(dropInServiceResult: DropInServiceResult) { + private fun handleDropInServiceResult(dropInServiceResult: BaseDropInServiceResult) { Logger.d(TAG, "handleDropInServiceResult - ${dropInServiceResult::class.simpleName}") dropInViewModel.isWaitingResult = false when (dropInServiceResult) { - is DropInServiceResult.Finished -> { - sendResult(dropInServiceResult.result) - } - is DropInServiceResult.Action -> { - val action = Action.SERIALIZER.deserialize(JSONObject(dropInServiceResult.actionJSON)) - actionHandler.handleAction(this, action, ::sendResult) - } - is DropInServiceResult.Balance -> { - handleBalanceResult(dropInServiceResult.balanceJSON) - } - is DropInServiceResult.Error -> { - Logger.d(TAG, "handleDropInServiceResult ERROR - reason: ${dropInServiceResult.reason}") - val reason = dropInServiceResult.reason ?: "Unspecified reason" - if (dropInServiceResult.errorMessage == null) { - showError(getString(R.string.payment_failed), reason, dropInServiceResult.dismissDropIn) - } else { - showError(dropInServiceResult.errorMessage, reason, dropInServiceResult.dismissDropIn) - } - } + is DropInServiceResult -> handleDropInServiceResult(dropInServiceResult) + is BalanceDropInServiceResult -> handleDropInServiceResult(dropInServiceResult) + } + } + + private fun handleDropInServiceResult(dropInServiceResult: DropInServiceResult) { + when (dropInServiceResult) { + is DropInServiceResult.Finished -> sendResult(dropInServiceResult.result) + is DropInServiceResult.Action -> handleAction(dropInServiceResult.actionJSON) + is DropInServiceResult.Error -> handleErrorDropInServiceResult(dropInServiceResult) + } + } + + private fun handleDropInServiceResult(dropInServiceResult: BalanceDropInServiceResult) { + when (dropInServiceResult) { + is BalanceDropInServiceResult.Balance -> handleBalanceResult(dropInServiceResult.balanceJSON) + is BalanceDropInServiceResult.Error -> handleErrorDropInServiceResult(dropInServiceResult) } } + private fun handleErrorDropInServiceResult(dropInServiceResult: DropInServiceResultError) { + Logger.d(TAG, "handleDropInServiceResult ERROR - reason: ${dropInServiceResult.reason}") + val reason = dropInServiceResult.reason ?: "Unspecified reason" + val errorMessage = dropInServiceResult.errorMessage ?: getString(R.string.payment_failed) + showError(errorMessage, reason, dropInServiceResult.dismissDropIn) + } + + private fun handleAction(actionJSON: String) { + val action = Action.SERIALIZER.deserialize(JSONObject(actionJSON)) + actionHandler.handleAction(this, action, ::sendResult) + } + private fun sendResult(content: String) { val resultHandlerIntent = dropInViewModel.resultHandlerIntent // Merchant requested the result to be sent back with a result intent diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index 09946a9670..4e5bfe1955 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -16,6 +16,7 @@ import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.core.model.getStringOrNull import com.adyen.checkout.core.model.toStringPretty +import com.adyen.checkout.dropin.service.BalanceDropInServiceResult import com.adyen.checkout.dropin.service.DropInService import com.adyen.checkout.dropin.service.DropInServiceResult import com.adyen.checkout.example.data.api.model.paymentsRequest.AdditionalData @@ -133,23 +134,23 @@ class ExampleAsyncDropInService : DropInService() { val requestBody = paymentRequest.toString().toRequestBody(CONTENT_TYPE) val response = paymentsRepository.balanceRequestAsync(requestBody) val result = handleBalanceResponse(response) - sendResult(result) + sendBalanceResult(result) } } - private fun handleBalanceResponse(response: ResponseBody?): DropInServiceResult { + private fun handleBalanceResponse(response: ResponseBody?): BalanceDropInServiceResult { return if (response != null) { val balanceJson = response.string() val jsonResponse = JSONObject(balanceJson) val resultCode = jsonResponse.getStringOrNull("resultCode") when (resultCode) { - "Success" -> DropInServiceResult.Balance(balanceJson) - "NotEnoughBalance" -> DropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false) - else -> DropInServiceResult.Error(reason = resultCode, dismissDropIn = false) + "Success" -> BalanceDropInServiceResult.Balance(balanceJson) + "NotEnoughBalance" -> BalanceDropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false) + else -> BalanceDropInServiceResult.Error(reason = resultCode, dismissDropIn = false) } } else { Logger.e(TAG, "FAILED") - DropInServiceResult.Error(reason = "IOException") + BalanceDropInServiceResult.Error(reason = "IOException") } } } From c10e3413bb72375ca83d0f593c5076bba59aae1d Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 22 Nov 2021 13:54:14 +0100 Subject: [PATCH 031/102] Temporarily make gift cards unsupported until feature is completely done --- .../adyen/checkout/components/util/PaymentMethodTypes.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java index a65b6dc87a..39c6d9fb85 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java +++ b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java @@ -98,7 +98,6 @@ public final class PaymentMethodTypes { DOTPAY, ENTERCASH, EPS, - GIFTCARD, GOOGLE_PAY, GOOGLE_PAY_LEGACY, IDEAL, @@ -157,7 +156,9 @@ public final class PaymentMethodTypes { ECONTEXT_SEVEN_ELEVEN, ECONTEXT_ATM, ECONTEXT_STORES, - ECONTEXT_ONLINE + ECONTEXT_ONLINE, + + GIFTCARD )); } From 0db19225ef737d41f377b8fb7ef205b6646783b5 Mon Sep 17 00:00:00 2001 From: Caio Faustino Date: Fri, 19 Nov 2021 10:06:28 +0100 Subject: [PATCH 032/102] Remove Koin and use Hilt instead. --- build.gradle | 3 +- example-app/build.gradle | 8 ++- .../example/CheckoutExampleApplication.kt | 14 +--- .../adyen/checkout/example/di/AppModule.kt | 11 --- .../checkout/example/di/NetworkModule.kt | 72 +++++++++++-------- .../checkout/example/di/RepositoryModule.kt | 14 +++- .../checkout/example/di/StorageModule.kt | 20 ++++-- .../checkout/example/di/ViewModelModule.kt | 18 ----- .../service/ExampleAsyncDropInService.kt | 10 ++- .../example/service/ExampleDropInService.kt | 12 ++-- .../checkout/example/ui/main/MainActivity.kt | 12 ++-- .../ui/main/PaymentMethodsViewModel.kt | 7 +- 12 files changed, 107 insertions(+), 94 deletions(-) delete mode 100644 example-app/src/main/java/com/adyen/checkout/example/di/AppModule.kt delete mode 100644 example-app/src/main/java/com/adyen/checkout/example/di/ViewModelModule.kt diff --git a/build.gradle b/build.gradle index 18986bf3c8..bb8ad4f870 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ buildscript { ext.detekt_gradle_plugin_version = "1.17.1" ext.spotbugs_gradle_plugin_version = "4.5.1" ext.dokka_version = "1.4.32" + ext.hilt_version = "2.40.1" repositories { google() @@ -28,6 +29,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:$spotbugs_gradle_plugin_version" classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" } } @@ -74,7 +76,6 @@ allprojects { ext.multidex_version = "2.0.1" ext.constraintlayout_version = '2.0.2' ext.preference_version = "1.1.1" - ext.koin_version = "2.2.2" ext.retrofit2_version = '2.9.0' ext.coroutines_adapter_version = "0.9.2" ext.moshi_adapters_version = '1.11.0' diff --git a/example-app/build.gradle b/example-app/build.gradle index 571a9f4c5c..8cbdbb6b1d 100644 --- a/example-app/build.gradle +++ b/example-app/build.gradle @@ -9,6 +9,9 @@ plugins { id 'com.android.application' id 'kotlin-android' + id 'kotlin-kapt' + id 'dagger.hilt.android.plugin' + } apply from: "${rootDir}/config/gradle/codeQuality.gradle" @@ -94,9 +97,8 @@ dependencies { implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$coroutines_adapter_version" - implementation "io.insert-koin:koin-android:$koin_version" - implementation "io.insert-koin:koin-test:$koin_version" - implementation "io.insert-koin:koin-androidx-viewmodel:$koin_version" + implementation "com.google.dagger:hilt-android:$hilt_version" + kapt "com.google.dagger:hilt-compiler:$hilt_version" // Tests testImplementation "junit:junit:$junit_version" diff --git a/example-app/src/main/java/com/adyen/checkout/example/CheckoutExampleApplication.kt b/example-app/src/main/java/com/adyen/checkout/example/CheckoutExampleApplication.kt index 89caf2e64e..b534962c13 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/CheckoutExampleApplication.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/CheckoutExampleApplication.kt @@ -11,10 +11,9 @@ package com.adyen.checkout.example import android.util.Log import androidx.multidex.MultiDexApplication import com.adyen.checkout.core.log.Logger -import com.adyen.checkout.example.di.appModule -import org.koin.android.ext.koin.androidContext -import org.koin.core.context.startKoin +import dagger.hilt.android.HiltAndroidApp +@HiltAndroidApp class CheckoutExampleApplication : MultiDexApplication() { companion object { @@ -22,13 +21,4 @@ class CheckoutExampleApplication : MultiDexApplication() { Logger.setLogcatLevel(Log.DEBUG) } } - - override fun onCreate() { - super.onCreate() - - startKoin { - androidContext(this@CheckoutExampleApplication) - modules(appModule) - } - } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/di/AppModule.kt b/example-app/src/main/java/com/adyen/checkout/example/di/AppModule.kt deleted file mode 100644 index 3f3aa68917..0000000000 --- a/example-app/src/main/java/com/adyen/checkout/example/di/AppModule.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2019 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - * - * Created by arman on 9/10/2019. - */ - -package com.adyen.checkout.example.di - -val appModule = listOf(networkModule, storageManager, repositoryModule, viewModelModule) diff --git a/example-app/src/main/java/com/adyen/checkout/example/di/NetworkModule.kt b/example-app/src/main/java/com/adyen/checkout/example/di/NetworkModule.kt index 265b8fc861..7c373b0e72 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/di/NetworkModule.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/di/NetworkModule.kt @@ -15,27 +15,42 @@ import com.adyen.checkout.example.data.api.CheckoutApiService import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import java.security.KeyStore +import java.util.* +import javax.inject.Singleton +import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509TrustManager import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import org.koin.dsl.module +import retrofit2.Converter import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory -import java.security.KeyStore -import java.util.Arrays -import javax.net.ssl.TrustManagerFactory -import javax.net.ssl.X509TrustManager -val networkModule = module { +@Module +@InstallIn(SingletonComponent::class) +object NetworkModule { - fun provideHttpClient(): OkHttpClient { - val builder = OkHttpClient.Builder().let { + private val BASE_URL = if (CheckoutApiService.isRealUrlAvailable()) + BuildConfig.MERCHANT_SERVER_URL + else + "http://myserver.com/my/endpoint/" + + @Singleton + @Provides + fun provideOkHttpClient(): OkHttpClient { + val builder = OkHttpClient.Builder() + + if (BuildConfig.DEBUG) { val interceptor = HttpLoggingInterceptor() interceptor.level = HttpLoggingInterceptor.Level.BODY - it.addNetworkInterceptor(interceptor) + builder.addNetworkInterceptor(interceptor) } if (Build.VERSION_CODES.JELLY_BEAN <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) { - val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) trustManagerFactory.init(null as KeyStore?) val trustManagers = trustManagerFactory.trustManagers @@ -50,25 +65,26 @@ val networkModule = module { return builder.build() } - fun provideApi(httpClient: OkHttpClient): CheckoutApiService { - val baseUrl = - if (CheckoutApiService.isRealUrlAvailable()) - BuildConfig.MERCHANT_SERVER_URL - else - "http://myserver.com/my/endpoint/" - return Retrofit.Builder() - .baseUrl(baseUrl) - .client(httpClient) - .addConverterFactory( - MoshiConverterFactory.create( - Moshi.Builder().add(KotlinJsonAdapterFactory()).build() - ) - ) + @Singleton + @Provides + fun provideConverterFactory(): Converter.Factory = MoshiConverterFactory.create( + Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + ) + + @Singleton + @Provides + fun provideRetrofit( + okHttpClient: OkHttpClient, + converterFactory: Converter.Factory, + ): Retrofit = + Retrofit.Builder() + .baseUrl(BASE_URL) + .client(okHttpClient) + .addConverterFactory(converterFactory) .addCallAdapterFactory(CoroutineCallAdapterFactory()) .build() - .create(CheckoutApiService::class.java) - } - single { provideHttpClient() } - single { provideApi(get()) } + @Provides + fun provideApiService(retrofit: Retrofit): CheckoutApiService = + retrofit.create(CheckoutApiService::class.java) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/di/RepositoryModule.kt b/example-app/src/main/java/com/adyen/checkout/example/di/RepositoryModule.kt index 4225b89730..3933c5ca46 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/di/RepositoryModule.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/di/RepositoryModule.kt @@ -8,10 +8,18 @@ package com.adyen.checkout.example.di +import com.adyen.checkout.example.data.api.CheckoutApiService import com.adyen.checkout.example.repositories.paymentMethods.PaymentsRepository import com.adyen.checkout.example.repositories.paymentMethods.PaymentsRepositoryImpl -import org.koin.dsl.module +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent -val repositoryModule = module { - factory { PaymentsRepositoryImpl(get()) } +@Module +@InstallIn(SingletonComponent::class) +object RepositoryModule { + + @Provides + fun providePaymentsRepository(checkoutApiService: CheckoutApiService): PaymentsRepository = PaymentsRepositoryImpl(checkoutApiService) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/di/StorageModule.kt b/example-app/src/main/java/com/adyen/checkout/example/di/StorageModule.kt index c8c921cb69..e3d63ac1e9 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/di/StorageModule.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/di/StorageModule.kt @@ -8,12 +8,24 @@ package com.adyen.checkout.example.di +import android.app.Application +import android.content.SharedPreferences import androidx.preference.PreferenceManager import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.data.storage.KeyValueStorageImpl -import org.koin.dsl.module +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent -val storageManager = module { - single { PreferenceManager.getDefaultSharedPreferences(get()) } - single { KeyValueStorageImpl(get(), get()) } +@Module +@InstallIn(SingletonComponent::class) +object StorageModule { + + @Provides + fun provideSharedPreferences(appContext: Application): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(appContext) + + @Provides + fun provideKeyValueStorage(appContext: Application, sharedPreferences: SharedPreferences): KeyValueStorage = + KeyValueStorageImpl(appContext, sharedPreferences) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/di/ViewModelModule.kt b/example-app/src/main/java/com/adyen/checkout/example/di/ViewModelModule.kt deleted file mode 100644 index d646f89621..0000000000 --- a/example-app/src/main/java/com/adyen/checkout/example/di/ViewModelModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2019 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - * - * Created by arman on 9/10/2019. - */ - -package com.adyen.checkout.example.di - -import com.adyen.checkout.example.ui.main.PaymentMethodsViewModel -import org.koin.androidx.viewmodel.dsl.viewModel - -import org.koin.dsl.module - -val viewModelModule = module { - viewModel { PaymentMethodsViewModel(get(), get()) } -} diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index 4e5bfe1955..1e9a7c905f 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -23,6 +23,8 @@ import com.adyen.checkout.example.data.api.model.paymentsRequest.AdditionalData import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.paymentMethods.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import okhttp3.MediaType @@ -30,12 +32,12 @@ import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.ResponseBody import org.json.JSONObject -import org.koin.android.ext.android.inject /** * This is just an example on how to make networkModule calls on the [DropInService]. * You should make the calls to your own servers and have additional data or processing if necessary. */ +@AndroidEntryPoint class ExampleAsyncDropInService : DropInService() { companion object { @@ -43,8 +45,10 @@ class ExampleAsyncDropInService : DropInService() { private val CONTENT_TYPE: MediaType = "application/json".toMediaType() } - private val paymentsRepository: PaymentsRepository by inject() - private val keyValueStorage: KeyValueStorage by inject() + @Inject + lateinit var paymentsRepository: PaymentsRepository + @Inject + lateinit var keyValueStorage: KeyValueStorage override fun onPaymentsCallRequested(paymentComponentState: PaymentComponentState<*>, paymentComponentJson: JSONObject) { launch(Dispatchers.IO) { diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt index 853d7dc592..6f5a05331b 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt @@ -17,19 +17,21 @@ import com.adyen.checkout.example.data.api.model.paymentsRequest.AdditionalData import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.paymentMethods.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent +import dagger.hilt.android.AndroidEntryPoint +import java.io.IOException +import javax.inject.Inject import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.ResponseBody import org.json.JSONObject -import org.koin.android.ext.android.inject import retrofit2.Call -import java.io.IOException /** * This is just an example on how to make networkModule calls on the [DropInService]. * You should make the calls to your own servers and have additional data or processing if necessary. */ +@AndroidEntryPoint class ExampleDropInService : DropInService() { companion object { @@ -37,8 +39,10 @@ class ExampleDropInService : DropInService() { private val CONTENT_TYPE: MediaType = "application/json".toMediaType() } - private val paymentsRepository: PaymentsRepository by inject() - private val keyValueStorage: KeyValueStorage by inject() + @Inject + lateinit var paymentsRepository: PaymentsRepository + @Inject + lateinit var keyValueStorage: KeyValueStorage override fun makePaymentsCall(paymentComponentJson: JSONObject): DropInServiceResult { Logger.d(TAG, "makePaymentsCall") diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt index 7b5e32f15e..5c19ec90b1 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/main/MainActivity.kt @@ -14,6 +14,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.Toast +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import com.adyen.checkout.adyen3ds2.Adyen3DS2Configuration @@ -36,10 +37,11 @@ import com.adyen.checkout.example.databinding.ActivityMainBinding import com.adyen.checkout.example.service.ExampleAsyncDropInService import com.adyen.checkout.example.ui.configuration.ConfigurationActivity import com.adyen.checkout.googlepay.GooglePayConfiguration -import java.util.Locale -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel +import dagger.hilt.android.AndroidEntryPoint +import java.util.* +import javax.inject.Inject +@AndroidEntryPoint class MainActivity : AppCompatActivity(), DropInCallback { companion object { @@ -47,8 +49,8 @@ class MainActivity : AppCompatActivity(), DropInCallback { } private lateinit var binding: ActivityMainBinding - private val paymentMethodsViewModel: PaymentMethodsViewModel by viewModel() - private val keyValueStorage: KeyValueStorage by inject() + private val paymentMethodsViewModel: PaymentMethodsViewModel by viewModels() + @Inject lateinit var keyValueStorage: KeyValueStorage private val dropInLauncher = DropIn.registerForDropInResult(this, this) diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt index f310a97d86..8af04b3eb5 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt @@ -16,14 +16,17 @@ import com.adyen.checkout.core.log.Logger import com.adyen.checkout.example.data.api.model.paymentsRequest.PaymentMethodsRequest import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.paymentMethods.PaymentsRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancel import kotlinx.coroutines.launch -import kotlin.coroutines.CoroutineContext -class PaymentMethodsViewModel( +@HiltViewModel +class PaymentMethodsViewModel @Inject constructor( private val paymentsRepository: PaymentsRepository, private val keyValueStorage: KeyValueStorage ) : ViewModel() { From efc0f94768838408ecb2f8e7e2602d0510bd2f83 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 22 Nov 2021 17:26:47 +0100 Subject: [PATCH 033/102] Improve DropInServiceResult types by making serialization to ModelObjects required --- .../model/payments/response/BalanceResult.kt | 16 +++++---- .../dropin/service/DropInServiceResult.kt | 33 ++++++++++++++++--- .../checkout/dropin/ui/DropInActivity.kt | 13 ++++---- .../checkout/dropin/ui/DropInViewModel.kt | 17 ++-------- .../service/ExampleAsyncDropInService.kt | 7 ++-- .../example/service/ExampleDropInService.kt | 4 ++- 6 files changed, 56 insertions(+), 34 deletions(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt index 9d3562564f..c296c683a5 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/BalanceResult.kt @@ -8,15 +8,18 @@ package com.adyen.checkout.components.model.payments.response import android.os.Parcel +import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.model.JsonUtils.writeToParcel import com.adyen.checkout.core.model.ModelObject +import com.adyen.checkout.core.model.ModelUtils import org.json.JSONException import org.json.JSONObject data class BalanceResult( - val balance: String, - val transactionLimit: String? + val balance: Amount, + val transactionLimit: Amount? ) : ModelObject() { override fun writeToParcel(dest: Parcel, flags: Int) { @@ -35,8 +38,8 @@ data class BalanceResult( override fun serialize(modelObject: BalanceResult): JSONObject { return JSONObject().apply { try { - putOpt(BALANCE, modelObject.balance) - putOpt(TRANSACTION_LIMIT, modelObject.transactionLimit) + putOpt(BALANCE, ModelUtils.serializeOpt(modelObject.balance, Amount.SERIALIZER)) + putOpt(TRANSACTION_LIMIT, ModelUtils.serializeOpt(modelObject.transactionLimit, Amount.SERIALIZER)) } catch (e: JSONException) { throw ModelSerializationException(BalanceResult::class.java, e) } @@ -45,8 +48,9 @@ data class BalanceResult( override fun deserialize(jsonObject: JSONObject): BalanceResult { return BalanceResult( - balance = jsonObject.optString(BALANCE, null), - transactionLimit = jsonObject.optString(TRANSACTION_LIMIT, null) + balance = ModelUtils.deserializeOpt(jsonObject.optJSONObject(BALANCE), Amount.SERIALIZER) + ?: throw CheckoutException("Balance not found"), + transactionLimit = ModelUtils.deserializeOpt(jsonObject.optJSONObject(TRANSACTION_LIMIT), Amount.SERIALIZER) ) } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt index 42accc985d..2a01ee6fc0 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt @@ -8,6 +8,11 @@ package com.adyen.checkout.dropin.service +import com.adyen.checkout.components.model.payments.response.BalanceResult +import com.adyen.checkout.core.exception.CheckoutException +import org.json.JSONException +import org.json.JSONObject + sealed class BaseDropInServiceResult internal interface DropInServiceResultError { @@ -31,8 +36,27 @@ sealed class DropInServiceResult : BaseDropInServiceResult() { /** * Call was successful and returned with an * [com.adyen.checkout.components.model.payments.response.Action] that needs to be handled. + * + * Use [com.adyen.checkout.components.model.payments.response.Action.SERIALIZER] to serialize + * your JSON response string. */ - class Action(val actionJSON: String) : DropInServiceResult() + class Action : DropInServiceResult { + val action: com.adyen.checkout.components.model.payments.response.Action + + constructor(action: com.adyen.checkout.components.model.payments.response.Action) { + this.action = action + } + + @Deprecated("Use the new constructor which takes an Action object as parameter") + constructor(actionJSON: String) { + val actionJSONObject = try { + JSONObject(actionJSON) + } catch (e: JSONException) { + throw CheckoutException("Provided action is not a JSON object") + } + action = com.adyen.checkout.components.model.payments.response.Action.SERIALIZER.deserialize(actionJSONObject) + } + } /** * Call failed with an error. Can have the localized error message which will be shown @@ -50,10 +74,11 @@ sealed class BalanceDropInServiceResult : BaseDropInServiceResult() { /** * Only applicable for gift card flow. * - * A call to fetch a gift card balance was successful and returned with a - * [com.adyen.checkout.components.model.payments.response.BalanceResult] that needs to be handled. + * A call to fetch a gift card balance was successful and returned with a [BalanceResult] that needs to be handled. + * + * Use [BalanceResult.SERIALIZER] to serialize your JSON response string. */ - class Balance(val balanceJSON: String) : BalanceDropInServiceResult() + class Balance(val balance: BalanceResult) : BalanceDropInServiceResult() /** * Call failed with an error. Can have the localized error message which will be shown diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index f1ed7d0a2c..487dba034d 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -30,6 +30,7 @@ import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.PaymentMethod import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod import com.adyen.checkout.components.model.payments.response.Action +import com.adyen.checkout.components.model.payments.response.BalanceResult import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil @@ -62,7 +63,6 @@ import com.adyen.checkout.googlepay.GooglePayConfiguration import com.adyen.checkout.redirect.RedirectUtil import com.adyen.checkout.wechatpay.WeChatPayUtils import kotlinx.coroutines.ExperimentalCoroutinesApi -import org.json.JSONObject private val TAG = LogUtil.getTag() @@ -410,14 +410,14 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleDropInServiceResult(dropInServiceResult: DropInServiceResult) { when (dropInServiceResult) { is DropInServiceResult.Finished -> sendResult(dropInServiceResult.result) - is DropInServiceResult.Action -> handleAction(dropInServiceResult.actionJSON) + is DropInServiceResult.Action -> handleAction(dropInServiceResult.action) is DropInServiceResult.Error -> handleErrorDropInServiceResult(dropInServiceResult) } } private fun handleDropInServiceResult(dropInServiceResult: BalanceDropInServiceResult) { when (dropInServiceResult) { - is BalanceDropInServiceResult.Balance -> handleBalanceResult(dropInServiceResult.balanceJSON) + is BalanceDropInServiceResult.Balance -> handleBalanceResult(dropInServiceResult.balance) is BalanceDropInServiceResult.Error -> handleErrorDropInServiceResult(dropInServiceResult) } } @@ -429,8 +429,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot showError(errorMessage, reason, dropInServiceResult.dismissDropIn) } - private fun handleAction(actionJSON: String) { - val action = Action.SERIALIZER.deserialize(JSONObject(actionJSON)) + private fun handleAction(action: Action) { actionHandler.handleAction(this, action, ::sendResult) } @@ -522,9 +521,9 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } } - private fun handleBalanceResult(balanceJson: String) { + private fun handleBalanceResult(balanceResult: BalanceResult) { Logger.v(TAG, "handleBalanceResult") - val result = dropInViewModel.handleBalanceResult(balanceJson) + val result = dropInViewModel.handleBalanceResult(balanceResult) Logger.d(TAG, "handleBalanceResult: ${result::class.java.simpleName}") when (result) { is GiftCardBalanceResult.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 5e477919ba..524fde6993 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -105,23 +105,12 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return paymentMethod } - fun handleBalanceResult(balanceJson: String): GiftCardBalanceResult { - val balanceJSONObject = try { - JSONObject(balanceJson) - } catch (e: JSONException) { - throw CheckoutException("Provided balance is not a JSON object") - } - val balanceResult = BalanceResult.SERIALIZER.deserialize(balanceJSONObject) + fun handleBalanceResult(balanceResult: BalanceResult): GiftCardBalanceResult { Logger.d(TAG, "handleBalanceResult - balance: ${balanceResult.balance} - transactionLimit: ${balanceResult.transactionLimit}") - val balance = Amount.SERIALIZER.deserialize(JSONObject(balanceResult.balance)) - val transactionLimitString = balanceResult.transactionLimit - val transactionLimit = - if (transactionLimitString == null) null - else Amount.SERIALIZER.deserialize(JSONObject(transactionLimitString)) val giftCardBalanceResult = GiftCardBalanceUtils.checkBalance( - balance = balance, - transactionLimit = transactionLimit, + balance = balanceResult.balance, + transactionLimit = balanceResult.transactionLimit, amountToBePaid = dropInConfiguration.amount ) val cachedGiftCardComponentState = cachedGiftCardComponentState ?: throw CheckoutException("Failed to retrieved cached gift card object") diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index 1e9a7c905f..7823f9482f 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -12,6 +12,8 @@ import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.components.ActionComponentData import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails +import com.adyen.checkout.components.model.payments.response.Action +import com.adyen.checkout.components.model.payments.response.BalanceResult import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.core.model.getStringOrNull @@ -107,7 +109,8 @@ class ExampleAsyncDropInService : DropInService() { return if (response != null) { val detailsResponse = JSONObject(response.string()) if (detailsResponse.has("action")) { - DropInServiceResult.Action(detailsResponse.get("action").toString()) + val action = Action.SERIALIZER.deserialize(detailsResponse.getJSONObject("action")) + DropInServiceResult.Action(action) } else { Logger.d(TAG, "Final result - ${detailsResponse.toStringPretty()}") @@ -148,7 +151,7 @@ class ExampleAsyncDropInService : DropInService() { val jsonResponse = JSONObject(balanceJson) val resultCode = jsonResponse.getStringOrNull("resultCode") when (resultCode) { - "Success" -> BalanceDropInServiceResult.Balance(balanceJson) + "Success" -> BalanceDropInServiceResult.Balance(BalanceResult.SERIALIZER.deserialize(jsonResponse)) "NotEnoughBalance" -> BalanceDropInServiceResult.Error(reason = "Not enough balance", dismissDropIn = false) else -> BalanceDropInServiceResult.Error(reason = resultCode, dismissDropIn = false) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt index 6f5a05331b..0ccd2d97d3 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt @@ -8,6 +8,7 @@ package com.adyen.checkout.example.service +import com.adyen.checkout.components.model.payments.response.Action import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.core.model.toStringPretty @@ -93,7 +94,8 @@ class ExampleDropInService : DropInService() { if (response.isSuccessful) { val detailsResponse = JSONObject(response.body()?.string() ?: "") if (detailsResponse.has("action")) { - DropInServiceResult.Action(detailsResponse.get("action").toString()) + val action = Action.SERIALIZER.deserialize(detailsResponse.getJSONObject("action")) + DropInServiceResult.Action(action) } else { Logger.d(TAG, "Final result - ${detailsResponse.toStringPretty()}") From 025a13577b46a12ebf8702edf1e0076f14701efa Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 22 Nov 2021 17:27:09 +0100 Subject: [PATCH 034/102] Implement Amount.toString() to improve logging --- .../adyen/checkout/components/model/payments/Amount.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java index ba739559d3..0043e0997d 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java @@ -95,4 +95,10 @@ public void setValue(int value) { public boolean isEmpty() { return EMPTY_CURRENCY.equals(currency) || value == EMPTY_VALUE; } + + @NonNull + @Override + public String toString() { + return value + " " + currency; + } } From 10670288f1f52746926b78a72aa680586d073f4e Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 12 Nov 2021 10:46:44 +0100 Subject: [PATCH 035/102] Add create order functionality --- .../model/payments/response/OrderResponse.kt | 72 +++++++++++++++++++ .../checkout/dropin/service/DropInService.kt | 19 ++++- .../dropin/service/DropInServiceResult.kt | 24 +++++++ .../checkout/dropin/ui/DropInActivity.kt | 35 ++++++++- .../example/data/api/CheckoutApiService.kt | 4 ++ .../paymentMethods/PaymentsRepository.kt | 7 ++ .../service/ExampleAsyncDropInService.kt | 35 +++++++++ .../checkout/example/service/RequestUtils.kt | 11 +++ 8 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/payments/response/OrderResponse.kt diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/OrderResponse.kt b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/OrderResponse.kt new file mode 100644 index 0000000000..9427b98c19 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/OrderResponse.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 12/11/2021. + */ +package com.adyen.checkout.components.model.payments.response + +import android.os.Parcel +import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.model.JsonUtils.writeToParcel +import com.adyen.checkout.core.model.ModelObject +import com.adyen.checkout.core.model.ModelUtils +import org.json.JSONException +import org.json.JSONObject + +data class OrderResponse( + val pspReference: String, + val orderData: String, + val reference: String?, + val amount: Amount?, + val remainingAmount: Amount?, + val expiresAt: String? +) : ModelObject() { + + override fun writeToParcel(dest: Parcel, flags: Int) { + writeToParcel(dest, SERIALIZER.serialize(this)) + } + + companion object { + private const val PSP_REFERENCE = "pspReference" + private const val ORDER_DATA = "orderData" + private const val REFERENCE = "reference" + private const val AMOUNT = "amount" + private const val REMAINING_AMOUNT = "remainingAmount" + private const val EXPIRES_AT = "expiresAt" + + @JvmField + val CREATOR = Creator(OrderResponse::class.java) + + @JvmField + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: OrderResponse): JSONObject { + return JSONObject().apply { + try { + putOpt(PSP_REFERENCE, modelObject.pspReference) + putOpt(ORDER_DATA, modelObject.orderData) + putOpt(REFERENCE, modelObject.reference) + putOpt(AMOUNT, ModelUtils.serializeOpt(modelObject.amount, Amount.SERIALIZER)) + putOpt(REMAINING_AMOUNT, ModelUtils.serializeOpt(modelObject.remainingAmount, Amount.SERIALIZER)) + putOpt(EXPIRES_AT, modelObject.expiresAt) + } catch (e: JSONException) { + throw ModelSerializationException(OrderResponse::class.java, e) + } + } + } + + override fun deserialize(jsonObject: JSONObject): OrderResponse { + return OrderResponse( + pspReference = jsonObject.optString(PSP_REFERENCE, ""), + orderData = jsonObject.optString(ORDER_DATA, ""), + reference = jsonObject.optString(REFERENCE, ""), + amount = ModelUtils.deserializeOpt(jsonObject.optJSONObject(AMOUNT), Amount.SERIALIZER), + remainingAmount = ModelUtils.deserializeOpt(jsonObject.optJSONObject(REMAINING_AMOUNT), Amount.SERIALIZER), + expiresAt = jsonObject.optString(EXPIRES_AT, "") + ) + } + } + } +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt index e2d4427eec..681da10b94 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInService.kt @@ -207,7 +207,13 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface protected fun sendBalanceResult(result: BalanceDropInServiceResult) { // send response back to activity - Logger.d(TAG, "dispatching DropInServiceResult") + Logger.d(TAG, "dispatching BalanceDropInServiceResult") + mResultLiveData.postValue(result) + } + + protected fun sendOrderResult(result: OrderDropInServiceResult) { + // send response back to activity + Logger.d(TAG, "dispatching OrderDropInServiceResult") mResultLiveData.postValue(result) } @@ -280,6 +286,16 @@ abstract class DropInService : Service(), CoroutineScope, DropInServiceInterface throw NotImplementedError("Method checkBalance is not implemented") } + override fun requestOrdersCall() { + Logger.d(TAG, "requestOrdersCall") + createOrder() + } + + // TODO docs + open fun createOrder() { + throw NotImplementedError("Method createOrder is not implemented") + } + override fun observeResult(owner: LifecycleOwner, observer: Observer) { mResultLiveData.observe(owner, observer) } @@ -311,4 +327,5 @@ internal interface DropInServiceInterface { fun requestPaymentsCall(paymentComponentState: PaymentComponentState<*>) fun requestDetailsCall(actionComponentData: ActionComponentData) fun requestBalanceCall(paymentMethodData: PaymentMethodDetails) + fun requestOrdersCall() } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt index 2a01ee6fc0..faa37e3c71 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.dropin.service import com.adyen.checkout.components.model.payments.response.BalanceResult +import com.adyen.checkout.components.model.payments.response.OrderResponse import com.adyen.checkout.core.exception.CheckoutException import org.json.JSONException import org.json.JSONObject @@ -90,3 +91,26 @@ sealed class BalanceDropInServiceResult : BaseDropInServiceResult() { override val dismissDropIn: Boolean = false ) : BalanceDropInServiceResult(), DropInServiceResultError } + +sealed class OrderDropInServiceResult : BaseDropInServiceResult() { + + /** + * Only applicable for gift card flow. + * + * A call to create a new order was successful and returned with a + * [OrderResponse] that needs to be handled. + * + * Use [OrderResponse.SERIALIZER] to serialize your JSON response string. + */ + class OrderCreated(val order: OrderResponse) : OrderDropInServiceResult() + + /** + * Call failed with an error. Can have the localized error message which will be shown + * in an Alert Dialog, otherwise a generic error message will be shown. + */ + class Error( + override val errorMessage: String? = null, + override val reason: String? = null, + override val dismissDropIn: Boolean = false + ) : OrderDropInServiceResult(), DropInServiceResultError +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 487dba034d..355e3f8526 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -31,6 +31,7 @@ import com.adyen.checkout.components.model.paymentmethods.PaymentMethod import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod import com.adyen.checkout.components.model.payments.response.Action import com.adyen.checkout.components.model.payments.response.BalanceResult +import com.adyen.checkout.components.model.payments.response.OrderResponse import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil @@ -46,6 +47,7 @@ import com.adyen.checkout.dropin.service.DropInService import com.adyen.checkout.dropin.service.DropInServiceInterface import com.adyen.checkout.dropin.service.DropInServiceResult import com.adyen.checkout.dropin.service.DropInServiceResultError +import com.adyen.checkout.dropin.service.OrderDropInServiceResult import com.adyen.checkout.dropin.ui.action.ActionComponentDialogFragment import com.adyen.checkout.dropin.ui.base.DropInBottomSheetDialogFragment import com.adyen.checkout.dropin.ui.component.CardComponentDialogFragment @@ -107,6 +109,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private var paymentDataQueue: PaymentComponentState<*>? = null private var actionDataQueue: ActionComponentData? = null private var balanceDataQueue: GiftCardComponentState? = null + private var orderDataQueue: Unit? = null private val serviceConnection = object : ServiceConnection { @@ -132,6 +135,11 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot requestBalanceCall(it) balanceDataQueue = null } + orderDataQueue?.let { + Logger.d(TAG, "Sending queued order request") + requestOrdersCall() + orderDataQueue = null + } } override fun onServiceDisconnected(className: ComponentName) { @@ -398,12 +406,25 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot dropInService?.requestBalanceCall(paymentMethod) } + private fun requestOrdersCall() { + Logger.d(TAG, "requestOrdersCall") + if (dropInService == null) { + Logger.e(TAG, "requestOrdersCall - service is disconnected") + orderDataQueue = Unit + return + } + dropInViewModel.isWaitingResult = true + setLoading(true) + dropInService?.requestOrdersCall() + } + private fun handleDropInServiceResult(dropInServiceResult: BaseDropInServiceResult) { Logger.d(TAG, "handleDropInServiceResult - ${dropInServiceResult::class.simpleName}") dropInViewModel.isWaitingResult = false when (dropInServiceResult) { is DropInServiceResult -> handleDropInServiceResult(dropInServiceResult) is BalanceDropInServiceResult -> handleDropInServiceResult(dropInServiceResult) + is OrderDropInServiceResult -> handleDropInServiceResult(dropInServiceResult) } } @@ -422,6 +443,13 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } } + private fun handleDropInServiceResult(dropInServiceResult: OrderDropInServiceResult) { + when (dropInServiceResult) { + is OrderDropInServiceResult.OrderCreated -> handleOrderResult(dropInServiceResult.order) + is OrderDropInServiceResult.Error -> handleErrorDropInServiceResult(dropInServiceResult) + } + } + private fun handleErrorDropInServiceResult(dropInServiceResult: DropInServiceResultError) { Logger.d(TAG, "handleDropInServiceResult ERROR - reason: ${dropInServiceResult.reason}") val reason = dropInServiceResult.reason ?: "Unspecified reason" @@ -548,7 +576,12 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleGiftCardPartialPayment(partialPayment: GiftCardBalanceResult.PartialPayment) { Logger.d(TAG, "handleGiftCardPartialPayment") setLoading(false) - // TODO handle partial payment + requestOrdersCall() + } + + private fun handleOrderResult(order: OrderResponse) { + Logger.v(TAG, "handleOrderResult") + // TODO handle order } companion object { diff --git a/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt b/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt index 461a2f6068..1a4f0e6fae 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/data/api/CheckoutApiService.kt @@ -55,4 +55,8 @@ interface CheckoutApiService { @Headers(BuildConfig.API_KEY_HEADER_NAME + ":" + BuildConfig.CHECKOUT_API_KEY) @POST("paymentMethods/balance") fun checkBalanceAsync(@Body balanceRequest: RequestBody): Deferred> + + @Headers(BuildConfig.API_KEY_HEADER_NAME + ":" + BuildConfig.CHECKOUT_API_KEY) + @POST("orders") + fun createOrderAsync(@Body orderRequest: RequestBody): Deferred> } diff --git a/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt b/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt index 95b1e9b5d4..ea8d23b3c3 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/repositories/paymentMethods/PaymentsRepository.kt @@ -23,6 +23,7 @@ interface PaymentsRepository { fun detailsRequest(paymentsRequest: RequestBody): Call suspend fun detailsRequestAsync(paymentsRequest: RequestBody): ResponseBody? suspend fun balanceRequestAsync(balanceRequest: RequestBody): ResponseBody? + suspend fun createOrderAsync(orderRequest: RequestBody): ResponseBody? } class PaymentsRepositoryImpl(private val checkoutApiService: CheckoutApiService) : PaymentsRepository, BaseRepository() { @@ -58,4 +59,10 @@ class PaymentsRepositoryImpl(private val checkoutApiService: CheckoutApiService) call = { checkoutApiService.checkBalanceAsync(balanceRequest).await() } ) } + + override suspend fun createOrderAsync(orderRequest: RequestBody): ResponseBody? { + return safeApiCall( + call = { checkoutApiService.createOrderAsync(orderRequest).await() } + ) + } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index 7823f9482f..aea39f9d74 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -14,6 +14,7 @@ import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.components.model.payments.response.Action import com.adyen.checkout.components.model.payments.response.BalanceResult +import com.adyen.checkout.components.model.payments.response.OrderResponse import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.core.model.getStringOrNull @@ -21,6 +22,7 @@ import com.adyen.checkout.core.model.toStringPretty import com.adyen.checkout.dropin.service.BalanceDropInServiceResult import com.adyen.checkout.dropin.service.DropInService import com.adyen.checkout.dropin.service.DropInServiceResult +import com.adyen.checkout.dropin.service.OrderDropInServiceResult import com.adyen.checkout.example.data.api.model.paymentsRequest.AdditionalData import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.paymentMethods.PaymentsRepository @@ -160,4 +162,37 @@ class ExampleAsyncDropInService : DropInService() { BalanceDropInServiceResult.Error(reason = "IOException") } } + + override fun createOrder() { + launch(Dispatchers.IO) { + Logger.d(TAG, "createOrder") + + val paymentRequest = createOrderRequest( + keyValueStorage.getAmount(), + keyValueStorage.getMerchantAccount() + ) + + val requestBody = paymentRequest.toString().toRequestBody(CONTENT_TYPE) + val response = paymentsRepository.createOrderAsync(requestBody) + + val result = handleOrderResponse(response) + sendOrderResult(result) + } + } + + @Suppress("NestedBlockDepth") + private fun handleOrderResponse(response: ResponseBody?): OrderDropInServiceResult { + return if (response != null) { + val orderJson = response.string() + val jsonResponse = JSONObject(orderJson) + val resultCode = jsonResponse.getStringOrNull("resultCode") + when (resultCode) { + "Success" -> OrderDropInServiceResult.OrderCreated(OrderResponse.SERIALIZER.deserialize(jsonResponse)) + else -> OrderDropInServiceResult.Error(reason = resultCode, dismissDropIn = false) + } + } else { + Logger.e(TAG, "FAILED") + OrderDropInServiceResult.Error(reason = "IOException") + } + } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt index 264bb684d4..971ec1eae5 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt @@ -59,3 +59,14 @@ fun createBalanceRequest( put("merchantAccount", merchantAccount) } } + +fun createOrderRequest( + amount: Amount, + merchantAccount: String +): JSONObject { + return JSONObject().apply { + put("amount", JSONObject(Gson().toJson(amount))) + put("merchantAccount", merchantAccount) + put("reference", "android-test-components_${System.currentTimeMillis()}") + } +} From 418a9b35e640f307093cb1dcd3cab1411ccb5585 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 12 Nov 2021 14:45:54 +0100 Subject: [PATCH 036/102] Add order to payments call if available --- .../model/payments/request/Order.kt | 54 +++++++++++++++++++ .../request/PaymentComponentData.java | 13 +++++ .../checkout/dropin/ui/DropInActivity.kt | 10 ++-- .../checkout/dropin/ui/DropInViewModel.kt | 49 +++++++++++++++++ .../checkout/example/service/RequestUtils.kt | 2 +- 5 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/payments/request/Order.kt diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/Order.kt b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/Order.kt new file mode 100644 index 0000000000..55e24e4c7f --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/Order.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 12/11/2021. + */ +package com.adyen.checkout.components.model.payments.request + +import android.os.Parcel +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.model.JsonUtils.writeToParcel +import com.adyen.checkout.core.model.ModelObject +import org.json.JSONException +import org.json.JSONObject + +data class Order( + val pspReference: String, + val orderData: String +) : ModelObject() { + + override fun writeToParcel(dest: Parcel, flags: Int) { + writeToParcel(dest, SERIALIZER.serialize(this)) + } + + companion object { + private const val PSP_REFERENCE = "pspReference" + private const val ORDER_DATA = "orderData" + + @JvmField + val CREATOR = Creator(Order::class.java) + + @JvmField + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: Order): JSONObject { + return JSONObject().apply { + try { + putOpt(PSP_REFERENCE, modelObject.pspReference) + putOpt(ORDER_DATA, modelObject.orderData) + } catch (e: JSONException) { + throw ModelSerializationException(Order::class.java, e) + } + } + } + + override fun deserialize(jsonObject: JSONObject): Order { + return Order( + pspReference = jsonObject.optString(PSP_REFERENCE, ""), + orderData = jsonObject.optString(ORDER_DATA, "") + ) + } + } + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentComponentData.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentComponentData.java index cb11014620..3b7ba7448f 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentComponentData.java +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentComponentData.java @@ -40,6 +40,7 @@ public class PaymentComponentData SERIALIZER = new Serializer() { @@ -61,6 +62,7 @@ public JSONObject serialize(@NonNull PaymentComponentData modelObject) { jsonObject.putOpt(DATE_OF_BIRTH, modelObject.getDateOfBirth()); jsonObject.putOpt(SOCIAL_SECURITY_NUMBER, modelObject.getSocialSecurityNumber()); jsonObject.putOpt(INSTALLMENTS, ModelUtils.serializeOpt(modelObject.getInstallments(), Installments.SERIALIZER)); + jsonObject.putOpt(ORDER, ModelUtils.serializeOpt(modelObject.getOrder(), Order.SERIALIZER)); } catch (JSONException e) { throw new ModelSerializationException(PaymentComponentData.class, e); } @@ -90,6 +92,7 @@ public PaymentComponentData deserialize(@NonNull JSONObject jsonObject) { paymentComponentData.setInstallments( ModelUtils.deserializeOpt(jsonObject.optJSONObject(INSTALLMENTS), Installments.SERIALIZER) ); + paymentComponentData.setOrder(ModelUtils.deserializeOpt(jsonObject.optJSONObject(ORDER), Order.SERIALIZER)); return paymentComponentData; } @@ -107,6 +110,7 @@ public PaymentComponentData deserialize(@NonNull JSONObject jsonObject) { private String dateOfBirth; private String socialSecurityNumber; private Installments installments; + private Order order; @Override public void writeToParcel(@NonNull Parcel dest, int flags) { @@ -219,4 +223,13 @@ public Installments getInstallments() { public void setInstallments(@Nullable Installments installments) { this.installments = installments; } + + @Nullable + public Order getOrder() { + return order; + } + + public void setOrder(@Nullable Order order) { + this.order = order; + } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 355e3f8526..155aac68ad 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -273,10 +273,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot } dropInViewModel.isWaitingResult = true setLoading(true) - // include amount value if merchant passed it to the DropIn - if (!dropInViewModel.dropInConfiguration.amount.isEmpty) { - paymentComponentState.data.amount = dropInViewModel.dropInConfiguration.amount - } + dropInViewModel.updatePaymentComponentStateForPaymentsCall(paymentComponentState) dropInService?.requestPaymentsCall(paymentComponentState) } @@ -581,7 +578,10 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleOrderResult(order: OrderResponse) { Logger.v(TAG, "handleOrderResult") - // TODO handle order + dropInViewModel.handleOrderResponse(order) + val paymentComponentState = dropInViewModel.cachedGiftCardComponentState + ?: throw CheckoutException("Lost reference to cached GiftCardComponentState") + requestPaymentsCall(paymentComponentState) } companion object { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 524fde6993..55c38e4103 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -11,11 +11,14 @@ package com.adyen.checkout.dropin.ui import android.content.Intent import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.components.model.payments.request.Order import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.components.model.payments.response.BalanceResult +import com.adyen.checkout.components.model.payments.response.OrderResponse import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil @@ -38,6 +41,8 @@ private const val DROP_IN_CONFIGURATION_KEY = "DROP_IN_CONFIGURATION_KEY" private const val DROP_IN_RESULT_INTENT_KEY = "DROP_IN_RESULT_INTENT_KEY" private const val IS_WAITING_FOR_RESULT_KEY = "IS_WAITING_FOR_RESULT_KEY" private const val CACHED_GIFT_CARD = "CACHED_GIFT_CARD" +private const val CURRENT_ORDER = "CURRENT_ORDER" +private const val PARTIAL_PAYMENT_AMOUNT = "PARTIAL_PAYMENT_AMOUNT" class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { @@ -61,6 +66,22 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode savedStateHandle[CACHED_GIFT_CARD] = value } + private var cachedPartialPaymentAmount: Amount? + get() { + return savedStateHandle.get(PARTIAL_PAYMENT_AMOUNT) + } + private set(value) { + savedStateHandle[PARTIAL_PAYMENT_AMOUNT] = value + } + + private var currentOrder: OrderResponse? + get() { + return savedStateHandle.get(CURRENT_ORDER) + } + private set(value) { + savedStateHandle[CURRENT_ORDER] = value + } + private fun getStateValueOrFail(key: String): T { val value: T? = savedStateHandle[key] if (value == null) { @@ -133,6 +154,7 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode ) } is GiftCardBalanceStatus.PartialPayment -> { + cachedPartialPaymentAmount = giftCardBalanceResult.amountPaid GiftCardBalanceResult.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) } } @@ -151,6 +173,33 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode ) } + fun handleOrderResponse(orderResponse: OrderResponse) { + currentOrder = orderResponse + Logger.d(TAG, "handleOrderResponse - Order cached") + } + + fun updatePaymentComponentStateForPaymentsCall(paymentComponentState: PaymentComponentState<*>) { + // include amount value if merchant passed it to the DropIn + val amount = when { + cachedPartialPaymentAmount != null -> cachedPartialPaymentAmount + !dropInConfiguration.amount.isEmpty -> dropInConfiguration.amount + else -> null + } + if (amount != null) { + paymentComponentState.data.amount = amount + } + currentOrder?.let { + paymentComponentState.data.order = createOrder(it) + } + } + + private fun createOrder(orderResponse: OrderResponse): Order { + return Order( + pspReference = orderResponse.pspReference, + orderData = orderResponse.orderData + ) + } + companion object { fun putIntentExtras( intent: Intent, diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt index 971ec1eae5..21a1fa8587 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt @@ -30,7 +30,7 @@ fun createPaymentRequest( return JSONObject(paymentComponentData.toString()).apply { put("shopperReference", shopperReference) - put("amount", JSONObject(Gson().toJson(amount))) + if (!has("amount")) put("amount", JSONObject(Gson().toJson(amount))) put("merchantAccount", merchantAccount) put("returnUrl", redirectUrl) put("countryCode", countryCode) From a578dc1cd5af8d410b61a4424dcd264e5f57a0bd Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 22 Nov 2021 17:49:40 +0100 Subject: [PATCH 037/102] Allow updating drop in with order and payment methods --- .../dropin/service/DropInServiceResult.kt | 19 +++++ .../checkout/dropin/ui/DropInActivity.kt | 8 ++ .../checkout/dropin/ui/DropInViewModel.kt | 18 +++-- .../paymentsRequest/PaymentMethodsRequest.kt | 6 +- .../service/ExampleAsyncDropInService.kt | 74 +++++++++++++++---- .../checkout/example/service/RequestUtils.kt | 15 ++++ .../ui/main/PaymentMethodsViewModel.kt | 19 ++--- 7 files changed, 124 insertions(+), 35 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt index faa37e3c71..4bf2c1dba1 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt @@ -8,6 +8,7 @@ package com.adyen.checkout.dropin.service +import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.payments.response.BalanceResult import com.adyen.checkout.components.model.payments.response.OrderResponse import com.adyen.checkout.core.exception.CheckoutException @@ -59,6 +60,24 @@ sealed class DropInServiceResult : BaseDropInServiceResult() { } } + /** + * Only applicable for gift card flow. + * + * Update drop-in with a new list of payment methods and optionally an order. + * + * After submitting a partial payment, you need to call /paymentMethods again with the new remaining payment amount, and + * pass the updated payment methods list, alongside the latest order object. + * + * Also after cancelling an order, you need to call /paymentMethods again with the original payment amount, and pass the + * updated payment methods list, with a null order object. + * + * Use [OrderResponse.SERIALIZER] to serialize your JSON response string. + * + * @param paymentMethodsApiResponse the updated payment methods list. + * @param order the order object returned from the backend, or null if an order was cancelled. + */ + class Update(val paymentMethodsApiResponse: PaymentMethodsApiResponse, val order: OrderResponse?) : DropInServiceResult() + /** * Call failed with an error. Can have the localized error message which will be shown * in an Alert Dialog, otherwise a generic error message will be shown. diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 155aac68ad..bf66d17e88 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -429,6 +429,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot when (dropInServiceResult) { is DropInServiceResult.Finished -> sendResult(dropInServiceResult.result) is DropInServiceResult.Action -> handleAction(dropInServiceResult.action) + is DropInServiceResult.Update -> handlePaymentMethodsUpdate(dropInServiceResult) is DropInServiceResult.Error -> handleErrorDropInServiceResult(dropInServiceResult) } } @@ -458,6 +459,13 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot actionHandler.handleAction(this, action, ::sendResult) } + private fun handlePaymentMethodsUpdate(dropInServiceResult: DropInServiceResult.Update) { + dropInViewModel.handlePaymentMethodsUpdate( + dropInServiceResult.paymentMethodsApiResponse, + dropInServiceResult.order + ) + } + private fun sendResult(content: String) { val resultHandlerIntent = dropInViewModel.resultHandlerIntent // Merchant requested the result to be sent back with a result intent diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 55c38e4103..527137a472 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -31,8 +31,6 @@ import com.adyen.checkout.giftcard.GiftCardComponentState import com.adyen.checkout.giftcard.util.GiftCardBalanceStatus import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent -import org.json.JSONException -import org.json.JSONObject private val TAG = LogUtil.getTag() @@ -173,9 +171,14 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode ) } - fun handleOrderResponse(orderResponse: OrderResponse) { - currentOrder = orderResponse - Logger.d(TAG, "handleOrderResponse - Order cached") + fun handleOrderResponse(orderResponse: OrderResponse?) { + if (orderResponse == null) { + currentOrder = null + Logger.d(TAG, "handleOrderResponse - Order cancelled") + } else { + currentOrder = orderResponse + Logger.d(TAG, "handleOrderResponse - Order cached") + } } fun updatePaymentComponentStateForPaymentsCall(paymentComponentState: PaymentComponentState<*>) { @@ -200,6 +203,11 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode ) } + fun handlePaymentMethodsUpdate(paymentMethodsApiResponse: PaymentMethodsApiResponse, order: OrderResponse?) { + handleOrderResponse(order) + // TODO handle paymentMethodsApiResponse + } + companion object { fun putIntentExtras( intent: Intent, diff --git a/example-app/src/main/java/com/adyen/checkout/example/data/api/model/paymentsRequest/PaymentMethodsRequest.kt b/example-app/src/main/java/com/adyen/checkout/example/data/api/model/paymentsRequest/PaymentMethodsRequest.kt index 760b673fba..d026f017b5 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/data/api/model/paymentsRequest/PaymentMethodsRequest.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/data/api/model/paymentsRequest/PaymentMethodsRequest.kt @@ -9,16 +9,18 @@ package com.adyen.checkout.example.data.api.model.paymentsRequest import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.components.model.payments.request.Order data class PaymentMethodsRequest( val merchantAccount: String, val shopperReference: String, // val additionalData: Any, // val allowedPaymentMethods: ArrayList, - val amount: Amount, + val amount: Amount?, // val blockedPaymentMethods: ArrayList, val countryCode: String = "NL", val shopperLocale: String = "en_US", val channel: String = "android", - val splitCardFundingSources: Boolean = false + val splitCardFundingSources: Boolean = false, + val order: Order? ) diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index aea39f9d74..5d0cc600d1 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.example.service import com.adyen.checkout.card.CardComponentState import com.adyen.checkout.components.ActionComponentData import com.adyen.checkout.components.PaymentComponentState +import com.adyen.checkout.components.model.payments.request.Order import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.components.model.payments.response.Action import com.adyen.checkout.components.model.payments.response.BalanceResult @@ -51,6 +52,7 @@ class ExampleAsyncDropInService : DropInService() { @Inject lateinit var paymentsRepository: PaymentsRepository + @Inject lateinit var keyValueStorage: KeyValueStorage @@ -79,7 +81,7 @@ class ExampleAsyncDropInService : DropInService() { val requestBody = paymentRequest.toString().toRequestBody(CONTENT_TYPE) val response = paymentsRepository.paymentsRequestAsync(requestBody) - val result = handleResponse(response) + val result = handleResponse(response) ?: return@launch sendResult(result) } } @@ -102,30 +104,72 @@ class ExampleAsyncDropInService : DropInService() { val requestBody = actionComponentJson.toString().toRequestBody(CONTENT_TYPE) val response = paymentsRepository.detailsRequestAsync(requestBody) - val result = handleResponse(response) + val result = handleResponse(response) ?: return@launch sendResult(result) } } - private fun handleResponse(response: ResponseBody?): DropInServiceResult { - return if (response != null) { - val detailsResponse = JSONObject(response.string()) - if (detailsResponse.has("action")) { - val action = Action.SERIALIZER.deserialize(detailsResponse.getJSONObject("action")) + private fun handleResponse(response: ResponseBody?): DropInServiceResult? { + val jsonResponse = if (response == null) null else JSONObject(response.string()) + return when { + jsonResponse == null -> { + Logger.e(TAG, "FAILED") + DropInServiceResult.Error(reason = "IOException") + } + isAction(jsonResponse) -> { + Logger.d(TAG, "Received action") + val action = Action.SERIALIZER.deserialize(jsonResponse.getJSONObject("action")) DropInServiceResult.Action(action) - } else { - Logger.d(TAG, "Final result - ${detailsResponse.toStringPretty()}") - - val resultCode = if (detailsResponse.has("resultCode")) { - detailsResponse.get("resultCode").toString() + } + isNonFullyPaidOrder(jsonResponse) -> { + Logger.d(TAG, "Received a non fully paid order") + fetchPaymentMethods(jsonResponse) + null + } + else -> { + Logger.d(TAG, "Final result - ${jsonResponse.toStringPretty()}") + val resultCode = if (jsonResponse.has("resultCode")) { + jsonResponse.get("resultCode").toString() } else { "EMPTY" } DropInServiceResult.Finished(resultCode) } - } else { - Logger.e(TAG, "FAILED") - DropInServiceResult.Error(reason = "IOException") + } + } + + private fun isAction(jsonResponse: JSONObject): Boolean { + return jsonResponse.has("action") + } + + private fun isNonFullyPaidOrder(jsonResponse: JSONObject): Boolean { + return jsonResponse.has("order") && getOrderFromResponse(jsonResponse).remainingAmount?.value ?: 0 > 0 + } + + private fun getOrderFromResponse(jsonResponse: JSONObject): OrderResponse { + val orderJSON = jsonResponse.getJSONObject("order") + return OrderResponse.SERIALIZER.deserialize(orderJSON) + } + + private fun fetchPaymentMethods(jsonResponse: JSONObject) { + launch(Dispatchers.IO) { + val order = getOrderFromResponse(jsonResponse) + val paymentMethods = paymentsRepository.getPaymentMethods( + getPaymentMethodRequest( + keyValueStorage, + Order( + pspReference = order.pspReference, + orderData = order.orderData + ) + ) + ) + val result = if (paymentMethods != null) { + DropInServiceResult.Update(paymentMethods, order) + } else { + Logger.e(TAG, "FAILED") + DropInServiceResult.Error(reason = "IOException") + } + sendResult(result) } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt index 21a1fa8587..ccec5caa5f 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/RequestUtils.kt @@ -9,12 +9,27 @@ package com.adyen.checkout.example.service import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.components.model.payments.request.Order import com.adyen.checkout.example.data.api.model.paymentsRequest.AdditionalData import com.adyen.checkout.example.data.api.model.paymentsRequest.Item +import com.adyen.checkout.example.data.api.model.paymentsRequest.PaymentMethodsRequest +import com.adyen.checkout.example.data.storage.KeyValueStorage import com.google.gson.Gson import org.json.JSONArray import org.json.JSONObject +fun getPaymentMethodRequest(keyValueStorage: KeyValueStorage, order: Order? = null): PaymentMethodsRequest { + return PaymentMethodsRequest( + merchantAccount = keyValueStorage.getMerchantAccount(), + shopperReference = keyValueStorage.getShopperReference(), + amount = if (order == null) keyValueStorage.getAmount() else null, + countryCode = keyValueStorage.getCountry(), + shopperLocale = keyValueStorage.getShopperLocale(), + splitCardFundingSources = keyValueStorage.isSplitCardFundingSources(), + order = order + ) +} + @Suppress("LongParameterList") fun createPaymentRequest( paymentComponentData: JSONObject, diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt index 8af04b3eb5..08f1d5d952 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/main/PaymentMethodsViewModel.kt @@ -13,11 +13,11 @@ import androidx.lifecycle.ViewModel import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger -import com.adyen.checkout.example.data.api.model.paymentsRequest.PaymentMethodsRequest import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.paymentMethods.PaymentsRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import com.adyen.checkout.example.service.getPaymentMethodRequest import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -45,21 +45,14 @@ class PaymentMethodsViewModel @Inject constructor( fun requestPaymentMethods() { scope.launch { - paymentMethodResponseLiveData.postValue(paymentsRepository.getPaymentMethods(getPaymentMethodRequest())) + paymentMethodResponseLiveData.postValue( + paymentsRepository.getPaymentMethods( + getPaymentMethodRequest(keyValueStorage) + ) + ) } } - private fun getPaymentMethodRequest(): PaymentMethodsRequest { - return PaymentMethodsRequest( - merchantAccount = keyValueStorage.getMerchantAccount(), - shopperReference = keyValueStorage.getShopperReference(), - amount = keyValueStorage.getAmount(), - countryCode = keyValueStorage.getCountry(), - shopperLocale = keyValueStorage.getShopperLocale(), - splitCardFundingSources = keyValueStorage.isSplitCardFundingSources() - ) - } - override fun onCleared() { super.onCleared() Logger.d(TAG, "onCleared") From cea82b25f01150ac3447bb4665ec192004c494a6 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 22 Nov 2021 18:10:02 +0100 Subject: [PATCH 038/102] Handle payment methods update and synchronize remaining amount across drop-in --- .../checkout/dropin/ui/DropInActivity.kt | 5 ++- .../checkout/dropin/ui/DropInViewModel.kt | 41 +++++++++++++++++-- .../component/CardComponentDialogFragment.kt | 4 +- .../GenericComponentDialogFragment.kt | 4 +- .../PreselectedStoredPaymentMethodFragment.kt | 2 +- .../googlepay/GooglePayConfiguration.java | 19 +++++++++ 6 files changed, 65 insertions(+), 10 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index bf66d17e88..639c2eb57e 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -382,7 +382,8 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot override fun startGooglePay(paymentMethod: PaymentMethod, googlePayConfiguration: GooglePayConfiguration) { Logger.d(TAG, "startGooglePay") - googlePayComponent = GooglePayComponent.PROVIDER.get(this, paymentMethod, googlePayConfiguration) + val configuration = dropInViewModel.updateGooglePayConfiguration(googlePayConfiguration) + googlePayComponent = GooglePayComponent.PROVIDER.get(this, paymentMethod, configuration) googlePayComponent.observe(this@DropInActivity, googlePayObserver) googlePayComponent.observeErrors(this@DropInActivity, googlePayErrorObserver) @@ -464,6 +465,8 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot dropInServiceResult.paymentMethodsApiResponse, dropInServiceResult.order ) + setLoading(false) + showPaymentMethodsDialog() } private fun sendResult(content: String) { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 527137a472..02f11b7958 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -31,6 +31,7 @@ import com.adyen.checkout.giftcard.GiftCardComponentState import com.adyen.checkout.giftcard.util.GiftCardBalanceStatus import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent +import com.adyen.checkout.googlepay.GooglePayConfiguration private val TAG = LogUtil.getTag() @@ -41,13 +42,29 @@ private const val IS_WAITING_FOR_RESULT_KEY = "IS_WAITING_FOR_RESULT_KEY" private const val CACHED_GIFT_CARD = "CACHED_GIFT_CARD" private const val CURRENT_ORDER = "CURRENT_ORDER" private const val PARTIAL_PAYMENT_AMOUNT = "PARTIAL_PAYMENT_AMOUNT" +private const val AMOUNT = "AMOUNT" class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { - val paymentMethodsApiResponse: PaymentMethodsApiResponse = getStateValueOrFail(PAYMENT_METHODS_RESPONSE_KEY) val dropInConfiguration: DropInConfiguration = getStateValueOrFail(DROP_IN_CONFIGURATION_KEY) val resultHandlerIntent: Intent? = savedStateHandle[DROP_IN_RESULT_INTENT_KEY] + var amount: Amount + get() { + return getStateValueOrFail(AMOUNT) + } + private set(value) { + savedStateHandle[AMOUNT] = value + } + + var paymentMethodsApiResponse: PaymentMethodsApiResponse + get() { + return getStateValueOrFail(PAYMENT_METHODS_RESPONSE_KEY) + } + private set(value) { + savedStateHandle[PAYMENT_METHODS_RESPONSE_KEY] = value + } + var isWaitingResult: Boolean get() { return savedStateHandle[IS_WAITING_FOR_RESULT_KEY] ?: false @@ -89,6 +106,10 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return value } + init { + amount = dropInConfiguration.amount + } + val showPreselectedStored = paymentMethodsApiResponse.storedPaymentMethods?.any { it.isEcommerce } == true && dropInConfiguration.showPreselectedStoredPaymentMethod val preselectedStoredPayment = paymentMethodsApiResponse.storedPaymentMethods?.firstOrNull { @@ -130,7 +151,7 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode val giftCardBalanceResult = GiftCardBalanceUtils.checkBalance( balance = balanceResult.balance, transactionLimit = balanceResult.transactionLimit, - amountToBePaid = dropInConfiguration.amount + amountToBePaid = amount ) val cachedGiftCardComponentState = cachedGiftCardComponentState ?: throw CheckoutException("Failed to retrieved cached gift card object") return when (giftCardBalanceResult) { @@ -174,9 +195,13 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode fun handleOrderResponse(orderResponse: OrderResponse?) { if (orderResponse == null) { currentOrder = null + amount = dropInConfiguration.amount + Logger.d(TAG, "handleOrderResponse - Amount reverted: ${amount.value}") Logger.d(TAG, "handleOrderResponse - Order cancelled") } else { currentOrder = orderResponse + amount = orderResponse.remainingAmount ?: throw CheckoutException("Provided order does not have a remainingAmount") + Logger.d(TAG, "handleOrderResponse - New amount set: ${amount.value}") Logger.d(TAG, "handleOrderResponse - Order cached") } } @@ -185,14 +210,17 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode // include amount value if merchant passed it to the DropIn val amount = when { cachedPartialPaymentAmount != null -> cachedPartialPaymentAmount - !dropInConfiguration.amount.isEmpty -> dropInConfiguration.amount + !amount.isEmpty -> amount else -> null } + cachedPartialPaymentAmount = null if (amount != null) { paymentComponentState.data.amount = amount + Logger.d(TAG, "Payment amount set: ${amount.value}") } currentOrder?.let { paymentComponentState.data.order = createOrder(it) + Logger.d(TAG, "Order appended to payment") } } @@ -205,7 +233,12 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode fun handlePaymentMethodsUpdate(paymentMethodsApiResponse: PaymentMethodsApiResponse, order: OrderResponse?) { handleOrderResponse(order) - // TODO handle paymentMethodsApiResponse + this.paymentMethodsApiResponse = paymentMethodsApiResponse + } + + fun updateGooglePayConfiguration(googlePayConfiguration: GooglePayConfiguration): GooglePayConfiguration { + if (currentOrder == null) return googlePayConfiguration + return GooglePayConfiguration.Builder(googlePayConfiguration).setAmount(amount).build() } companion object { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/CardComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/CardComponentDialogFragment.kt index d596c2c345..0f0e4f84bc 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/CardComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/CardComponentDialogFragment.kt @@ -68,8 +68,8 @@ class CardComponentDialogFragment : BaseComponentDialogFragment() { val cardComponent = component as CardComponent - if (!dropInConfiguration.amount.isEmpty) { - val value = CurrencyUtils.formatAmount(dropInConfiguration.amount, dropInConfiguration.shopperLocale) + if (!dropInViewModel.amount.isEmpty) { + val value = CurrencyUtils.formatAmount(dropInViewModel.amount, dropInConfiguration.shopperLocale) binding.payButton.text = String.format(resources.getString(R.string.pay_button_with_value), value) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GenericComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GenericComponentDialogFragment.kt index 232d02c31a..4dfc7eb0c4 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GenericComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/GenericComponentDialogFragment.kt @@ -60,8 +60,8 @@ class GenericComponentDialogFragment : BaseComponentDialogFragment() { Logger.d(TAG, "onViewCreated") binding.header.text = paymentMethod.name - if (!dropInConfiguration.amount.isEmpty) { - val value = CurrencyUtils.formatAmount(dropInConfiguration.amount, dropInConfiguration.shopperLocale) + if (!dropInViewModel.amount.isEmpty) { + val value = CurrencyUtils.formatAmount(dropInViewModel.amount, dropInConfiguration.shopperLocale) binding.payButton.text = String.format(resources.getString(R.string.pay_button_with_value), value) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt index f1607cc11f..4ef0e56e73 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt @@ -114,7 +114,7 @@ class PreselectedStoredPaymentMethodFragment : DropInBottomSheetDialogFragment() binding.payButton.setText(R.string.continue_button) } else { val value = CurrencyUtils.formatAmount( - dropInViewModel.dropInConfiguration.amount, + dropInViewModel.amount, dropInViewModel.dropInConfiguration.shopperLocale ) binding.payButton.text = getString(R.string.pay_button_with_value, value) diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java b/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java index 949adbcb92..94a32283bd 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java @@ -244,6 +244,25 @@ public Builder(@NonNull Locale shopperLocale, @NonNull Environment environment, super(shopperLocale, environment, clientKey); } + public Builder(@NonNull GooglePayConfiguration configuration) { + super(configuration.getShopperLocale(), configuration.getEnvironment(), configuration.getClientKey()); + mBuilderMerchantAccount = configuration.getMerchantAccount(); + mBuilderGooglePayEnvironment = configuration.getGooglePayEnvironment(); + mBuilderAmount = configuration.getAmount(); + mBuilderTotalPriceStatus = configuration.getTotalPriceStatus(); + mBuilderCountryCode = configuration.getCountryCode(); + mBuilderMerchantInfo = configuration.getMerchantInfo(); + mBuilderAllowedAuthMethods = configuration.getAllowedAuthMethods(); + mBuilderAllowedCardNetworks = configuration.getAllowedCardNetworks(); + mBuilderAllowPrepaidCards = configuration.isAllowPrepaidCards(); + mBuilderEmailRequired = configuration.isEmailRequired(); + mBuilderExistingPaymentMethodRequired = configuration.isExistingPaymentMethodRequired(); + mBuilderShippingAddressRequired = configuration.isShippingAddressRequired(); + mBuilderShippingAddressParameters = configuration.getShippingAddressParameters(); + mBuilderBillingAddressRequired = configuration.isBillingAddressRequired(); + mBuilderBillingAddressParameters = configuration.getBillingAddressParameters(); + } + @Override @NonNull public Builder setShopperLocale(@NonNull Locale builderShopperLocale) { From 7fbd811dff22297a56be95a98b900e90f85c409d Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 24 Nov 2021 18:01:58 +0100 Subject: [PATCH 039/102] Do not create order if already created --- .../com/adyen/checkout/dropin/ui/DropInActivity.kt | 13 ++++++------- .../com/adyen/checkout/dropin/ui/DropInViewModel.kt | 3 ++- .../dropin/ui/giftcard/GiftCardBalanceResult.kt | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 639c2eb57e..63062da0f7 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -564,7 +564,8 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot when (result) { is GiftCardBalanceResult.Error -> showError(getString(result.errorMessage), result.reason, result.terminateDropIn) is GiftCardBalanceResult.FullPayment -> handleGiftCardFullPayment(result) - is GiftCardBalanceResult.PartialPayment -> handleGiftCardPartialPayment(result) + is GiftCardBalanceResult.RequestOrderCreation -> requestOrdersCall() + is GiftCardBalanceResult.RequestPartialPayment -> requestPartialPayment() } } @@ -581,15 +582,13 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot .show(supportFragmentManager, GIFT_CARD_PAYMENT_CONFIRMATION_FRAGMENT_TAG) } - private fun handleGiftCardPartialPayment(partialPayment: GiftCardBalanceResult.PartialPayment) { - Logger.d(TAG, "handleGiftCardPartialPayment") - setLoading(false) - requestOrdersCall() - } - private fun handleOrderResult(order: OrderResponse) { Logger.v(TAG, "handleOrderResult") dropInViewModel.handleOrderResponse(order) + requestPartialPayment() + } + + private fun requestPartialPayment() { val paymentComponentState = dropInViewModel.cachedGiftCardComponentState ?: throw CheckoutException("Lost reference to cached GiftCardComponentState") requestPaymentsCall(paymentComponentState) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 02f11b7958..6694ba7fb1 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -174,7 +174,8 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode } is GiftCardBalanceStatus.PartialPayment -> { cachedPartialPaymentAmount = giftCardBalanceResult.amountPaid - GiftCardBalanceResult.PartialPayment(giftCardBalanceResult.amountPaid, giftCardBalanceResult.remainingBalance) + if (currentOrder == null) GiftCardBalanceResult.RequestOrderCreation + else GiftCardBalanceResult.RequestPartialPayment } } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceResult.kt index c54b623e9e..3c58c11ab5 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardBalanceResult.kt @@ -9,10 +9,10 @@ package com.adyen.checkout.dropin.ui.giftcard import androidx.annotation.StringRes -import com.adyen.checkout.components.model.payments.Amount sealed class GiftCardBalanceResult { class FullPayment(val data: GiftCardPaymentConfirmationData) : GiftCardBalanceResult() - class PartialPayment(val amountPaid: Amount, val remainingBalance: Amount) : GiftCardBalanceResult() + object RequestOrderCreation : GiftCardBalanceResult() + object RequestPartialPayment : GiftCardBalanceResult() class Error(@StringRes val errorMessage: Int, val reason: String, val terminateDropIn: Boolean) : GiftCardBalanceResult() } From 5ed23aea25b139b3b3a46fcef488efccd4e882ae Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 24 Nov 2021 18:15:05 +0100 Subject: [PATCH 040/102] Code fixes --- .../com/adyen/checkout/dropin/service/DropInServiceResult.kt | 1 + .../main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt | 1 + .../adyen/checkout/example/service/ExampleAsyncDropInService.kt | 1 + 3 files changed, 3 insertions(+) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt index 4bf2c1dba1..69bb0256ee 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/service/DropInServiceResult.kt @@ -42,6 +42,7 @@ sealed class DropInServiceResult : BaseDropInServiceResult() { * Use [com.adyen.checkout.components.model.payments.response.Action.SERIALIZER] to serialize * your JSON response string. */ + @Suppress("MemberNameEqualsClassName") class Action : DropInServiceResult { val action: com.adyen.checkout.components.model.payments.response.Action diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 6694ba7fb1..150e4e333b 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -44,6 +44,7 @@ private const val CURRENT_ORDER = "CURRENT_ORDER" private const val PARTIAL_PAYMENT_AMOUNT = "PARTIAL_PAYMENT_AMOUNT" private const val AMOUNT = "AMOUNT" +@Suppress("TooManyFunctions") class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { val dropInConfiguration: DropInConfiguration = getStateValueOrFail(DROP_IN_CONFIGURATION_KEY) diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt index 5d0cc600d1..0c4eeb36f9 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAsyncDropInService.kt @@ -42,6 +42,7 @@ import org.json.JSONObject * This is just an example on how to make networkModule calls on the [DropInService]. * You should make the calls to your own servers and have additional data or processing if necessary. */ +@Suppress("TooManyFunctions") @AndroidEntryPoint class ExampleAsyncDropInService : DropInService() { From eb66f85438aab8c315537b098d21b9b88d10c3c9 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 3 Dec 2021 11:12:33 +0100 Subject: [PATCH 041/102] Minor fixes --- .../checkout/components/model/payments/Amount.java | 4 ++-- .../com/adyen/checkout/dropin/ui/DropInViewModel.kt | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java index 0043e0997d..2406c66e6b 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/Amount.java @@ -96,9 +96,9 @@ public boolean isEmpty() { return EMPTY_CURRENCY.equals(currency) || value == EMPTY_VALUE; } - @NonNull @Override + @NonNull public String toString() { - return value + " " + currency; + return "Amount(" + currency + ", " + value + ")"; } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 150e4e333b..69b1d91dba 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -198,12 +198,12 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode if (orderResponse == null) { currentOrder = null amount = dropInConfiguration.amount - Logger.d(TAG, "handleOrderResponse - Amount reverted: ${amount.value}") + Logger.d(TAG, "handleOrderResponse - Amount reverted: $amount") Logger.d(TAG, "handleOrderResponse - Order cancelled") } else { currentOrder = orderResponse amount = orderResponse.remainingAmount ?: throw CheckoutException("Provided order does not have a remainingAmount") - Logger.d(TAG, "handleOrderResponse - New amount set: ${amount.value}") + Logger.d(TAG, "handleOrderResponse - New amount set: $amount") Logger.d(TAG, "handleOrderResponse - Order cached") } } @@ -216,9 +216,9 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode else -> null } cachedPartialPaymentAmount = null - if (amount != null) { - paymentComponentState.data.amount = amount - Logger.d(TAG, "Payment amount set: ${amount.value}") + amount?.let { + paymentComponentState.data.amount = it + Logger.d(TAG, "Payment amount set: $it") } currentOrder?.let { paymentComponentState.data.order = createOrder(it) From 42a63f29b8dea4553e81b579bbef5711ddb5559f Mon Sep 17 00:00:00 2001 From: jreij Date: Thu, 25 Nov 2021 14:02:10 +0100 Subject: [PATCH 042/102] Add order status checkout shopper endpoint and repository --- .../components/api/OrderStatusConnection.kt | 42 +++++++++++ .../model/connection/OrderPaymentMethod.kt | 70 ++++++++++++++++++ .../model/connection/OrderStatusRequest.kt | 52 ++++++++++++++ .../model/connection/OrderStatusResponse.kt | 71 +++++++++++++++++++ .../repository/OrderStatusRepository.kt | 48 +++++++++++++ 5 files changed, 283 insertions(+) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/api/OrderStatusConnection.kt create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderPaymentMethod.kt create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusRequest.kt create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusResponse.kt create mode 100644 components-core/src/main/java/com/adyen/checkout/components/repository/OrderStatusRepository.kt diff --git a/components-core/src/main/java/com/adyen/checkout/components/api/OrderStatusConnection.kt b/components-core/src/main/java/com/adyen/checkout/components/api/OrderStatusConnection.kt new file mode 100644 index 0000000000..990d346c03 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/api/OrderStatusConnection.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 15/11/2021. + */ + +package com.adyen.checkout.components.api + +import com.adyen.checkout.components.model.connection.OrderStatusRequest +import com.adyen.checkout.components.model.connection.OrderStatusResponse +import com.adyen.checkout.core.api.Connection +import com.adyen.checkout.core.api.Environment +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.core.model.toStringPretty +import java.io.IOException +import org.json.JSONException +import org.json.JSONObject + +private val TAG = LogUtil.getTag() +private const val ENDPOINT = "v1/order/status?clientKey=" + +class OrderStatusConnection( + private val request: OrderStatusRequest, + environment: Environment, + clientKey: String +) : Connection( + "${environment.baseUrl}$ENDPOINT$clientKey" +) { + @Throws(IOException::class, JSONException::class) + override fun call(): OrderStatusResponse { + Logger.v(TAG, "call - $url") + val requestJson = OrderStatusRequest.SERIALIZER.serialize(request) + Logger.v(TAG, "request - ${requestJson.toStringPretty()}") + val result = post(CONTENT_TYPE_JSON_HEADER, requestJson.toString().toByteArray(Charsets.UTF_8)) + val resultJson = JSONObject(String(result, Charsets.UTF_8)) + Logger.v(TAG, "response: ${resultJson.toStringPretty()}") + return OrderStatusResponse.SERIALIZER.deserialize(resultJson) + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderPaymentMethod.kt b/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderPaymentMethod.kt new file mode 100644 index 0000000000..c14bbc5b90 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderPaymentMethod.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 15/11/2021. + */ + +package com.adyen.checkout.components.model.connection + +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.model.JsonUtils +import com.adyen.checkout.core.model.ModelObject +import com.adyen.checkout.core.model.ModelUtils +import org.json.JSONException +import org.json.JSONObject + +data class OrderPaymentMethod( + val type: String, + val amount: Amount, + val lastFour: String, + val transactionLimit: Amount? +) : ModelObject() { + + override fun writeToParcel(parcel: Parcel, flags: Int) { + JsonUtils.writeToParcel(parcel, SERIALIZER.serialize(this)) + } + + companion object { + private const val TYPE = "type" + private const val AMOUNT = "amount" + private const val LAST_FOUR = "lastFour" + private const val TRANSACTION_LIMIT = "transactionLimit" + + @JvmField + val CREATOR: Parcelable.Creator = Creator(OrderPaymentMethod::class.java) + + @JvmStatic + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: OrderPaymentMethod): JSONObject { + val jsonObject = JSONObject() + try { + jsonObject.putOpt(TYPE, modelObject.type) + jsonObject.putOpt(LAST_FOUR, modelObject.lastFour) + jsonObject.putOpt(AMOUNT, ModelUtils.serializeOpt(modelObject.amount, Amount.SERIALIZER)) + jsonObject.putOpt(TRANSACTION_LIMIT, ModelUtils.serializeOpt(modelObject.transactionLimit, Amount.SERIALIZER)) + } catch (e: JSONException) { + throw ModelSerializationException(OrderPaymentMethod::class.java, e) + } + return jsonObject + } + + override fun deserialize(jsonObject: JSONObject): OrderPaymentMethod { + return try { + OrderPaymentMethod( + type = jsonObject.getString(TYPE), + lastFour = jsonObject.getString(LAST_FOUR), + amount = ModelUtils.deserializeOpt(jsonObject.optJSONObject(AMOUNT), Amount.SERIALIZER) ?: Amount.EMPTY, + transactionLimit = ModelUtils.deserializeOpt(jsonObject.optJSONObject(TRANSACTION_LIMIT), Amount.SERIALIZER) + ) + } catch (e: JSONException) { + throw ModelSerializationException(OrderPaymentMethod::class.java, e) + } + } + } + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusRequest.kt b/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusRequest.kt new file mode 100644 index 0000000000..43b23f631a --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusRequest.kt @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 15/11/2021. + */ + +package com.adyen.checkout.components.model.connection + +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.model.JsonUtils +import com.adyen.checkout.core.model.ModelObject +import org.json.JSONException +import org.json.JSONObject + +data class OrderStatusRequest(val orderData: String) : ModelObject() { + + override fun writeToParcel(parcel: Parcel, flags: Int) { + JsonUtils.writeToParcel(parcel, SERIALIZER.serialize(this)) + } + + companion object { + private const val ORDER_DATA = "orderData" + + @JvmField + val CREATOR: Parcelable.Creator = Creator(OrderStatusRequest::class.java) + + @JvmStatic + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: OrderStatusRequest): JSONObject { + val jsonObject = JSONObject() + try { + jsonObject.putOpt(ORDER_DATA, modelObject.orderData) + } catch (e: JSONException) { + throw ModelSerializationException(OrderStatusRequest::class.java, e) + } + return jsonObject + } + + override fun deserialize(jsonObject: JSONObject): OrderStatusRequest { + return try { + OrderStatusRequest(orderData = jsonObject.getString(ORDER_DATA)) + } catch (e: JSONException) { + throw ModelSerializationException(OrderStatusRequest::class.java, e) + } + } + } + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusResponse.kt b/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusResponse.kt new file mode 100644 index 0000000000..13e9d94616 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/connection/OrderStatusResponse.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 15/11/2021. + */ + +package com.adyen.checkout.components.model.connection + +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.model.JsonUtils +import com.adyen.checkout.core.model.ModelObject +import com.adyen.checkout.core.model.ModelUtils +import org.json.JSONException +import org.json.JSONObject + +data class OrderStatusResponse( + val paymentMethods: List, + val remainingAmount: Amount +) : ModelObject() { + + override fun writeToParcel(parcel: Parcel, flags: Int) { + JsonUtils.writeToParcel(parcel, SERIALIZER.serialize(this)) + } + + companion object { + private const val PAYMENT_METHODS = "paymentMethods" + private const val REMAINING_AMOUNT = "remainingAmount" + + @JvmField + val CREATOR: Parcelable.Creator = Creator(OrderStatusResponse::class.java) + + @JvmStatic + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: OrderStatusResponse): JSONObject { + val jsonObject = JSONObject() + try { + jsonObject.putOpt( + PAYMENT_METHODS, + ModelUtils.serializeOptList(modelObject.paymentMethods, OrderPaymentMethod.SERIALIZER) + ) + jsonObject.putOpt(REMAINING_AMOUNT, modelObject.remainingAmount) + } catch (e: JSONException) { + throw ModelSerializationException(OrderStatusResponse::class.java, e) + } + return jsonObject + } + + override fun deserialize(jsonObject: JSONObject): OrderStatusResponse { + return try { + OrderStatusResponse( + paymentMethods = ModelUtils.deserializeOptList( + jsonObject.optJSONArray(PAYMENT_METHODS), + OrderPaymentMethod.SERIALIZER + ).orEmpty(), + remainingAmount = ModelUtils.deserializeOpt( + jsonObject.optJSONObject(REMAINING_AMOUNT), + Amount.SERIALIZER + ) ?: Amount.EMPTY + ) + } catch (e: JSONException) { + throw ModelSerializationException(OrderStatusResponse::class.java, e) + } + } + } + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/repository/OrderStatusRepository.kt b/components-core/src/main/java/com/adyen/checkout/components/repository/OrderStatusRepository.kt new file mode 100644 index 0000000000..e3fcca67fa --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/repository/OrderStatusRepository.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 15/11/2021. + */ + +package com.adyen.checkout.components.repository + +import com.adyen.checkout.components.api.OrderStatusConnection +import com.adyen.checkout.components.api.suspendedCall +import com.adyen.checkout.components.base.Configuration +import com.adyen.checkout.components.model.connection.OrderStatusRequest +import com.adyen.checkout.components.model.connection.OrderStatusResponse +import com.adyen.checkout.core.exception.CheckoutException +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger +import java.io.IOException +import org.json.JSONException + +class OrderStatusRepository { + + companion object { + private val TAG = LogUtil.getTag() + } + + suspend fun getOrderStatus( + configuration: Configuration, + orderData: String + ): OrderStatusResponse { + Logger.d(TAG, "Getting order status") + try { + val request = OrderStatusRequest(orderData) + return OrderStatusConnection( + request, + environment = configuration.environment, + clientKey = configuration.clientKey + ).suspendedCall() + } catch (e: IOException) { + Logger.e(TAG, "OrderStatusConnection Failed", e) + throw CheckoutException("Unable to get order status") + } catch (e: JSONException) { + Logger.e(TAG, "OrderStatusConnection unexpected result", e) + throw CheckoutException("Unable to get order status") + } + } +} From 604583f1fe78b23233e61e3937dda17b591920b4 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 26 Nov 2021 10:02:35 +0100 Subject: [PATCH 043/102] Fetch order status and show used gift cards --- .../checkout/dropin/ui/DropInActivity.kt | 35 ++++++-- .../checkout/dropin/ui/DropInActivityEvent.kt | 16 ++++ .../checkout/dropin/ui/DropInViewModel.kt | 82 ++++++++++++++++--- .../dropin/ui/DropInViewModelFactory.kt | 26 ++++++ .../base/DropInBottomSheetDialogFragment.kt | 2 + ...ftCardPaymentConfirmationDialogFragment.kt | 9 +- .../checkout/dropin/ui/order/OrderModel.kt | 47 +++++++++++ .../GiftCardPaymentMethodModel.kt | 6 +- .../PaymentMethodListDialogFragment.kt | 1 + .../PaymentMethodsListViewModel.kt | 19 +++++ 10 files changed, 215 insertions(+), 28 deletions(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModelFactory.kt create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/order/OrderModel.kt diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 63062da0f7..545c1eda82 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -21,6 +21,7 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.DialogFragment import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope import com.adyen.checkout.components.ActionComponentData import com.adyen.checkout.components.ComponentError import com.adyen.checkout.components.PaymentComponentState @@ -65,6 +66,7 @@ import com.adyen.checkout.googlepay.GooglePayConfiguration import com.adyen.checkout.redirect.RedirectUtil import com.adyen.checkout.wechatpay.WeChatPayUtils import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collect private val TAG = LogUtil.getTag() @@ -83,7 +85,7 @@ private const val GOOGLE_PAY_REQUEST_CODE = 1 @Suppress("TooManyFunctions") class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Protocol, ActionHandler.ActionHandlingInterface { - private val dropInViewModel: DropInViewModel by viewModels() + private val dropInViewModel: DropInViewModel by viewModels { DropInViewModelFactory(this, intent.extras) } private lateinit var googlePayComponent: GooglePayComponent @@ -189,6 +191,8 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot handleIntent(intent) sendAnalyticsEvent() + + initObservers() } private fun noDialogPresent(): Boolean { @@ -465,8 +469,6 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot dropInServiceResult.paymentMethodsApiResponse, dropInServiceResult.order ) - setLoading(false) - showPaymentMethodsDialog() } private fun sendResult(content: String) { @@ -538,6 +540,24 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot AnalyticsDispatcher.dispatchEvent(this, dropInViewModel.dropInConfiguration.environment, analyticEvent) } + private fun initObservers() { + lifecycleScope.launchWhenStarted { + dropInViewModel.eventsFlow.collect { handleEvent(it) } + } + } + + private fun handleEvent(event: DropInActivityEvent) { + when (event) { + is DropInActivityEvent.MakePartialPayment -> { + requestPaymentsCall(event.paymentComponentState) + } + is DropInActivityEvent.ShowPaymentMethods -> { + setLoading(false) + showPaymentMethodsDialog() + } + } + } + private fun hideFragmentDialog(tag: String) { getFragmentByTag(tag)?.dismiss() } @@ -584,14 +604,11 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot private fun handleOrderResult(order: OrderResponse) { Logger.v(TAG, "handleOrderResult") - dropInViewModel.handleOrderResponse(order) - requestPartialPayment() + dropInViewModel.handleOrderCreated(order) } - private fun requestPartialPayment() { - val paymentComponentState = dropInViewModel.cachedGiftCardComponentState - ?: throw CheckoutException("Lost reference to cached GiftCardComponentState") - requestPaymentsCall(paymentComponentState) + override fun requestPartialPayment() { + dropInViewModel.partialPaymentRequested() } companion object { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt new file mode 100644 index 0000000000..5bf67da4ee --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 29/11/2021. + */ + +package com.adyen.checkout.dropin.ui + +import com.adyen.checkout.components.PaymentComponentState + +sealed class DropInActivityEvent { + class MakePartialPayment(val paymentComponentState: PaymentComponentState<*>) : DropInActivityEvent() + object ShowPaymentMethods : DropInActivityEvent() +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index 69b1d91dba..d31935a237 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.dropin.ui import android.content.Intent import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.PaymentMethodsApiResponse import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod @@ -19,6 +20,7 @@ import com.adyen.checkout.components.model.payments.request.Order import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.components.model.payments.response.BalanceResult import com.adyen.checkout.components.model.payments.response.OrderResponse +import com.adyen.checkout.components.repository.OrderStatusRepository import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil @@ -27,11 +29,17 @@ import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.R import com.adyen.checkout.dropin.ui.giftcard.GiftCardBalanceResult import com.adyen.checkout.dropin.ui.giftcard.GiftCardPaymentConfirmationData +import com.adyen.checkout.dropin.ui.order.OrderModel +import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodsListViewModel import com.adyen.checkout.giftcard.GiftCardComponentState import com.adyen.checkout.giftcard.util.GiftCardBalanceStatus import com.adyen.checkout.giftcard.util.GiftCardBalanceUtils import com.adyen.checkout.googlepay.GooglePayComponent import com.adyen.checkout.googlepay.GooglePayConfiguration +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch private val TAG = LogUtil.getTag() @@ -45,7 +53,13 @@ private const val PARTIAL_PAYMENT_AMOUNT = "PARTIAL_PAYMENT_AMOUNT" private const val AMOUNT = "AMOUNT" @Suppress("TooManyFunctions") -class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { +class DropInViewModel( + private val savedStateHandle: SavedStateHandle, + private val orderStatusRepository: OrderStatusRepository = OrderStatusRepository() +) : ViewModel() { + + private val eventChannel = Channel(Channel.BUFFERED) + internal val eventsFlow = eventChannel.receiveAsFlow() val dropInConfiguration: DropInConfiguration = getStateValueOrFail(DROP_IN_CONFIGURATION_KEY) val resultHandlerIntent: Intent? = savedStateHandle[DROP_IN_RESULT_INTENT_KEY] @@ -74,7 +88,7 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode savedStateHandle[IS_WAITING_FOR_RESULT_KEY] = value } - var cachedGiftCardComponentState: GiftCardComponentState? + private var cachedGiftCardComponentState: GiftCardComponentState? get() { return savedStateHandle.get(CACHED_GIFT_CARD) } @@ -90,9 +104,9 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode savedStateHandle[PARTIAL_PAYMENT_AMOUNT] = value } - private var currentOrder: OrderResponse? + var currentOrder: OrderModel? get() { - return savedStateHandle.get(CURRENT_ORDER) + return savedStateHandle.get(CURRENT_ORDER) } private set(value) { savedStateHandle[CURRENT_ORDER] = value @@ -194,15 +208,25 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode ) } - fun handleOrderResponse(orderResponse: OrderResponse?) { - if (orderResponse == null) { + fun handleOrderCreated(orderResponse: OrderResponse) { + viewModelScope.launch(Dispatchers.IO) { + handleOrderResponse(orderResponse) + if (currentOrder != null) { + partialPaymentRequested() + } + } + } + + private suspend fun handleOrderResponse(orderResponse: OrderResponse?) { + val orderModel = getOrderStatus(orderResponse) + if (orderModel == null) { currentOrder = null amount = dropInConfiguration.amount Logger.d(TAG, "handleOrderResponse - Amount reverted: $amount") Logger.d(TAG, "handleOrderResponse - Order cancelled") } else { - currentOrder = orderResponse - amount = orderResponse.remainingAmount ?: throw CheckoutException("Provided order does not have a remainingAmount") + currentOrder = orderModel + amount = orderModel.remainingAmount Logger.d(TAG, "handleOrderResponse - New amount set: $amount") Logger.d(TAG, "handleOrderResponse - Order cached") } @@ -226,16 +250,19 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode } } - private fun createOrder(orderResponse: OrderResponse): Order { + private fun createOrder(order: OrderModel): Order { return Order( - pspReference = orderResponse.pspReference, - orderData = orderResponse.orderData + pspReference = order.pspReference, + orderData = order.orderData ) } fun handlePaymentMethodsUpdate(paymentMethodsApiResponse: PaymentMethodsApiResponse, order: OrderResponse?) { - handleOrderResponse(order) - this.paymentMethodsApiResponse = paymentMethodsApiResponse + viewModelScope.launch(Dispatchers.IO) { + handleOrderResponse(order) + this@DropInViewModel.paymentMethodsApiResponse = paymentMethodsApiResponse + sendEvent(DropInActivityEvent.ShowPaymentMethods) + } } fun updateGooglePayConfiguration(googlePayConfiguration: GooglePayConfiguration): GooglePayConfiguration { @@ -243,6 +270,35 @@ class DropInViewModel(private val savedStateHandle: SavedStateHandle) : ViewMode return GooglePayConfiguration.Builder(googlePayConfiguration).setAmount(amount).build() } + private suspend fun getOrderStatus(orderResponse: OrderResponse?): OrderModel? { + if (orderResponse == null) return null + return try { + val orderStatus = orderStatusRepository.getOrderStatus(dropInConfiguration, orderResponse.orderData) + OrderModel( + orderData = orderResponse.orderData, + pspReference = orderResponse.pspReference, + remainingAmount = orderStatus.remainingAmount, + paymentMethods = orderStatus.paymentMethods + ) + } catch (e: CheckoutException) { + Logger.e(PaymentMethodsListViewModel.TAG, "Unable to fetch order details") + null + } + } + + fun partialPaymentRequested() { + val paymentComponentState = cachedGiftCardComponentState + ?: throw CheckoutException("Lost reference to cached GiftCardComponentState") + sendEvent(DropInActivityEvent.MakePartialPayment(paymentComponentState)) + } + + private fun sendEvent(event: DropInActivityEvent) { + viewModelScope.launch { + Logger.d(TAG, "sendEvent - ${event::class.simpleName}") + eventChannel.send(event) + } + } + companion object { fun putIntentExtras( intent: Intent, diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModelFactory.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModelFactory.kt new file mode 100644 index 0000000000..cded6ce72e --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModelFactory.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 29/11/2021. + */ + +package com.adyen.checkout.dropin.ui + +import android.os.Bundle +import androidx.lifecycle.AbstractSavedStateViewModelFactory +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.savedstate.SavedStateRegistryOwner +import com.adyen.checkout.components.repository.OrderStatusRepository + +class DropInViewModelFactory( + owner: SavedStateRegistryOwner, + defaultArgs: Bundle? +) : AbstractSavedStateViewModelFactory(owner, defaultArgs) { + override fun create(key: String, modelClass: Class, handle: SavedStateHandle): T { + @Suppress("UNCHECKED_CAST") + return DropInViewModel(handle, OrderStatusRepository()) as T + } +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt index e81070b38c..b0bc645a4b 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt @@ -89,6 +89,7 @@ abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragment() { /** * Interface for Drop-in fragments to interact with the main Activity */ + @Suppress("TooManyFunctions") interface Protocol { fun showPreselectedDialog() fun showPaymentMethodsDialog() @@ -100,5 +101,6 @@ abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragment() { fun terminateDropIn() fun startGooglePay(paymentMethod: PaymentMethod, googlePayConfiguration: GooglePayConfiguration) fun requestBalanceCall(giftCardComponentState: GiftCardComponentState) + fun requestPartialPayment() } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt index e82a51dad8..50c95c072b 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt @@ -17,7 +17,6 @@ import android.view.ViewGroup import androidx.recyclerview.widget.LinearLayoutManager import com.adyen.checkout.components.api.ImageLoader import com.adyen.checkout.components.util.CurrencyUtils -import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.R @@ -73,9 +72,7 @@ class GiftCardPaymentConfirmationDialogFragment : DropInBottomSheetDialogFragmen initRecyclerView() binding.payButton.setOnClickListener { - val paymentComponentState = dropInViewModel.cachedGiftCardComponentState - ?: throw CheckoutException("Lost reference to cached GiftCardComponentState") - protocol.requestPaymentsCall(paymentComponentState) + protocol.requestPartialPayment() } } @@ -83,7 +80,9 @@ class GiftCardPaymentConfirmationDialogFragment : DropInBottomSheetDialogFragmen val paymentMethods = listOf( GiftCardPaymentMethodModel( imageId = giftCardPaymentConfirmationData.brand, - lastFour = giftCardPaymentConfirmationData.lastFourDigits + lastFour = giftCardPaymentConfirmationData.lastFourDigits, + amount = null, + transactionLimit = null ) ) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/order/OrderModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/order/OrderModel.kt new file mode 100644 index 0000000000..27024638eb --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/order/OrderModel.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 29/11/2021. + */ + +package com.adyen.checkout.dropin.ui.order + +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.model.connection.OrderPaymentMethod +import com.adyen.checkout.components.model.payments.Amount + +data class OrderModel( + val orderData: String, + val pspReference: String, + val remainingAmount: Amount, + val paymentMethods: List +) : Parcelable { + + @Suppress("UNCHECKED_CAST") + private constructor(parcel: Parcel) : this( + orderData = parcel.readString().orEmpty(), + pspReference = parcel.readString().orEmpty(), + remainingAmount = parcel.readParcelable(Amount::class.java.classLoader)!!, + paymentMethods = parcel.readArrayList(OrderPaymentMethod::class.java.classLoader) as List + ) + + companion object { + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = OrderModel(source) + override fun newArray(size: Int) = arrayOfNulls(size) + } + } + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeString(orderData) + dest.writeString(pspReference) + dest.writeParcelable(remainingAmount, flags) + dest.writeList(paymentMethods) + } + + override fun describeContents() = Parcelable.CONTENTS_FILE_DESCRIPTOR +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt index 871fb78f69..ee21eaecd3 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt @@ -8,9 +8,13 @@ package com.adyen.checkout.dropin.ui.paymentmethods +import com.adyen.checkout.components.model.payments.Amount + data class GiftCardPaymentMethodModel( val imageId: String, - val lastFour: String + val lastFour: String, + val amount: Amount?, + val transactionLimit: Amount? ) : PaymentMethodListItem { override fun getViewType(): Int = PaymentMethodListItem.GIFT_CARD_PAYMENT_METHOD } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt index b58ab220e5..874373548a 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt @@ -50,6 +50,7 @@ class PaymentMethodListDialogFragment : DropInBottomSheetDialogFragment(), Payme requireActivity().application, dropInViewModel.paymentMethodsApiResponse.paymentMethods.orEmpty(), dropInViewModel.paymentMethodsApiResponse.storedPaymentMethods.orEmpty(), + dropInViewModel.currentOrder, dropInViewModel.dropInConfiguration ) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt index 7d1b779f89..8362692245 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt @@ -22,12 +22,14 @@ import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.checkPaymentMethodAvailability +import com.adyen.checkout.dropin.ui.order.OrderModel import com.adyen.checkout.dropin.ui.stored.makeStoredModel class PaymentMethodsListViewModel( application: Application, private val paymentMethods: List, storedPaymentMethods: List, + order: OrderModel?, val dropInConfiguration: DropInConfiguration ) : AndroidViewModel(application), ComponentAvailableCallback { @@ -40,11 +42,13 @@ class PaymentMethodsListViewModel( private val storedPaymentMethodsList = mutableListOf() private val paymentMethodsList = mutableListOf() + private val orderPaymentMethodsList: List init { Logger.d(TAG, "onPaymentMethodsResponseChanged") setupStoredPaymentMethods(storedPaymentMethods) setupPaymentMethods(paymentMethods) + orderPaymentMethodsList = setupOrderPaymentMethods(order) } fun getPaymentMethod(model: PaymentMethodModel): PaymentMethod { @@ -154,6 +158,10 @@ class PaymentMethodsListViewModel( private fun onPaymentMethodsReady() { Logger.d(TAG, "onPaymentMethodsReady: ${storedPaymentMethodsList.size} - ${paymentMethodsList.size}") paymentMethodsMutableLiveData.value = mutableListOf().apply { + if (orderPaymentMethodsList.isNotEmpty()) { + addAll(orderPaymentMethodsList) + // TODO add header + } if (storedPaymentMethodsList.isNotEmpty()) { add(PaymentMethodHeader(PaymentMethodHeader.TYPE_STORED_HEADER)) addAll(storedPaymentMethodsList) @@ -168,6 +176,17 @@ class PaymentMethodsListViewModel( } } + private fun setupOrderPaymentMethods(order: OrderModel?): List { + return order?.paymentMethods.orEmpty().map { + GiftCardPaymentMethodModel( + imageId = it.type, + lastFour = it.lastFour, + amount = it.amount, + transactionLimit = it.transactionLimit + ) + } + } + companion object { val TAG = LogUtil.getTag() From 68766891696fc81eadc05e628986b49e04a9ec53 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 26 Nov 2021 10:09:52 +0100 Subject: [PATCH 044/102] Adding gift card string resources --- drop-in/src/main/res/template/values/strings.xml.tt | 4 ++++ drop-in/src/main/res/values-cs-rCZ/strings.xml | 4 ++++ drop-in/src/main/res/values-da-rDK/strings.xml | 4 ++++ drop-in/src/main/res/values-de-rDE/strings.xml | 4 ++++ drop-in/src/main/res/values-el-rGR/strings.xml | 4 ++++ drop-in/src/main/res/values-es-rES/strings.xml | 4 ++++ drop-in/src/main/res/values-fi-rFI/strings.xml | 4 ++++ drop-in/src/main/res/values-fr-rFR/strings.xml | 4 ++++ drop-in/src/main/res/values-hr-rHR/strings.xml | 4 ++++ drop-in/src/main/res/values-hu-rHU/strings.xml | 4 ++++ drop-in/src/main/res/values-it-rIT/strings.xml | 4 ++++ drop-in/src/main/res/values-ja-rJP/strings.xml | 4 ++++ drop-in/src/main/res/values-ko-rKR/strings.xml | 4 ++++ drop-in/src/main/res/values-nb-rNO/strings.xml | 4 ++++ drop-in/src/main/res/values-nl-rNL/strings.xml | 4 ++++ drop-in/src/main/res/values-pl-rPL/strings.xml | 4 ++++ drop-in/src/main/res/values-pt-rBR/strings.xml | 4 ++++ drop-in/src/main/res/values-ro-rRO/strings.xml | 4 ++++ drop-in/src/main/res/values-ru-rRU/strings.xml | 4 ++++ drop-in/src/main/res/values-sk-rSK/strings.xml | 4 ++++ drop-in/src/main/res/values-sl-rSI/strings.xml | 4 ++++ drop-in/src/main/res/values-sv-rSE/strings.xml | 4 ++++ drop-in/src/main/res/values-zh-rCN/strings.xml | 4 ++++ drop-in/src/main/res/values-zh-rTW/strings.xml | 4 ++++ drop-in/src/main/res/values/strings.xml | 4 ++++ 25 files changed, 100 insertions(+) diff --git a/drop-in/src/main/res/template/values/strings.xml.tt b/drop-in/src/main/res/template/values/strings.xml.tt index 7ec3787582..16379655a9 100644 --- a/drop-in/src/main/res/template/values/strings.xml.tt +++ b/drop-in/src/main/res/template/values/strings.xml.tt @@ -25,4 +25,8 @@ %%error.giftcard.no-balance%% %%error.giftcard.currency-error%% %%partialPayment.remainingBalance%% + %%partialPayment.payRemainingAmount%% + %%paymentmethods.giftcard%% + %%storedPaymentMethod.disable.button%% + %%giftcardTransactionLimit%% diff --git a/drop-in/src/main/res/values-cs-rCZ/strings.xml b/drop-in/src/main/res/values-cs-rCZ/strings.xml index 291c765c3b..0290ea7877 100644 --- a/drop-in/src/main/res/values-cs-rCZ/strings.xml +++ b/drop-in/src/main/res/values-cs-rCZ/strings.xml @@ -25,4 +25,8 @@ Na dárkové kartě je nulový zůstatek Dárkové karty jsou platné jenom v měně, ve které byly vystavené Zbývající zůstatek bude %s + Zvolte, jakým způsobem se má %s zaplatit + Přidaná dárková karta + Odebrat + Maximální povolená částka za jednu transakci touto dárkovou kartou je %s. \ No newline at end of file diff --git a/drop-in/src/main/res/values-da-rDK/strings.xml b/drop-in/src/main/res/values-da-rDK/strings.xml index f30d22f242..0c7c2bd075 100644 --- a/drop-in/src/main/res/values-da-rDK/strings.xml +++ b/drop-in/src/main/res/values-da-rDK/strings.xml @@ -25,4 +25,8 @@ Saldoen på gavekortet er 0 Gavekort er kun gyldige i udstedelsesvalutaen Restbeløbet vil være %s + Vælg betalingsmåden for de resterende %s + Gavekort tilføjet + Fjern + Maks. %s tilladt pr. transaktion på dette gavekort \ No newline at end of file diff --git a/drop-in/src/main/res/values-de-rDE/strings.xml b/drop-in/src/main/res/values-de-rDE/strings.xml index df5ea552c0..6bac69e9d3 100644 --- a/drop-in/src/main/res/values-de-rDE/strings.xml +++ b/drop-in/src/main/res/values-de-rDE/strings.xml @@ -25,4 +25,8 @@ Auf dieser Geschenkkarte ist kein Guthaben vorhanden Geschenkkarten sind nur in der Währung gültig, in der sie ausgestellt wurden Es verbleibt ein Restbetrag von %s + Wählen Sie eine Zahlungsmethode für den verbleibenden Betrag von %s aus + Geschenkgutschein hinzugefügt + Entfernen + Der zulässige Höchstbetrag pro Transaktion für diese Geschenkkarte ist %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-el-rGR/strings.xml b/drop-in/src/main/res/values-el-rGR/strings.xml index bcfa0b1886..7f94c6f009 100644 --- a/drop-in/src/main/res/values-el-rGR/strings.xml +++ b/drop-in/src/main/res/values-el-rGR/strings.xml @@ -25,4 +25,8 @@ Η συγκεκριμένη δωροκάρτα έχει μηδενικό υπόλοιπο Οι δωροκάρτες ισχύουν μόνο για το νόμισμα στο οποίο εκδόθηκαν Το υπόλοιπο θα είναι %s + Επιλέξτε έναν τρόπο πληρωμής για το εναπομείναν ποσό %s + Προστέθηκε δωροκάρτα + Αφαίρεση + Το μέγιστο επιτρεπόμενο ποσό ανά συναλλαγή σε αυτήν τη δωροκάρτα είναι %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-es-rES/strings.xml b/drop-in/src/main/res/values-es-rES/strings.xml index 01bfc5d171..e0d942cc6b 100644 --- a/drop-in/src/main/res/values-es-rES/strings.xml +++ b/drop-in/src/main/res/values-es-rES/strings.xml @@ -25,4 +25,8 @@ Esta tarjeta regalo no tiene saldo Las tarjetas regalo solo son válidas en la moneda en que fueron emitidas El saldo restante será %s + Seleccione el método de pago para la cantidad restante: %s + Tarjeta de regalo añadida + Eliminar + Se permite un máximo de %s por transacción en esta tarjeta regalo \ No newline at end of file diff --git a/drop-in/src/main/res/values-fi-rFI/strings.xml b/drop-in/src/main/res/values-fi-rFI/strings.xml index bd44c2f892..6fe1868465 100644 --- a/drop-in/src/main/res/values-fi-rFI/strings.xml +++ b/drop-in/src/main/res/values-fi-rFI/strings.xml @@ -25,4 +25,8 @@ Lahjakortin saldo on nolla Gift cards are only valid in the currency they were issued in Jäljellä oleva saldo on %s + Valitse maksutapa jäljelle jääneelle prosentille %s + Lisätty lahjakortti + Poista + Maks. %s sallittu tapahtumaa kohti tällä lahjakortilla \ No newline at end of file diff --git a/drop-in/src/main/res/values-fr-rFR/strings.xml b/drop-in/src/main/res/values-fr-rFR/strings.xml index dc7caceed7..a24dc4b8cb 100644 --- a/drop-in/src/main/res/values-fr-rFR/strings.xml +++ b/drop-in/src/main/res/values-fr-rFR/strings.xml @@ -25,4 +25,8 @@ Aucun solde n\'est disponible sur cette carte cadeau Les cartes cadeaux sont valables uniquement dans la devise dans laquelle elles ont été émises Le solde restant sera de %s + Sélectionnez un mode de paiement pour régler le solde de %s + Carte-cadeau ajoutée + Supprimer + Montant maximum autorisé par transaction avec cette carte cadeau : %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-hr-rHR/strings.xml b/drop-in/src/main/res/values-hr-rHR/strings.xml index 45eb0990be..1efe158121 100644 --- a/drop-in/src/main/res/values-hr-rHR/strings.xml +++ b/drop-in/src/main/res/values-hr-rHR/strings.xml @@ -25,4 +25,8 @@ Stanje na ovoj poklon-kartici iznosi nula Poklon-kartice vrijede samo u valuti u kojoj su izdane Preostalo stanje na računu iznosit će %s + Odaberite način plaćanja za preostali iznos %s + Dodana poklon-kartica + Ukloni + Na ovoj je poklon-kartici maks. dopušteno %s po transakciji \ No newline at end of file diff --git a/drop-in/src/main/res/values-hu-rHU/strings.xml b/drop-in/src/main/res/values-hu-rHU/strings.xml index 14ca014770..20210ca124 100644 --- a/drop-in/src/main/res/values-hu-rHU/strings.xml +++ b/drop-in/src/main/res/values-hu-rHU/strings.xml @@ -25,4 +25,8 @@ Az ajándékkártya egyenlege nulla Az ajándékkártyák csak abban a pénznemben érvényesek, amelyre kiállították azokat A fennmaradó egyenleg %s lesz + Fizetési mód választása a fennmaradó %s számára + Hozzáadott ajándékkártya + Eltávolítás + Ezen az ajándékkártyán a tranzakciónként engedélyezett maximális összeg %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-it-rIT/strings.xml b/drop-in/src/main/res/values-it-rIT/strings.xml index 5970bc450c..28a4bc8430 100644 --- a/drop-in/src/main/res/values-it-rIT/strings.xml +++ b/drop-in/src/main/res/values-it-rIT/strings.xml @@ -25,4 +25,8 @@ Questo buono regalo ha un saldo pari a zero I buono regalo sono validi solo nella valuta in cui sono state emessi Il saldo rimanente sarà di %s + Seleziona metodo di pagamento per i restanti %s + Carta regalo aggiunta + Rimuovi + Importo massimo di %s per transazione su questo buono regalo \ No newline at end of file diff --git a/drop-in/src/main/res/values-ja-rJP/strings.xml b/drop-in/src/main/res/values-ja-rJP/strings.xml index 3361edcb9c..b072a3c624 100644 --- a/drop-in/src/main/res/values-ja-rJP/strings.xml +++ b/drop-in/src/main/res/values-ja-rJP/strings.xml @@ -25,4 +25,8 @@ このギフトカードの残高はゼロです ギフトカードは、発行された通貨でのみ有効です。 残りの残高は%sになります + 残りの%sの支払方法を選択してください + 追加したギフトカード + 削除 + このギフトカードでの取引ごとに許可される最大%s \ No newline at end of file diff --git a/drop-in/src/main/res/values-ko-rKR/strings.xml b/drop-in/src/main/res/values-ko-rKR/strings.xml index 571360b41c..555f6df0a2 100644 --- a/drop-in/src/main/res/values-ko-rKR/strings.xml +++ b/drop-in/src/main/res/values-ko-rKR/strings.xml @@ -25,4 +25,8 @@ 이 기프트 카드에는 잔액이 없습니다 기프트 카드는 발급된 통화로만 사용하실 수 있습니다 남은 잔액은 %s입니다 + 남은 %s에 대한 결제 수단 선택 + 추가된 기프트카드 + 삭제 + 이 기프트카드로 건당 결제 가능한 최고 액수는 %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-nb-rNO/strings.xml b/drop-in/src/main/res/values-nb-rNO/strings.xml index c6bcf37d56..40b244df85 100644 --- a/drop-in/src/main/res/values-nb-rNO/strings.xml +++ b/drop-in/src/main/res/values-nb-rNO/strings.xml @@ -25,4 +25,8 @@ Dette gavekortet har en saldo på null Gavekort er kun gyldige i den valutaen de ble utstedt i Gjenværende saldo vil være %s + Velg betalingsmetode for de gjenstående %s + La til gavekort + Fjern + Maksimalt %s per transaksjon er tillatt på dette gavekortet \ No newline at end of file diff --git a/drop-in/src/main/res/values-nl-rNL/strings.xml b/drop-in/src/main/res/values-nl-rNL/strings.xml index ced9f8f450..c076d5d8d2 100644 --- a/drop-in/src/main/res/values-nl-rNL/strings.xml +++ b/drop-in/src/main/res/values-nl-rNL/strings.xml @@ -25,4 +25,8 @@ Deze cadeaukaart heeft geen saldo Cadeaukaarten zijn alleen geldig in de valuta waarin ze zijn uitgegeven Het resterende saldo is %s + Selecteer betaalmethode voor de resterende %s + Cadeaukaart toegevoegd + Verwijderen + Max. %s toegestaan per transactie met deze cadeaubon \ No newline at end of file diff --git a/drop-in/src/main/res/values-pl-rPL/strings.xml b/drop-in/src/main/res/values-pl-rPL/strings.xml index da03662cf7..b5db7559f0 100644 --- a/drop-in/src/main/res/values-pl-rPL/strings.xml +++ b/drop-in/src/main/res/values-pl-rPL/strings.xml @@ -25,4 +25,8 @@ Saldo karty podarunkowej jest puste Karty podarunkowe są ważne tylko w walucie, w której zostały wydane Pozostałe saldo wynosi %s + Wybierz metodę płatności dla pozostałych %s + Dodano kartę podarunkową + Usuń + Maks. dozwolona kwota (%s) na transakcję tą kartą upominkową \ No newline at end of file diff --git a/drop-in/src/main/res/values-pt-rBR/strings.xml b/drop-in/src/main/res/values-pt-rBR/strings.xml index 217d23d4ba..dc34f200d6 100644 --- a/drop-in/src/main/res/values-pt-rBR/strings.xml +++ b/drop-in/src/main/res/values-pt-rBR/strings.xml @@ -25,4 +25,8 @@ Este vale-presente tem saldo zero Os vales-presente são válidos somente na moeda em que foram emitidos O saldo restante será %s + Selecione o método de pagamento dos %s restantes + Vale presentes + Remover + Máximo de %s permitido por transação neste cartão-presente \ No newline at end of file diff --git a/drop-in/src/main/res/values-ro-rRO/strings.xml b/drop-in/src/main/res/values-ro-rRO/strings.xml index 0bd2e1686f..02c75a7eeb 100644 --- a/drop-in/src/main/res/values-ro-rRO/strings.xml +++ b/drop-in/src/main/res/values-ro-rRO/strings.xml @@ -25,4 +25,8 @@ Acest card cadou are soldul zero Cardurile cadou sunt valabile numai în moneda în care au fost emise Soldul rămas va fi de %s + Selectați metoda de plată pentru suma de %s rămasă + Card cadou adăugat + Ștergere + Pentru acest card cadou, suma maximă permisă per tranzacție este de %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-ru-rRU/strings.xml b/drop-in/src/main/res/values-ru-rRU/strings.xml index e9e027550c..1242cafcb8 100644 --- a/drop-in/src/main/res/values-ru-rRU/strings.xml +++ b/drop-in/src/main/res/values-ru-rRU/strings.xml @@ -25,4 +25,8 @@ На этой подарочной карте нет средств Принимаются только подарочные карты соответствующей валюты Остаток на балансе составит %s + Выбрать другой способ оплаты оставшейся суммы %s + Подарочные карты + Удалить + Максимальная сумма операции по этой подарочной карте: %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-sk-rSK/strings.xml b/drop-in/src/main/res/values-sk-rSK/strings.xml index 54eca8d694..8c299eab62 100644 --- a/drop-in/src/main/res/values-sk-rSK/strings.xml +++ b/drop-in/src/main/res/values-sk-rSK/strings.xml @@ -25,4 +25,8 @@ Táto darčeková karta má nulový zostatok Darčekové karty sú platné iba v mene, v ktorej boli vydané Zvyšný zostatok bude %s + Vyberte spôsob platby pre zvyšné %s + Pridaná darčeková karta + Odstrániť + Pre transakciu s touto darčekovou kartou je povolené maximum %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-sl-rSI/strings.xml b/drop-in/src/main/res/values-sl-rSI/strings.xml index 88aad46c8f..09f5fb99e5 100644 --- a/drop-in/src/main/res/values-sl-rSI/strings.xml +++ b/drop-in/src/main/res/values-sl-rSI/strings.xml @@ -25,4 +25,8 @@ Na tej darilni kartici ni sredstev Darilne kartice so veljavne samo za valuto, za katero so bile izdane Preostalo stanje bo %s + Izberite vrsto plačila za preostali znesek %s + Dodana darilna kartica + Odstrani + Za posamezno transakcijo na tej darilni kartici je dovoljeno največ %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-sv-rSE/strings.xml b/drop-in/src/main/res/values-sv-rSE/strings.xml index 6436c90d2c..ba214d8d22 100644 --- a/drop-in/src/main/res/values-sv-rSE/strings.xml +++ b/drop-in/src/main/res/values-sv-rSE/strings.xml @@ -25,4 +25,8 @@ Saldot för detta presentkort är noll Presentkort är endast giltiga i den valuta som de utfärdades i Återstående saldo blir %s + Välj betalningssätt för återstående %s + Tillagt presentkort + Ta bort + Maximalt %s per transaktion är tillåtet på detta presentkort \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rCN/strings.xml b/drop-in/src/main/res/values-zh-rCN/strings.xml index 60ec5770f7..3011706e91 100644 --- a/drop-in/src/main/res/values-zh-rCN/strings.xml +++ b/drop-in/src/main/res/values-zh-rCN/strings.xml @@ -25,4 +25,8 @@ 礼品卡余额为零 礼品卡仅以其发行的货币为有效货币 剩余额度为 %s + 选择支付方式支付剩余的 %s + 已添加礼品卡 + 删除 + 此礼品卡上每笔交易允许的最大金额为 %s \ No newline at end of file diff --git a/drop-in/src/main/res/values-zh-rTW/strings.xml b/drop-in/src/main/res/values-zh-rTW/strings.xml index 2343d72d33..6bbf507fd5 100644 --- a/drop-in/src/main/res/values-zh-rTW/strings.xml +++ b/drop-in/src/main/res/values-zh-rTW/strings.xml @@ -25,4 +25,8 @@ 此禮品卡的餘額為零 禮品卡只能以其簽發時所使用的貨幣進行結算 餘額將為 %s + 選取付款方式來支付剩餘的 %s + 已新增禮品卡 + 移除 + 此禮品卡每筆交易的金額上限為 %s \ No newline at end of file diff --git a/drop-in/src/main/res/values/strings.xml b/drop-in/src/main/res/values/strings.xml index 096bdb48c0..4db41881de 100644 --- a/drop-in/src/main/res/values/strings.xml +++ b/drop-in/src/main/res/values/strings.xml @@ -25,4 +25,8 @@ This gift card has zero balance Gift cards are only valid in the currency they were issued in Remaining balance will be %s + Select payment method for the remaining %s + Added giftcard + Remove + Max. %s allowed per transaction on this gift card \ No newline at end of file From 456b545c555b16ddc5e9864f5d398856849ceb08 Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 26 Nov 2021 12:29:19 +0100 Subject: [PATCH 045/102] Show paid amount and max transaction amount for gift cards --- ...ftCardPaymentConfirmationDialogFragment.kt | 3 ++- .../GiftCardPaymentMethodModel.kt | 4 +++- .../ui/paymentmethods/PaymentMethodAdapter.kt | 22 ++++++++++++++++++- .../PaymentMethodsListViewModel.kt | 6 ++--- .../res/layout/payment_methods_list_item.xml | 16 +++++++++++--- drop-in/src/main/res/values/strings.xml | 1 + 6 files changed, 43 insertions(+), 9 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt index 50c95c072b..ea855aa150 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt @@ -82,7 +82,8 @@ class GiftCardPaymentConfirmationDialogFragment : DropInBottomSheetDialogFragmen imageId = giftCardPaymentConfirmationData.brand, lastFour = giftCardPaymentConfirmationData.lastFourDigits, amount = null, - transactionLimit = null + transactionLimit = null, + shopperLocale = null ) ) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt index ee21eaecd3..6056fe62b7 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/GiftCardPaymentMethodModel.kt @@ -9,12 +9,14 @@ package com.adyen.checkout.dropin.ui.paymentmethods import com.adyen.checkout.components.model.payments.Amount +import java.util.Locale data class GiftCardPaymentMethodModel( val imageId: String, val lastFour: String, val amount: Amount?, - val transactionLimit: Amount? + val transactionLimit: Amount?, + val shopperLocale: Locale? ) : PaymentMethodListItem { override fun getViewType(): Int = PaymentMethodListItem.GIFT_CARD_PAYMENT_METHOD } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt index 2ca4bf0ac4..0fddead7be 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt @@ -15,6 +15,7 @@ import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.adyen.checkout.components.api.ImageLoader import com.adyen.checkout.components.ui.view.RoundCornerImageView +import com.adyen.checkout.components.util.CurrencyUtils import com.adyen.checkout.components.util.DateUtils import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil @@ -83,12 +84,14 @@ class PaymentMethodAdapter( imageLoader.load(storedCardModel.imageId, holder.logo) holder.detail.text = DateUtils.parseDateToView(storedCardModel.expiryMonth, storedCardModel.expiryYear) holder.detail.visibility = View.VISIBLE + holder.endText.visibility = View.GONE } private fun bindGenericStored(holder: StoredPaymentMethodVH, genericStoredModel: GenericStoredModel) { holder.text.text = genericStoredModel.name holder.detail.visibility = View.GONE imageLoader.load(genericStoredModel.imageId, holder.logo) + holder.endText.visibility = View.GONE } private fun bindPaymentMethod(holder: PaymentMethodVH, position: Int) { @@ -103,6 +106,7 @@ class PaymentMethodAdapter( holder.itemView.setOnClickListener { onPaymentMethodClick(paymentMethod) } + holder.endText.visibility = View.GONE } private fun bindGiftCardPaymentMethod(holder: GiftCardPaymentMethodVH, position: Int) { @@ -111,7 +115,20 @@ class PaymentMethodAdapter( val context = holder.itemView.context holder.text.text = context.getString(R.string.card_number_4digit, giftCardPaymentMethod.lastFour) imageLoader.load(giftCardPaymentMethod.imageId, holder.logo) - holder.detail.visibility = View.GONE + if (giftCardPaymentMethod.transactionLimit == null || giftCardPaymentMethod.shopperLocale == null) { + holder.detail.visibility = View.GONE + } else { + holder.detail.visibility = View.VISIBLE + val value = CurrencyUtils.formatAmount(giftCardPaymentMethod.transactionLimit, giftCardPaymentMethod.shopperLocale) + holder.detail.text = context.getString(R.string.checkout_giftcard_max_transaction_limit, value) + } + if (giftCardPaymentMethod.amount == null || giftCardPaymentMethod.shopperLocale == null) { + holder.endText.visibility = View.GONE + } else { + holder.endText.visibility = View.VISIBLE + val value = CurrencyUtils.formatAmount(giftCardPaymentMethod.amount, giftCardPaymentMethod.shopperLocale) + holder.endText.text = context.getString(R.string.checkout_negative_amount, value) + } holder.itemView.setOnClickListener(null) } @@ -161,18 +178,21 @@ class PaymentMethodAdapter( internal val text: TextView = rootView.findViewById(R.id.textView_text) internal val detail: TextView = rootView.findViewById(R.id.textView_detail) internal val logo: RoundCornerImageView = rootView.findViewById(R.id.imageView_logo) + internal val endText: TextView = rootView.findViewById(R.id.textView_endText) } class PaymentMethodVH(rootView: View) : BaseViewHolder(rootView) { internal val text: TextView = rootView.findViewById(R.id.textView_text) internal val detail: TextView = rootView.findViewById(R.id.textView_detail) internal val logo: RoundCornerImageView = rootView.findViewById(R.id.imageView_logo) + internal val endText: TextView = rootView.findViewById(R.id.textView_endText) } class GiftCardPaymentMethodVH(rootView: View) : BaseViewHolder(rootView) { internal val text: TextView = rootView.findViewById(R.id.textView_text) internal val detail: TextView = rootView.findViewById(R.id.textView_detail) internal val logo: RoundCornerImageView = rootView.findViewById(R.id.imageView_logo) + internal val endText: TextView = rootView.findViewById(R.id.textView_endText) } class HeaderVH(rootView: View) : BaseViewHolder(rootView) { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt index 8362692245..2730b971b1 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt @@ -42,13 +42,12 @@ class PaymentMethodsListViewModel( private val storedPaymentMethodsList = mutableListOf() private val paymentMethodsList = mutableListOf() - private val orderPaymentMethodsList: List + private val orderPaymentMethodsList: List = setupOrderPaymentMethods(order) init { Logger.d(TAG, "onPaymentMethodsResponseChanged") setupStoredPaymentMethods(storedPaymentMethods) setupPaymentMethods(paymentMethods) - orderPaymentMethodsList = setupOrderPaymentMethods(order) } fun getPaymentMethod(model: PaymentMethodModel): PaymentMethod { @@ -182,7 +181,8 @@ class PaymentMethodsListViewModel( imageId = it.type, lastFour = it.lastFour, amount = it.amount, - transactionLimit = it.transactionLimit + transactionLimit = it.transactionLimit, + shopperLocale = dropInConfiguration.shopperLocale ) } } diff --git a/drop-in/src/main/res/layout/payment_methods_list_item.xml b/drop-in/src/main/res/layout/payment_methods_list_item.xml index 5fef1ee8ff..678d2c43ef 100644 --- a/drop-in/src/main/res/layout/payment_methods_list_item.xml +++ b/drop-in/src/main/res/layout/payment_methods_list_item.xml @@ -38,16 +38,16 @@ app:strokeColor="@color/stroke_color"/> + \ No newline at end of file diff --git a/drop-in/src/main/res/values/strings.xml b/drop-in/src/main/res/values/strings.xml index 4db41881de..c455ba49fb 100644 --- a/drop-in/src/main/res/values/strings.xml +++ b/drop-in/src/main/res/values/strings.xml @@ -29,4 +29,5 @@ Added giftcard Remove Max. %s allowed per transaction on this gift card + - %s \ No newline at end of file From 393157a25898bbb3579010cd42a15b39ec7f045d Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 26 Nov 2021 14:44:25 +0100 Subject: [PATCH 046/102] Add remaining amount note --- .../ui/paymentmethods/PaymentMethodAdapter.kt | 16 ++++++++++++++++ .../ui/paymentmethods/PaymentMethodListItem.kt | 1 + .../ui/paymentmethods/PaymentMethodNote.kt | 14 ++++++++++++++ .../PaymentMethodsListViewModel.kt | 13 +++++++++++-- .../background_payment_methods_note.xml | 13 +++++++++++++ .../res/layout/payment_methods_list_note.xml | 17 +++++++++++++++++ drop-in/src/main/res/values/styles.xml | 14 ++++++++++++++ ui-core/src/main/res/values/colors.xml | 2 ++ 8 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodNote.kt create mode 100644 drop-in/src/main/res/drawable/background_payment_methods_note.xml create mode 100644 drop-in/src/main/res/layout/payment_methods_list_note.xml diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt index 0fddead7be..ed5086f04c 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.dropin.R import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.GIFT_CARD_PAYMENT_METHOD import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.PAYMENT_METHOD import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.PAYMENT_METHODS_HEADER +import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.PAYMENT_METHODS_NOTE import com.adyen.checkout.dropin.ui.paymentmethods.PaymentMethodListItem.Companion.STORED_PAYMENT_METHOD @SuppressWarnings("TooManyFunctions") @@ -43,6 +44,7 @@ class PaymentMethodAdapter( STORED_PAYMENT_METHOD -> StoredPaymentMethodVH(getView(parent, R.layout.payment_methods_list_item)) PAYMENT_METHOD -> PaymentMethodVH(getView(parent, R.layout.payment_methods_list_item)) GIFT_CARD_PAYMENT_METHOD -> GiftCardPaymentMethodVH(getView(parent, R.layout.payment_methods_list_item)) + PAYMENT_METHODS_NOTE -> NoteVH(getView(parent, R.layout.payment_methods_list_note)) else -> throw CheckoutException("Unexpected viewType on onCreateViewHolder - $viewType") } } @@ -57,6 +59,7 @@ class PaymentMethodAdapter( is StoredPaymentMethodVH -> bindStoredPaymentMethod(holder, position) is PaymentMethodVH -> bindPaymentMethod(holder, position) is GiftCardPaymentMethodVH -> bindGiftCardPaymentMethod(holder, position) + is NoteVH -> bindNote(holder, position) } } @@ -133,6 +136,11 @@ class PaymentMethodAdapter( holder.itemView.setOnClickListener(null) } + private fun bindNote(holder: NoteVH, position: Int) { + val header = getNoteAt(position) + holder.note.text = header.note + } + override fun getItemCount(): Int { return paymentMethods.size } @@ -153,6 +161,10 @@ class PaymentMethodAdapter( return paymentMethods[position] as GiftCardPaymentMethodModel } + private fun getNoteAt(position: Int): PaymentMethodNote { + return paymentMethods[position] as PaymentMethodNote + } + private fun onStoredPaymentMethodClick(storedPaymentMethodModel: StoredPaymentMethodModel) { onPaymentMethodSelectedCallback?.onStoredPaymentMethodSelected(storedPaymentMethodModel) } @@ -199,5 +211,9 @@ class PaymentMethodAdapter( internal val title: TextView = rootView.findViewById(R.id.payment_method_header) } + class NoteVH(rootView: View) : BaseViewHolder(rootView) { + internal val note: TextView = rootView.findViewById(R.id.payment_method_note) + } + open class BaseViewHolder(rootView: View) : RecyclerView.ViewHolder(rootView) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt index 25dbcf7fda..dc4e728119 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListItem.kt @@ -18,5 +18,6 @@ interface PaymentMethodListItem { const val STORED_PAYMENT_METHOD = 2 const val PAYMENT_METHOD = 3 const val GIFT_CARD_PAYMENT_METHOD = 4 + const val PAYMENT_METHODS_NOTE = 5 } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodNote.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodNote.kt new file mode 100644 index 0000000000..605db4c065 --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodNote.kt @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 26/11/2021. + */ + +package com.adyen.checkout.dropin.ui.paymentmethods + +data class PaymentMethodNote(val note: String) : PaymentMethodListItem { + + override fun getViewType(): Int = PaymentMethodListItem.PAYMENT_METHODS_NOTE +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt index 2730b971b1..d5ea07c1b8 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt @@ -16,11 +16,13 @@ import com.adyen.checkout.components.ComponentAvailableCallback import com.adyen.checkout.components.base.Configuration import com.adyen.checkout.components.model.paymentmethods.PaymentMethod import com.adyen.checkout.components.model.paymentmethods.StoredPaymentMethod +import com.adyen.checkout.components.util.CurrencyUtils import com.adyen.checkout.components.util.PaymentMethodTypes import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger import com.adyen.checkout.dropin.DropInConfiguration +import com.adyen.checkout.dropin.R import com.adyen.checkout.dropin.checkPaymentMethodAvailability import com.adyen.checkout.dropin.ui.order.OrderModel import com.adyen.checkout.dropin.ui.stored.makeStoredModel @@ -29,7 +31,7 @@ class PaymentMethodsListViewModel( application: Application, private val paymentMethods: List, storedPaymentMethods: List, - order: OrderModel?, + private val order: OrderModel?, val dropInConfiguration: DropInConfiguration ) : AndroidViewModel(application), ComponentAvailableCallback { @@ -159,7 +161,14 @@ class PaymentMethodsListViewModel( paymentMethodsMutableLiveData.value = mutableListOf().apply { if (orderPaymentMethodsList.isNotEmpty()) { addAll(orderPaymentMethodsList) - // TODO add header + order?.remainingAmount?.let { remainingAmount -> + val value = CurrencyUtils.formatAmount(remainingAmount, dropInConfiguration.shopperLocale) + add( + PaymentMethodNote( + getApplication().getString(R.string.checkout_giftcard_pay_remaining_amount, value) + ) + ) + } } if (storedPaymentMethodsList.isNotEmpty()) { add(PaymentMethodHeader(PaymentMethodHeader.TYPE_STORED_HEADER)) diff --git a/drop-in/src/main/res/drawable/background_payment_methods_note.xml b/drop-in/src/main/res/drawable/background_payment_methods_note.xml new file mode 100644 index 0000000000..690fc828f1 --- /dev/null +++ b/drop-in/src/main/res/drawable/background_payment_methods_note.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/drop-in/src/main/res/layout/payment_methods_list_note.xml b/drop-in/src/main/res/layout/payment_methods_list_note.xml new file mode 100644 index 0000000000..d9b7c7d381 --- /dev/null +++ b/drop-in/src/main/res/layout/payment_methods_list_note.xml @@ -0,0 +1,17 @@ + + + diff --git a/drop-in/src/main/res/values/styles.xml b/drop-in/src/main/res/values/styles.xml index 5b76dec7e2..837a6c0b92 100644 --- a/drop-in/src/main/res/values/styles.xml +++ b/drop-in/src/main/res/values/styles.xml @@ -58,4 +58,18 @@ 12sp + + \ No newline at end of file diff --git a/ui-core/src/main/res/values/colors.xml b/ui-core/src/main/res/values/colors.xml index 92975e58d3..dd3bcf1210 100644 --- a/ui-core/src/main/res/values/colors.xml +++ b/ui-core/src/main/res/values/colors.xml @@ -14,4 +14,6 @@ #1A73E8 #DE000000 #17000000 + #7F4A00 + #FFEACC \ No newline at end of file From 9c3a66581fcc229117d2a7a0558b55bb51953fdd Mon Sep 17 00:00:00 2001 From: jreij Date: Fri, 26 Nov 2021 15:18:39 +0100 Subject: [PATCH 047/102] Add action header --- .../ui/paymentmethods/PaymentMethodAdapter.kt | 17 +++++++++- .../ui/paymentmethods/PaymentMethodHeader.kt | 8 +++++ .../PaymentMethodListDialogFragment.kt | 10 ++++++ .../PaymentMethodsListViewModel.kt | 1 + .../PreselectedStoredPaymentMethodFragment.kt | 2 +- .../layout/payment_methods_list_header.xml | 33 +++++++++++++------ drop-in/src/main/res/values/styles.xml | 14 ++++++++ 7 files changed, 73 insertions(+), 12 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt index ed5086f04c..ac01f64e55 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt @@ -66,6 +66,15 @@ class PaymentMethodAdapter( private fun bindHeader(holder: HeaderVH, position: Int) { val header = getHeaderAt(position) holder.title.setText(header.titleResId) + if (header.actionResId == null) { + holder.action.visibility = View.GONE + } else { + holder.action.visibility = View.VISIBLE + holder.action.setText(header.actionResId) + holder.action.setOnClickListener { + onHeaderActionClick(header) + } + } } private fun bindStoredPaymentMethod(holder: StoredPaymentMethodVH, position: Int) { @@ -173,6 +182,10 @@ class PaymentMethodAdapter( onPaymentMethodSelectedCallback?.onPaymentMethodSelected(paymentMethod) } + private fun onHeaderActionClick(header: PaymentMethodHeader) { + onPaymentMethodSelectedCallback?.onHeaderActionSelected(header) + } + private fun getView(parent: ViewGroup, id: Int): View { return LayoutInflater.from(parent.context).inflate(id, parent, false) } @@ -184,6 +197,7 @@ class PaymentMethodAdapter( interface OnPaymentMethodSelectedCallback { fun onStoredPaymentMethodSelected(storedPaymentMethodModel: StoredPaymentMethodModel) fun onPaymentMethodSelected(paymentMethod: PaymentMethodModel) + fun onHeaderActionSelected(header: PaymentMethodHeader) } class StoredPaymentMethodVH(rootView: View) : BaseViewHolder(rootView) { @@ -208,7 +222,8 @@ class PaymentMethodAdapter( } class HeaderVH(rootView: View) : BaseViewHolder(rootView) { - internal val title: TextView = rootView.findViewById(R.id.payment_method_header) + internal val title: TextView = rootView.findViewById(R.id.payment_method_header_title) + internal val action: TextView = rootView.findViewById(R.id.payment_method_header_action) } class NoteVH(rootView: View) : BaseViewHolder(rootView) { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodHeader.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodHeader.kt index d598e5c0d8..d403b89043 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodHeader.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodHeader.kt @@ -19,14 +19,22 @@ data class PaymentMethodHeader( TYPE_STORED_HEADER -> R.string.store_payment_methods_header TYPE_REGULAR_HEADER_WITH_STORED -> R.string.other_payment_methods TYPE_REGULAR_HEADER_WITHOUT_STORED -> R.string.payment_methods_header + TYPE_GIFT_CARD_HEADER -> R.string.checkout_giftcard_payment_methods_header else -> R.string.payment_methods_header } + @StringRes + val actionResId: Int? = when (type) { + TYPE_GIFT_CARD_HEADER -> R.string.checkout_giftcard_remove_button + else -> null + } + override fun getViewType(): Int = PaymentMethodListItem.PAYMENT_METHODS_HEADER companion object { const val TYPE_STORED_HEADER = 0 const val TYPE_REGULAR_HEADER_WITH_STORED = 1 const val TYPE_REGULAR_HEADER_WITHOUT_STORED = 2 + const val TYPE_GIFT_CARD_HEADER = 3 } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt index 874373548a..ec62d6899a 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodListDialogFragment.kt @@ -135,6 +135,16 @@ class PaymentMethodListDialogFragment : DropInBottomSheetDialogFragment(), Payme } } + override fun onHeaderActionSelected(header: PaymentMethodHeader) { + when (header.type) { + PaymentMethodHeader.TYPE_GIFT_CARD_HEADER -> showCancelOrderAlert() + } + } + + private fun showCancelOrderAlert() { + // TODO show alert and cancel order + } + private fun sendPayment(type: String) { val paymentComponentData = PaymentComponentData() paymentComponentData.paymentMethod = GenericPaymentMethod(type) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt index d5ea07c1b8..a341813341 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodsListViewModel.kt @@ -160,6 +160,7 @@ class PaymentMethodsListViewModel( Logger.d(TAG, "onPaymentMethodsReady: ${storedPaymentMethodsList.size} - ${paymentMethodsList.size}") paymentMethodsMutableLiveData.value = mutableListOf().apply { if (orderPaymentMethodsList.isNotEmpty()) { + add(PaymentMethodHeader(PaymentMethodHeader.TYPE_GIFT_CARD_HEADER)) addAll(orderPaymentMethodsList) order?.remainingAmount?.let { remainingAmount -> val value = CurrencyUtils.formatAmount(remainingAmount, dropInConfiguration.shopperLocale) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt index 4ef0e56e73..d64fb0b259 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/stored/PreselectedStoredPaymentMethodFragment.kt @@ -106,7 +106,7 @@ class PreselectedStoredPaymentMethodFragment : DropInBottomSheetDialogFragment() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Logger.d(TAG, "onViewCreated") - binding.paymentMethodsListHeader.paymentMethodHeader.setText(R.string.store_payment_methods_header) + binding.paymentMethodsListHeader.paymentMethodHeaderTitle.setText(R.string.store_payment_methods_header) binding.storedPaymentMethodItem.root.setBackgroundColor(android.R.color.transparent) observe() diff --git a/drop-in/src/main/res/layout/payment_methods_list_header.xml b/drop-in/src/main/res/layout/payment_methods_list_header.xml index f6fae800da..dc9eb3356b 100644 --- a/drop-in/src/main/res/layout/payment_methods_list_header.xml +++ b/drop-in/src/main/res/layout/payment_methods_list_header.xml @@ -1,5 +1,4 @@ - - - - \ No newline at end of file + android:orientation="horizontal"> + + + + + \ No newline at end of file diff --git a/drop-in/src/main/res/values/styles.xml b/drop-in/src/main/res/values/styles.xml index 837a6c0b92..d09728e1a5 100644 --- a/drop-in/src/main/res/values/styles.xml +++ b/drop-in/src/main/res/values/styles.xml @@ -36,6 +36,7 @@ @dimen/standard_margin @dimen/standard_margin @dimen/standard_half_margin + @dimen/standard_half_margin @dimen/standard_margin @dimen/standard_margin true @@ -72,4 +73,17 @@ @dimen/standard_margin + + \ No newline at end of file From f4a98cea832c5832072dee52700add0a8d05ccc6 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 29 Nov 2021 15:52:31 +0100 Subject: [PATCH 048/102] Add already paid payment methods to gift card confirmation fragment --- ...ftCardPaymentConfirmationDialogFragment.kt | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt index ea855aa150..9cd7ebaeae 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/giftcard/GiftCardPaymentConfirmationDialogFragment.kt @@ -77,16 +77,25 @@ class GiftCardPaymentConfirmationDialogFragment : DropInBottomSheetDialogFragmen } private fun initRecyclerView() { - val paymentMethods = listOf( + val alreadyPaidMethods = dropInViewModel.currentOrder?.paymentMethods.orEmpty().map { GiftCardPaymentMethodModel( - imageId = giftCardPaymentConfirmationData.brand, - lastFour = giftCardPaymentConfirmationData.lastFourDigits, - amount = null, - transactionLimit = null, - shopperLocale = null + imageId = it.type, + lastFour = it.lastFour, + amount = it.amount, + transactionLimit = it.transactionLimit, + shopperLocale = giftCardPaymentConfirmationData.shopperLocale ) + } + val currentPaymentMethod = GiftCardPaymentMethodModel( + imageId = giftCardPaymentConfirmationData.brand, + lastFour = giftCardPaymentConfirmationData.lastFourDigits, + amount = null, + transactionLimit = null, + shopperLocale = null ) + val paymentMethods = alreadyPaidMethods + currentPaymentMethod + val imageLoader = ImageLoader.getInstance( requireContext(), dropInViewModel.dropInConfiguration.environment From 6130c7e8b0f10c6e16cce9ac74ca3da37674dda0 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:41:11 +0100 Subject: [PATCH 049/102] Voucher: Create module --- settings.gradle | 3 +- voucher/.gitignore | 1 + voucher/build.gradle | 45 ++++++++++++++++++++++++++++ voucher/consumer-rules.pro | 0 voucher/proguard-rules.pro | 21 +++++++++++++ voucher/src/main/AndroidManifest.xml | 11 +++++++ 6 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 voucher/.gitignore create mode 100644 voucher/build.gradle create mode 100644 voucher/consumer-rules.pro create mode 100644 voucher/proguard-rules.pro create mode 100644 voucher/src/main/AndroidManifest.xml diff --git a/settings.gradle b/settings.gradle index a1ee212ca0..567f90795a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,4 +22,5 @@ include ':3ds2', ':redirect', ':sepa', ':ui-core', - ':wechatpay' \ No newline at end of file + ':wechatpay', + ':voucher' diff --git a/voucher/.gitignore b/voucher/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/voucher/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/voucher/build.gradle b/voucher/build.gradle new file mode 100644 index 0000000000..97c27bf6f4 --- /dev/null +++ b/voucher/build.gradle @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 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 29/11/2021. + */ + +plugins { + id 'com.android.library' + id 'kotlin-android' +} + +ext.mavenArtifactId = "voucher" +ext.mavenArtifactName = "Adyen Checkout Voucher component" +ext.mavenArtifactDescription = "Adyen checkout voucher component for Adyen's Checkout API." + +android { + compileSdkVersion compile_sdk_version + + defaultConfig { + minSdkVersion min_sdk_version + targetSdkVersion target_sdk_version + versionCode version_code + versionName version_name + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } +} + +dependencies { + // Checkout + api project(':components-core') + api project(':ui-core') +} \ No newline at end of file diff --git a/voucher/consumer-rules.pro b/voucher/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/voucher/proguard-rules.pro b/voucher/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/voucher/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/voucher/src/main/AndroidManifest.xml b/voucher/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..abc34fd1b2 --- /dev/null +++ b/voucher/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file From 46c8ddc8311ae4f017a91994e6b45a0c0c7354f2 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 30 Nov 2021 12:57:34 +0100 Subject: [PATCH 050/102] Voucher: Add component and provider --- .../payments/response/VoucherAction.java | 13 ++++ .../components/util/PaymentMethodTypes.java | 1 + .../checkout/voucher/VoucherComponent.kt | 57 +++++++++++++++ .../voucher/VoucherComponentProvider.kt | 62 +++++++++++++++++ .../checkout/voucher/VoucherConfiguration.kt | 69 +++++++++++++++++++ .../checkout/voucher/VoucherOutputData.kt | 17 +++++ 6 files changed, 219 insertions(+) create mode 100644 voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt create mode 100644 voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponentProvider.kt create mode 100644 voucher/src/main/java/com/adyen/checkout/voucher/VoucherConfiguration.kt create mode 100644 voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/VoucherAction.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/VoucherAction.java index 56bef2fc5a..61d2673f48 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/VoucherAction.java +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/response/VoucherAction.java @@ -37,6 +37,7 @@ public class VoucherAction extends Action { private static final String REFERENCE = "reference"; private static final String ALTERNATIVE_REFERENCE = "alternativeReference"; private static final String MERCHANT_NAME = "merchantName"; + private static final String URL = "url"; @NonNull public static final Serializer SERIALIZER = new Serializer() { @@ -59,6 +60,7 @@ public JSONObject serialize(@NonNull VoucherAction modelObject) { jsonObject.putOpt(REFERENCE, modelObject.getReference()); jsonObject.putOpt(ALTERNATIVE_REFERENCE, modelObject.getAlternativeReference()); jsonObject.putOpt(MERCHANT_NAME, modelObject.getMerchantName()); + jsonObject.putOpt(URL, modelObject.getUrl()); } catch (JSONException e) { throw new ModelSerializationException(VoucherAction.class, e); } @@ -83,6 +85,7 @@ public VoucherAction deserialize(@NonNull JSONObject jsonObject) { voucherAction.setReference(jsonObject.optString(REFERENCE)); voucherAction.setAlternativeReference(jsonObject.optString(ALTERNATIVE_REFERENCE)); voucherAction.setMerchantName(jsonObject.optString(MERCHANT_NAME)); + voucherAction.setUrl(jsonObject.optString(URL)); return voucherAction; } }; @@ -95,6 +98,7 @@ public VoucherAction deserialize(@NonNull JSONObject jsonObject) { private String reference; private String alternativeReference; private String merchantName; + private String url; @Override public void writeToParcel(@NonNull Parcel dest, int flags) { @@ -172,4 +176,13 @@ public String getMerchantName() { public void setMerchantName(@Nullable String merchantName) { this.merchantName = merchantName; } + + @Nullable + public String getUrl() { + return url; + } + + public void setUrl(@Nullable String url) { + this.url = url; + } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java index 39c6d9fb85..42b1b35134 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java +++ b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java @@ -36,6 +36,7 @@ public final class PaymentMethodTypes { public static final String GOOGLE_PAY = "googlepay"; public static final String GOOGLE_PAY_LEGACY = "paywithgoogle"; public static final String SEPA = "sepadirectdebit"; + public static final String BACS = "directdebit_GB"; public static final String BCMC = "bcmc"; public static final String MB_WAY = "mbway"; public static final String BLIK = "blik"; diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt new file mode 100644 index 0000000000..2069afb225 --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 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 29/11/2021. + */ + +package com.adyen.checkout.voucher + +import android.app.Activity +import android.app.Application +import android.content.Context +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer +import androidx.lifecycle.SavedStateHandle +import com.adyen.checkout.components.ActionComponentData +import com.adyen.checkout.components.ActionComponentProvider +import com.adyen.checkout.components.ViewableComponent +import com.adyen.checkout.components.base.BaseActionComponent +import com.adyen.checkout.components.model.payments.response.Action + +class VoucherComponent( + savedStateHandle: SavedStateHandle, + application: Application, + configuration: VoucherConfiguration, +) : BaseActionComponent(savedStateHandle, application, configuration), + ViewableComponent { + + private val mOutputLiveData = MutableLiveData() + + override fun canHandleAction(action: Action): Boolean { + return PROVIDER.canHandleAction(action) + } + + override fun observeOutputData(lifecycleOwner: LifecycleOwner, observer: Observer) { + mOutputLiveData.observe(lifecycleOwner, observer) + } + + override fun getOutputData(): VoucherOutputData? { + return mOutputLiveData.value + } + + override fun sendAnalyticsEvent(context: Context) { + // no ops + } + + override fun handleActionInternal(activity: Activity, action: Action) { + TODO("Not yet implemented") + } + + companion object { + @JvmField + val PROVIDER: ActionComponentProvider = VoucherComponentProvider() + } +} \ No newline at end of file diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponentProvider.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponentProvider.kt new file mode 100644 index 0000000000..7ffb71d7d6 --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponentProvider.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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 29/11/2021. + */ + +package com.adyen.checkout.voucher + +import android.app.Application +import android.os.Bundle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelStoreOwner +import androidx.savedstate.SavedStateRegistryOwner +import com.adyen.checkout.components.ActionComponentProvider +import com.adyen.checkout.components.base.lifecycle.viewModelFactory +import com.adyen.checkout.components.model.payments.response.Action +import com.adyen.checkout.components.model.payments.response.VoucherAction +import com.adyen.checkout.components.util.PaymentMethodTypes + +private val PAYMENT_METHODS = listOf(PaymentMethodTypes.BACS) + +class VoucherComponentProvider : ActionComponentProvider { + + override fun get( + owner: T, + application: Application, + configuration: VoucherConfiguration + ): VoucherComponent where T: SavedStateRegistryOwner, T : ViewModelStoreOwner { + return get(owner, owner, application, configuration, null) + } + + override fun get(savedStateRegistryOwner: SavedStateRegistryOwner, viewModelStoreOwner: ViewModelStoreOwner, application: Application, configuration: VoucherConfiguration, defaultArgs: Bundle?): VoucherComponent { + val voucherFactory = viewModelFactory(savedStateRegistryOwner, defaultArgs) { savedStateHandle -> + VoucherComponent( + savedStateHandle, + application, + configuration + ) + } + return ViewModelProvider(viewModelStoreOwner, voucherFactory).get(VoucherComponent::class.java) + } + + @Deprecated( + "You can safely remove this method, it will always return true as all action components require a configuration.", + ReplaceWith("true") + ) + override fun requiresConfiguration(): Boolean = true + + override fun canHandleAction(action: Action): Boolean { + return supportedActionTypes.contains(action.type) && PAYMENT_METHODS.contains(action.paymentMethodType) + } + + override fun requiresView(action: Action): Boolean { + return true + } + + override fun getSupportedActionTypes(): List { + return listOf(VoucherAction.ACTION_TYPE) + } +} \ No newline at end of file diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherConfiguration.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherConfiguration.kt new file mode 100644 index 0000000000..2c6e83819f --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherConfiguration.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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 29/11/2021. + */ + +package com.adyen.checkout.voucher + +import android.content.Context +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.base.BaseConfigurationBuilder +import com.adyen.checkout.components.base.Configuration +import com.adyen.checkout.core.api.Environment +import java.util.Locale + +class VoucherConfiguration: Configuration { + + private constructor(builder: Builder) : super(builder.builderShopperLocale, builder.builderEnvironment, builder.builderClientKey) + + private constructor(parcel: Parcel) : super(parcel) + + + class Builder: BaseConfigurationBuilder { + /** + * Constructor for Builder with default values. + * + * @param context A context + * @param clientKey Your Client Key used for network calls from the SDK to Adyen. + */ + constructor(context: Context, clientKey: String) : super(context, clientKey) + + /** + * Builder with required parameters. + * + * @param shopperLocale The Locale of the shopper. + * @param environment The [Environment] to be used for network calls to Adyen. + * @param clientKey Your Client Key used for network calls from the SDK to Adyen. + */ + constructor(shopperLocale: Locale, environment: Environment, clientKey: String) : super(shopperLocale, environment, clientKey) + + override fun setShopperLocale(builderShopperLocale: Locale): Builder { + return super.setShopperLocale(builderShopperLocale) as Builder + } + + override fun setEnvironment(builderEnvironment: Environment): Builder { + return super.setEnvironment(builderEnvironment) as Builder + } + + override fun buildInternal(): VoucherConfiguration { + return VoucherConfiguration(this) + } + } + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(`in`: Parcel): VoucherConfiguration { + return VoucherConfiguration(`in`) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } +} \ No newline at end of file diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt new file mode 100644 index 0000000000..034be2a3d2 --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021 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 29/11/2021. + */ + +package com.adyen.checkout.voucher + +import com.adyen.checkout.components.base.OutputData + +class VoucherOutputData : OutputData { + override fun isValid(): Boolean { + return true + } +} \ No newline at end of file From 7279eaeb4b590d146b8ddd3622dfb9241187e1b5 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 30 Nov 2021 16:01:59 +0100 Subject: [PATCH 051/102] Voucher: Add voucher view --- voucher/build.gradle | 4 ++ .../com/adyen/checkout/voucher/VoucherView.kt | 60 +++++++++++++++++++ voucher/src/main/res/layout/voucher_view.xml | 43 +++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt create mode 100644 voucher/src/main/res/layout/voucher_view.xml diff --git a/voucher/build.gradle b/voucher/build.gradle index 97c27bf6f4..06605efb57 100644 --- a/voucher/build.gradle +++ b/voucher/build.gradle @@ -36,6 +36,10 @@ android { kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() } + + buildFeatures { + viewBinding true + } } dependencies { diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt new file mode 100644 index 0000000000..7e3b408005 --- /dev/null +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 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 30/11/2021. + */ + +package com.adyen.checkout.voucher + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.Observer +import com.adyen.checkout.components.ActionComponentData +import com.adyen.checkout.components.ui.view.AdyenLinearLayout +import com.adyen.checkout.voucher.databinding.VoucherViewBinding + +class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + AdyenLinearLayout(context, attrs, defStyleAttr), + Observer { + + private val binding: VoucherViewBinding = VoucherViewBinding.inflate(LayoutInflater.from(context), this) + + init { + orientation = VERTICAL + val padding = resources.getDimension(R.dimen.standard_double_margin).toInt() + setPadding(padding, padding, padding, padding) + } + + override fun onComponentAttached() { + // no ops + } + + override fun initView() { + // TODO implement + } + + override fun isConfirmationRequired(): Boolean { + return false + } + + override fun highlightValidationErrors() { + // no validation required + } + + override fun initLocalizedStrings(localizedContext: Context) { + // TODO implement + } + + override fun observeComponentChanges(lifecycleOwner: LifecycleOwner) { + component.observeOutputData(lifecycleOwner, this) + } + + override fun onChanged(outputData: VoucherOutputData?) { + if (outputData == null) return + } + +} \ No newline at end of file diff --git a/voucher/src/main/res/layout/voucher_view.xml b/voucher/src/main/res/layout/voucher_view.xml new file mode 100644 index 0000000000..9fd9f6fd3e --- /dev/null +++ b/voucher/src/main/res/layout/voucher_view.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + \ No newline at end of file From be973a2ebae89e319c923830f84fd2c1e4e20c22 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 30 Nov 2021 16:07:03 +0100 Subject: [PATCH 052/102] Voucher: Add voucher support to drop in --- drop-in/build.gradle | 1 + .../adyen/checkout/dropin/ComponentParsingProvider.kt | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drop-in/build.gradle b/drop-in/build.gradle index da7f0044fe..3bd7a8463c 100644 --- a/drop-in/build.gradle +++ b/drop-in/build.gradle @@ -69,6 +69,7 @@ dependencies { api project(":redirect") api project(':sepa') api project(':wechatpay') + api project(':voucher') // Dependencies implementation "androidx.recyclerview:recyclerview:$recyclerview_version" diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt index 3e2c4fb1a4..8d4f26c6cc 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt @@ -82,6 +82,9 @@ import com.adyen.checkout.redirect.RedirectConfiguration import com.adyen.checkout.sepa.SepaComponent import com.adyen.checkout.sepa.SepaConfiguration import com.adyen.checkout.sepa.SepaView +import com.adyen.checkout.voucher.VoucherComponent +import com.adyen.checkout.voucher.VoucherConfiguration +import com.adyen.checkout.voucher.VoucherView import com.adyen.checkout.wechatpay.WeChatPayActionComponent import com.adyen.checkout.wechatpay.WeChatPayActionConfiguration import com.adyen.checkout.wechatpay.WeChatPayProvider @@ -143,6 +146,7 @@ internal inline fun getDefaultConfigForAction( QRCodeConfiguration::class -> QRCodeConfiguration.Builder(shopperLocale, environment, clientKey) Adyen3DS2Configuration::class -> Adyen3DS2Configuration.Builder(shopperLocale, environment, clientKey) WeChatPayActionConfiguration::class -> WeChatPayActionConfiguration.Builder(shopperLocale, environment, clientKey) + VoucherConfiguration::class -> VoucherConfiguration.Builder(shopperLocale, environment, clientKey) else -> throw CheckoutException("Unable to find component configuration for class - ${T::class}") } @@ -335,6 +339,7 @@ internal fun getViewFor( // GooglePay and WeChatPay do not require a View in Drop-in ActionTypes.AWAIT -> AwaitView(context) ActionTypes.QR_CODE -> QRCodeView(context) + ActionTypes.VOUCHER -> VoucherView(context) else -> { throw CheckoutException("Unable to find view for type - $paymentType") } @@ -353,7 +358,8 @@ internal fun getActionProviderFor(action: Action): ActionComponentProvider { QRCodeComponent.PROVIDER.get(activity, activity.application, dropInConfiguration.getConfigurationForAction()) } + VoucherComponent.PROVIDER -> { + VoucherComponent.PROVIDER.get(activity, activity.application, dropInConfiguration.getConfigurationForAction()) + } else -> { throw CheckoutException("Unable to find component for provider - $provider") } From e1a94e274cdbbedaac9ce6be48801a4d20a50cef Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:35:02 +0100 Subject: [PATCH 053/102] Voucher: Add image loader to voucher view --- .../java/com/adyen/checkout/voucher/VoucherComponent.kt | 7 ++++++- .../java/com/adyen/checkout/voucher/VoucherOutputData.kt | 8 ++++++-- .../main/java/com/adyen/checkout/voucher/VoucherView.kt | 9 ++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt index 2069afb225..4b71a20f5c 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt @@ -47,7 +47,12 @@ class VoucherComponent( } override fun handleActionInternal(activity: Activity, action: Action) { - TODO("Not yet implemented") + mOutputLiveData.postValue( + VoucherOutputData( + true, + action.paymentMethodType + ) + ) } companion object { diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt index 034be2a3d2..6cea34e670 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt @@ -10,8 +10,12 @@ package com.adyen.checkout.voucher import com.adyen.checkout.components.base.OutputData -class VoucherOutputData : OutputData { +data class VoucherOutputData( + private val isValid: Boolean, + val paymentMethodType: String?, + val url: String? +) : OutputData { override fun isValid(): Boolean { - return true + return isValid } } \ No newline at end of file diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt index 7e3b408005..2c6b78b670 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt @@ -14,6 +14,7 @@ import android.view.LayoutInflater import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer import com.adyen.checkout.components.ActionComponentData +import com.adyen.checkout.components.api.ImageLoader import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.voucher.databinding.VoucherViewBinding @@ -23,6 +24,8 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe private val binding: VoucherViewBinding = VoucherViewBinding.inflate(LayoutInflater.from(context), this) + private lateinit var imageLoader: ImageLoader + init { orientation = VERTICAL val padding = resources.getDimension(R.dimen.standard_double_margin).toInt() @@ -30,7 +33,7 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe } override fun onComponentAttached() { - // no ops + imageLoader = ImageLoader.getInstance(context, component.configuration.environment) } override fun initView() { @@ -55,6 +58,10 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe override fun onChanged(outputData: VoucherOutputData?) { if (outputData == null) return + + if (!outputData.paymentMethodType.isNullOrEmpty()) { + imageLoader.load(outputData.paymentMethodType, binding.imageViewLogo) + } } } \ No newline at end of file From e5fb8a6f7712f0b0702392a31be1b19e72e20fdd Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 2 Dec 2021 10:15:46 +0100 Subject: [PATCH 054/102] Voucher: Load payment method logo --- .../checkout/components/api/ImageLoader.kt | 31 ++++++++++++++++++- .../checkout/voucher/VoucherComponent.kt | 3 +- .../com/adyen/checkout/voucher/VoucherView.kt | 3 +- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt b/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt index e4ebd451f5..adaf52cca2 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt @@ -39,6 +39,34 @@ class ImageLoader(private val logoApi: LogoApi) { load(txVariant, "", view, placeholder, errorFallback) } + /** + * Load image to ImageView with place holder before load and error fallback image. + */ + @JvmOverloads + fun load( + txVariant: String, + view: ImageView, + size: LogoApi.Size?, + @DrawableRes placeholder: Int = 0, + @DrawableRes errorFallback: Int = 0 + ) { + load(txVariant, "", view, size, placeholder, errorFallback) + } + + /** + * Load image to ImageView with place holder before load and error fallback image. + */ + @JvmOverloads + fun load( + txVariant: String, + txSubVariant: String, + view: ImageView, + @DrawableRes placeholder: Int = 0, + @DrawableRes errorFallback: Int = 0 + ) { + load(txVariant, txSubVariant, view, null, placeholder, errorFallback) + } + /** * Load image to ImageView with place holder before load and error fallback image. */ @@ -47,6 +75,7 @@ class ImageLoader(private val logoApi: LogoApi) { txVariant: String, txSubVariant: String, view: ImageView, + size: LogoApi.Size?, @DrawableRes placeholder: Int = 0, @DrawableRes errorFallback: Int = 0 ) { @@ -83,7 +112,7 @@ class ImageLoader(private val logoApi: LogoApi) { } imageViews[id] = WeakReference(view) callbacks[id] = callback - logoApi.getLogo(txVariant, txSubVariant, null, callback) + logoApi.getLogo(txVariant, txSubVariant, size, callback) } companion object { diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt index 4b71a20f5c..6efa9173e8 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt @@ -50,7 +50,8 @@ class VoucherComponent( mOutputLiveData.postValue( VoucherOutputData( true, - action.paymentMethodType + action.paymentMethodType, + null ) ) } diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt index 2c6b78b670..89deb740e7 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt @@ -15,6 +15,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer import com.adyen.checkout.components.ActionComponentData import com.adyen.checkout.components.api.ImageLoader +import com.adyen.checkout.components.api.LogoApi import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.voucher.databinding.VoucherViewBinding @@ -60,7 +61,7 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe if (outputData == null) return if (!outputData.paymentMethodType.isNullOrEmpty()) { - imageLoader.load(outputData.paymentMethodType, binding.imageViewLogo) + imageLoader.load(outputData.paymentMethodType, binding.imageViewLogo, LogoApi.Size.MEDIUM) } } From a9fe7cf28fd60539356bc1de12f883040d9693d3 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 2 Dec 2021 10:21:24 +0100 Subject: [PATCH 055/102] Voucher: Add translations --- voucher/src/main/res/template/values/strings.xml.tt | 13 +++++++++++++ voucher/src/main/res/values-cs-rCZ/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-da-rDK/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-de-rDE/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-el-rGR/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-es-rES/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-fi-rFI/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-fr-rFR/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-hr-rHR/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-hu-rHU/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-it-rIT/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-ja-rJP/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-ko-rKR/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-nb-rNO/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-nl-rNL/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-pl-rPL/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-pt-rBR/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-ro-rRO/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-ru-rRU/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-sk-rSK/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-sl-rSI/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-sv-rSE/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-zh-rCN/strings.xml | 13 +++++++++++++ voucher/src/main/res/values-zh-rTW/strings.xml | 13 +++++++++++++ voucher/src/main/res/values/strings.xml | 13 +++++++++++++ 25 files changed, 325 insertions(+) create mode 100644 voucher/src/main/res/template/values/strings.xml.tt create mode 100644 voucher/src/main/res/values-cs-rCZ/strings.xml create mode 100644 voucher/src/main/res/values-da-rDK/strings.xml create mode 100644 voucher/src/main/res/values-de-rDE/strings.xml create mode 100644 voucher/src/main/res/values-el-rGR/strings.xml create mode 100644 voucher/src/main/res/values-es-rES/strings.xml create mode 100644 voucher/src/main/res/values-fi-rFI/strings.xml create mode 100644 voucher/src/main/res/values-fr-rFR/strings.xml create mode 100644 voucher/src/main/res/values-hr-rHR/strings.xml create mode 100644 voucher/src/main/res/values-hu-rHU/strings.xml create mode 100644 voucher/src/main/res/values-it-rIT/strings.xml create mode 100644 voucher/src/main/res/values-ja-rJP/strings.xml create mode 100644 voucher/src/main/res/values-ko-rKR/strings.xml create mode 100644 voucher/src/main/res/values-nb-rNO/strings.xml create mode 100644 voucher/src/main/res/values-nl-rNL/strings.xml create mode 100644 voucher/src/main/res/values-pl-rPL/strings.xml create mode 100644 voucher/src/main/res/values-pt-rBR/strings.xml create mode 100644 voucher/src/main/res/values-ro-rRO/strings.xml create mode 100644 voucher/src/main/res/values-ru-rRU/strings.xml create mode 100644 voucher/src/main/res/values-sk-rSK/strings.xml create mode 100644 voucher/src/main/res/values-sl-rSI/strings.xml create mode 100644 voucher/src/main/res/values-sv-rSE/strings.xml create mode 100644 voucher/src/main/res/values-zh-rCN/strings.xml create mode 100644 voucher/src/main/res/values-zh-rTW/strings.xml create mode 100644 voucher/src/main/res/values/strings.xml diff --git a/voucher/src/main/res/template/values/strings.xml.tt b/voucher/src/main/res/template/values/strings.xml.tt new file mode 100644 index 0000000000..2281fe7921 --- /dev/null +++ b/voucher/src/main/res/template/values/strings.xml.tt @@ -0,0 +1,13 @@ + + + + + %%bacs.result.introduction%% + %%download.pdf%% + \ No newline at end of file diff --git a/voucher/src/main/res/values-cs-rCZ/strings.xml b/voucher/src/main/res/values-cs-rCZ/strings.xml new file mode 100644 index 0000000000..55b2d951ed --- /dev/null +++ b/voucher/src/main/res/values-cs-rCZ/strings.xml @@ -0,0 +1,13 @@ + + + + + Stáhněte si pokyny k přímému inkasu (DDI / podpisové právo) + Stáhnout PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-da-rDK/strings.xml b/voucher/src/main/res/values-da-rDK/strings.xml new file mode 100644 index 0000000000..f0b16d9917 --- /dev/null +++ b/voucher/src/main/res/values-da-rDK/strings.xml @@ -0,0 +1,13 @@ + + + + + Download vejledningen til direkte debitering (fuldmagt til direkte debitering) + Download PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-de-rDE/strings.xml b/voucher/src/main/res/values-de-rDE/strings.xml new file mode 100644 index 0000000000..74425783fc --- /dev/null +++ b/voucher/src/main/res/values-de-rDE/strings.xml @@ -0,0 +1,13 @@ + + + + + Laden Sie Ihre Lastschriftanweisung (DDI/Einzugsermächtigung) herunter + PDF herunterladen + \ No newline at end of file diff --git a/voucher/src/main/res/values-el-rGR/strings.xml b/voucher/src/main/res/values-el-rGR/strings.xml new file mode 100644 index 0000000000..fb5931b7f7 --- /dev/null +++ b/voucher/src/main/res/values-el-rGR/strings.xml @@ -0,0 +1,13 @@ + + + + + Κατεβάστε την Εντολή Άμεσης Χρέωσης (DDI/Εντολή) + Λήψη PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-es-rES/strings.xml b/voucher/src/main/res/values-es-rES/strings.xml new file mode 100644 index 0000000000..4156c5c40e --- /dev/null +++ b/voucher/src/main/res/values-es-rES/strings.xml @@ -0,0 +1,13 @@ + + + + + Descargue su instrucción de débito directo (IDD/mandato) + Descargar PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-fi-rFI/strings.xml b/voucher/src/main/res/values-fi-rFI/strings.xml new file mode 100644 index 0000000000..624acafbaf --- /dev/null +++ b/voucher/src/main/res/values-fi-rFI/strings.xml @@ -0,0 +1,13 @@ + + + + + Lataa suoraveloitusohjeet (DDI / Mandate) + Lataa PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-fr-rFR/strings.xml b/voucher/src/main/res/values-fr-rFR/strings.xml new file mode 100644 index 0000000000..e2db93e4ee --- /dev/null +++ b/voucher/src/main/res/values-fr-rFR/strings.xml @@ -0,0 +1,13 @@ + + + + + Téléchargez votre mandat de prélèvement (DDI) + Télécharger le PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-hr-rHR/strings.xml b/voucher/src/main/res/values-hr-rHR/strings.xml new file mode 100644 index 0000000000..d187d2f3e6 --- /dev/null +++ b/voucher/src/main/res/values-hr-rHR/strings.xml @@ -0,0 +1,13 @@ + + + + + Preuzmite upute za izravno terećenje (DDI / mandat) + Preuzmite PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-hu-rHU/strings.xml b/voucher/src/main/res/values-hu-rHU/strings.xml new file mode 100644 index 0000000000..e4bc2e2f23 --- /dev/null +++ b/voucher/src/main/res/values-hu-rHU/strings.xml @@ -0,0 +1,13 @@ + + + + + Beszedési megbízási utasítás (meghatalmazás) letöltése + PDF letöltése + \ No newline at end of file diff --git a/voucher/src/main/res/values-it-rIT/strings.xml b/voucher/src/main/res/values-it-rIT/strings.xml new file mode 100644 index 0000000000..3c360fd58f --- /dev/null +++ b/voucher/src/main/res/values-it-rIT/strings.xml @@ -0,0 +1,13 @@ + + + + + Scarica le Istruzioni per l\'addebito diretto (DDI / Mandato) + Scarica PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-ja-rJP/strings.xml b/voucher/src/main/res/values-ja-rJP/strings.xml new file mode 100644 index 0000000000..fb07f36631 --- /dev/null +++ b/voucher/src/main/res/values-ja-rJP/strings.xml @@ -0,0 +1,13 @@ + + + + + 自動引き落としの説明 (DDI/委任状) をダウンロードする + PDFをダウンロード + \ No newline at end of file diff --git a/voucher/src/main/res/values-ko-rKR/strings.xml b/voucher/src/main/res/values-ko-rKR/strings.xml new file mode 100644 index 0000000000..7cbf74b650 --- /dev/null +++ b/voucher/src/main/res/values-ko-rKR/strings.xml @@ -0,0 +1,13 @@ + + + + + 자동 이체 안내(DDI/필수) 다운로드 + PDF 다운로드 + \ No newline at end of file diff --git a/voucher/src/main/res/values-nb-rNO/strings.xml b/voucher/src/main/res/values-nb-rNO/strings.xml new file mode 100644 index 0000000000..20f0eac63f --- /dev/null +++ b/voucher/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,13 @@ + + + + + Last ned instruksjoner for direktebelastning (DDI/ mandat) + Last ned PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-nl-rNL/strings.xml b/voucher/src/main/res/values-nl-rNL/strings.xml new file mode 100644 index 0000000000..b4a3cc810d --- /dev/null +++ b/voucher/src/main/res/values-nl-rNL/strings.xml @@ -0,0 +1,13 @@ + + + + + Download uw machtiging automatische incasso + PDF downloaden + \ No newline at end of file diff --git a/voucher/src/main/res/values-pl-rPL/strings.xml b/voucher/src/main/res/values-pl-rPL/strings.xml new file mode 100644 index 0000000000..3004975529 --- /dev/null +++ b/voucher/src/main/res/values-pl-rPL/strings.xml @@ -0,0 +1,13 @@ + + + + + Pobierz dyspozycję polecenia zapłaty (DDI/upoważnienie) + Pobierz PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-pt-rBR/strings.xml b/voucher/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000..685e2e2623 --- /dev/null +++ b/voucher/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,13 @@ + + + + + Baixar instrução de débito direto (DDI) + Baixar PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-ro-rRO/strings.xml b/voucher/src/main/res/values-ro-rRO/strings.xml new file mode 100644 index 0000000000..fcbfa82ed7 --- /dev/null +++ b/voucher/src/main/res/values-ro-rRO/strings.xml @@ -0,0 +1,13 @@ + + + + + Descărcați instrucțiunile de debitare directă (DDI/mandat) + Descărcați PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-ru-rRU/strings.xml b/voucher/src/main/res/values-ru-rRU/strings.xml new file mode 100644 index 0000000000..b38663f078 --- /dev/null +++ b/voucher/src/main/res/values-ru-rRU/strings.xml @@ -0,0 +1,13 @@ + + + + + Загрузить распоряжение прямого дебетования (DDI / поручение) + Загрузить PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-sk-rSK/strings.xml b/voucher/src/main/res/values-sk-rSK/strings.xml new file mode 100644 index 0000000000..d58e729028 --- /dev/null +++ b/voucher/src/main/res/values-sk-rSK/strings.xml @@ -0,0 +1,13 @@ + + + + + Stiahnite si pokyny k inkasu (DDI/Mandát) + Stiahnuť vo formáte PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-sl-rSI/strings.xml b/voucher/src/main/res/values-sl-rSI/strings.xml new file mode 100644 index 0000000000..bb2ae5a2f5 --- /dev/null +++ b/voucher/src/main/res/values-sl-rSI/strings.xml @@ -0,0 +1,13 @@ + + + + + Prenesite navodila za neposredno bremenitev (DDI/mandat) + Prenos datoteke PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-sv-rSE/strings.xml b/voucher/src/main/res/values-sv-rSE/strings.xml new file mode 100644 index 0000000000..96dd891ee5 --- /dev/null +++ b/voucher/src/main/res/values-sv-rSE/strings.xml @@ -0,0 +1,13 @@ + + + + + Ladda ner din instruktion för autogiro/direktdebitering (DDI / Mandate) + Ladda ner PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values-zh-rCN/strings.xml b/voucher/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..cb8210293c --- /dev/null +++ b/voucher/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,13 @@ + + + + + 下载您的直接借记指示(DDI/委托) + 下载 PDF 文件 + \ No newline at end of file diff --git a/voucher/src/main/res/values-zh-rTW/strings.xml b/voucher/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..916de17426 --- /dev/null +++ b/voucher/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,13 @@ + + + + + 下載您的直接扣款指示(DDI/授權) + 下載 PDF + \ No newline at end of file diff --git a/voucher/src/main/res/values/strings.xml b/voucher/src/main/res/values/strings.xml new file mode 100644 index 0000000000..6bcc8c8b1a --- /dev/null +++ b/voucher/src/main/res/values/strings.xml @@ -0,0 +1,13 @@ + + + + + Download your Direct Debit Instruction (DDI / Mandate) + Download PDF + \ No newline at end of file From 39735b86457a9ce4edc7f16ff89f525986903340 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 2 Dec 2021 11:05:35 +0100 Subject: [PATCH 056/102] Voucher: Use translated strings and update ui --- .../com/adyen/checkout/voucher/VoucherView.kt | 3 +++ voucher/src/main/res/layout/voucher_view.xml | 19 ++++--------- voucher/src/main/res/values/styles.xml | 27 +++++++++++++++++++ 3 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 voucher/src/main/res/values/styles.xml diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt index 89deb740e7..207176f08c 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt @@ -9,13 +9,16 @@ package com.adyen.checkout.voucher import android.content.Context +import android.net.Uri import android.util.AttributeSet import android.view.LayoutInflater +import androidx.browser.customtabs.CustomTabsIntent import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer import com.adyen.checkout.components.ActionComponentData import com.adyen.checkout.components.api.ImageLoader import com.adyen.checkout.components.api.LogoApi +import com.adyen.checkout.components.ui.util.ThemeUtil import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.voucher.databinding.VoucherViewBinding diff --git a/voucher/src/main/res/layout/voucher_view.xml b/voucher/src/main/res/layout/voucher_view.xml index 9fd9f6fd3e..58710d6c6f 100644 --- a/voucher/src/main/res/layout/voucher_view.xml +++ b/voucher/src/main/res/layout/voucher_view.xml @@ -13,31 +13,22 @@ android:orientation="vertical" tools:parentTag="android.widget.LinearLayout"> - - + tools:src="@drawable/ic_placeholder_image" /> + android:layout_height="wrap_content" /> + android:gravity="center_horizontal" /> \ No newline at end of file diff --git a/voucher/src/main/res/values/styles.xml b/voucher/src/main/res/values/styles.xml new file mode 100644 index 0000000000..bd176f0148 --- /dev/null +++ b/voucher/src/main/res/values/styles.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file From c14fb1d347f0b27ba65ffabde22a6eded0016fb1 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 2 Dec 2021 11:05:53 +0100 Subject: [PATCH 057/102] Voucher: Show result pdf in browser --- voucher/build.gradle | 3 +++ .../com/adyen/checkout/voucher/VoucherComponent.kt | 14 ++++++++++++-- .../adyen/checkout/voucher/VoucherOutputData.kt | 3 +-- .../java/com/adyen/checkout/voucher/VoucherView.kt | 13 ++++++++++++- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/voucher/build.gradle b/voucher/build.gradle index 06605efb57..aa7716c92c 100644 --- a/voucher/build.gradle +++ b/voucher/build.gradle @@ -46,4 +46,7 @@ dependencies { // Checkout api project(':components-core') api project(':ui-core') + + // Dependencies + implementation "androidx.browser:browser:$browser_version" } \ No newline at end of file diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt index 6efa9173e8..bfb473faeb 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt @@ -20,6 +20,8 @@ import com.adyen.checkout.components.ActionComponentProvider import com.adyen.checkout.components.ViewableComponent import com.adyen.checkout.components.base.BaseActionComponent import com.adyen.checkout.components.model.payments.response.Action +import com.adyen.checkout.components.model.payments.response.VoucherAction +import com.adyen.checkout.core.exception.ComponentException class VoucherComponent( savedStateHandle: SavedStateHandle, @@ -29,6 +31,7 @@ class VoucherComponent( ViewableComponent { private val mOutputLiveData = MutableLiveData() + private var url: String? = null override fun canHandleAction(action: Action): Boolean { return PROVIDER.canHandleAction(action) @@ -46,16 +49,23 @@ class VoucherComponent( // no ops } + @Throws(ComponentException::class) override fun handleActionInternal(activity: Activity, action: Action) { + if (action !is VoucherAction) throw ComponentException("Unsupported action") + url = action.url + mOutputLiveData.postValue( VoucherOutputData( true, - action.paymentMethodType, - null + action.paymentMethodType ) ) } + fun getDownloadUrl(): String? { + return url + } + companion object { @JvmField val PROVIDER: ActionComponentProvider = VoucherComponentProvider() diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt index 6cea34e670..b0ccad5c8f 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherOutputData.kt @@ -12,8 +12,7 @@ import com.adyen.checkout.components.base.OutputData data class VoucherOutputData( private val isValid: Boolean, - val paymentMethodType: String?, - val url: String? + val paymentMethodType: String? ) : OutputData { override fun isValid(): Boolean { return isValid diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt index 207176f08c..1417023a59 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt @@ -41,7 +41,9 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe } override fun initView() { - // TODO implement + binding.textViewDownload.setOnClickListener { + launchDownloadIntent() + } } override fun isConfirmationRequired(): Boolean { @@ -68,4 +70,13 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe } } + private fun launchDownloadIntent() { + val url = component.getDownloadUrl() ?: return + val intent = CustomTabsIntent.Builder() + .setShowTitle(true) + .setToolbarColor(ThemeUtil.getPrimaryThemeColor(context)) + .build() + intent.launchUrl(context, Uri.parse(url)) + } + } \ No newline at end of file From c6a71bdb34612b910b4443979a2bf2113d34a42d Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 6 Dec 2021 11:01:25 +0100 Subject: [PATCH 058/102] Voucher: Add finish button --- .../adyen3ds2/Adyen3DS2ComponentProvider.kt | 4 ++++ .../checkout/await/AwaitComponentProvider.kt | 4 ++++ .../components/ActionComponentProvider.java | 5 +++++ .../java/com/adyen/checkout/dropin/DropIn.kt | 1 + .../checkout/dropin/ui/DropInActivity.kt | 5 +++++ .../action/ActionComponentDialogFragment.kt | 9 ++++++++ .../base/DropInBottomSheetDialogFragment.kt | 1 + .../res/layout/fragment_action_component.xml | 21 ++++++++++++------- .../qrcode/QRCodeComponentProvider.kt | 4 ++++ .../redirect/RedirectComponentProvider.kt | 4 ++++ .../voucher/VoucherComponentProvider.kt | 4 ++++ .../com/adyen/checkout/voucher/VoucherView.kt | 2 +- .../main/res/template/values/strings.xml.tt | 1 + .../src/main/res/values-cs-rCZ/strings.xml | 1 + .../src/main/res/values-da-rDK/strings.xml | 1 + .../src/main/res/values-de-rDE/strings.xml | 1 + .../src/main/res/values-el-rGR/strings.xml | 1 + .../src/main/res/values-es-rES/strings.xml | 1 + .../src/main/res/values-fi-rFI/strings.xml | 1 + .../src/main/res/values-fr-rFR/strings.xml | 1 + .../src/main/res/values-hr-rHR/strings.xml | 1 + .../src/main/res/values-hu-rHU/strings.xml | 1 + .../src/main/res/values-it-rIT/strings.xml | 1 + .../src/main/res/values-ja-rJP/strings.xml | 1 + .../src/main/res/values-ko-rKR/strings.xml | 1 + .../src/main/res/values-nb-rNO/strings.xml | 1 + .../src/main/res/values-nl-rNL/strings.xml | 1 + .../src/main/res/values-pl-rPL/strings.xml | 1 + .../src/main/res/values-pt-rBR/strings.xml | 1 + .../src/main/res/values-ro-rRO/strings.xml | 1 + .../src/main/res/values-ru-rRU/strings.xml | 1 + .../src/main/res/values-sk-rSK/strings.xml | 1 + .../src/main/res/values-sl-rSI/strings.xml | 1 + .../src/main/res/values-sv-rSE/strings.xml | 1 + .../src/main/res/values-zh-rCN/strings.xml | 1 + .../src/main/res/values-zh-rTW/strings.xml | 1 + voucher/src/main/res/values/strings.xml | 1 + voucher/src/main/res/values/styles.xml | 6 ++++-- .../WeChatPayActionComponentProvider.kt | 4 ++++ 39 files changed, 89 insertions(+), 10 deletions(-) diff --git a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/Adyen3DS2ComponentProvider.kt b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/Adyen3DS2ComponentProvider.kt index 5f0d8eb7dc..1429531986 100644 --- a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/Adyen3DS2ComponentProvider.kt +++ b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/Adyen3DS2ComponentProvider.kt @@ -70,4 +70,8 @@ class Adyen3DS2ComponentProvider : ActionComponentProvider getSupportedActionTypes(); + + /** + * @return If the provided component provides details to make an API call to /payments/detail end point. + */ + boolean providesDetails(); } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/DropIn.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/DropIn.kt index 27f785551b..398b0b1eb8 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/DropIn.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/DropIn.kt @@ -39,6 +39,7 @@ object DropIn { const val RESULT_KEY = "payment_result" const val ERROR_REASON_KEY = "error_reason" const val ERROR_REASON_USER_CANCELED = "Canceled by user" + const val FINISHED_WITH_ACTION = "finish_with_action" /** * Register your Activity or Fragment with the Activity Result API and receive the final diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 63062da0f7..d853523fd1 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -416,6 +416,11 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot dropInService?.requestOrdersCall() } + override fun finishWithAction() { + Logger.d(TAG, "finishWithActionCall") + sendResult(DropIn.FINISHED_WITH_ACTION) + } + private fun handleDropInServiceResult(dropInServiceResult: BaseDropInServiceResult) { Logger.d(TAG, "handleDropInServiceResult - ${dropInServiceResult::class.simpleName}") dropInViewModel.isWaitingResult = false diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt index 60107c9daa..2502f1a312 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt @@ -13,6 +13,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.lifecycle.Observer import com.adyen.checkout.components.ActionComponent import com.adyen.checkout.components.ActionComponentData @@ -81,6 +82,14 @@ class ActionComponentDialogFragment : DropInBottomSheetDialogFragment(), Observe actionComponent = getComponent(action) attachComponent(actionComponent, componentView) + val shouldShowFinishButton = getActionProviderFor(action)?.providesDetails() == false + if (shouldShowFinishButton) { + with(binding.buttonFinish) { + isVisible = true + setOnClickListener { protocol.finishWithAction() } + } + } + if (!isHandled) { (actionComponent as ActionComponent<*>).handleAction(requireActivity(), action) isHandled = true diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt index e81070b38c..ec05b99dce 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt @@ -100,5 +100,6 @@ abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragment() { fun terminateDropIn() fun startGooglePay(paymentMethod: PaymentMethod, googlePayConfiguration: GooglePayConfiguration) fun requestBalanceCall(giftCardComponentState: GiftCardComponentState) + fun finishWithAction() } } diff --git a/drop-in/src/main/res/layout/fragment_action_component.xml b/drop-in/src/main/res/layout/fragment_action_component.xml index 841aaaf1f6..68d66027f3 100644 --- a/drop-in/src/main/res/layout/fragment_action_component.xml +++ b/drop-in/src/main/res/layout/fragment_action_component.xml @@ -1,5 +1,4 @@ - - - + android:layout_height="wrap_content" /> + tools:text="Header" /> + android:layout_height="wrap_content" /> + + \ No newline at end of file diff --git a/qr-code/src/main/java/com/adyen/checkout/qrcode/QRCodeComponentProvider.kt b/qr-code/src/main/java/com/adyen/checkout/qrcode/QRCodeComponentProvider.kt index 7bd5cd9421..8e27e399f2 100644 --- a/qr-code/src/main/java/com/adyen/checkout/qrcode/QRCodeComponentProvider.kt +++ b/qr-code/src/main/java/com/adyen/checkout/qrcode/QRCodeComponentProvider.kt @@ -72,4 +72,8 @@ class QRCodeComponentProvider : ActionComponentProvider { return listOf(VoucherAction.ACTION_TYPE) } + + override fun providesDetails(): Boolean { + return false + } } \ No newline at end of file diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt index 1417023a59..2db8a1e700 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt @@ -32,7 +32,7 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe init { orientation = VERTICAL - val padding = resources.getDimension(R.dimen.standard_double_margin).toInt() + val padding = resources.getDimension(R.dimen.standard_margin).toInt() setPadding(padding, padding, padding, padding) } diff --git a/voucher/src/main/res/template/values/strings.xml.tt b/voucher/src/main/res/template/values/strings.xml.tt index 2281fe7921..945da45451 100644 --- a/voucher/src/main/res/template/values/strings.xml.tt +++ b/voucher/src/main/res/template/values/strings.xml.tt @@ -10,4 +10,5 @@ %%bacs.result.introduction%% %%download.pdf%% + %%voucher.finish%% \ No newline at end of file diff --git a/voucher/src/main/res/values-cs-rCZ/strings.xml b/voucher/src/main/res/values-cs-rCZ/strings.xml index 55b2d951ed..3760438119 100644 --- a/voucher/src/main/res/values-cs-rCZ/strings.xml +++ b/voucher/src/main/res/values-cs-rCZ/strings.xml @@ -10,4 +10,5 @@ Stáhněte si pokyny k přímému inkasu (DDI / podpisové právo) Stáhnout PDF + Dokončit \ No newline at end of file diff --git a/voucher/src/main/res/values-da-rDK/strings.xml b/voucher/src/main/res/values-da-rDK/strings.xml index f0b16d9917..c0fb41d673 100644 --- a/voucher/src/main/res/values-da-rDK/strings.xml +++ b/voucher/src/main/res/values-da-rDK/strings.xml @@ -10,4 +10,5 @@ Download vejledningen til direkte debitering (fuldmagt til direkte debitering) Download PDF + Afslut \ No newline at end of file diff --git a/voucher/src/main/res/values-de-rDE/strings.xml b/voucher/src/main/res/values-de-rDE/strings.xml index 74425783fc..40befd8b1a 100644 --- a/voucher/src/main/res/values-de-rDE/strings.xml +++ b/voucher/src/main/res/values-de-rDE/strings.xml @@ -10,4 +10,5 @@ Laden Sie Ihre Lastschriftanweisung (DDI/Einzugsermächtigung) herunter PDF herunterladen + Abschließen \ No newline at end of file diff --git a/voucher/src/main/res/values-el-rGR/strings.xml b/voucher/src/main/res/values-el-rGR/strings.xml index fb5931b7f7..cb0ad1df50 100644 --- a/voucher/src/main/res/values-el-rGR/strings.xml +++ b/voucher/src/main/res/values-el-rGR/strings.xml @@ -10,4 +10,5 @@ Κατεβάστε την Εντολή Άμεσης Χρέωσης (DDI/Εντολή) Λήψη PDF + Τέλος \ No newline at end of file diff --git a/voucher/src/main/res/values-es-rES/strings.xml b/voucher/src/main/res/values-es-rES/strings.xml index 4156c5c40e..33ba3f0d3a 100644 --- a/voucher/src/main/res/values-es-rES/strings.xml +++ b/voucher/src/main/res/values-es-rES/strings.xml @@ -10,4 +10,5 @@ Descargue su instrucción de débito directo (IDD/mandato) Descargar PDF + Finalizar \ No newline at end of file diff --git a/voucher/src/main/res/values-fi-rFI/strings.xml b/voucher/src/main/res/values-fi-rFI/strings.xml index 624acafbaf..5741d47490 100644 --- a/voucher/src/main/res/values-fi-rFI/strings.xml +++ b/voucher/src/main/res/values-fi-rFI/strings.xml @@ -10,4 +10,5 @@ Lataa suoraveloitusohjeet (DDI / Mandate) Lataa PDF + Lopeta \ No newline at end of file diff --git a/voucher/src/main/res/values-fr-rFR/strings.xml b/voucher/src/main/res/values-fr-rFR/strings.xml index e2db93e4ee..060730a6bb 100644 --- a/voucher/src/main/res/values-fr-rFR/strings.xml +++ b/voucher/src/main/res/values-fr-rFR/strings.xml @@ -10,4 +10,5 @@ Téléchargez votre mandat de prélèvement (DDI) Télécharger le PDF + Terminer \ No newline at end of file diff --git a/voucher/src/main/res/values-hr-rHR/strings.xml b/voucher/src/main/res/values-hr-rHR/strings.xml index d187d2f3e6..2a00909371 100644 --- a/voucher/src/main/res/values-hr-rHR/strings.xml +++ b/voucher/src/main/res/values-hr-rHR/strings.xml @@ -10,4 +10,5 @@ Preuzmite upute za izravno terećenje (DDI / mandat) Preuzmite PDF + Završi \ No newline at end of file diff --git a/voucher/src/main/res/values-hu-rHU/strings.xml b/voucher/src/main/res/values-hu-rHU/strings.xml index e4bc2e2f23..cc9492d15c 100644 --- a/voucher/src/main/res/values-hu-rHU/strings.xml +++ b/voucher/src/main/res/values-hu-rHU/strings.xml @@ -10,4 +10,5 @@ Beszedési megbízási utasítás (meghatalmazás) letöltése PDF letöltése + Befejezés \ No newline at end of file diff --git a/voucher/src/main/res/values-it-rIT/strings.xml b/voucher/src/main/res/values-it-rIT/strings.xml index 3c360fd58f..ff01eeb23b 100644 --- a/voucher/src/main/res/values-it-rIT/strings.xml +++ b/voucher/src/main/res/values-it-rIT/strings.xml @@ -10,4 +10,5 @@ Scarica le Istruzioni per l\'addebito diretto (DDI / Mandato) Scarica PDF + Completa \ No newline at end of file diff --git a/voucher/src/main/res/values-ja-rJP/strings.xml b/voucher/src/main/res/values-ja-rJP/strings.xml index fb07f36631..47c4835dde 100644 --- a/voucher/src/main/res/values-ja-rJP/strings.xml +++ b/voucher/src/main/res/values-ja-rJP/strings.xml @@ -10,4 +10,5 @@ 自動引き落としの説明 (DDI/委任状) をダウンロードする PDFをダウンロード + 完了 \ No newline at end of file diff --git a/voucher/src/main/res/values-ko-rKR/strings.xml b/voucher/src/main/res/values-ko-rKR/strings.xml index 7cbf74b650..3be720d63b 100644 --- a/voucher/src/main/res/values-ko-rKR/strings.xml +++ b/voucher/src/main/res/values-ko-rKR/strings.xml @@ -10,4 +10,5 @@ 자동 이체 안내(DDI/필수) 다운로드 PDF 다운로드 + 완료 \ No newline at end of file diff --git a/voucher/src/main/res/values-nb-rNO/strings.xml b/voucher/src/main/res/values-nb-rNO/strings.xml index 20f0eac63f..cdc2ae945c 100644 --- a/voucher/src/main/res/values-nb-rNO/strings.xml +++ b/voucher/src/main/res/values-nb-rNO/strings.xml @@ -10,4 +10,5 @@ Last ned instruksjoner for direktebelastning (DDI/ mandat) Last ned PDF + Fullfør \ No newline at end of file diff --git a/voucher/src/main/res/values-nl-rNL/strings.xml b/voucher/src/main/res/values-nl-rNL/strings.xml index b4a3cc810d..0455626d95 100644 --- a/voucher/src/main/res/values-nl-rNL/strings.xml +++ b/voucher/src/main/res/values-nl-rNL/strings.xml @@ -10,4 +10,5 @@ Download uw machtiging automatische incasso PDF downloaden + Voltooien \ No newline at end of file diff --git a/voucher/src/main/res/values-pl-rPL/strings.xml b/voucher/src/main/res/values-pl-rPL/strings.xml index 3004975529..549a8d40e8 100644 --- a/voucher/src/main/res/values-pl-rPL/strings.xml +++ b/voucher/src/main/res/values-pl-rPL/strings.xml @@ -10,4 +10,5 @@ Pobierz dyspozycję polecenia zapłaty (DDI/upoważnienie) Pobierz PDF + Zakończ \ No newline at end of file diff --git a/voucher/src/main/res/values-pt-rBR/strings.xml b/voucher/src/main/res/values-pt-rBR/strings.xml index 685e2e2623..8612569e3d 100644 --- a/voucher/src/main/res/values-pt-rBR/strings.xml +++ b/voucher/src/main/res/values-pt-rBR/strings.xml @@ -10,4 +10,5 @@ Baixar instrução de débito direto (DDI) Baixar PDF + Concluir \ No newline at end of file diff --git a/voucher/src/main/res/values-ro-rRO/strings.xml b/voucher/src/main/res/values-ro-rRO/strings.xml index fcbfa82ed7..09fb165fa8 100644 --- a/voucher/src/main/res/values-ro-rRO/strings.xml +++ b/voucher/src/main/res/values-ro-rRO/strings.xml @@ -10,4 +10,5 @@ Descărcați instrucțiunile de debitare directă (DDI/mandat) Descărcați PDF + Finalizați \ No newline at end of file diff --git a/voucher/src/main/res/values-ru-rRU/strings.xml b/voucher/src/main/res/values-ru-rRU/strings.xml index b38663f078..038cb4cdde 100644 --- a/voucher/src/main/res/values-ru-rRU/strings.xml +++ b/voucher/src/main/res/values-ru-rRU/strings.xml @@ -10,4 +10,5 @@ Загрузить распоряжение прямого дебетования (DDI / поручение) Загрузить PDF + Готово \ No newline at end of file diff --git a/voucher/src/main/res/values-sk-rSK/strings.xml b/voucher/src/main/res/values-sk-rSK/strings.xml index d58e729028..93ceab4ee2 100644 --- a/voucher/src/main/res/values-sk-rSK/strings.xml +++ b/voucher/src/main/res/values-sk-rSK/strings.xml @@ -10,4 +10,5 @@ Stiahnite si pokyny k inkasu (DDI/Mandát) Stiahnuť vo formáte PDF + Dokončiť \ No newline at end of file diff --git a/voucher/src/main/res/values-sl-rSI/strings.xml b/voucher/src/main/res/values-sl-rSI/strings.xml index bb2ae5a2f5..b9628cea4c 100644 --- a/voucher/src/main/res/values-sl-rSI/strings.xml +++ b/voucher/src/main/res/values-sl-rSI/strings.xml @@ -10,4 +10,5 @@ Prenesite navodila za neposredno bremenitev (DDI/mandat) Prenos datoteke PDF + Zaključi \ No newline at end of file diff --git a/voucher/src/main/res/values-sv-rSE/strings.xml b/voucher/src/main/res/values-sv-rSE/strings.xml index 96dd891ee5..5b9759f445 100644 --- a/voucher/src/main/res/values-sv-rSE/strings.xml +++ b/voucher/src/main/res/values-sv-rSE/strings.xml @@ -10,4 +10,5 @@ Ladda ner din instruktion för autogiro/direktdebitering (DDI / Mandate) Ladda ner PDF + Avsluta \ No newline at end of file diff --git a/voucher/src/main/res/values-zh-rCN/strings.xml b/voucher/src/main/res/values-zh-rCN/strings.xml index cb8210293c..08a4637d38 100644 --- a/voucher/src/main/res/values-zh-rCN/strings.xml +++ b/voucher/src/main/res/values-zh-rCN/strings.xml @@ -10,4 +10,5 @@ 下载您的直接借记指示(DDI/委托) 下载 PDF 文件 + 完成 \ No newline at end of file diff --git a/voucher/src/main/res/values-zh-rTW/strings.xml b/voucher/src/main/res/values-zh-rTW/strings.xml index 916de17426..7832791c00 100644 --- a/voucher/src/main/res/values-zh-rTW/strings.xml +++ b/voucher/src/main/res/values-zh-rTW/strings.xml @@ -10,4 +10,5 @@ 下載您的直接扣款指示(DDI/授權) 下載 PDF + 完成 \ No newline at end of file diff --git a/voucher/src/main/res/values/strings.xml b/voucher/src/main/res/values/strings.xml index 6bcc8c8b1a..2182137e8f 100644 --- a/voucher/src/main/res/values/strings.xml +++ b/voucher/src/main/res/values/strings.xml @@ -10,4 +10,5 @@ Download your Direct Debit Instruction (DDI / Mandate) Download PDF + Finish \ No newline at end of file diff --git a/voucher/src/main/res/values/styles.xml b/voucher/src/main/res/values/styles.xml index bd176f0148..771113cba9 100644 --- a/voucher/src/main/res/values/styles.xml +++ b/voucher/src/main/res/values/styles.xml @@ -8,20 +8,22 @@ + \ No newline at end of file diff --git a/wechatpay/src/main/java/com/adyen/checkout/wechatpay/WeChatPayActionComponentProvider.kt b/wechatpay/src/main/java/com/adyen/checkout/wechatpay/WeChatPayActionComponentProvider.kt index c3e0bd44eb..23702b3805 100644 --- a/wechatpay/src/main/java/com/adyen/checkout/wechatpay/WeChatPayActionComponentProvider.kt +++ b/wechatpay/src/main/java/com/adyen/checkout/wechatpay/WeChatPayActionComponentProvider.kt @@ -62,4 +62,8 @@ class WeChatPayActionComponentProvider : ActionComponentProvider Date: Thu, 9 Dec 2021 09:54:00 +0100 Subject: [PATCH 059/102] Minor fixes --- .../checkout/dropin/ui/DropInActivityEvent.kt | 2 +- .../adyen/checkout/dropin/ui/DropInViewModel.kt | 4 ++-- .../ui/paymentmethods/PaymentMethodAdapter.kt | 16 +++++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt index 5bf67da4ee..ac003f7646 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivityEvent.kt @@ -11,6 +11,6 @@ package com.adyen.checkout.dropin.ui import com.adyen.checkout.components.PaymentComponentState sealed class DropInActivityEvent { - class MakePartialPayment(val paymentComponentState: PaymentComponentState<*>) : DropInActivityEvent() + data class MakePartialPayment(val paymentComponentState: PaymentComponentState<*>) : DropInActivityEvent() object ShowPaymentMethods : DropInActivityEvent() } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt index d31935a237..a402defdd1 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInViewModel.kt @@ -218,7 +218,7 @@ class DropInViewModel( } private suspend fun handleOrderResponse(orderResponse: OrderResponse?) { - val orderModel = getOrderStatus(orderResponse) + val orderModel = getOrderDetails(orderResponse) if (orderModel == null) { currentOrder = null amount = dropInConfiguration.amount @@ -270,7 +270,7 @@ class DropInViewModel( return GooglePayConfiguration.Builder(googlePayConfiguration).setAmount(amount).build() } - private suspend fun getOrderStatus(orderResponse: OrderResponse?): OrderModel? { + private suspend fun getOrderDetails(orderResponse: OrderResponse?): OrderModel? { if (orderResponse == null) return null return try { val orderStatus = orderStatusRepository.getOrderStatus(dropInConfiguration, orderResponse.orderData) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt index ac01f64e55..b36dc562d5 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/paymentmethods/PaymentMethodAdapter.kt @@ -66,13 +66,15 @@ class PaymentMethodAdapter( private fun bindHeader(holder: HeaderVH, position: Int) { val header = getHeaderAt(position) holder.title.setText(header.titleResId) - if (header.actionResId == null) { - holder.action.visibility = View.GONE - } else { - holder.action.visibility = View.VISIBLE - holder.action.setText(header.actionResId) - holder.action.setOnClickListener { - onHeaderActionClick(header) + with(holder.action) { + if (header.actionResId == null) { + visibility = View.GONE + } else { + visibility = View.VISIBLE + setText(header.actionResId) + setOnClickListener { + onHeaderActionClick(header) + } } } } From f077cf6968d378ebf5ef06a2ace381ccb244f21a Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 7 Dec 2021 16:28:55 +0100 Subject: [PATCH 060/102] Voucher: Extract loading logo to private function --- .../com/adyen/checkout/voucher/VoucherComponent.kt | 1 + .../java/com/adyen/checkout/voucher/VoucherView.kt | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt index bfb473faeb..eaa9d25505 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt @@ -32,6 +32,7 @@ class VoucherComponent( private val mOutputLiveData = MutableLiveData() private var url: String? = null + private var paymentMethodType: String? = null override fun canHandleAction(action: Action): Boolean { return PROVIDER.canHandleAction(action) diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt index 2db8a1e700..5ce635d20d 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherView.kt @@ -55,7 +55,7 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe } override fun initLocalizedStrings(localizedContext: Context) { - // TODO implement + // no ops } override fun observeComponentChanges(lifecycleOwner: LifecycleOwner) { @@ -64,10 +64,7 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe override fun onChanged(outputData: VoucherOutputData?) { if (outputData == null) return - - if (!outputData.paymentMethodType.isNullOrEmpty()) { - imageLoader.load(outputData.paymentMethodType, binding.imageViewLogo, LogoApi.Size.MEDIUM) - } + loadLogo(outputData.paymentMethodType) } private fun launchDownloadIntent() { @@ -79,4 +76,10 @@ class VoucherView @JvmOverloads constructor(context: Context, attrs: AttributeSe intent.launchUrl(context, Uri.parse(url)) } + private fun loadLogo(paymentMethodType: String?) { + if (!paymentMethodType.isNullOrEmpty()) { + imageLoader.load(paymentMethodType, binding.imageViewLogo, LogoApi.Size.MEDIUM) + } + } + } \ No newline at end of file From 111416444ae1489989c24f9c14f5d431927e4f3a Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 7 Dec 2021 16:50:13 +0100 Subject: [PATCH 061/102] Voucher: Code fixes --- .../main/java/com/adyen/checkout/components/api/ImageLoader.kt | 1 + .../checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt b/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt index adaf52cca2..7ddcbfa705 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt @@ -70,6 +70,7 @@ class ImageLoader(private val logoApi: LogoApi) { /** * Load image to ImageView with place holder before load and error fallback image. */ + @Suppress("LongParameterList") @JvmOverloads fun load( txVariant: String, diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt index ec05b99dce..aae73ecb06 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/base/DropInBottomSheetDialogFragment.kt @@ -89,6 +89,7 @@ abstract class DropInBottomSheetDialogFragment : BottomSheetDialogFragment() { /** * Interface for Drop-in fragments to interact with the main Activity */ + @Suppress("TooManyFunctions") interface Protocol { fun showPreselectedDialog() fun showPaymentMethodsDialog() From 41129b8a06ab63b3c4bcdd65128cb2647b4c4b41 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 7 Dec 2021 16:55:40 +0100 Subject: [PATCH 062/102] Remove going back to payment method list logic on back press in ActionComponentDialogFragment --- .../dropin/ui/action/ActionComponentDialogFragment.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt index 2502f1a312..ebd75f252e 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt @@ -102,12 +102,7 @@ class ActionComponentDialogFragment : DropInBottomSheetDialogFragment(), Observe } override fun onBackPressed(): Boolean { - // polling will be canceled by lifecycle event - if (dropInViewModel.shouldSkipToSinglePaymentMethod()) { - protocol.terminateDropIn() - } else { - protocol.showPaymentMethodsDialog() - } + protocol.terminateDropIn() return true } From daadbef91fbd07fe54cf7916a83ebba866be71f4 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 9 Dec 2021 16:43:53 +0100 Subject: [PATCH 063/102] Voucher: Update docs for provideDetails function --- .../adyen/checkout/components/ActionComponentProvider.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/ActionComponentProvider.java b/components-core/src/main/java/com/adyen/checkout/components/ActionComponentProvider.java index 1f8001133e..4efd2ac9af 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/ActionComponentProvider.java +++ b/components-core/src/main/java/com/adyen/checkout/components/ActionComponentProvider.java @@ -13,6 +13,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.Observer; import androidx.lifecycle.SavedStateHandle; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelStoreOwner; @@ -89,7 +91,10 @@ ComponentT get( List getSupportedActionTypes(); /** - * @return If the provided component provides details to make an API call to /payments/detail end point. + * Checks if the provided component will trigger updates that can be observed using + * {@link Component#observe(LifecycleOwner, Observer)}. If returns false, no events will be fired. + * + * @return If the provided component provides details to make an API call to /payments/details end point. */ boolean providesDetails(); } From 3c88d7d4d878f6f69b49081a7cb9ae8bd9e1c483 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 10 Dec 2021 11:08:07 +0100 Subject: [PATCH 064/102] Pass default size instead of null in ImageLoader while loading an image --- .../main/java/com/adyen/checkout/components/api/ImageLoader.kt | 2 +- .../src/main/java/com/adyen/checkout/components/api/LogoApi.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt b/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt index 7ddcbfa705..3031ea9848 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/api/ImageLoader.kt @@ -64,7 +64,7 @@ class ImageLoader(private val logoApi: LogoApi) { @DrawableRes placeholder: Int = 0, @DrawableRes errorFallback: Int = 0 ) { - load(txVariant, txSubVariant, view, null, placeholder, errorFallback) + load(txVariant, txSubVariant, view, LogoApi.DEFAULT_SIZE, placeholder, errorFallback) } /** diff --git a/components-core/src/main/java/com/adyen/checkout/components/api/LogoApi.kt b/components-core/src/main/java/com/adyen/checkout/components/api/LogoApi.kt index 21d46b4ee2..d97717686f 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/api/LogoApi.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/api/LogoApi.kt @@ -23,7 +23,7 @@ class LogoApi(host: String, displayMetrics: DisplayMetrics) { // %1$s = size, %2$s = txVariant(/txSubVariant)-densityExtension private const val LOGO_PATH = "images/logos/%1\$s/%2\$s.png" - private val DEFAULT_SIZE = Size.SMALL + val DEFAULT_SIZE = Size.SMALL const val KILO_BYTE_SIZE = 1024 private const val CACHE_FRACTION_SIZE = 8 private val LRU_CACHE_MAX_SIZE = getMaxCacheSize() From 0bb4caa2905a634bfbeaeb9b35cfc9ab7d688d15 Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 13 Dec 2021 14:10:18 +0100 Subject: [PATCH 065/102] EnvFix: Fix Environment equals method --- .../src/main/java/com/adyen/checkout/core/api/Environment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/api/Environment.java b/checkout-core/src/main/java/com/adyen/checkout/core/api/Environment.java index a41c875e5c..02d452cf34 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/api/Environment.java +++ b/checkout-core/src/main/java/com/adyen/checkout/core/api/Environment.java @@ -89,7 +89,7 @@ public boolean equals(Object o) { return false; } final Environment that = (Environment) o; - return mBaseUrl.toString().equals(that.toString()); + return mBaseUrl.toString().equals(that.mBaseUrl.toString()); } @Override From f140169d94405d5dcfc91eb4bb3c192ca0ac625f Mon Sep 17 00:00:00 2001 From: jreij Date: Mon, 13 Dec 2021 14:11:02 +0100 Subject: [PATCH 066/102] EnvFix: Use equals instead of == operator in GooglePayConfiguration java class --- .../com/adyen/checkout/googlepay/GooglePayConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java b/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java index 94a32283bd..48f9fb9ac8 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/GooglePayConfiguration.java @@ -210,7 +210,7 @@ public static final class Builder extends BaseConfigurationBuilder Date: Mon, 1 Nov 2021 11:00:03 +0100 Subject: [PATCH 067/102] BACS: Create module --- bacs/build.gradle | 60 +++++++++++++++++++++++++++++++ bacs/consumer-rules.pro | 0 bacs/proguard-rules.pro | 21 +++++++++++ bacs/src/main/AndroidManifest.xml | 11 ++++++ settings.gradle | 6 ++-- 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 bacs/build.gradle create mode 100644 bacs/consumer-rules.pro create mode 100644 bacs/proguard-rules.pro create mode 100644 bacs/src/main/AndroidManifest.xml diff --git a/bacs/build.gradle b/bacs/build.gradle new file mode 100644 index 0000000000..4fdf803657 --- /dev/null +++ b/bacs/build.gradle @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 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 1/11/2021. + */ + +plugins { + id 'com.android.library' + id 'kotlin-android' +} + +// Maven artifact +ext.mavenArtifactId = "bacs" +ext.mavenArtifactName = "Adyen BACS Direct Debit component" +ext.mavenArtifactDescription = "Adyen checkout BACS Direct Debit component client for Adyen's Checkout API." + +apply from: "${rootDir}/config/gradle/sharedTasks.gradle" + +android { + compileSdkVersion compile_sdk_version + + defaultConfig { + minSdkVersion min_sdk_version + targetSdkVersion target_sdk_version + versionCode version_code + versionName version_name + + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + consumerProguardFiles "consumer-rules.pro" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + + buildFeatures { + viewBinding true + } +} + +dependencies { + // Checkout + api project(':components-core') + api project(':ui-core') + + // Dependencies + implementation "com.google.android.material:material:$material_version" + + //Tests + testImplementation "junit:junit:$junit_version" + androidTestImplementation "androidx.test.ext:junit:$test_ext_version" + androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" +} \ No newline at end of file diff --git a/bacs/consumer-rules.pro b/bacs/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bacs/proguard-rules.pro b/bacs/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/bacs/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/bacs/src/main/AndroidManifest.xml b/bacs/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..1b7119cb59 --- /dev/null +++ b/bacs/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 567f90795a..874eaa8570 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,7 @@ include ':3ds2', ':await', ':components-core', + ':bacs', ':bcmc', ':blik', ':checkout-core', @@ -22,5 +23,6 @@ include ':3ds2', ':redirect', ':sepa', ':ui-core', - ':wechatpay', - ':voucher' + ':voucher', + ':wechatpay' + From a697ce1c9fa9b77d82db31f0665e582ecc8a8c2e Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 2 Nov 2021 11:31:08 +0100 Subject: [PATCH 068/102] BACS: Add BacsDirectDebitConfiguration --- .../bacs/BacsDirectDebitConfiguration.kt | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt new file mode 100644 index 0000000000..7bc08c76dc --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 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 2/11/2021. + */ + +package com.adyen.checkout.bacs + +import android.content.Context +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.components.base.BaseConfigurationBuilder +import com.adyen.checkout.components.base.Configuration +import com.adyen.checkout.core.api.Environment +import java.util.* + +class BacsDirectDebitConfiguration: Configuration { + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel?): BacsDirectDebitConfiguration? { + if (source == null) return null + return BacsDirectDebitConfiguration(source) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + internal constructor(builder: Builder) : super(builder.builderShopperLocale, builder.builderEnvironment, builder.builderClientKey) + internal constructor(parcel: Parcel) : super(parcel) + + class Builder: BaseConfigurationBuilder { + + constructor(context: Context, clientKey: String): super(context, clientKey) + + /** + * Builder with required parameters. + * + * @param shopperLocale The Locale of the shopper. + * @param environment The [Environment] to be used for network calls to Adyen. + * @param clientKey Your Client Key used for network calls from the SDK to Adyen. + */ + constructor(shopperLocale: Locale, environment: Environment, clientKey: String) : super(shopperLocale, environment, clientKey) + + override fun setShopperLocale(builderShopperLocale: Locale): Builder { + return super.setShopperLocale(builderShopperLocale) as Builder + } + + override fun setEnvironment(builderEnvironment: Environment): Builder { + return super.setEnvironment(builderEnvironment) as Builder + } + + override fun buildInternal(): BacsDirectDebitConfiguration { + return BacsDirectDebitConfiguration(this) + } + } +} \ No newline at end of file From 3987b630403a127dc26a68279e78ebf269d0ccc0 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 5 Nov 2021 10:29:36 +0100 Subject: [PATCH 069/102] BACS: Add BacsDirectDebitComponent --- .../checkout/bacs/BacsDirectDebitComponent.kt | 37 +++++++++++++++++ .../checkout/bacs/BacsDirectDebitInputData.kt | 18 ++++++++ .../bacs/BacsDirectDebitOutputData.kt | 28 +++++++++++++ .../request/BacsDirectDebitPaymentMethod.kt | 41 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt create mode 100644 components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt new file mode 100644 index 0000000000..8adf1c0184 --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 2/11/2021. + */ + +package com.adyen.checkout.bacs + +import androidx.lifecycle.SavedStateHandle +import com.adyen.checkout.components.GenericComponentState +import com.adyen.checkout.components.base.BasePaymentComponent +import com.adyen.checkout.components.base.GenericPaymentMethodDelegate +import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPaymentMethod +import com.adyen.checkout.components.util.PaymentMethodTypes + +private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.BACS) + +class BacsDirectDebitComponent( + savedStateHandle: SavedStateHandle, + paymentMethodDelegate: GenericPaymentMethodDelegate, + configuration: BacsDirectDebitConfiguration +) : + BasePaymentComponent>(savedStateHandle, paymentMethodDelegate, configuration) { + + override fun getSupportedPaymentMethodTypes() = PAYMENT_METHOD_TYPES + + override fun onInputDataChanged(inputData: BacsDirectDebitInputData): BacsDirectDebitOutputData { + TODO("Not yet implemented") + } + + override fun createComponentState(): GenericComponentState { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt new file mode 100644 index 0000000000..146a40fd9a --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 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 2/11/2021. + */ + +package com.adyen.checkout.bacs + +import com.adyen.checkout.components.base.InputData + +data class BacsDirectDebitInputData( + var holderName: String = "", + var bankAccountNumber: String = "", + var bankLocationId: String = "", + var shopperEmail: String = "" +): InputData \ No newline at end of file diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt new file mode 100644 index 0000000000..3a340aa05d --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 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 2/11/2021. + */ + +package com.adyen.checkout.bacs + +import com.adyen.checkout.components.base.OutputData +import com.adyen.checkout.components.ui.FieldState + +class BacsDirectDebitOutputData( + val holderNameState: FieldState, + val bankAccountNumberState: FieldState, + val bankLocationIdState: FieldState, + val shopperEmailState: FieldState +): OutputData { + + override fun isValid(): Boolean { + return holderNameState.validation.isValid() && + bankAccountNumberState.validation.isValid() && + bankLocationIdState.validation.isValid() && + shopperEmailState.validation.isValid() + } + +} \ No newline at end of file diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt new file mode 100644 index 0000000000..98325b812b --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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 2/11/2021. + */ + +package com.adyen.checkout.components.model.payments.request + +import android.os.Parcel +import android.os.Parcelable +import com.adyen.checkout.core.model.JsonUtils +import org.json.JSONObject + +class BacsDirectDebitPaymentMethod: PaymentMethodDetails() { + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = Creator(BacsDirectDebitPaymentMethod::class.java) + + @JvmStatic + val SERIALIZER: Serializer = object : Serializer { + + override fun serialize(modelObject: BacsDirectDebitPaymentMethod): JSONObject { + val jsonObject = JSONObject() + //TODO serialize + return jsonObject + } + + override fun deserialize(jsonObject: JSONObject): BacsDirectDebitPaymentMethod { + // TODO deserialize + return BacsDirectDebitPaymentMethod() + } + } + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + JsonUtils.writeToParcel(parcel, SERIALIZER.serialize(this)) + } +} \ No newline at end of file From a0632497f15b53b29bec2a7c5e79e43d7edbfad0 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 5 Nov 2021 14:05:52 +0100 Subject: [PATCH 070/102] BACS: Make ui for input view --- .../checkout/bacs/BacsDirectDebitView.kt | 50 ++++++++++++++++ .../res/layout/bacs_direct_debit_view.xml | 59 +++++++++++++++++++ bacs/src/main/res/values/styles.xml | 33 +++++++++++ 3 files changed, 142 insertions(+) create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt create mode 100644 bacs/src/main/res/layout/bacs_direct_debit_view.xml create mode 100644 bacs/src/main/res/values/styles.xml diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt new file mode 100644 index 0000000000..76969bff99 --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 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 2/11/2021. + */ + +package com.adyen.checkout.bacs + +import android.content.Context +import android.util.AttributeSet +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.Observer +import com.adyen.checkout.components.GenericComponentState +import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPaymentMethod +import com.adyen.checkout.components.ui.view.AdyenLinearLayout + +class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0): + AdyenLinearLayout, BacsDirectDebitComponent>(context, attrs, defStyleAttr), + Observer { + + override fun onComponentAttached() { + TODO("Not yet implemented") + } + + override fun initView() { + TODO("Not yet implemented") + } + + override fun isConfirmationRequired(): Boolean { + TODO("Not yet implemented") + } + + override fun highlightValidationErrors() { + TODO("Not yet implemented") + } + + override fun initLocalizedStrings(localizedContext: Context) { + TODO("Not yet implemented") + } + + override fun observeComponentChanges(lifecycleOwner: LifecycleOwner) { + TODO("Not yet implemented") + } + + override fun onChanged(t: BacsDirectDebitOutputData?) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/bacs/src/main/res/layout/bacs_direct_debit_view.xml b/bacs/src/main/res/layout/bacs_direct_debit_view.xml new file mode 100644 index 0000000000..6c87c98bfe --- /dev/null +++ b/bacs/src/main/res/layout/bacs_direct_debit_view.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bacs/src/main/res/values/styles.xml b/bacs/src/main/res/values/styles.xml new file mode 100644 index 0000000000..b69c12b50c --- /dev/null +++ b/bacs/src/main/res/values/styles.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + \ No newline at end of file From 185b979a1fe3c60c3e1126c825c0af69405cbec5 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:16:58 +0100 Subject: [PATCH 071/102] BACS: Fix typo in BACS payment method name --- .../com/adyen/checkout/components/util/PaymentMethodTypes.java | 1 + 1 file changed, 1 insertion(+) diff --git a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java index 42b1b35134..f95e2bf15f 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java +++ b/components-core/src/main/java/com/adyen/checkout/components/util/PaymentMethodTypes.java @@ -108,6 +108,7 @@ public final class PaymentMethodTypes { MOLPAY_VIETNAM, OPEN_BANKING, SEPA, + BACS, SCHEME, BLIK, WECHAT_PAY_SDK, From a61ad34e3fc63b475f4dcec4da96700a099cfb22 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:17:38 +0100 Subject: [PATCH 072/102] BACS: Add BacsDirectDebitComponent to ComponentParsingProvider --- drop-in/build.gradle | 1 + .../adyen/checkout/dropin/ComponentParsingProvider.kt | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drop-in/build.gradle b/drop-in/build.gradle index 3bd7a8463c..22bb396d5e 100644 --- a/drop-in/build.gradle +++ b/drop-in/build.gradle @@ -68,6 +68,7 @@ dependencies { api project(':openbanking') api project(":redirect") api project(':sepa') + api project(':bacs') api project(':wechatpay') api project(':voucher') diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt index 8d4f26c6cc..b8db55b23d 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt @@ -17,6 +17,9 @@ import com.adyen.checkout.adyen3ds2.Adyen3DS2Configuration import com.adyen.checkout.await.AwaitComponent import com.adyen.checkout.await.AwaitConfiguration import com.adyen.checkout.await.AwaitView +import com.adyen.checkout.bacs.BacsDirectDebitComponent +import com.adyen.checkout.bacs.BacsDirectDebitConfiguration +import com.adyen.checkout.bacs.BacsDirectDebitView import com.adyen.checkout.bcmc.BcmcComponent import com.adyen.checkout.bcmc.BcmcConfiguration import com.adyen.checkout.bcmc.BcmcView @@ -123,6 +126,7 @@ internal fun getDefaultConfigForPaymentMethod( PaymentMethodTypes.MOLPAY_VIETNAM -> MolpayConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.OPEN_BANKING -> OpenBankingConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.SEPA -> SepaConfiguration.Builder(shopperLocale, environment, clientKey) + PaymentMethodTypes.BACS -> BacsDirectDebitConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.SCHEME -> CardConfiguration.Builder(shopperLocale, environment, clientKey) else -> throw CheckoutException("Unable to find component configuration for paymentMethod - $paymentMethod") } @@ -299,7 +303,10 @@ internal fun getComponentFor( val sepaConfiguration: SepaConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.SEPA) SepaComponent.PROVIDER.get(fragment, paymentMethod, sepaConfiguration) } - + PaymentMethodTypes.BACS -> { + val bacsConfiguration: BacsDirectDebitConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.BACS) + BacsDirectDebitComponent.PROVIDER.get(fragment, paymentMethod, bacsConfiguration) + } else -> { throw CheckoutException("Unable to find component for type - ${paymentMethod.type}") } @@ -335,6 +342,7 @@ internal fun getViewFor( PaymentMethodTypes.OPEN_BANKING -> OpenBankingRecyclerView(context) PaymentMethodTypes.SCHEME -> CardView(context) PaymentMethodTypes.SEPA -> SepaView(context) + PaymentMethodTypes.BACS -> BacsDirectDebitView(context) PaymentMethodTypes.BLIK -> BlikView(context) // GooglePay and WeChatPay do not require a View in Drop-in ActionTypes.AWAIT -> AwaitView(context) From 5826e8a82d9ac5c7688332656a654db7ca3b3766 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:18:08 +0100 Subject: [PATCH 073/102] BACS: Implement BacsDirectDebitView --- .../checkout/bacs/BacsDirectDebitComponent.kt | 28 ++- .../bacs/BacsDirectDebitConfiguration.kt | 8 +- .../checkout/bacs/BacsDirectDebitInputData.kt | 4 +- .../bacs/BacsDirectDebitOutputData.kt | 9 +- .../checkout/bacs/BacsDirectDebitView.kt | 165 ++++++++++++++++-- .../res/layout/bacs_direct_debit_view.xml | 4 + 6 files changed, 194 insertions(+), 24 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index 8adf1c0184..d6ede730a8 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -10,9 +10,14 @@ package com.adyen.checkout.bacs import androidx.lifecycle.SavedStateHandle import com.adyen.checkout.components.GenericComponentState +import com.adyen.checkout.components.PaymentComponentProvider import com.adyen.checkout.components.base.BasePaymentComponent +import com.adyen.checkout.components.base.GenericPaymentComponentProvider import com.adyen.checkout.components.base.GenericPaymentMethodDelegate import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPaymentMethod +import com.adyen.checkout.components.model.payments.request.PaymentComponentData +import com.adyen.checkout.components.ui.FieldState +import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.util.PaymentMethodTypes private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.BACS) @@ -28,10 +33,27 @@ class BacsDirectDebitComponent( override fun getSupportedPaymentMethodTypes() = PAYMENT_METHOD_TYPES override fun onInputDataChanged(inputData: BacsDirectDebitInputData): BacsDirectDebitOutputData { - TODO("Not yet implemented") + // TODO + return BacsDirectDebitOutputData( + FieldState("", Validation.Valid), + FieldState("", Validation.Valid), + FieldState("", Validation.Valid), + FieldState("", Validation.Valid) + ) } override fun createComponentState(): GenericComponentState { - TODO("Not yet implemented") + // TODO + return GenericComponentState( + PaymentComponentData(), + true, + true + ) } -} \ No newline at end of file + + companion object { + @JvmStatic + val PROVIDER: PaymentComponentProvider = + GenericPaymentComponentProvider(BacsDirectDebitComponent::class.java) + } +} diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt index 7bc08c76dc..9b7af30db9 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt @@ -16,7 +16,7 @@ import com.adyen.checkout.components.base.Configuration import com.adyen.checkout.core.api.Environment import java.util.* -class BacsDirectDebitConfiguration: Configuration { +class BacsDirectDebitConfiguration : Configuration { companion object { @JvmField @@ -35,9 +35,9 @@ class BacsDirectDebitConfiguration: Configuration { internal constructor(builder: Builder) : super(builder.builderShopperLocale, builder.builderEnvironment, builder.builderClientKey) internal constructor(parcel: Parcel) : super(parcel) - class Builder: BaseConfigurationBuilder { + class Builder : BaseConfigurationBuilder { - constructor(context: Context, clientKey: String): super(context, clientKey) + constructor(context: Context, clientKey: String) : super(context, clientKey) /** * Builder with required parameters. @@ -60,4 +60,4 @@ class BacsDirectDebitConfiguration: Configuration { return BacsDirectDebitConfiguration(this) } } -} \ No newline at end of file +} diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt index 146a40fd9a..e2fe469b7e 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt @@ -13,6 +13,6 @@ import com.adyen.checkout.components.base.InputData data class BacsDirectDebitInputData( var holderName: String = "", var bankAccountNumber: String = "", - var bankLocationId: String = "", + var sortCode: String = "", var shopperEmail: String = "" -): InputData \ No newline at end of file +) : InputData diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt index 3a340aa05d..f1a2243b3c 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt @@ -14,15 +14,14 @@ import com.adyen.checkout.components.ui.FieldState class BacsDirectDebitOutputData( val holderNameState: FieldState, val bankAccountNumberState: FieldState, - val bankLocationIdState: FieldState, + val sortCodeState: FieldState, val shopperEmailState: FieldState -): OutputData { +) : OutputData { override fun isValid(): Boolean { return holderNameState.validation.isValid() && bankAccountNumberState.validation.isValid() && - bankLocationIdState.validation.isValid() && + sortCodeState.validation.isValid() && shopperEmailState.validation.isValid() } - -} \ No newline at end of file +} diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt index 76969bff99..a38ddc7f21 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt @@ -10,41 +10,186 @@ package com.adyen.checkout.bacs import android.content.Context import android.util.AttributeSet +import android.view.LayoutInflater import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer +import com.adyen.checkout.bacs.databinding.BacsDirectDebitViewBinding import com.adyen.checkout.components.GenericComponentState import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPaymentMethod +import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.ui.view.AdyenLinearLayout +import com.adyen.checkout.components.ui.view.AdyenTextInputEditText -class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0): - AdyenLinearLayout, BacsDirectDebitComponent>(context, attrs, defStyleAttr), +@Suppress("TooManyFunctions") +class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + AdyenLinearLayout, + BacsDirectDebitComponent>(context, attrs, defStyleAttr), Observer { + private val binding: BacsDirectDebitViewBinding = BacsDirectDebitViewBinding.inflate(LayoutInflater.from(context), this) + + private val mBacsDirectDebitInputData = BacsDirectDebitInputData() + + init { + orientation = VERTICAL + val padding = resources.getDimension(R.dimen.standard_margin).toInt() + setPadding(padding, padding, padding, 0) + } + override fun onComponentAttached() { - TODO("Not yet implemented") + // no ops } override fun initView() { - TODO("Not yet implemented") + initHolderNameInput() + initBankAccountNumberInput() + initSortCodeInput() + initShopperEmailInput() } override fun isConfirmationRequired(): Boolean { - TODO("Not yet implemented") + return true } override fun highlightValidationErrors() { - TODO("Not yet implemented") + component.outputData?.let { + var isErrorFocused = false + val holderNameValidation = it.holderNameState.validation + if (holderNameValidation is Validation.Invalid) { + isErrorFocused = true + binding.editTextHolderName.requestFocus() + binding.textInputLayoutHolderName.error = mLocalizedContext.getString(holderNameValidation.reason) + } + val bankAccountNumberValidation = it.bankAccountNumberState.validation + if (bankAccountNumberValidation is Validation.Invalid) { + if (!isErrorFocused) { + isErrorFocused = true + binding.editTextBankAccountNumber.requestFocus() + } + binding.textInputLayoutBankAccountNumber.error = mLocalizedContext.getString(bankAccountNumberValidation.reason) + } + val sortCodeValidation = it.sortCodeState.validation + if (sortCodeValidation is Validation.Invalid) { + if (!isErrorFocused) { + isErrorFocused = true + binding.editTextSortCode.requestFocus() + } + binding.textInputLayoutSortCode.error = mLocalizedContext.getString(sortCodeValidation.reason) + } + val shopperEmailValidation = it.shopperEmailState.validation + if (shopperEmailValidation is Validation.Invalid) { + if (!isErrorFocused) { + isErrorFocused = true + binding.editTextShopperEmail.requestFocus() + } + binding.textInputLayoutShopperEmail.error = mLocalizedContext.getString(shopperEmailValidation.reason) + } + } } override fun initLocalizedStrings(localizedContext: Context) { - TODO("Not yet implemented") + val attrs = intArrayOf(android.R.attr.hint) + + // Holder Name + var typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_HolderNameInput, attrs) + binding.textInputLayoutHolderName.hint = typedArray.getString(0) + typedArray.recycle() + + // Account Number + typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_AccountNumberInput, attrs) + binding.textInputLayoutBankAccountNumber.hint = typedArray.getString(0) + typedArray.recycle() + + // Sort Code + typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_SortCodeInput, attrs) + binding.textInputLayoutSortCode.hint = typedArray.getString(0) + typedArray.recycle() + + // Shopper Email + typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_ShopperEmailInput, attrs) + binding.textInputLayoutShopperEmail.hint = typedArray.getString(0) + typedArray.recycle() } override fun observeComponentChanges(lifecycleOwner: LifecycleOwner) { - TODO("Not yet implemented") + component.observeOutputData(lifecycleOwner, this) } override fun onChanged(t: BacsDirectDebitOutputData?) { - TODO("Not yet implemented") + // + } + + private fun notifyInputDataChanged() { + component.inputDataChanged(mBacsDirectDebitInputData) + } + + private fun initHolderNameInput() { + val holderNameEditText = binding.editTextHolderName as? AdyenTextInputEditText + holderNameEditText?.setOnChangeListener { + mBacsDirectDebitInputData.holderName = it.toString() + notifyInputDataChanged() + binding.textInputLayoutHolderName.error = null + } + holderNameEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> + val holderNameValidation = component.outputData?.holderNameState?.validation + if (hasFocus) { + binding.textInputLayoutHolderName.error = null + } else if (holderNameValidation != null && holderNameValidation is Validation.Invalid) { + binding.textInputLayoutHolderName.error = mLocalizedContext.getString(holderNameValidation.reason) + } + } + } + + private fun initBankAccountNumberInput() { + val bankAccountNumberEditText = binding.editTextBankAccountNumber as? AdyenTextInputEditText + bankAccountNumberEditText?.setOnChangeListener { + mBacsDirectDebitInputData.bankAccountNumber = it.toString() + notifyInputDataChanged() + binding.textInputLayoutBankAccountNumber.error = null + } + bankAccountNumberEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> + val bankAccountNumberValidation = component.outputData?.bankAccountNumberState?.validation + if (hasFocus) { + binding.textInputLayoutBankAccountNumber.error = null + } else if (bankAccountNumberValidation != null && bankAccountNumberValidation is Validation.Invalid) { + binding.editTextBankAccountNumber.error = mLocalizedContext.getString(bankAccountNumberValidation.reason) + } + } + } + + private fun initSortCodeInput() { + val sortCodeEditText = binding.editTextSortCode as? AdyenTextInputEditText + sortCodeEditText?.setOnChangeListener { + mBacsDirectDebitInputData.sortCode = it.toString() + notifyInputDataChanged() + binding.textInputLayoutSortCode.error = null + } + sortCodeEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> + val sortCodeValidation = component.outputData?.sortCodeState?.validation + if (hasFocus) { + binding.textInputLayoutSortCode.error = null + } else if (sortCodeValidation != null && sortCodeValidation is Validation.Invalid) { + binding.textInputLayoutSortCode.error = mLocalizedContext.getString(sortCodeValidation.reason) + } + } + } + + private fun initShopperEmailInput() { + val shopperEmailEditText = binding.editTextShopperEmail as? AdyenTextInputEditText + shopperEmailEditText?.setOnChangeListener { + mBacsDirectDebitInputData.shopperEmail = it.toString() + notifyInputDataChanged() + binding.textInputLayoutShopperEmail.error = null + } + shopperEmailEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> + val shopperEmailValidation = component.outputData?.shopperEmailState?.validation + if (hasFocus) { + binding.textInputLayoutShopperEmail.error = null + } else if (shopperEmailValidation != null && shopperEmailValidation is Validation.Invalid) { + binding.textInputLayoutShopperEmail.error = mLocalizedContext.getString(shopperEmailValidation.reason) + } + } } -} \ No newline at end of file +} diff --git a/bacs/src/main/res/layout/bacs_direct_debit_view.xml b/bacs/src/main/res/layout/bacs_direct_debit_view.xml index 6c87c98bfe..de207e3475 100644 --- a/bacs/src/main/res/layout/bacs_direct_debit_view.xml +++ b/bacs/src/main/res/layout/bacs_direct_debit_view.xml @@ -20,6 +20,7 @@ android:layout_height="wrap_content"> @@ -31,6 +32,7 @@ android:layout_height="wrap_content"> @@ -42,6 +44,7 @@ android:layout_height="wrap_content"> @@ -53,6 +56,7 @@ android:layout_height="wrap_content"> From a88209babeedab8f978e429a02a5f7fe45794869 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 11 Nov 2021 11:32:24 +0100 Subject: [PATCH 074/102] BACS: Add translations --- .../main/res/template/values/strings.xml.tt | 19 +++++++++++++++++++ bacs/src/main/res/values-cs-rCZ/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-da-rDK/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-de-rDE/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-el-rGR/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-es-rES/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-fi-rFI/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-fr-rFR/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-hr-rHR/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-hu-rHU/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-it-rIT/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-ja-rJP/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-ko-rKR/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-nb-rNO/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-nl-rNL/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-pl-rPL/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-pt-rBR/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-ro-rRO/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-ru-rRU/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-sk-rSK/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-sl-rSI/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-sv-rSE/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-zh-rCN/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values-zh-rTW/strings.xml | 19 +++++++++++++++++++ bacs/src/main/res/values/strings.xml | 19 +++++++++++++++++++ 25 files changed, 475 insertions(+) create mode 100644 bacs/src/main/res/template/values/strings.xml.tt create mode 100644 bacs/src/main/res/values-cs-rCZ/strings.xml create mode 100644 bacs/src/main/res/values-da-rDK/strings.xml create mode 100644 bacs/src/main/res/values-de-rDE/strings.xml create mode 100644 bacs/src/main/res/values-el-rGR/strings.xml create mode 100644 bacs/src/main/res/values-es-rES/strings.xml create mode 100644 bacs/src/main/res/values-fi-rFI/strings.xml create mode 100644 bacs/src/main/res/values-fr-rFR/strings.xml create mode 100644 bacs/src/main/res/values-hr-rHR/strings.xml create mode 100644 bacs/src/main/res/values-hu-rHU/strings.xml create mode 100644 bacs/src/main/res/values-it-rIT/strings.xml create mode 100644 bacs/src/main/res/values-ja-rJP/strings.xml create mode 100644 bacs/src/main/res/values-ko-rKR/strings.xml create mode 100644 bacs/src/main/res/values-nb-rNO/strings.xml create mode 100644 bacs/src/main/res/values-nl-rNL/strings.xml create mode 100644 bacs/src/main/res/values-pl-rPL/strings.xml create mode 100644 bacs/src/main/res/values-pt-rBR/strings.xml create mode 100644 bacs/src/main/res/values-ro-rRO/strings.xml create mode 100644 bacs/src/main/res/values-ru-rRU/strings.xml create mode 100644 bacs/src/main/res/values-sk-rSK/strings.xml create mode 100644 bacs/src/main/res/values-sl-rSI/strings.xml create mode 100644 bacs/src/main/res/values-sv-rSE/strings.xml create mode 100644 bacs/src/main/res/values-zh-rCN/strings.xml create mode 100644 bacs/src/main/res/values-zh-rTW/strings.xml create mode 100644 bacs/src/main/res/values/strings.xml diff --git a/bacs/src/main/res/template/values/strings.xml.tt b/bacs/src/main/res/template/values/strings.xml.tt new file mode 100644 index 0000000000..5a754a66bb --- /dev/null +++ b/bacs/src/main/res/template/values/strings.xml.tt @@ -0,0 +1,19 @@ + + + + %%bacs.accountHolderName%% + %%bacs.accountNumber%% + %%bacs.bankLocationId%% + %%shopperEmail%% + + %%bacs.accountHolderName.invalid%% + %%bacs.accountNumber.invalid%% + %%bacs.bankLocationId.invalid%% + %%shopperEmail.invalid%% + \ No newline at end of file diff --git a/bacs/src/main/res/values-cs-rCZ/strings.xml b/bacs/src/main/res/values-cs-rCZ/strings.xml new file mode 100644 index 0000000000..b88a035d1d --- /dev/null +++ b/bacs/src/main/res/values-cs-rCZ/strings.xml @@ -0,0 +1,19 @@ + + + + Jméno držitele bankovního účtu + Číslo bankovního účtu + Kód Sort + E-mailová adresa + + Neplatné jméno držitele bankovního účtu + Neplatné číslo bankovního účtu + Neplatný kód Sort + Neplatná e-mailová adresa + \ No newline at end of file diff --git a/bacs/src/main/res/values-da-rDK/strings.xml b/bacs/src/main/res/values-da-rDK/strings.xml new file mode 100644 index 0000000000..811ccd3116 --- /dev/null +++ b/bacs/src/main/res/values-da-rDK/strings.xml @@ -0,0 +1,19 @@ + + + + Bankkontohavers navn + Bankkontonummer + Registreringsnummer + E-mailadresse + + Ugyldigt navn på bankkontohaver + Ugyldigt bankkontonummer + Ugyldigt registreringsnummer + Ugyldig e-mailadresse + \ No newline at end of file diff --git a/bacs/src/main/res/values-de-rDE/strings.xml b/bacs/src/main/res/values-de-rDE/strings.xml new file mode 100644 index 0000000000..1a2fb5e667 --- /dev/null +++ b/bacs/src/main/res/values-de-rDE/strings.xml @@ -0,0 +1,19 @@ + + + + Name des Bankkontoinhabers + Bankkontonummer + Bankleitzahl + E-Mail-Adresse + + Ungültiger Bankkontoinhabername + Ungültige Bankkontonummer + Ungültige Bankleitzahl + Ungültige E-Mail-Adresse + \ No newline at end of file diff --git a/bacs/src/main/res/values-el-rGR/strings.xml b/bacs/src/main/res/values-el-rGR/strings.xml new file mode 100644 index 0000000000..955e3f60eb --- /dev/null +++ b/bacs/src/main/res/values-el-rGR/strings.xml @@ -0,0 +1,19 @@ + + + + Όνομα δικαιούχου τραπεζικού λογαριασμού + Αριθμός τραπεζικού λογαριασμού + Κωδικός τράπεζας + Διεύθυνση email + + Μη έγκυρο όνομα δικαιούχου τραπεζικού λογαριασμού + Μη έγκυρος αριθμός τραπεζικού λογαριασμού + Μη έγκυρος κωδικός τράπεζας + Μη έγκυρη διεύθυνση email + \ No newline at end of file diff --git a/bacs/src/main/res/values-es-rES/strings.xml b/bacs/src/main/res/values-es-rES/strings.xml new file mode 100644 index 0000000000..a69370ca42 --- /dev/null +++ b/bacs/src/main/res/values-es-rES/strings.xml @@ -0,0 +1,19 @@ + + + + Nombre del titular de la cuenta bancaria + Número de cuenta bancaria + Código de sucursal + Dirección de correo electrónico + + El nombre del titular de la cuenta bancaria no es válido + El número de cuenta bancaria no es válido + El código de sucursal no es válido + La dirección de correo electrónico no es válida + \ No newline at end of file diff --git a/bacs/src/main/res/values-fi-rFI/strings.xml b/bacs/src/main/res/values-fi-rFI/strings.xml new file mode 100644 index 0000000000..6c634f446c --- /dev/null +++ b/bacs/src/main/res/values-fi-rFI/strings.xml @@ -0,0 +1,19 @@ + + + + Tilinhaltijan nimi + Pankkitilinumero + Lajittelukoodi + Sähköpostiosoite + + Ei-kelvollinen tilinhaltijan nimi + Väärä tilin numero + Ei-kelvollinen lajittelukoodi + Ei-kelvollinen sähköpostiosoite + \ No newline at end of file diff --git a/bacs/src/main/res/values-fr-rFR/strings.xml b/bacs/src/main/res/values-fr-rFR/strings.xml new file mode 100644 index 0000000000..4d2aa26a72 --- /dev/null +++ b/bacs/src/main/res/values-fr-rFR/strings.xml @@ -0,0 +1,19 @@ + + + + Nom du titulaire du compte bancaire + Numéro du compte bancaire + Code de tri (sort code) + Adresse e-mail + + Nom du titulaire du compte bancaire incorrect + Numéro du compte bancaire incorrect + Code de tri (sort code) non valide + Adresse e-mail incorrecte + \ No newline at end of file diff --git a/bacs/src/main/res/values-hr-rHR/strings.xml b/bacs/src/main/res/values-hr-rHR/strings.xml new file mode 100644 index 0000000000..6feae9af26 --- /dev/null +++ b/bacs/src/main/res/values-hr-rHR/strings.xml @@ -0,0 +1,19 @@ + + + + Ime vlasnika bankovnog računa + Broj bankovnog računa + Identifikacijski kôd banke (UK) + Adresa e-pošte + + Nevažeće ime vlasnika bankovnog računa + Nevažeći broj bankovnog računa + Nevažeći identifikacijski kôd banke (UK) + Nevažeća adresa e-pošte + \ No newline at end of file diff --git a/bacs/src/main/res/values-hu-rHU/strings.xml b/bacs/src/main/res/values-hu-rHU/strings.xml new file mode 100644 index 0000000000..b122e11217 --- /dev/null +++ b/bacs/src/main/res/values-hu-rHU/strings.xml @@ -0,0 +1,19 @@ + + + + Bankszámla-tulajdonos neve + Bankszámlaszám + Banki azonosító + E-mail-cím + + A bankszámla-tulajdonos neve érvénytelen + Érvénytelen bankszámlaszám + Érvénytelen banki azonosító + Érvénytelen e-mail-cím + \ No newline at end of file diff --git a/bacs/src/main/res/values-it-rIT/strings.xml b/bacs/src/main/res/values-it-rIT/strings.xml new file mode 100644 index 0000000000..8a694dfbb6 --- /dev/null +++ b/bacs/src/main/res/values-it-rIT/strings.xml @@ -0,0 +1,19 @@ + + + + Nome del titolare del conto bancario + Numero di conto bancario + Sort code + Indirizzo e-mail + + Nome del titolare del conto bancario non valido + Numero di conto bancario non valido + Sort code non valido + Indirizzo e-mail non valido + \ No newline at end of file diff --git a/bacs/src/main/res/values-ja-rJP/strings.xml b/bacs/src/main/res/values-ja-rJP/strings.xml new file mode 100644 index 0000000000..33dc2c52e8 --- /dev/null +++ b/bacs/src/main/res/values-ja-rJP/strings.xml @@ -0,0 +1,19 @@ + + + + 銀行口座名義 + 銀行口座番号 + ソートコード + Eメールアドレス + + 銀行口座名義が無効です + 銀行口座番号が無効です + ソートコードが無効です + Eメールアドレスが無効です + \ No newline at end of file diff --git a/bacs/src/main/res/values-ko-rKR/strings.xml b/bacs/src/main/res/values-ko-rKR/strings.xml new file mode 100644 index 0000000000..4eeee827b7 --- /dev/null +++ b/bacs/src/main/res/values-ko-rKR/strings.xml @@ -0,0 +1,19 @@ + + + + 예금주 이름 + 계좌 번호 + 은행 식별 코드 + 이메일 주소 + + 예금주 이름이 유효하지 않습니다 + 계좌 번호가 유효하지 않습니다 + 은행 식별 코드가 유효하지 않습니다 + 유효하지 않은 이메일 주소 + \ No newline at end of file diff --git a/bacs/src/main/res/values-nb-rNO/strings.xml b/bacs/src/main/res/values-nb-rNO/strings.xml new file mode 100644 index 0000000000..6c712aa7ce --- /dev/null +++ b/bacs/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,19 @@ + + + + Kontoholders navn + Bankkontonummer + Sorteringskode + E-postadresse + + Ugyldig kontoholdernavn + Ugyldig bankkontonummer + Ugyldig sorteringskode + Ugyldig e-postadresse + \ No newline at end of file diff --git a/bacs/src/main/res/values-nl-rNL/strings.xml b/bacs/src/main/res/values-nl-rNL/strings.xml new file mode 100644 index 0000000000..24290d0f13 --- /dev/null +++ b/bacs/src/main/res/values-nl-rNL/strings.xml @@ -0,0 +1,19 @@ + + + + Naam bankrekeninghouder + Bankrekeningnummer + Bankcode + E-mailadres + + Ongeldige naam bankrekeninghouder + Ongeldig bankrekeningnummer + Ongeldige bankcode + Ongeldig e-mailadres + \ No newline at end of file diff --git a/bacs/src/main/res/values-pl-rPL/strings.xml b/bacs/src/main/res/values-pl-rPL/strings.xml new file mode 100644 index 0000000000..f6dbadaf1a --- /dev/null +++ b/bacs/src/main/res/values-pl-rPL/strings.xml @@ -0,0 +1,19 @@ + + + + Imię i nazwisko posiadacza rachunku + Numer rachunku + Numer rozliczeniowy SORT + Adres e-mail + + Nieprawidłowe imię i nazwisko posiadacza rachunku + Nieprawidłowy numer rachunku + Nieprawidłowy numer rozliczeniowy SORT + Niepoprawny adres email + \ No newline at end of file diff --git a/bacs/src/main/res/values-pt-rBR/strings.xml b/bacs/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000..949aeb218d --- /dev/null +++ b/bacs/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,19 @@ + + + + Nome do titular da conta bancária + Número da conta bancária + Código de classificação + Endereço de e-mail + + Nome do titular da conta bancária inválido + Número da conta bancária inválido + Código de classificação inválido + Endereço de e-mail inválido + \ No newline at end of file diff --git a/bacs/src/main/res/values-ro-rRO/strings.xml b/bacs/src/main/res/values-ro-rRO/strings.xml new file mode 100644 index 0000000000..274abb6212 --- /dev/null +++ b/bacs/src/main/res/values-ro-rRO/strings.xml @@ -0,0 +1,19 @@ + + + + Numele titularului contului bancar + Numărul contului bancar + Cod de identificare bancară + Adresă de e-mail + + Numele titularului contului bancar este incorect + Numărul contului bancar este incorect + Cod de identificare bancară incorect + Adresă de e-mail incorectă + \ No newline at end of file diff --git a/bacs/src/main/res/values-ru-rRU/strings.xml b/bacs/src/main/res/values-ru-rRU/strings.xml new file mode 100644 index 0000000000..5a7b32765c --- /dev/null +++ b/bacs/src/main/res/values-ru-rRU/strings.xml @@ -0,0 +1,19 @@ + + + + Имя владельца банковского счета + Номер банковского счета + Код банка + Адрес эл. почты + + Неверное имя владельца банковского счета + Неверный номер банковского счета + Неверный код банка + Недействительный адрес эл. почты + \ No newline at end of file diff --git a/bacs/src/main/res/values-sk-rSK/strings.xml b/bacs/src/main/res/values-sk-rSK/strings.xml new file mode 100644 index 0000000000..031a0a0379 --- /dev/null +++ b/bacs/src/main/res/values-sk-rSK/strings.xml @@ -0,0 +1,19 @@ + + + + Meno majiteľa bankového účtu + Číslo bankového účtu + Variabilný symbol + E-mailová adresa + + Neplatné meno majiteľa bankového účtu + Neplatné číslo bankového účtu + Neplatný variabilný symbol + Neplatná emailová adresa + \ No newline at end of file diff --git a/bacs/src/main/res/values-sl-rSI/strings.xml b/bacs/src/main/res/values-sl-rSI/strings.xml new file mode 100644 index 0000000000..88d45daea1 --- /dev/null +++ b/bacs/src/main/res/values-sl-rSI/strings.xml @@ -0,0 +1,19 @@ + + + + Ime imetnika bančnega računa + Številka bančnega računa + Številka banke + Elektronski naslov + + Neveljavno ime imetnika računa + Neveljavna številka bančnega računa + Neveljavna številka banke + Neveljaven elektronski naslov + \ No newline at end of file diff --git a/bacs/src/main/res/values-sv-rSE/strings.xml b/bacs/src/main/res/values-sv-rSE/strings.xml new file mode 100644 index 0000000000..bfc3334350 --- /dev/null +++ b/bacs/src/main/res/values-sv-rSE/strings.xml @@ -0,0 +1,19 @@ + + + + Bankkontoinnehavarens namn + Bankkontonummer + Clearingnummer + E-postadress + + Ogiltigt namn på bankkontoinnehavare + Ogiltigt bankkontonummer + Ogiltigt clearingnummer + Ogiltig e-postadress + \ No newline at end of file diff --git a/bacs/src/main/res/values-zh-rCN/strings.xml b/bacs/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..efabf10344 --- /dev/null +++ b/bacs/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,19 @@ + + + + 银行账户持有人姓名 + 银行账号 + 分类代码 + 电子邮件地址 + + 无效的银行账户持有人姓名 + 无效的银行账号 + 无效的分类代码 + 无效的邮件地址 + \ No newline at end of file diff --git a/bacs/src/main/res/values-zh-rTW/strings.xml b/bacs/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..e2ae31aaf2 --- /dev/null +++ b/bacs/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,19 @@ + + + + 銀行帳戶持有人姓名 + 銀行帳戶號碼 + 銀行代碼 + 電子郵件地址 + + 銀行帳戶持有人姓名無效 + 銀行帳戶號碼無效 + 銀行代碼無效 + 電子郵件地址無效 + \ No newline at end of file diff --git a/bacs/src/main/res/values/strings.xml b/bacs/src/main/res/values/strings.xml new file mode 100644 index 0000000000..e4c27ae35d --- /dev/null +++ b/bacs/src/main/res/values/strings.xml @@ -0,0 +1,19 @@ + + + + Bank account holder name + Bank account number + Sort code + Email address + + Invalid bank account holder name + Invalid bank account number + Invalid sort code + Invalid email address + \ No newline at end of file From 5145346abc3e892106d2c68431f31ffe15a88e5b Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 11 Nov 2021 11:35:22 +0100 Subject: [PATCH 075/102] BACS: Add BacsDirectDebitValidationUtils --- .../bacs/BacsDirectDebitValidationUtils.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt new file mode 100644 index 0000000000..05c37f868d --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 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 9/11/2021. + */ + +package com.adyen.checkout.bacs + +import com.adyen.checkout.components.ui.FieldState +import com.adyen.checkout.components.ui.Validation + +object BacsDirectDebitValidationUtils { + + fun validateHolderName(holderName: String): FieldState { + return if (holderName.isBlank()) { + FieldState(holderName, Validation.Invalid(0)) + } else { + FieldState(holderName, Validation.Valid) + } + } + + fun validateBankAccountNumber(bankAccountNumber: String): FieldState { + + } + + fun validateSortCode(sortCode: String): FieldState { + + } + + fun validateShopperEmail(shopperEmail: String): FieldState { + + } +} \ No newline at end of file From 3aa42cd250a6e42c86be727e32a403a00f577bae Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 11 Nov 2021 14:05:18 +0100 Subject: [PATCH 076/102] BACS: Add validation for input fields --- .../checkout/bacs/BacsDirectDebitComponent.kt | 10 ++++---- .../bacs/BacsDirectDebitValidationUtils.kt | 24 +++++++++++++++---- .../checkout/bacs/BacsDirectDebitView.kt | 13 ++++++---- bacs/src/main/res/values/styles.xml | 12 +++++----- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index d6ede730a8..09a4906d9a 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -19,6 +19,7 @@ import com.adyen.checkout.components.model.payments.request.PaymentComponentData import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.util.PaymentMethodTypes +import com.adyen.checkout.components.util.ValidationUtils private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.BACS) @@ -33,12 +34,11 @@ class BacsDirectDebitComponent( override fun getSupportedPaymentMethodTypes() = PAYMENT_METHOD_TYPES override fun onInputDataChanged(inputData: BacsDirectDebitInputData): BacsDirectDebitOutputData { - // TODO return BacsDirectDebitOutputData( - FieldState("", Validation.Valid), - FieldState("", Validation.Valid), - FieldState("", Validation.Valid), - FieldState("", Validation.Valid) + BacsDirectDebitValidationUtils.validateHolderName(inputData.holderName), + BacsDirectDebitValidationUtils.validateBankAccountNumber(inputData.bankAccountNumber), + BacsDirectDebitValidationUtils.validateSortCode(inputData.sortCode), + BacsDirectDebitValidationUtils.validateShopperEmail(inputData.shopperEmail) ) } diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt index 05c37f868d..610a47bc6f 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt @@ -10,26 +10,42 @@ package com.adyen.checkout.bacs import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.ui.Validation +import com.adyen.checkout.components.util.ValidationUtils + +private const val BANK_ACCOUNT_NUMBER_LENGTH = 8 +private const val SORT_CODE_LENGTH = 6 object BacsDirectDebitValidationUtils { fun validateHolderName(holderName: String): FieldState { return if (holderName.isBlank()) { - FieldState(holderName, Validation.Invalid(0)) + FieldState(holderName, Validation.Invalid(R.string.bacs_holder_name_invalid)) } else { FieldState(holderName, Validation.Valid) } } fun validateBankAccountNumber(bankAccountNumber: String): FieldState { - + return if (bankAccountNumber.length == BANK_ACCOUNT_NUMBER_LENGTH) { + FieldState(bankAccountNumber, Validation.Valid) + } else { + FieldState(bankAccountNumber, Validation.Invalid(R.string.bacs_account_number_invalid)) + } } fun validateSortCode(sortCode: String): FieldState { - + return if (sortCode.length == SORT_CODE_LENGTH) { + FieldState(sortCode, Validation.Valid) + } else { + FieldState(sortCode, Validation.Invalid(R.string.bacs_sort_code_invalid)) + } } fun validateShopperEmail(shopperEmail: String): FieldState { - + return if (ValidationUtils.isEmailValid(shopperEmail)) { + FieldState(shopperEmail, Validation.Valid) + } else { + FieldState(shopperEmail, Validation.Invalid(R.string.bacs_shopper_email_invalid)) + } } } \ No newline at end of file diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt index a38ddc7f21..a35a085856 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt @@ -19,6 +19,10 @@ import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPayme import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.components.ui.view.AdyenTextInputEditText +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger + +private val TAG = LogUtil.getTag() @Suppress("TooManyFunctions") class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : @@ -26,7 +30,7 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att BacsDirectDebitConfiguration, GenericComponentState, BacsDirectDebitComponent>(context, attrs, defStyleAttr), - Observer { + Observer { private val binding: BacsDirectDebitViewBinding = BacsDirectDebitViewBinding.inflate(LayoutInflater.from(context), this) @@ -117,8 +121,8 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att component.observeOutputData(lifecycleOwner, this) } - override fun onChanged(t: BacsDirectDebitOutputData?) { - // + override fun onChanged(bacsDirectDebitOutputData: BacsDirectDebitOutputData) { + Logger.v(TAG, "bacsDirectDebitOutputData changed") } private fun notifyInputDataChanged() { @@ -134,6 +138,7 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att } holderNameEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> val holderNameValidation = component.outputData?.holderNameState?.validation + Logger.d(TAG, "outputData ${component.outputData.toString()}") if (hasFocus) { binding.textInputLayoutHolderName.error = null } else if (holderNameValidation != null && holderNameValidation is Validation.Invalid) { @@ -154,7 +159,7 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att if (hasFocus) { binding.textInputLayoutBankAccountNumber.error = null } else if (bankAccountNumberValidation != null && bankAccountNumberValidation is Validation.Invalid) { - binding.editTextBankAccountNumber.error = mLocalizedContext.getString(bankAccountNumberValidation.reason) + binding.textInputLayoutBankAccountNumber.error = mLocalizedContext.getString(bankAccountNumberValidation.reason) } } } diff --git a/bacs/src/main/res/values/styles.xml b/bacs/src/main/res/values/styles.xml index b69c12b50c..7a91bb50a1 100644 --- a/bacs/src/main/res/values/styles.xml +++ b/bacs/src/main/res/values/styles.xml @@ -9,25 +9,25 @@ \ No newline at end of file From 95f6cffc12d7507e68a7bdc6f72c46fff7f7b08e Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:50:53 +0100 Subject: [PATCH 077/102] BACS: Implement BacsDirectDebitPaymentMethod --- .../checkout/bacs/BacsDirectDebitComponent.kt | 21 +++++++--- .../request/BacsDirectDebitPaymentMethod.kt | 39 +++++++++++++++---- .../payments/request/CardPaymentMethod.java | 2 +- .../request/PaymentMethodDetails.java | 2 + 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index 09a4906d9a..0339b9ce16 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -16,10 +16,7 @@ import com.adyen.checkout.components.base.GenericPaymentComponentProvider import com.adyen.checkout.components.base.GenericPaymentMethodDelegate import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPaymentMethod import com.adyen.checkout.components.model.payments.request.PaymentComponentData -import com.adyen.checkout.components.ui.FieldState -import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.util.PaymentMethodTypes -import com.adyen.checkout.components.util.ValidationUtils private val PAYMENT_METHOD_TYPES = arrayOf(PaymentMethodTypes.BACS) @@ -43,10 +40,22 @@ class BacsDirectDebitComponent( } override fun createComponentState(): GenericComponentState { - // TODO + val paymentComponentData = PaymentComponentData() + val bacsDirectDebitPaymentMethod = BacsDirectDebitPaymentMethod().apply { + type = BacsDirectDebitPaymentMethod.PAYMENT_METHOD_TYPE + holderName = outputData?.holderNameState?.value + bankAccountNumber = outputData?.bankAccountNumberState?.value + bankLocationId = outputData?.sortCodeState?.value + } + + paymentComponentData.apply { + shopperEmail = outputData?.shopperEmailState?.value + paymentMethod = bacsDirectDebitPaymentMethod + } + return GenericComponentState( - PaymentComponentData(), - true, + paymentComponentData, + outputData?.isValid ?: false, true ) } diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt index 98325b812b..b1a68bfd0a 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/BacsDirectDebitPaymentMethod.kt @@ -10,27 +10,46 @@ package com.adyen.checkout.components.model.payments.request import android.os.Parcel import android.os.Parcelable +import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.model.JsonUtils +import org.json.JSONException import org.json.JSONObject -class BacsDirectDebitPaymentMethod: PaymentMethodDetails() { +class BacsDirectDebitPaymentMethod : PaymentMethodDetails() { companion object { + private const val HOLDER_NAME = "holderName" + private const val BANK_ACCOUNT_NUMBER = "bankAccountNumber" + private const val BANK_LOCATION_ID = "bankLocationId" + + const val PAYMENT_METHOD_TYPE = "directdebit_GB" + @JvmField val CREATOR: Parcelable.Creator = Creator(BacsDirectDebitPaymentMethod::class.java) - @JvmStatic + @JvmField val SERIALIZER: Serializer = object : Serializer { override fun serialize(modelObject: BacsDirectDebitPaymentMethod): JSONObject { - val jsonObject = JSONObject() - //TODO serialize - return jsonObject + return try { + JSONObject().apply { + putOpt(TYPE, modelObject.type) + putOpt(HOLDER_NAME, modelObject.holderName) + putOpt(BANK_ACCOUNT_NUMBER, modelObject.bankAccountNumber) + putOpt(BANK_LOCATION_ID, modelObject.bankLocationId) + } + } catch (e: JSONException) { + throw ModelSerializationException(BacsDirectDebitPaymentMethod::class.java, e) + } } override fun deserialize(jsonObject: JSONObject): BacsDirectDebitPaymentMethod { - // TODO deserialize - return BacsDirectDebitPaymentMethod() + return BacsDirectDebitPaymentMethod().apply { + type = jsonObject.optString(TYPE, null) + holderName = jsonObject.optString(HOLDER_NAME, null) + bankAccountNumber = jsonObject.optString(BANK_ACCOUNT_NUMBER, null) + bankLocationId = jsonObject.optString(BANK_LOCATION_ID, null) + } } } } @@ -38,4 +57,8 @@ class BacsDirectDebitPaymentMethod: PaymentMethodDetails() { override fun writeToParcel(parcel: Parcel, flags: Int) { JsonUtils.writeToParcel(parcel, SERIALIZER.serialize(this)) } -} \ No newline at end of file + + var holderName: String? = null + var bankAccountNumber: String? = null + var bankLocationId: String? = null +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/CardPaymentMethod.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/CardPaymentMethod.java index 1d57b7ff7b..ef5703a2e4 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/CardPaymentMethod.java +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/CardPaymentMethod.java @@ -63,7 +63,7 @@ public JSONObject serialize(@NonNull CardPaymentMethod modelObject) { jsonObject.putOpt(THREEDS2_SDK_VERSION, modelObject.getThreeDS2SdkVersion()); jsonObject.putOpt(FUNDING_SOURCE, modelObject.getFundingSource()); } catch (JSONException e) { - throw new ModelSerializationException(IdealPaymentMethod.class, e); + throw new ModelSerializationException(CardPaymentMethod.class, e); } return jsonObject; } diff --git a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java index 8c4aabe21c..fe00ce4016 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java +++ b/components-core/src/main/java/com/adyen/checkout/components/model/payments/request/PaymentMethodDetails.java @@ -93,6 +93,8 @@ static Serializer getChildSerializer(@NonNull St return MBWayPaymentMethod.SERIALIZER; case BlikPaymentMethod.PAYMENT_METHOD_TYPE: return BlikPaymentMethod.SERIALIZER; + case BacsDirectDebitPaymentMethod.PAYMENT_METHOD_TYPE: + return BacsDirectDebitPaymentMethod.SERIALIZER; default: return GenericPaymentMethod.SERIALIZER; } From 4d569d897d63503ff2672c58d09a0379a340a51b Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 11 Nov 2021 16:47:59 +0100 Subject: [PATCH 078/102] BACS: Set next focus input fields for input screen --- bacs/src/main/res/layout/bacs_direct_debit_view.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bacs/src/main/res/layout/bacs_direct_debit_view.xml b/bacs/src/main/res/layout/bacs_direct_debit_view.xml index de207e3475..af46fd6895 100644 --- a/bacs/src/main/res/layout/bacs_direct_debit_view.xml +++ b/bacs/src/main/res/layout/bacs_direct_debit_view.xml @@ -22,6 +22,8 @@ @@ -34,6 +36,8 @@ @@ -46,6 +50,8 @@ From 12eb2a5cc122545645c70bced645c541e1a0a29c Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:38:40 +0100 Subject: [PATCH 079/102] BACS: Add consent switches --- .../adyen/checkout/bacs/BacsDirectDebitComponent.kt | 10 ++++++---- .../adyen/checkout/bacs/BacsDirectDebitInputData.kt | 4 +++- .../checkout/bacs/BacsDirectDebitOutputData.kt | 7 +++++-- .../com/adyen/checkout/bacs/BacsDirectDebitView.kt | 13 +++++++++++++ bacs/src/main/res/layout/bacs_direct_debit_view.xml | 12 ++++++++++++ bacs/src/main/res/values/styles.xml | 10 ++++++++++ .../checkout/components/util/CheckoutCurrency.java | 2 +- 7 files changed, 50 insertions(+), 8 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index 0339b9ce16..7497279e72 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -32,10 +32,12 @@ class BacsDirectDebitComponent( override fun onInputDataChanged(inputData: BacsDirectDebitInputData): BacsDirectDebitOutputData { return BacsDirectDebitOutputData( - BacsDirectDebitValidationUtils.validateHolderName(inputData.holderName), - BacsDirectDebitValidationUtils.validateBankAccountNumber(inputData.bankAccountNumber), - BacsDirectDebitValidationUtils.validateSortCode(inputData.sortCode), - BacsDirectDebitValidationUtils.validateShopperEmail(inputData.shopperEmail) + holderNameState = BacsDirectDebitValidationUtils.validateHolderName(inputData.holderName), + bankAccountNumberState = BacsDirectDebitValidationUtils.validateBankAccountNumber(inputData.bankAccountNumber), + sortCodeState = BacsDirectDebitValidationUtils.validateSortCode(inputData.sortCode), + shopperEmailState = BacsDirectDebitValidationUtils.validateShopperEmail(inputData.shopperEmail), + isAmountConsentChecked = inputData.isAmountConsentChecked, + isAccountConsentChecked = inputData.isAccountConsentChecked ) } diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt index e2fe469b7e..66ee9b058f 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt @@ -14,5 +14,7 @@ data class BacsDirectDebitInputData( var holderName: String = "", var bankAccountNumber: String = "", var sortCode: String = "", - var shopperEmail: String = "" + var shopperEmail: String = "", + var isAmountConsentChecked: Boolean = false, + var isAccountConsentChecked: Boolean = false ) : InputData diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt index f1a2243b3c..ec46a9acd9 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitOutputData.kt @@ -15,13 +15,16 @@ class BacsDirectDebitOutputData( val holderNameState: FieldState, val bankAccountNumberState: FieldState, val sortCodeState: FieldState, - val shopperEmailState: FieldState + val shopperEmailState: FieldState, + val isAmountConsentChecked: Boolean, + val isAccountConsentChecked: Boolean ) : OutputData { override fun isValid(): Boolean { return holderNameState.validation.isValid() && bankAccountNumberState.validation.isValid() && sortCodeState.validation.isValid() && - shopperEmailState.validation.isValid() + shopperEmailState.validation.isValid() && + isAmountConsentChecked && isAccountConsentChecked } } diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt index a35a085856..a151ecc4cd 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt @@ -51,6 +51,7 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att initBankAccountNumberInput() initSortCodeInput() initShopperEmailInput() + initConsentSwitches() } override fun isConfirmationRequired(): Boolean { @@ -197,4 +198,16 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att } } } + + private fun initConsentSwitches() { + binding.switchConsentAmount.setOnCheckedChangeListener { _, isChecked -> + mBacsDirectDebitInputData.isAmountConsentChecked = isChecked + notifyInputDataChanged() + } + + binding.switchConsentAccount.setOnCheckedChangeListener { _, isChecked -> + mBacsDirectDebitInputData.isAccountConsentChecked = isChecked + notifyInputDataChanged() + } + } } diff --git a/bacs/src/main/res/layout/bacs_direct_debit_view.xml b/bacs/src/main/res/layout/bacs_direct_debit_view.xml index af46fd6895..1c5d5b1cc5 100644 --- a/bacs/src/main/res/layout/bacs_direct_debit_view.xml +++ b/bacs/src/main/res/layout/bacs_direct_debit_view.xml @@ -66,4 +66,16 @@ style="@style/AdyenCheckout.Bacs.ShopperEmailInput" tools:ignore="RequiredSize" /> + + + + \ No newline at end of file diff --git a/bacs/src/main/res/values/styles.xml b/bacs/src/main/res/values/styles.xml index 7a91bb50a1..d3f6852e4b 100644 --- a/bacs/src/main/res/values/styles.xml +++ b/bacs/src/main/res/values/styles.xml @@ -30,4 +30,14 @@ @string/bacs_shopper_email_hint textEmailAddress + + + + + + \ No newline at end of file diff --git a/components-core/src/main/java/com/adyen/checkout/components/util/CheckoutCurrency.java b/components-core/src/main/java/com/adyen/checkout/components/util/CheckoutCurrency.java index 07f8440df1..5455f168cf 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/util/CheckoutCurrency.java +++ b/components-core/src/main/java/com/adyen/checkout/components/util/CheckoutCurrency.java @@ -186,7 +186,7 @@ public static boolean isSupported(@Nullable String currency) { * Find the instance of {@link CheckoutCurrency} based on the currency code. * * @param currency The currency code. - * @return The CheckoutCurrency instance, or throws a {@link com.adyen.checkout.core.exeption.CheckoutException} if the code is not supported. + * @return The CheckoutCurrency instance, or throws a {@link com.adyen.checkout.core.exception.CheckoutException} if the code is not supported. */ @NonNull public static CheckoutCurrency find(@Nullable String currency) { From b1e8f4b3f34ecbb330b17eddafe3839b9ed8cedf Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 19 Nov 2021 13:12:10 +0100 Subject: [PATCH 080/102] BACS: Add BacsDirectDebitDialogFragment --- .../dropin/ComponentParsingProvider.kt | 2 - .../checkout/dropin/ui/DropInActivity.kt | 3 + .../BacsDirectDebitDialogFragment.kt | 72 +++++++++++++++++++ .../fragment_bacs_direct_debit_component.xml | 57 +++++++++++++++ 4 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt create mode 100644 drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt index b8db55b23d..8c06d455c6 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt @@ -19,7 +19,6 @@ import com.adyen.checkout.await.AwaitConfiguration import com.adyen.checkout.await.AwaitView import com.adyen.checkout.bacs.BacsDirectDebitComponent import com.adyen.checkout.bacs.BacsDirectDebitConfiguration -import com.adyen.checkout.bacs.BacsDirectDebitView import com.adyen.checkout.bcmc.BcmcComponent import com.adyen.checkout.bcmc.BcmcConfiguration import com.adyen.checkout.bcmc.BcmcView @@ -342,7 +341,6 @@ internal fun getViewFor( PaymentMethodTypes.OPEN_BANKING -> OpenBankingRecyclerView(context) PaymentMethodTypes.SCHEME -> CardView(context) PaymentMethodTypes.SEPA -> SepaView(context) - PaymentMethodTypes.BACS -> BacsDirectDebitView(context) PaymentMethodTypes.BLIK -> BlikView(context) // GooglePay and WeChatPay do not require a View in Drop-in ActionTypes.AWAIT -> AwaitView(context) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index c38f13544e..622a04c004 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -51,6 +51,7 @@ import com.adyen.checkout.dropin.service.DropInServiceResultError import com.adyen.checkout.dropin.service.OrderDropInServiceResult import com.adyen.checkout.dropin.ui.action.ActionComponentDialogFragment import com.adyen.checkout.dropin.ui.base.DropInBottomSheetDialogFragment +import com.adyen.checkout.dropin.ui.component.BacsDirectDebitDialogFragment import com.adyen.checkout.dropin.ui.component.CardComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GenericComponentDialogFragment import com.adyen.checkout.dropin.ui.component.GiftCardComponentDialogFragment @@ -353,6 +354,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot hideAllScreens() val dialogFragment = when (storedPaymentMethod.type) { PaymentMethodTypes.SCHEME -> CardComponentDialogFragment + PaymentMethodTypes.BACS -> BacsDirectDebitDialogFragment else -> GenericComponentDialogFragment }.newInstance(storedPaymentMethod, dropInViewModel.dropInConfiguration, fromPreselected) @@ -364,6 +366,7 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot hideAllScreens() val dialogFragment = when (paymentMethod.type) { PaymentMethodTypes.SCHEME -> CardComponentDialogFragment + PaymentMethodTypes.BACS -> BacsDirectDebitDialogFragment PaymentMethodTypes.GIFTCARD -> GiftCardComponentDialogFragment else -> GenericComponentDialogFragment }.newInstance(paymentMethod, dropInViewModel.dropInConfiguration) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt new file mode 100644 index 0000000000..c657c6056e --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 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/11/2021. + */ + +package com.adyen.checkout.dropin.ui.component + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import com.adyen.checkout.bacs.BacsDirectDebitComponent +import com.adyen.checkout.bacs.BacsDirectDebitView +import com.adyen.checkout.components.PaymentComponentState +import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails +import com.adyen.checkout.core.log.LogUtil +import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.dropin.databinding.FragmentBacsDirectDebitComponentBinding +import com.adyen.checkout.dropin.ui.base.BaseComponentDialogFragment +import com.google.android.material.bottomsheet.BottomSheetBehavior + +class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { + + private lateinit var binding: FragmentBacsDirectDebitComponentBinding + + companion object : BaseCompanion(BacsDirectDebitDialogFragment::class.java) { + private val TAG = LogUtil.getTag() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + binding = FragmentBacsDirectDebitComponentBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Logger.d(TAG, "onViewCreated") + binding.header.text = paymentMethod.name + + val bacsDirectDebitComponent = component as BacsDirectDebitComponent + + component.observe(viewLifecycleOwner, this) + bacsDirectDebitComponent.observeErrors(viewLifecycleOwner, createErrorHandlerObserver()) + + val bacsDirectDebitView = BacsDirectDebitView(requireContext()) + binding.viewContainer.addView(bacsDirectDebitView) + bacsDirectDebitView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + + if (bacsDirectDebitView.isConfirmationRequired) { + binding.payButton.setOnClickListener { componentDialogViewModel.payButtonClicked() } + setInitViewState(BottomSheetBehavior.STATE_EXPANDED) + bacsDirectDebitView.requestFocus() + } else { + binding.payButton.isVisible = false + } + } + + override fun onChanged(paymentComponentState: PaymentComponentState?) { + TODO("Not yet implemented") + } + + override fun setPaymentPendingInitialization(pending: Boolean) { + TODO("Not yet implemented") + } + + override fun highlightValidationErrors() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml new file mode 100644 index 0000000000..8591c67d9d --- /dev/null +++ b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file From 90973aaa9e0f3fe478d5391dbdd35bd379e92748 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 23 Nov 2021 09:57:22 +0100 Subject: [PATCH 081/102] BACS: Add confirmation step --- .../checkout/bacs/BacsDirectDebitComponent.kt | 20 +++-- .../bacs/BacsDirectDebitComponentState.kt | 20 +++++ .../bacs/BacsDirectDebitConfirmationView.kt | 86 +++++++++++++++++++ .../checkout/bacs/BacsDirectDebitInputData.kt | 3 +- .../checkout/bacs/BacsDirectDebitMode.kt | 14 +++ .../bacs/BacsDirectDebitValidationUtils.kt | 2 +- .../checkout/bacs/BacsDirectDebitView.kt | 5 +- .../bacs_direct_debit_confirmation_view.xml | 78 +++++++++++++++++ .../BacsDirectDebitDialogFragment.kt | 52 +++++++++-- 9 files changed, 264 insertions(+), 16 deletions(-) create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt create mode 100644 bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitMode.kt create mode 100644 bacs/src/main/res/layout/bacs_direct_debit_confirmation_view.xml diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index 7497279e72..f281841476 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -9,7 +9,6 @@ package com.adyen.checkout.bacs import androidx.lifecycle.SavedStateHandle -import com.adyen.checkout.components.GenericComponentState import com.adyen.checkout.components.PaymentComponentProvider import com.adyen.checkout.components.base.BasePaymentComponent import com.adyen.checkout.components.base.GenericPaymentComponentProvider @@ -26,7 +25,7 @@ class BacsDirectDebitComponent( configuration: BacsDirectDebitConfiguration ) : BasePaymentComponent>(savedStateHandle, paymentMethodDelegate, configuration) { + BacsDirectDebitComponentState>(savedStateHandle, paymentMethodDelegate, configuration) { override fun getSupportedPaymentMethodTypes() = PAYMENT_METHOD_TYPES @@ -41,7 +40,7 @@ class BacsDirectDebitComponent( ) } - override fun createComponentState(): GenericComponentState { + override fun createComponentState(): BacsDirectDebitComponentState { val paymentComponentData = PaymentComponentData() val bacsDirectDebitPaymentMethod = BacsDirectDebitPaymentMethod().apply { type = BacsDirectDebitPaymentMethod.PAYMENT_METHOD_TYPE @@ -55,13 +54,24 @@ class BacsDirectDebitComponent( paymentMethod = bacsDirectDebitPaymentMethod } - return GenericComponentState( + return BacsDirectDebitComponentState( paymentComponentData, outputData?.isValid ?: false, - true + mLatestInputData?.mode == BacsDirectDebitMode.CONFIRMATION, + mLatestInputData?.mode ?: BacsDirectDebitMode.INPUT ) } + fun handleContinueClick() { + mLatestInputData?.mode = BacsDirectDebitMode.CONFIRMATION + notifyStateChanged() + } + + fun handleBackPress() { + mLatestInputData?.mode = BacsDirectDebitMode.INPUT + notifyStateChanged() + } + companion object { @JvmStatic val PROVIDER: PaymentComponentProvider = diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt new file mode 100644 index 0000000000..d63d88e3ca --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 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/11/2021. + */ + +package com.adyen.checkout.bacs + +import com.adyen.checkout.components.PaymentComponentState +import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPaymentMethod +import com.adyen.checkout.components.model.payments.request.PaymentComponentData + +class BacsDirectDebitComponentState( + paymentComponentData: PaymentComponentData, + isInputValid: Boolean, + isReady: Boolean, + val mode: BacsDirectDebitMode = BacsDirectDebitMode.INPUT +) : PaymentComponentState(paymentComponentData, isInputValid, isReady) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt new file mode 100644 index 0000000000..15368e245e --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 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 18/11/2021. + */ + +package com.adyen.checkout.bacs + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.Observer +import com.adyen.checkout.bacs.databinding.BacsDirectDebitConfirmationViewBinding +import com.adyen.checkout.components.ui.view.AdyenLinearLayout + +class BacsDirectDebitConfirmationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + AdyenLinearLayout(context, attrs, defStyleAttr), + Observer { + + private val binding: BacsDirectDebitConfirmationViewBinding = BacsDirectDebitConfirmationViewBinding.inflate(LayoutInflater.from(context), this) + + init { + orientation = VERTICAL + val padding = resources.getDimension(R.dimen.standard_margin).toInt() + setPadding(padding, padding, padding, 0) + } + + override fun onComponentAttached() { + component.outputData?.let { + binding.editTextHolderName.setText(it.holderNameState.value) + binding.editTextBankAccountNumber.setText(it.bankAccountNumberState.value) + binding.editTextSortCode.setText(it.sortCodeState.value) + binding.editTextShopperEmail.setText(it.shopperEmailState.value) + } + } + + override fun initView() { + // no ops + } + + override fun isConfirmationRequired(): Boolean { + return true + } + + override fun highlightValidationErrors() { + // no ops + } + + override fun initLocalizedStrings(localizedContext: Context) { + val attrs = intArrayOf(android.R.attr.hint) + + // Holder Name + var typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_HolderNameInput, attrs) + binding.textInputLayoutHolderName.hint = typedArray.getString(0) + typedArray.recycle() + + // Account Number + typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_AccountNumberInput, attrs) + binding.textInputLayoutBankAccountNumber.hint = typedArray.getString(0) + typedArray.recycle() + + // Sort Code + typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_SortCodeInput, attrs) + binding.textInputLayoutSortCode.hint = typedArray.getString(0) + typedArray.recycle() + + // Shopper Email + typedArray = localizedContext.obtainStyledAttributes(R.style.AdyenCheckout_Bacs_ShopperEmailInput, attrs) + binding.textInputLayoutShopperEmail.hint = typedArray.getString(0) + typedArray.recycle() + } + + override fun observeComponentChanges(lifecycleOwner: LifecycleOwner) { + component.observeOutputData(lifecycleOwner, this) + } + + override fun onChanged(t: BacsDirectDebitOutputData?) { + // no ops + } +} diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt index 66ee9b058f..4c2547c837 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputData.kt @@ -16,5 +16,6 @@ data class BacsDirectDebitInputData( var sortCode: String = "", var shopperEmail: String = "", var isAmountConsentChecked: Boolean = false, - var isAccountConsentChecked: Boolean = false + var isAccountConsentChecked: Boolean = false, + var mode: BacsDirectDebitMode = BacsDirectDebitMode.INPUT ) : InputData diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitMode.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitMode.kt new file mode 100644 index 0000000000..a58780386e --- /dev/null +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitMode.kt @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 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/11/2021. + */ + +package com.adyen.checkout.bacs + +enum class BacsDirectDebitMode { + INPUT, + CONFIRMATION +} diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt index 610a47bc6f..57ac8a2ba8 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitValidationUtils.kt @@ -48,4 +48,4 @@ object BacsDirectDebitValidationUtils { FieldState(shopperEmail, Validation.Invalid(R.string.bacs_shopper_email_invalid)) } } -} \ No newline at end of file +} diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt index a151ecc4cd..e24859e4a2 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt @@ -14,8 +14,6 @@ import android.view.LayoutInflater import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer import com.adyen.checkout.bacs.databinding.BacsDirectDebitViewBinding -import com.adyen.checkout.components.GenericComponentState -import com.adyen.checkout.components.model.payments.request.BacsDirectDebitPaymentMethod import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.components.ui.view.AdyenTextInputEditText @@ -28,7 +26,7 @@ private val TAG = LogUtil.getTag() class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AdyenLinearLayout, + BacsDirectDebitComponentState, BacsDirectDebitComponent>(context, attrs, defStyleAttr), Observer { @@ -139,7 +137,6 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att } holderNameEditText?.onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> val holderNameValidation = component.outputData?.holderNameState?.validation - Logger.d(TAG, "outputData ${component.outputData.toString()}") if (hasFocus) { binding.textInputLayoutHolderName.error = null } else if (holderNameValidation != null && holderNameValidation is Validation.Invalid) { diff --git a/bacs/src/main/res/layout/bacs_direct_debit_confirmation_view.xml b/bacs/src/main/res/layout/bacs_direct_debit_confirmation_view.xml new file mode 100644 index 0000000000..3221715d46 --- /dev/null +++ b/bacs/src/main/res/layout/bacs_direct_debit_confirmation_view.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt index c657c6056e..c63b22d947 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -12,9 +12,9 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.children import androidx.core.view.isVisible -import com.adyen.checkout.bacs.BacsDirectDebitComponent -import com.adyen.checkout.bacs.BacsDirectDebitView +import com.adyen.checkout.bacs.* import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.core.log.LogUtil @@ -50,7 +50,9 @@ class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { bacsDirectDebitView.attach(bacsDirectDebitComponent, viewLifecycleOwner) if (bacsDirectDebitView.isConfirmationRequired) { - binding.payButton.setOnClickListener { componentDialogViewModel.payButtonClicked() } + binding.payButton.setOnClickListener { + handlePayClick() + } setInitViewState(BottomSheetBehavior.STATE_EXPANDED) bacsDirectDebitView.requestFocus() } else { @@ -59,14 +61,54 @@ class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { } override fun onChanged(paymentComponentState: PaymentComponentState?) { - TODO("Not yet implemented") + val bacsDirectDebitComponent = component as BacsDirectDebitComponent + val bacsDirectDebitComponentState = paymentComponentState as? BacsDirectDebitComponentState + + if (bacsDirectDebitComponentState != null) { + when (bacsDirectDebitComponentState.mode) { + BacsDirectDebitMode.INPUT -> { + val isInputViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitView } + if (!isInputViewAttached) { + val bacsDirectDebitView = BacsDirectDebitView(requireContext()) + binding.viewContainer.apply { + removeAllViews() + addView(bacsDirectDebitView) + bacsDirectDebitView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + } + } + } + BacsDirectDebitMode.CONFIRMATION -> { + val isConfirmationViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitConfirmationView } + if (!isConfirmationViewAttached) { + val bacsDirectDebitConfirmationView = BacsDirectDebitConfirmationView(requireContext()) + binding.viewContainer.apply { + removeAllViews() + addView(bacsDirectDebitConfirmationView) + bacsDirectDebitConfirmationView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + } + } + } + } + } + + componentDialogViewModel.componentStateChanged(bacsDirectDebitComponent.state) } override fun setPaymentPendingInitialization(pending: Boolean) { - TODO("Not yet implemented") + binding.payButton.isVisible = !pending + if (pending) binding.progressBar.show() + else binding.progressBar.hide() } override fun highlightValidationErrors() { TODO("Not yet implemented") } + + private fun handlePayClick() { + val bacsDirectDebitComponent = component as BacsDirectDebitComponent + when ((bacsDirectDebitComponent.state as? BacsDirectDebitComponentState)?.mode) { + BacsDirectDebitMode.INPUT -> bacsDirectDebitComponent.handleContinueClick() + BacsDirectDebitMode.CONFIRMATION -> componentDialogViewModel.payButtonClicked() + } + } } \ No newline at end of file From 193cdd1a5fef6c4ebaab3317348a50af1d5bbc84 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 23 Nov 2021 15:42:45 +0100 Subject: [PATCH 082/102] BACS: Handle navigation from input to confirmation mode --- .../adyen/checkout/bacs/BacsDirectDebitComponent.kt | 2 +- .../checkout/bacs/BacsDirectDebitComponentState.kt | 6 +++++- .../checkout/dropin/ui/ComponentDialogViewModel.kt | 7 ++++--- .../ui/component/BacsDirectDebitDialogFragment.kt | 12 ++++++++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index f281841476..e74fcd504b 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -57,7 +57,7 @@ class BacsDirectDebitComponent( return BacsDirectDebitComponentState( paymentComponentData, outputData?.isValid ?: false, - mLatestInputData?.mode == BacsDirectDebitMode.CONFIRMATION, + true, mLatestInputData?.mode ?: BacsDirectDebitMode.INPUT ) } diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt index d63d88e3ca..51df88a7b4 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponentState.kt @@ -17,4 +17,8 @@ class BacsDirectDebitComponentState( isInputValid: Boolean, isReady: Boolean, val mode: BacsDirectDebitMode = BacsDirectDebitMode.INPUT -) : PaymentComponentState(paymentComponentData, isInputValid, isReady) +) : PaymentComponentState(paymentComponentData, isInputValid, isReady) { + override fun isValid(): Boolean { + return super.isValid() && mode == BacsDirectDebitMode.CONFIRMATION + } +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/ComponentDialogViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/ComponentDialogViewModel.kt index b39a85615d..f375655a65 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/ComponentDialogViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/ComponentDialogViewModel.kt @@ -41,10 +41,11 @@ class ComponentDialogViewModel(private val savedStateHandle: SavedStateHandle) : "componentState.isReady: ${componentState?.isReady}" ) val paymentState = when { - componentState == null -> ComponentFragmentState.INVALID_UI + componentState == null -> ComponentFragmentState.IDLE + !componentState.isInputValid -> ComponentFragmentState.INVALID_UI componentState.isValid -> ComponentFragmentState.PAYMENT_READY - componentState.isInputValid && !componentState.isReady -> ComponentFragmentState.AWAITING_COMPONENT_INITIALIZATION - else -> ComponentFragmentState.INVALID_UI + !componentState.isReady -> ComponentFragmentState.AWAITING_COMPONENT_INITIALIZATION + else -> ComponentFragmentState.IDLE } Logger.v(TAG, "payButtonClicked - setting state $paymentState") setComponentFragmentState(paymentState) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt index c63b22d947..5eb6c6cb75 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -101,14 +101,18 @@ class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { } override fun highlightValidationErrors() { - TODO("Not yet implemented") + binding.viewContainer.children.firstOrNull { it is BacsDirectDebitView }?.let { + (it as BacsDirectDebitView).highlightValidationErrors() + } } private fun handlePayClick() { + componentDialogViewModel.payButtonClicked() val bacsDirectDebitComponent = component as BacsDirectDebitComponent - when ((bacsDirectDebitComponent.state as? BacsDirectDebitComponentState)?.mode) { - BacsDirectDebitMode.INPUT -> bacsDirectDebitComponent.handleContinueClick() - BacsDirectDebitMode.CONFIRMATION -> componentDialogViewModel.payButtonClicked() + val mode = (bacsDirectDebitComponent.state as? BacsDirectDebitComponentState)?.mode + val isInputMode = mode == BacsDirectDebitMode.INPUT + if (isInputMode && bacsDirectDebitComponent.state?.isInputValid == true) { + bacsDirectDebitComponent.handleContinueClick() } } } \ No newline at end of file From 98f0942b7f8f2ce3cdc67b8dde9f1a1cdf162e76 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 23 Nov 2021 16:28:46 +0100 Subject: [PATCH 083/102] BACS: Handle back press in BacsDirectDebitDialogFragment --- .../checkout/bacs/BacsDirectDebitView.kt | 9 ++- .../BacsDirectDebitDialogFragment.kt | 72 ++++++++++++------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt index e24859e4a2..6a67d87dd6 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt @@ -41,7 +41,14 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att } override fun onComponentAttached() { - // no ops + component.outputData?.let { + binding.editTextHolderName.setText(it.holderNameState.value) + binding.editTextBankAccountNumber.setText(it.bankAccountNumberState.value) + binding.editTextSortCode.setText(it.sortCodeState.value) + binding.editTextShopperEmail.setText(it.shopperEmailState.value) + binding.switchConsentAmount.isChecked = it.isAmountConsentChecked + binding.switchConsentAccount.isChecked = it.isAccountConsentChecked + } } override fun initView() { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt index 5eb6c6cb75..c0dc55c56f 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -14,7 +14,11 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.children import androidx.core.view.isVisible -import com.adyen.checkout.bacs.* +import com.adyen.checkout.bacs.BacsDirectDebitComponent +import com.adyen.checkout.bacs.BacsDirectDebitComponentState +import com.adyen.checkout.bacs.BacsDirectDebitConfirmationView +import com.adyen.checkout.bacs.BacsDirectDebitMode +import com.adyen.checkout.bacs.BacsDirectDebitView import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.core.log.LogUtil @@ -23,7 +27,7 @@ import com.adyen.checkout.dropin.databinding.FragmentBacsDirectDebitComponentBin import com.adyen.checkout.dropin.ui.base.BaseComponentDialogFragment import com.google.android.material.bottomsheet.BottomSheetBehavior -class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { +class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { private lateinit var binding: FragmentBacsDirectDebitComponentBinding @@ -66,28 +70,8 @@ class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { if (bacsDirectDebitComponentState != null) { when (bacsDirectDebitComponentState.mode) { - BacsDirectDebitMode.INPUT -> { - val isInputViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitView } - if (!isInputViewAttached) { - val bacsDirectDebitView = BacsDirectDebitView(requireContext()) - binding.viewContainer.apply { - removeAllViews() - addView(bacsDirectDebitView) - bacsDirectDebitView.attach(bacsDirectDebitComponent, viewLifecycleOwner) - } - } - } - BacsDirectDebitMode.CONFIRMATION -> { - val isConfirmationViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitConfirmationView } - if (!isConfirmationViewAttached) { - val bacsDirectDebitConfirmationView = BacsDirectDebitConfirmationView(requireContext()) - binding.viewContainer.apply { - removeAllViews() - addView(bacsDirectDebitConfirmationView) - bacsDirectDebitConfirmationView.attach(bacsDirectDebitComponent, viewLifecycleOwner) - } - } - } + BacsDirectDebitMode.INPUT -> attachInputView() + BacsDirectDebitMode.CONFIRMATION -> attachConfirmationView() } } @@ -106,6 +90,18 @@ class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { } } + override fun onBackPressed(): Boolean { + val bacsDirectDebitComponent = component as BacsDirectDebitComponent + val mode = (bacsDirectDebitComponent.state as? BacsDirectDebitComponentState)?.mode + val isConfirmationMode = mode == BacsDirectDebitMode.CONFIRMATION + return if (isConfirmationMode) { + bacsDirectDebitComponent.handleBackPress() + true + } else { + super.onBackPressed() + } + } + private fun handlePayClick() { componentDialogViewModel.payButtonClicked() val bacsDirectDebitComponent = component as BacsDirectDebitComponent @@ -115,4 +111,30 @@ class BacsDirectDebitDialogFragment: BaseComponentDialogFragment() { bacsDirectDebitComponent.handleContinueClick() } } -} \ No newline at end of file + + private fun attachInputView() { + val bacsDirectDebitComponent = component as BacsDirectDebitComponent + val isInputViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitView } + if (!isInputViewAttached) { + val bacsDirectDebitView = BacsDirectDebitView(requireContext()) + binding.viewContainer.apply { + removeAllViews() + addView(bacsDirectDebitView) + bacsDirectDebitView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + } + } + } + + private fun attachConfirmationView() { + val bacsDirectDebitComponent = component as BacsDirectDebitComponent + val isConfirmationViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitConfirmationView } + if (!isConfirmationViewAttached) { + val bacsDirectDebitConfirmationView = BacsDirectDebitConfirmationView(requireContext()) + binding.viewContainer.apply { + removeAllViews() + addView(bacsDirectDebitConfirmationView) + bacsDirectDebitConfirmationView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + } + } + } +} From ea83ac1a5a8605bec7adf5c705e4b48e49903cd7 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 7 Dec 2021 17:33:54 +0100 Subject: [PATCH 084/102] BACS: Auto focus next field if bank account number or sort code is valid --- .../checkout/bacs/BacsDirectDebitView.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt index 6a67d87dd6..47fbdfc2da 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt @@ -11,9 +11,11 @@ package com.adyen.checkout.bacs import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import android.view.View import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer import com.adyen.checkout.bacs.databinding.BacsDirectDebitViewBinding +import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.components.ui.view.AdyenTextInputEditText @@ -129,6 +131,8 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att override fun onChanged(bacsDirectDebitOutputData: BacsDirectDebitOutputData) { Logger.v(TAG, "bacsDirectDebitOutputData changed") + onBankAccountNumberValidated(bacsDirectDebitOutputData.bankAccountNumberState) + onSortCodeValidated(bacsDirectDebitOutputData.sortCodeState) } private fun notifyInputDataChanged() { @@ -214,4 +218,22 @@ class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: Att notifyInputDataChanged() } } + + private fun onBankAccountNumberValidated(bankAccountNumberFieldState: FieldState) { + if (bankAccountNumberFieldState.validation.isValid()) { + goToNextInputIfFocus(binding.editTextBankAccountNumber) + } + } + + private fun onSortCodeValidated(sortCodeFieldState: FieldState) { + if (sortCodeFieldState.validation.isValid()) { + goToNextInputIfFocus(binding.editTextSortCode) + } + } + + private fun goToNextInputIfFocus(view: View?) { + if (rootView.findFocus() === view && view != null) { + findViewById(view.nextFocusForwardId).requestFocus() + } + } } From e5efb4bd16b4a18fcf3043584c21978f7b0a88f1 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 8 Dec 2021 12:44:59 +0100 Subject: [PATCH 085/102] BACS: Rename BacsDirectDebitView to BacsDirectDebitInputView --- ...bitView.kt => BacsDirectDebitInputView.kt} | 6 ++--- ...w.xml => bacs_direct_debit_input_view.xml} | 0 .../BacsDirectDebitDialogFragment.kt | 24 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) rename bacs/src/main/java/com/adyen/checkout/bacs/{BacsDirectDebitView.kt => BacsDirectDebitInputView.kt} (96%) rename bacs/src/main/res/layout/{bacs_direct_debit_view.xml => bacs_direct_debit_input_view.xml} (100%) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt similarity index 96% rename from bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt rename to bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt index 47fbdfc2da..3c1a0a2e13 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt @@ -14,7 +14,7 @@ import android.view.LayoutInflater import android.view.View import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer -import com.adyen.checkout.bacs.databinding.BacsDirectDebitViewBinding +import com.adyen.checkout.bacs.databinding.BacsDirectDebitInputViewBinding import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.ui.view.AdyenLinearLayout @@ -25,14 +25,14 @@ import com.adyen.checkout.core.log.Logger private val TAG = LogUtil.getTag() @Suppress("TooManyFunctions") -class BacsDirectDebitView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : +class BacsDirectDebitInputView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AdyenLinearLayout(context, attrs, defStyleAttr), Observer { - private val binding: BacsDirectDebitViewBinding = BacsDirectDebitViewBinding.inflate(LayoutInflater.from(context), this) + private val binding: BacsDirectDebitInputViewBinding = BacsDirectDebitInputViewBinding.inflate(LayoutInflater.from(context), this) private val mBacsDirectDebitInputData = BacsDirectDebitInputData() diff --git a/bacs/src/main/res/layout/bacs_direct_debit_view.xml b/bacs/src/main/res/layout/bacs_direct_debit_input_view.xml similarity index 100% rename from bacs/src/main/res/layout/bacs_direct_debit_view.xml rename to bacs/src/main/res/layout/bacs_direct_debit_input_view.xml diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt index c0dc55c56f..dec4e59c85 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -18,7 +18,7 @@ import com.adyen.checkout.bacs.BacsDirectDebitComponent import com.adyen.checkout.bacs.BacsDirectDebitComponentState import com.adyen.checkout.bacs.BacsDirectDebitConfirmationView import com.adyen.checkout.bacs.BacsDirectDebitMode -import com.adyen.checkout.bacs.BacsDirectDebitView +import com.adyen.checkout.bacs.BacsDirectDebitInputView import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.core.log.LogUtil @@ -49,16 +49,16 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { component.observe(viewLifecycleOwner, this) bacsDirectDebitComponent.observeErrors(viewLifecycleOwner, createErrorHandlerObserver()) - val bacsDirectDebitView = BacsDirectDebitView(requireContext()) - binding.viewContainer.addView(bacsDirectDebitView) - bacsDirectDebitView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + val bacsDirectDebitInputView = BacsDirectDebitInputView(requireContext()) + binding.viewContainer.addView(bacsDirectDebitInputView) + bacsDirectDebitInputView.attach(bacsDirectDebitComponent, viewLifecycleOwner) - if (bacsDirectDebitView.isConfirmationRequired) { + if (bacsDirectDebitInputView.isConfirmationRequired) { binding.payButton.setOnClickListener { handlePayClick() } setInitViewState(BottomSheetBehavior.STATE_EXPANDED) - bacsDirectDebitView.requestFocus() + bacsDirectDebitInputView.requestFocus() } else { binding.payButton.isVisible = false } @@ -85,8 +85,8 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { } override fun highlightValidationErrors() { - binding.viewContainer.children.firstOrNull { it is BacsDirectDebitView }?.let { - (it as BacsDirectDebitView).highlightValidationErrors() + binding.viewContainer.children.firstOrNull { it is BacsDirectDebitInputView }?.let { + (it as BacsDirectDebitInputView).highlightValidationErrors() } } @@ -114,13 +114,13 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { private fun attachInputView() { val bacsDirectDebitComponent = component as BacsDirectDebitComponent - val isInputViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitView } + val isInputViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitInputView } if (!isInputViewAttached) { - val bacsDirectDebitView = BacsDirectDebitView(requireContext()) + val bacsDirectDebitInputView = BacsDirectDebitInputView(requireContext()) binding.viewContainer.apply { removeAllViews() - addView(bacsDirectDebitView) - bacsDirectDebitView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + addView(bacsDirectDebitInputView) + bacsDirectDebitInputView.attach(bacsDirectDebitComponent, viewLifecycleOwner) } } } From b998477fed736fc3d1da198427d6d362a12c1f95 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 8 Dec 2021 15:40:41 +0100 Subject: [PATCH 086/102] BACS: Add translations for pay button --- bacs/src/main/res/template/values/strings.xml.tt | 3 +++ bacs/src/main/res/values-cs-rCZ/strings.xml | 3 +++ bacs/src/main/res/values-da-rDK/strings.xml | 3 +++ bacs/src/main/res/values-de-rDE/strings.xml | 3 +++ bacs/src/main/res/values-el-rGR/strings.xml | 3 +++ bacs/src/main/res/values-es-rES/strings.xml | 3 +++ bacs/src/main/res/values-fi-rFI/strings.xml | 3 +++ bacs/src/main/res/values-fr-rFR/strings.xml | 3 +++ bacs/src/main/res/values-hr-rHR/strings.xml | 3 +++ bacs/src/main/res/values-hu-rHU/strings.xml | 3 +++ bacs/src/main/res/values-it-rIT/strings.xml | 3 +++ bacs/src/main/res/values-ja-rJP/strings.xml | 3 +++ bacs/src/main/res/values-ko-rKR/strings.xml | 3 +++ bacs/src/main/res/values-nb-rNO/strings.xml | 3 +++ bacs/src/main/res/values-nl-rNL/strings.xml | 3 +++ bacs/src/main/res/values-pl-rPL/strings.xml | 3 +++ bacs/src/main/res/values-pt-rBR/strings.xml | 3 +++ bacs/src/main/res/values-ro-rRO/strings.xml | 3 +++ bacs/src/main/res/values-ru-rRU/strings.xml | 3 +++ bacs/src/main/res/values-sk-rSK/strings.xml | 3 +++ bacs/src/main/res/values-sl-rSI/strings.xml | 3 +++ bacs/src/main/res/values-sv-rSE/strings.xml | 3 +++ bacs/src/main/res/values-zh-rCN/strings.xml | 3 +++ bacs/src/main/res/values-zh-rTW/strings.xml | 3 +++ bacs/src/main/res/values/strings.xml | 3 +++ 25 files changed, 75 insertions(+) diff --git a/bacs/src/main/res/template/values/strings.xml.tt b/bacs/src/main/res/template/values/strings.xml.tt index 5a754a66bb..1d7efcf005 100644 --- a/bacs/src/main/res/template/values/strings.xml.tt +++ b/bacs/src/main/res/template/values/strings.xml.tt @@ -16,4 +16,7 @@ %%bacs.accountNumber.invalid%% %%bacs.bankLocationId.invalid%% %%shopperEmail.invalid%% + + %%continue%% + %%bacs.confirm%% \ No newline at end of file diff --git a/bacs/src/main/res/values-cs-rCZ/strings.xml b/bacs/src/main/res/values-cs-rCZ/strings.xml index b88a035d1d..a502b82e0c 100644 --- a/bacs/src/main/res/values-cs-rCZ/strings.xml +++ b/bacs/src/main/res/values-cs-rCZ/strings.xml @@ -16,4 +16,7 @@ Neplatné číslo bankovního účtu Neplatný kód Sort Neplatná e-mailová adresa + + Pokračovat + Potvrdit a zaplatit \ No newline at end of file diff --git a/bacs/src/main/res/values-da-rDK/strings.xml b/bacs/src/main/res/values-da-rDK/strings.xml index 811ccd3116..f82dadc912 100644 --- a/bacs/src/main/res/values-da-rDK/strings.xml +++ b/bacs/src/main/res/values-da-rDK/strings.xml @@ -16,4 +16,7 @@ Ugyldigt bankkontonummer Ugyldigt registreringsnummer Ugyldig e-mailadresse + + Fortsæt + Bekræft, og betal \ No newline at end of file diff --git a/bacs/src/main/res/values-de-rDE/strings.xml b/bacs/src/main/res/values-de-rDE/strings.xml index 1a2fb5e667..5be8a5e908 100644 --- a/bacs/src/main/res/values-de-rDE/strings.xml +++ b/bacs/src/main/res/values-de-rDE/strings.xml @@ -16,4 +16,7 @@ Ungültige Bankkontonummer Ungültige Bankleitzahl Ungültige E-Mail-Adresse + + Weiter + Bestätigen und bezahlen \ No newline at end of file diff --git a/bacs/src/main/res/values-el-rGR/strings.xml b/bacs/src/main/res/values-el-rGR/strings.xml index 955e3f60eb..18e76367a9 100644 --- a/bacs/src/main/res/values-el-rGR/strings.xml +++ b/bacs/src/main/res/values-el-rGR/strings.xml @@ -16,4 +16,7 @@ Μη έγκυρος αριθμός τραπεζικού λογαριασμού Μη έγκυρος κωδικός τράπεζας Μη έγκυρη διεύθυνση email + + Συνέχεια + Επιβεβαίωση και πληρωμή \ No newline at end of file diff --git a/bacs/src/main/res/values-es-rES/strings.xml b/bacs/src/main/res/values-es-rES/strings.xml index a69370ca42..63b4bc9b26 100644 --- a/bacs/src/main/res/values-es-rES/strings.xml +++ b/bacs/src/main/res/values-es-rES/strings.xml @@ -16,4 +16,7 @@ El número de cuenta bancaria no es válido El código de sucursal no es válido La dirección de correo electrónico no es válida + + Continuar + Confirmar y pagar \ No newline at end of file diff --git a/bacs/src/main/res/values-fi-rFI/strings.xml b/bacs/src/main/res/values-fi-rFI/strings.xml index 6c634f446c..8defd6c2ba 100644 --- a/bacs/src/main/res/values-fi-rFI/strings.xml +++ b/bacs/src/main/res/values-fi-rFI/strings.xml @@ -16,4 +16,7 @@ Väärä tilin numero Ei-kelvollinen lajittelukoodi Ei-kelvollinen sähköpostiosoite + + Jatka + Vahvista ja maksa \ No newline at end of file diff --git a/bacs/src/main/res/values-fr-rFR/strings.xml b/bacs/src/main/res/values-fr-rFR/strings.xml index 4d2aa26a72..1574d832fd 100644 --- a/bacs/src/main/res/values-fr-rFR/strings.xml +++ b/bacs/src/main/res/values-fr-rFR/strings.xml @@ -16,4 +16,7 @@ Numéro du compte bancaire incorrect Code de tri (sort code) non valide Adresse e-mail incorrecte + + Continuer + Confirmer et payer \ No newline at end of file diff --git a/bacs/src/main/res/values-hr-rHR/strings.xml b/bacs/src/main/res/values-hr-rHR/strings.xml index 6feae9af26..973bdd005d 100644 --- a/bacs/src/main/res/values-hr-rHR/strings.xml +++ b/bacs/src/main/res/values-hr-rHR/strings.xml @@ -16,4 +16,7 @@ Nevažeći broj bankovnog računa Nevažeći identifikacijski kôd banke (UK) Nevažeća adresa e-pošte + + Nastavi + Potvrdi i plati \ No newline at end of file diff --git a/bacs/src/main/res/values-hu-rHU/strings.xml b/bacs/src/main/res/values-hu-rHU/strings.xml index b122e11217..6c62ba1be6 100644 --- a/bacs/src/main/res/values-hu-rHU/strings.xml +++ b/bacs/src/main/res/values-hu-rHU/strings.xml @@ -16,4 +16,7 @@ Érvénytelen bankszámlaszám Érvénytelen banki azonosító Érvénytelen e-mail-cím + + Folytatás + Megerősítés és fizetés \ No newline at end of file diff --git a/bacs/src/main/res/values-it-rIT/strings.xml b/bacs/src/main/res/values-it-rIT/strings.xml index 8a694dfbb6..ef9335182f 100644 --- a/bacs/src/main/res/values-it-rIT/strings.xml +++ b/bacs/src/main/res/values-it-rIT/strings.xml @@ -16,4 +16,7 @@ Numero di conto bancario non valido Sort code non valido Indirizzo e-mail non valido + + Continua + Conferma e paga \ No newline at end of file diff --git a/bacs/src/main/res/values-ja-rJP/strings.xml b/bacs/src/main/res/values-ja-rJP/strings.xml index 33dc2c52e8..845f87f93a 100644 --- a/bacs/src/main/res/values-ja-rJP/strings.xml +++ b/bacs/src/main/res/values-ja-rJP/strings.xml @@ -16,4 +16,7 @@ 銀行口座番号が無効です ソートコードが無効です Eメールアドレスが無効です + + 続ける + 確認して支払う \ No newline at end of file diff --git a/bacs/src/main/res/values-ko-rKR/strings.xml b/bacs/src/main/res/values-ko-rKR/strings.xml index 4eeee827b7..d13401d92c 100644 --- a/bacs/src/main/res/values-ko-rKR/strings.xml +++ b/bacs/src/main/res/values-ko-rKR/strings.xml @@ -16,4 +16,7 @@ 계좌 번호가 유효하지 않습니다 은행 식별 코드가 유효하지 않습니다 유효하지 않은 이메일 주소 + + 계속 + 확인 및 결제 \ No newline at end of file diff --git a/bacs/src/main/res/values-nb-rNO/strings.xml b/bacs/src/main/res/values-nb-rNO/strings.xml index 6c712aa7ce..8b1ad8311e 100644 --- a/bacs/src/main/res/values-nb-rNO/strings.xml +++ b/bacs/src/main/res/values-nb-rNO/strings.xml @@ -16,4 +16,7 @@ Ugyldig bankkontonummer Ugyldig sorteringskode Ugyldig e-postadresse + + Fortsett + Bekreft og betal \ No newline at end of file diff --git a/bacs/src/main/res/values-nl-rNL/strings.xml b/bacs/src/main/res/values-nl-rNL/strings.xml index 24290d0f13..e1eeb05ee6 100644 --- a/bacs/src/main/res/values-nl-rNL/strings.xml +++ b/bacs/src/main/res/values-nl-rNL/strings.xml @@ -16,4 +16,7 @@ Ongeldig bankrekeningnummer Ongeldige bankcode Ongeldig e-mailadres + + Doorgaan + Bevestigen en betalen \ No newline at end of file diff --git a/bacs/src/main/res/values-pl-rPL/strings.xml b/bacs/src/main/res/values-pl-rPL/strings.xml index f6dbadaf1a..9108f0461d 100644 --- a/bacs/src/main/res/values-pl-rPL/strings.xml +++ b/bacs/src/main/res/values-pl-rPL/strings.xml @@ -16,4 +16,7 @@ Nieprawidłowy numer rachunku Nieprawidłowy numer rozliczeniowy SORT Niepoprawny adres email + + Kontynuuj + Potwierdź i zapłać \ No newline at end of file diff --git a/bacs/src/main/res/values-pt-rBR/strings.xml b/bacs/src/main/res/values-pt-rBR/strings.xml index 949aeb218d..63a220928c 100644 --- a/bacs/src/main/res/values-pt-rBR/strings.xml +++ b/bacs/src/main/res/values-pt-rBR/strings.xml @@ -16,4 +16,7 @@ Número da conta bancária inválido Código de classificação inválido Endereço de e-mail inválido + + Continuar + Confirmar e pagar \ No newline at end of file diff --git a/bacs/src/main/res/values-ro-rRO/strings.xml b/bacs/src/main/res/values-ro-rRO/strings.xml index 274abb6212..5b7b3a80ec 100644 --- a/bacs/src/main/res/values-ro-rRO/strings.xml +++ b/bacs/src/main/res/values-ro-rRO/strings.xml @@ -16,4 +16,7 @@ Numărul contului bancar este incorect Cod de identificare bancară incorect Adresă de e-mail incorectă + + Continuare + Confirmați și plătiți \ No newline at end of file diff --git a/bacs/src/main/res/values-ru-rRU/strings.xml b/bacs/src/main/res/values-ru-rRU/strings.xml index 5a7b32765c..5ceedafbab 100644 --- a/bacs/src/main/res/values-ru-rRU/strings.xml +++ b/bacs/src/main/res/values-ru-rRU/strings.xml @@ -16,4 +16,7 @@ Неверный номер банковского счета Неверный код банка Недействительный адрес эл. почты + + Продолжить + Подтвердить и оплатить \ No newline at end of file diff --git a/bacs/src/main/res/values-sk-rSK/strings.xml b/bacs/src/main/res/values-sk-rSK/strings.xml index 031a0a0379..84047e0d48 100644 --- a/bacs/src/main/res/values-sk-rSK/strings.xml +++ b/bacs/src/main/res/values-sk-rSK/strings.xml @@ -16,4 +16,7 @@ Neplatné číslo bankového účtu Neplatný variabilný symbol Neplatná emailová adresa + + Pokračovať + Potvrdiť a zaplatiť \ No newline at end of file diff --git a/bacs/src/main/res/values-sl-rSI/strings.xml b/bacs/src/main/res/values-sl-rSI/strings.xml index 88d45daea1..ef13a8c0b9 100644 --- a/bacs/src/main/res/values-sl-rSI/strings.xml +++ b/bacs/src/main/res/values-sl-rSI/strings.xml @@ -16,4 +16,7 @@ Neveljavna številka bančnega računa Neveljavna številka banke Neveljaven elektronski naslov + + Nadaljuj + Potrdi in plačaj \ No newline at end of file diff --git a/bacs/src/main/res/values-sv-rSE/strings.xml b/bacs/src/main/res/values-sv-rSE/strings.xml index bfc3334350..5ac5b970ae 100644 --- a/bacs/src/main/res/values-sv-rSE/strings.xml +++ b/bacs/src/main/res/values-sv-rSE/strings.xml @@ -16,4 +16,7 @@ Ogiltigt bankkontonummer Ogiltigt clearingnummer Ogiltig e-postadress + + Fortsätt + Bekräfta och betala \ No newline at end of file diff --git a/bacs/src/main/res/values-zh-rCN/strings.xml b/bacs/src/main/res/values-zh-rCN/strings.xml index efabf10344..32c9a2e30f 100644 --- a/bacs/src/main/res/values-zh-rCN/strings.xml +++ b/bacs/src/main/res/values-zh-rCN/strings.xml @@ -16,4 +16,7 @@ 无效的银行账号 无效的分类代码 无效的邮件地址 + + 继续 + 确认并支付 \ No newline at end of file diff --git a/bacs/src/main/res/values-zh-rTW/strings.xml b/bacs/src/main/res/values-zh-rTW/strings.xml index e2ae31aaf2..7f09205ee9 100644 --- a/bacs/src/main/res/values-zh-rTW/strings.xml +++ b/bacs/src/main/res/values-zh-rTW/strings.xml @@ -16,4 +16,7 @@ 銀行帳戶號碼無效 銀行代碼無效 電子郵件地址無效 + + 繼續 + 確認並支付 \ No newline at end of file diff --git a/bacs/src/main/res/values/strings.xml b/bacs/src/main/res/values/strings.xml index e4c27ae35d..15e11311e3 100644 --- a/bacs/src/main/res/values/strings.xml +++ b/bacs/src/main/res/values/strings.xml @@ -16,4 +16,7 @@ Invalid bank account number Invalid sort code Invalid email address + + Continue + Confirm and pay \ No newline at end of file From 870809aa77c57671c0fd58e04c8e92de48bdb17e Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 8 Dec 2021 15:42:20 +0100 Subject: [PATCH 087/102] BACS: Handle navigation between steps in fragment --- .../checkout/bacs/BacsDirectDebitComponent.kt | 8 ++++---- .../bacs/BacsDirectDebitConfirmationView.kt | 1 + .../checkout/bacs/BacsDirectDebitInputView.kt | 1 + .../component/BacsDirectDebitDialogFragment.kt | 16 +++++++++------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index e74fcd504b..359129c811 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -62,13 +62,13 @@ class BacsDirectDebitComponent( ) } - fun handleContinueClick() { - mLatestInputData?.mode = BacsDirectDebitMode.CONFIRMATION + fun setInputMode() { + mLatestInputData?.mode = BacsDirectDebitMode.INPUT notifyStateChanged() } - fun handleBackPress() { - mLatestInputData?.mode = BacsDirectDebitMode.INPUT + fun setConfirmationMode() { + mLatestInputData?.mode = BacsDirectDebitMode.CONFIRMATION notifyStateChanged() } diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt index 15368e245e..f8df495156 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfirmationView.kt @@ -38,6 +38,7 @@ class BacsDirectDebitConfirmationView @JvmOverloads constructor(context: Context binding.editTextSortCode.setText(it.sortCodeState.value) binding.editTextShopperEmail.setText(it.shopperEmailState.value) } + component.setConfirmationMode() } override fun initView() { diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt index 3c1a0a2e13..bb4741fb63 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt @@ -51,6 +51,7 @@ class BacsDirectDebitInputView @JvmOverloads constructor(context: Context, attrs binding.switchConsentAmount.isChecked = it.isAmountConsentChecked binding.switchConsentAccount.isChecked = it.isAccountConsentChecked } + component.setInputMode() } override fun initView() { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt index dec4e59c85..33bc633e5d 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.components.PaymentComponentState import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger +import com.adyen.checkout.dropin.R import com.adyen.checkout.dropin.databinding.FragmentBacsDirectDebitComponentBinding import com.adyen.checkout.dropin.ui.base.BaseComponentDialogFragment import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -55,7 +56,7 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { if (bacsDirectDebitInputView.isConfirmationRequired) { binding.payButton.setOnClickListener { - handlePayClick() + handleContinueClick() } setInitViewState(BottomSheetBehavior.STATE_EXPANDED) bacsDirectDebitInputView.requestFocus() @@ -69,10 +70,11 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { val bacsDirectDebitComponentState = paymentComponentState as? BacsDirectDebitComponentState if (bacsDirectDebitComponentState != null) { - when (bacsDirectDebitComponentState.mode) { - BacsDirectDebitMode.INPUT -> attachInputView() - BacsDirectDebitMode.CONFIRMATION -> attachConfirmationView() + val payButtonText = when (bacsDirectDebitComponentState.mode) { + BacsDirectDebitMode.INPUT -> R.string.bacs_continue + BacsDirectDebitMode.CONFIRMATION -> R.string.bacs_confirm_and_pay } + binding.payButton.setText(payButtonText) } componentDialogViewModel.componentStateChanged(bacsDirectDebitComponent.state) @@ -95,20 +97,20 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { val mode = (bacsDirectDebitComponent.state as? BacsDirectDebitComponentState)?.mode val isConfirmationMode = mode == BacsDirectDebitMode.CONFIRMATION return if (isConfirmationMode) { - bacsDirectDebitComponent.handleBackPress() + attachInputView() true } else { super.onBackPressed() } } - private fun handlePayClick() { + private fun handleContinueClick() { componentDialogViewModel.payButtonClicked() val bacsDirectDebitComponent = component as BacsDirectDebitComponent val mode = (bacsDirectDebitComponent.state as? BacsDirectDebitComponentState)?.mode val isInputMode = mode == BacsDirectDebitMode.INPUT if (isInputMode && bacsDirectDebitComponent.state?.isInputValid == true) { - bacsDirectDebitComponent.handleContinueClick() + attachConfirmationView() } } From 846f0508b295d6274f7e50e62376e0e90c747803 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Wed, 8 Dec 2021 15:56:58 +0100 Subject: [PATCH 088/102] BACS: Reformat fragment layout --- .../fragment_bacs_direct_debit_component.xml | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml index 8591c67d9d..d7402e0ec9 100644 --- a/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml +++ b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml @@ -7,16 +7,16 @@ --> + android:orientation="vertical" + android:paddingBottom="@dimen/standard_margin"> + android:layout_height="wrap_content" /> + tools:text="Header" /> - + + + + android:layout_weight="1" /> + android:text="@string/pay_button" /> Date: Thu, 9 Dec 2021 14:44:28 +0100 Subject: [PATCH 089/102] BACS: Add slide animation between input and confirmation views --- .../BacsDirectDebitDialogFragment.kt | 69 ++++++++++++++++--- .../main/res/anim/slide_in_left_to_right.xml | 13 ++++ .../main/res/anim/slide_in_right_to_left.xml | 11 +++ .../main/res/anim/slide_out_left_to_right.xml | 12 ++++ .../main/res/anim/slide_out_right_to_left.xml | 12 ++++ .../fragment_bacs_direct_debit_component.xml | 3 +- 6 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 drop-in/src/main/res/anim/slide_in_left_to_right.xml create mode 100644 drop-in/src/main/res/anim/slide_in_right_to_left.xml create mode 100644 drop-in/src/main/res/anim/slide_out_left_to_right.xml create mode 100644 drop-in/src/main/res/anim/slide_out_right_to_left.xml diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt index 33bc633e5d..ebc364bd24 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -8,10 +8,15 @@ package com.adyen.checkout.dropin.ui.component +import android.app.Dialog import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.WindowManager +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.widget.FrameLayout import androidx.core.view.children import androidx.core.view.isVisible import com.adyen.checkout.bacs.BacsDirectDebitComponent @@ -27,7 +32,9 @@ import com.adyen.checkout.dropin.R import com.adyen.checkout.dropin.databinding.FragmentBacsDirectDebitComponentBinding import com.adyen.checkout.dropin.ui.base.BaseComponentDialogFragment import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +@Suppress("TooManyFunctions") class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { private lateinit var binding: FragmentBacsDirectDebitComponentBinding @@ -65,6 +72,13 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { } } + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + Logger.d(TAG, "onCreateDialog") + val dialog = super.onCreateDialog(savedInstanceState) + setDialogToFullScreen(dialog) + return dialog + } + override fun onChanged(paymentComponentState: PaymentComponentState?) { val bacsDirectDebitComponent = component as BacsDirectDebitComponent val bacsDirectDebitComponentState = paymentComponentState as? BacsDirectDebitComponentState @@ -118,11 +132,24 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { val bacsDirectDebitComponent = component as BacsDirectDebitComponent val isInputViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitInputView } if (!isInputViewAttached) { - val bacsDirectDebitInputView = BacsDirectDebitInputView(requireContext()) + val inputView = BacsDirectDebitInputView(requireContext()) + val confirmationRemoveAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_out_left_to_right) + val inputAddAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_in_left_to_right) binding.viewContainer.apply { - removeAllViews() - addView(bacsDirectDebitInputView) - bacsDirectDebitInputView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + val confirmationView = children.firstOrNull { it is BacsDirectDebitConfirmationView } + confirmationRemoveAnimation.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation?) { + // no ops + } + override fun onAnimationEnd(animation: Animation?) { removeView(confirmationView) } + override fun onAnimationRepeat(animation: Animation?) { + // no ops + } + }) + addView(inputView) + confirmationView?.startAnimation(confirmationRemoveAnimation) + inputView.startAnimation(inputAddAnimation) + inputView.attach(bacsDirectDebitComponent, viewLifecycleOwner) } } } @@ -131,12 +158,38 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { val bacsDirectDebitComponent = component as BacsDirectDebitComponent val isConfirmationViewAttached = binding.viewContainer.children.any { it is BacsDirectDebitConfirmationView } if (!isConfirmationViewAttached) { - val bacsDirectDebitConfirmationView = BacsDirectDebitConfirmationView(requireContext()) + val confirmationView = BacsDirectDebitConfirmationView(requireContext()) + val confirmationAddAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_in_right_to_left) + val inputRemoveAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_out_right_to_left) binding.viewContainer.apply { - removeAllViews() - addView(bacsDirectDebitConfirmationView) - bacsDirectDebitConfirmationView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + val inputView = children.firstOrNull { it is BacsDirectDebitInputView } + inputRemoveAnimation.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation?) { + // no ops + } + override fun onAnimationEnd(animation: Animation?) { removeView(inputView) } + override fun onAnimationRepeat(animation: Animation?) { + // no ops + } + }) + addView(confirmationView) + inputView?.startAnimation(inputRemoveAnimation) + confirmationView.startAnimation(confirmationAddAnimation) + confirmationView.attach(bacsDirectDebitComponent, viewLifecycleOwner) } } } + + private fun setDialogToFullScreen(dialog: Dialog) { + dialog.setOnShowListener { + val bottomSheetDialog = dialog as BottomSheetDialog + val bottomSheet = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet) + val layoutParams = bottomSheet?.layoutParams + val behavior = bottomSheet?.let { BottomSheetBehavior.from(it) } + behavior?.isDraggable = false + layoutParams?.height = WindowManager.LayoutParams.MATCH_PARENT + bottomSheet?.layoutParams = layoutParams + behavior?.state = BottomSheetBehavior.STATE_EXPANDED + } + } } diff --git a/drop-in/src/main/res/anim/slide_in_left_to_right.xml b/drop-in/src/main/res/anim/slide_in_left_to_right.xml new file mode 100644 index 0000000000..557cc6dce3 --- /dev/null +++ b/drop-in/src/main/res/anim/slide_in_left_to_right.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/drop-in/src/main/res/anim/slide_in_right_to_left.xml b/drop-in/src/main/res/anim/slide_in_right_to_left.xml new file mode 100644 index 0000000000..4179ff0230 --- /dev/null +++ b/drop-in/src/main/res/anim/slide_in_right_to_left.xml @@ -0,0 +1,11 @@ + + \ No newline at end of file diff --git a/drop-in/src/main/res/anim/slide_out_left_to_right.xml b/drop-in/src/main/res/anim/slide_out_left_to_right.xml new file mode 100644 index 0000000000..44e7bba579 --- /dev/null +++ b/drop-in/src/main/res/anim/slide_out_left_to_right.xml @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/drop-in/src/main/res/anim/slide_out_right_to_left.xml b/drop-in/src/main/res/anim/slide_out_right_to_left.xml new file mode 100644 index 0000000000..d2fcdaa577 --- /dev/null +++ b/drop-in/src/main/res/anim/slide_out_right_to_left.xml @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml index d7402e0ec9..91a277f539 100644 --- a/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml +++ b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml @@ -29,7 +29,8 @@ + android:layout_weight="1" + android:fillViewport="true"> Date: Mon, 13 Dec 2021 12:59:40 +0100 Subject: [PATCH 090/102] BACS: Add amount to configuration --- .../bacs/BacsDirectDebitConfiguration.kt | 31 +++++++++++++++++-- .../dropin/ComponentParsingProvider.kt | 4 ++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt index 9b7af30db9..c2b7e5ea10 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt @@ -13,11 +13,17 @@ import android.os.Parcel import android.os.Parcelable import com.adyen.checkout.components.base.BaseConfigurationBuilder import com.adyen.checkout.components.base.Configuration +import com.adyen.checkout.components.model.payments.Amount +import com.adyen.checkout.components.util.CheckoutCurrency import com.adyen.checkout.core.api.Environment +import com.adyen.checkout.core.exception.CheckoutException +import com.adyen.checkout.core.model.JsonUtils import java.util.* class BacsDirectDebitConfiguration : Configuration { + val amount: Amount + companion object { @JvmField val CREATOR: Parcelable.Creator = object : Parcelable.Creator { @@ -32,11 +38,24 @@ class BacsDirectDebitConfiguration : Configuration { } } - internal constructor(builder: Builder) : super(builder.builderShopperLocale, builder.builderEnvironment, builder.builderClientKey) - internal constructor(parcel: Parcel) : super(parcel) + internal constructor(builder: Builder) : super(builder.builderShopperLocale, builder.builderEnvironment, builder.builderClientKey) { + this.amount = builder.amount + } + + internal constructor(parcel: Parcel) : super(parcel) { + amount = Amount.CREATOR.createFromParcel(parcel) + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + super.writeToParcel(parcel, flags) + JsonUtils.writeToParcel(parcel, Amount.SERIALIZER.serialize(amount)) + } class Builder : BaseConfigurationBuilder { + var amount: Amount = Amount.EMPTY + private set + constructor(context: Context, clientKey: String) : super(context, clientKey) /** @@ -59,5 +78,13 @@ class BacsDirectDebitConfiguration : Configuration { override fun buildInternal(): BacsDirectDebitConfiguration { return BacsDirectDebitConfiguration(this) } + + fun setAmount(amount: Amount): Builder { + if (!CheckoutCurrency.isSupported(amount.currency) || amount.value < 0) { + throw CheckoutException("Currency is not valid.") + } + this.amount = amount + return this + } } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt index 8c06d455c6..151629999f 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt @@ -125,7 +125,9 @@ internal fun getDefaultConfigForPaymentMethod( PaymentMethodTypes.MOLPAY_VIETNAM -> MolpayConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.OPEN_BANKING -> OpenBankingConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.SEPA -> SepaConfiguration.Builder(shopperLocale, environment, clientKey) - PaymentMethodTypes.BACS -> BacsDirectDebitConfiguration.Builder(shopperLocale, environment, clientKey) + PaymentMethodTypes.BACS -> BacsDirectDebitConfiguration.Builder(shopperLocale, environment, clientKey).apply { + if (!dropInConfiguration.amount.isEmpty) setAmount(dropInConfiguration.amount) + } PaymentMethodTypes.SCHEME -> CardConfiguration.Builder(shopperLocale, environment, clientKey) else -> throw CheckoutException("Unable to find component configuration for paymentMethod - $paymentMethod") } From db247f3930748b16ca1d21943d4148e8eaec5729 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 13 Dec 2021 13:41:25 +0100 Subject: [PATCH 091/102] Add setter functions to DropInConfiguration.Builder for BACS and Voucher --- .../checkout/dropin/DropInConfiguration.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInConfiguration.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInConfiguration.kt index 3159e2095d..9710e102ba 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/DropInConfiguration.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/DropInConfiguration.kt @@ -14,6 +14,7 @@ import android.os.Parcel import android.os.Parcelable import com.adyen.checkout.adyen3ds2.Adyen3DS2Configuration import com.adyen.checkout.await.AwaitConfiguration +import com.adyen.checkout.bacs.BacsDirectDebitConfiguration import com.adyen.checkout.bcmc.BcmcConfiguration import com.adyen.checkout.blik.BlikConfiguration import com.adyen.checkout.card.CardConfiguration @@ -39,6 +40,7 @@ import com.adyen.checkout.openbanking.OpenBankingConfiguration import com.adyen.checkout.qrcode.QRCodeConfiguration import com.adyen.checkout.redirect.RedirectConfiguration import com.adyen.checkout.sepa.SepaConfiguration +import com.adyen.checkout.voucher.VoucherConfiguration import com.adyen.checkout.wechatpay.WeChatPayActionConfiguration import java.util.* import kotlin.collections.HashMap @@ -336,6 +338,14 @@ class DropInConfiguration : Configuration, Parcelable { return this } + /** + * Add configuration for BACS Direct Debit payment method. + */ + fun addBacsDirectDebitConfiguration(bacsDirectDebitConfiguration: BacsDirectDebitConfiguration): Builder { + availablePaymentConfigs[PaymentMethodTypes.BACS] = bacsDirectDebitConfiguration + return this + } + /** * Add configuration for 3DS2 action. */ @@ -376,6 +386,14 @@ class DropInConfiguration : Configuration, Parcelable { return this } + /** + * Add configuration for Voucher action. + */ + fun addVoucherActionConfiguration(configuration: VoucherConfiguration): Builder { + availableActionConfigs[configuration::class.java] = configuration + return this + } + override fun buildInternal(): DropInConfiguration { return DropInConfiguration(this) } From 36fdccf63af54379086a0e00c933b1371e0237d8 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 13 Dec 2021 13:42:32 +0100 Subject: [PATCH 092/102] BACS: Show amount in consent if specified --- .../com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt | 2 +- .../com/adyen/checkout/bacs/BacsDirectDebitInputView.kt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt index c2b7e5ea10..5189d73045 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitConfiguration.kt @@ -53,7 +53,7 @@ class BacsDirectDebitConfiguration : Configuration { class Builder : BaseConfigurationBuilder { - var amount: Amount = Amount.EMPTY + internal var amount: Amount = Amount.EMPTY private set constructor(context: Context, clientKey: String) : super(context, clientKey) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt index bb4741fb63..8c86bc16c0 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt @@ -19,6 +19,7 @@ import com.adyen.checkout.components.ui.FieldState import com.adyen.checkout.components.ui.Validation import com.adyen.checkout.components.ui.view.AdyenLinearLayout import com.adyen.checkout.components.ui.view.AdyenTextInputEditText +import com.adyen.checkout.components.util.CurrencyUtils import com.adyen.checkout.core.log.LogUtil import com.adyen.checkout.core.log.Logger @@ -52,6 +53,11 @@ class BacsDirectDebitInputView @JvmOverloads constructor(context: Context, attrs binding.switchConsentAccount.isChecked = it.isAccountConsentChecked } component.setInputMode() + if (!component.configuration.amount.isEmpty) { + val formattedAmount = CurrencyUtils.formatAmount(component.configuration.amount, component.configuration.shopperLocale) + // TODO update translations + // binding.switchConsentAmount.text = resources.getString(R.string.bacs_consent_amount_specified, formattedAmount) + } } override fun initView() { From def3ba2505bdd8387fd3decee7372945491349d3 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 14 Dec 2021 09:45:38 +0100 Subject: [PATCH 093/102] BACS: Update translations --- .../com/adyen/checkout/bacs/BacsDirectDebitInputView.kt | 3 +-- bacs/src/main/res/template/values/strings.xml.tt | 4 ++++ bacs/src/main/res/values-cs-rCZ/strings.xml | 4 ++++ bacs/src/main/res/values-da-rDK/strings.xml | 4 ++++ bacs/src/main/res/values-de-rDE/strings.xml | 4 ++++ bacs/src/main/res/values-el-rGR/strings.xml | 4 ++++ bacs/src/main/res/values-es-rES/strings.xml | 4 ++++ bacs/src/main/res/values-fi-rFI/strings.xml | 4 ++++ bacs/src/main/res/values-fr-rFR/strings.xml | 4 ++++ bacs/src/main/res/values-hr-rHR/strings.xml | 4 ++++ bacs/src/main/res/values-hu-rHU/strings.xml | 4 ++++ bacs/src/main/res/values-it-rIT/strings.xml | 4 ++++ bacs/src/main/res/values-ja-rJP/strings.xml | 4 ++++ bacs/src/main/res/values-ko-rKR/strings.xml | 4 ++++ bacs/src/main/res/values-nb-rNO/strings.xml | 4 ++++ bacs/src/main/res/values-nl-rNL/strings.xml | 4 ++++ bacs/src/main/res/values-pl-rPL/strings.xml | 4 ++++ bacs/src/main/res/values-pt-rBR/strings.xml | 4 ++++ bacs/src/main/res/values-ro-rRO/strings.xml | 4 ++++ bacs/src/main/res/values-ru-rRU/strings.xml | 4 ++++ bacs/src/main/res/values-sk-rSK/strings.xml | 4 ++++ bacs/src/main/res/values-sl-rSI/strings.xml | 4 ++++ bacs/src/main/res/values-sv-rSE/strings.xml | 4 ++++ bacs/src/main/res/values-zh-rCN/strings.xml | 4 ++++ bacs/src/main/res/values-zh-rTW/strings.xml | 4 ++++ bacs/src/main/res/values/strings.xml | 4 ++++ bacs/src/main/res/values/styles.xml | 6 ++---- 27 files changed, 103 insertions(+), 6 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt index 8c86bc16c0..57ca2c6ae7 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt @@ -55,8 +55,7 @@ class BacsDirectDebitInputView @JvmOverloads constructor(context: Context, attrs component.setInputMode() if (!component.configuration.amount.isEmpty) { val formattedAmount = CurrencyUtils.formatAmount(component.configuration.amount, component.configuration.shopperLocale) - // TODO update translations - // binding.switchConsentAmount.text = resources.getString(R.string.bacs_consent_amount_specified, formattedAmount) + binding.switchConsentAmount.text = resources.getString(R.string.bacs_consent_amount_specified, formattedAmount) } } diff --git a/bacs/src/main/res/template/values/strings.xml.tt b/bacs/src/main/res/template/values/strings.xml.tt index 1d7efcf005..f8f4a76a28 100644 --- a/bacs/src/main/res/template/values/strings.xml.tt +++ b/bacs/src/main/res/template/values/strings.xml.tt @@ -17,6 +17,10 @@ %%bacs.bankLocationId.invalid%% %%shopperEmail.invalid%% + %%bacs.consent.account%% + %%bacs.consent.amount%% + %%bacs.consent.amount.specified%% + %%continue%% %%bacs.confirm%% \ No newline at end of file diff --git a/bacs/src/main/res/values-cs-rCZ/strings.xml b/bacs/src/main/res/values-cs-rCZ/strings.xml index a502b82e0c..3bb75f3fca 100644 --- a/bacs/src/main/res/values-cs-rCZ/strings.xml +++ b/bacs/src/main/res/values-cs-rCZ/strings.xml @@ -17,6 +17,10 @@ Neplatný kód Sort Neplatná e-mailová adresa + Potvrzuji, že účet je veden na moje jméno a jsem jediným disponentem, jehož podpis je nutný ke schválení přímého inkasa. + Souhlasím s tím, že mi bude následující částka odečtena z bankovního účtu. + Souhlasím, aby mi částka %s byla odečtena z bankovního účtu. + Pokračovat Potvrdit a zaplatit \ No newline at end of file diff --git a/bacs/src/main/res/values-da-rDK/strings.xml b/bacs/src/main/res/values-da-rDK/strings.xml index f82dadc912..924a2b7fda 100644 --- a/bacs/src/main/res/values-da-rDK/strings.xml +++ b/bacs/src/main/res/values-da-rDK/strings.xml @@ -17,6 +17,10 @@ Ugyldigt registreringsnummer Ugyldig e-mailadresse + Jeg bekræfter, at kontoen er i mit navn, og at jeg er den eneste underskriver, der kræves for at godkende direkte debitering af kontoen. + Jeg accepterer, at beløbet ovenfor trækkes på min bankkonto. + Jeg accepterer, at %s hæves på min bankkonto. + Fortsæt Bekræft, og betal \ No newline at end of file diff --git a/bacs/src/main/res/values-de-rDE/strings.xml b/bacs/src/main/res/values-de-rDE/strings.xml index 5be8a5e908..e46d6e0447 100644 --- a/bacs/src/main/res/values-de-rDE/strings.xml +++ b/bacs/src/main/res/values-de-rDE/strings.xml @@ -17,6 +17,10 @@ Ungültige Bankleitzahl Ungültige E-Mail-Adresse + Ich bestätige, dass das Konto unter meinem Namen läuft und ich der einzige erforderliche Unterzeichner bin, um die Lastschrift für dieses Konto zu autorisieren. + Ich bin damit einverstanden, dass der oben genannte Betrag von meinem Bankkonto abgebucht wird. + Ich bin damit einverstanden, dass %s von meinem Bankkonto abgebucht wird. + Weiter Bestätigen und bezahlen \ No newline at end of file diff --git a/bacs/src/main/res/values-el-rGR/strings.xml b/bacs/src/main/res/values-el-rGR/strings.xml index 18e76367a9..c1f2629a37 100644 --- a/bacs/src/main/res/values-el-rGR/strings.xml +++ b/bacs/src/main/res/values-el-rGR/strings.xml @@ -17,6 +17,10 @@ Μη έγκυρος κωδικός τράπεζας Μη έγκυρη διεύθυνση email + Επιβεβαιώνω ότι ο λογαριασμός είναι στο όνομά μου και πως είμαι ο/η μοναδικός/μοναδική υπογράφων/υπογράφουσα που απαιτείται για εξουσιοδότηση της Άμεσης Χρέωσης σε αυτόν τον λογαριασμό. + Αποδέχομαι ότι το πιο πάνω ποσό θα αφαιρεθεί από τον τραπεζικό λογαριασμό μου. + Αποδέχομαι ότι το ποσό %s θα αφαιρεθεί από τον τραπεζικό λογαριασμό μου. + Συνέχεια Επιβεβαίωση και πληρωμή \ No newline at end of file diff --git a/bacs/src/main/res/values-es-rES/strings.xml b/bacs/src/main/res/values-es-rES/strings.xml index 63b4bc9b26..867e8d2194 100644 --- a/bacs/src/main/res/values-es-rES/strings.xml +++ b/bacs/src/main/res/values-es-rES/strings.xml @@ -17,6 +17,10 @@ El código de sucursal no es válido La dirección de correo electrónico no es válida + Confirmo que la cuenta está a mi nombre y soy el único firmante necesario para autorizar débitos directos en esta cuenta. + Estoy de acuerdo con que la cantidad anterior se deduzca de mi cuenta bancaria. + Estoy de acuerdo en que se deduzca la siguiente cantidad de mi cuenta bancaria: %s. + Continuar Confirmar y pagar \ No newline at end of file diff --git a/bacs/src/main/res/values-fi-rFI/strings.xml b/bacs/src/main/res/values-fi-rFI/strings.xml index 8defd6c2ba..7ece4bb135 100644 --- a/bacs/src/main/res/values-fi-rFI/strings.xml +++ b/bacs/src/main/res/values-fi-rFI/strings.xml @@ -17,6 +17,10 @@ Ei-kelvollinen lajittelukoodi Ei-kelvollinen sähköpostiosoite + Vahvistan, että tili on nimessäni ja olen ainoa allekirjoittaja, joka vaaditaan valtuuttamaan suoraveloitus tällä tilillä. + Hyväksyn, että alla oleva summa veloitetaan pankkitililtäni. + Hyväksyn, että %s veloitetaan pankkitililtäni. + Jatka Vahvista ja maksa \ No newline at end of file diff --git a/bacs/src/main/res/values-fr-rFR/strings.xml b/bacs/src/main/res/values-fr-rFR/strings.xml index 1574d832fd..1c5af7ec52 100644 --- a/bacs/src/main/res/values-fr-rFR/strings.xml +++ b/bacs/src/main/res/values-fr-rFR/strings.xml @@ -17,6 +17,10 @@ Code de tri (sort code) non valide Adresse e-mail incorrecte + Je confirme être le titulaire du compte et qu\'aucune autre signature que la mienne n\'est requise pour autoriser un prélèvement sur ce compte. + J\'accepte que le montant ci-dessus soit déduit de mon compte bancaire. + J\'accepte que le montant de %s soit prélevé sur mon compte bancaire. + Continuer Confirmer et payer \ No newline at end of file diff --git a/bacs/src/main/res/values-hr-rHR/strings.xml b/bacs/src/main/res/values-hr-rHR/strings.xml index 973bdd005d..06c099cba1 100644 --- a/bacs/src/main/res/values-hr-rHR/strings.xml +++ b/bacs/src/main/res/values-hr-rHR/strings.xml @@ -17,6 +17,10 @@ Nevažeći identifikacijski kôd banke (UK) Nevažeća adresa e-pošte + Potvrđujem da je račun na moje ime i da sam jedini potpisnik potreban za autorizaciju izravnog terećenja na ovom računu. + Slažem se da se gore navedeni iznos oduzme s mog bankovnog računa. + Slažem se da će moj bankovni račun biti terećen za %s. + Nastavi Potvrdi i plati \ No newline at end of file diff --git a/bacs/src/main/res/values-hu-rHU/strings.xml b/bacs/src/main/res/values-hu-rHU/strings.xml index 6c62ba1be6..a28c2951df 100644 --- a/bacs/src/main/res/values-hu-rHU/strings.xml +++ b/bacs/src/main/res/values-hu-rHU/strings.xml @@ -17,6 +17,10 @@ Érvénytelen banki azonosító Érvénytelen e-mail-cím + Megerősítem, hogy a bankszámla az én nevemen van, és én vagyok a bankszámlát érintő beszedési megbízás jóváhagyásához szükséges egyetlen aláíró. + Elfogadom, hogy a fenti összeget levonják a bankszámlámról. + Elfogadom, hogy %s levonásra kerüljön a bankszámlámról. + Folytatás Megerősítés és fizetés \ No newline at end of file diff --git a/bacs/src/main/res/values-it-rIT/strings.xml b/bacs/src/main/res/values-it-rIT/strings.xml index ef9335182f..54c98c2c60 100644 --- a/bacs/src/main/res/values-it-rIT/strings.xml +++ b/bacs/src/main/res/values-it-rIT/strings.xml @@ -17,6 +17,10 @@ Sort code non valido Indirizzo e-mail non valido + Confermo che il conto è intestato al sottoscritto e che sono l\'unico firmatario a dover autorizzare l\'addebito diretto su questo conto. + Accetto che l\'importo sopra indicato venga detratto dal mio conto bancario. + Accetto che l\'importo di %s venga detratto dal mio conto bancario. + Continua Conferma e paga \ No newline at end of file diff --git a/bacs/src/main/res/values-ja-rJP/strings.xml b/bacs/src/main/res/values-ja-rJP/strings.xml index 845f87f93a..092ea20c71 100644 --- a/bacs/src/main/res/values-ja-rJP/strings.xml +++ b/bacs/src/main/res/values-ja-rJP/strings.xml @@ -17,6 +17,10 @@ ソートコードが無効です Eメールアドレスが無効です + 口座が私の名義であることを確認し、この口座からの自動引き落としを承認するために必要な唯一の署名者であることを確認します。 + 上記の金額が私の銀行口座から引き落とされることに同意します。 + %sが私の銀行口座から引き落とされることに同意します。 + 続ける 確認して支払う \ No newline at end of file diff --git a/bacs/src/main/res/values-ko-rKR/strings.xml b/bacs/src/main/res/values-ko-rKR/strings.xml index d13401d92c..5d3e84e7e1 100644 --- a/bacs/src/main/res/values-ko-rKR/strings.xml +++ b/bacs/src/main/res/values-ko-rKR/strings.xml @@ -17,6 +17,10 @@ 은행 식별 코드가 유효하지 않습니다 유효하지 않은 이메일 주소 + 본인이 이 계좌의 예금주이며, 이 계좌에서의 자동 이체를 승인하기 위해 필요한 유일한 서명인입니다. + 계좌에서 위의 금액을 이체하는 것에 동의합니다. + 은행 계좌에서 %s이(가) 출금되는 것에 동의합니다. + 계속 확인 및 결제 \ No newline at end of file diff --git a/bacs/src/main/res/values-nb-rNO/strings.xml b/bacs/src/main/res/values-nb-rNO/strings.xml index 8b1ad8311e..0fdfb33d4a 100644 --- a/bacs/src/main/res/values-nb-rNO/strings.xml +++ b/bacs/src/main/res/values-nb-rNO/strings.xml @@ -17,6 +17,10 @@ Ugyldig sorteringskode Ugyldig e-postadresse + Jeg bekrefter at kontoen står i mitt navn, og at jeg er den eneste signataren som kreves for å autorisere direktebelastningen på denne kontoen. + Jeg samtykker til at beløpet ovenfor blir trukket fra bankkontoen min. + Jeg godtar at %s blir trukket fra kontoen min. + Fortsett Bekreft og betal \ No newline at end of file diff --git a/bacs/src/main/res/values-nl-rNL/strings.xml b/bacs/src/main/res/values-nl-rNL/strings.xml index e1eeb05ee6..d0987317ea 100644 --- a/bacs/src/main/res/values-nl-rNL/strings.xml +++ b/bacs/src/main/res/values-nl-rNL/strings.xml @@ -17,6 +17,10 @@ Ongeldige bankcode Ongeldig e-mailadres + Ik bevestig dat de rekening op mijn naam staat en dat ik de enige ondertekenaar ben die toestemming kan geven voor automatische incasso\'s vanaf deze rekening. + Ik ga ermee akkoord dat het bovengenoemde bedrag van mijn bankrekening wordt afgeschreven. + Ik ga ermee akkoord dat er %s van mijn bankrekening wordt afgeschreven. + Doorgaan Bevestigen en betalen \ No newline at end of file diff --git a/bacs/src/main/res/values-pl-rPL/strings.xml b/bacs/src/main/res/values-pl-rPL/strings.xml index 9108f0461d..6ddb6a0fe8 100644 --- a/bacs/src/main/res/values-pl-rPL/strings.xml +++ b/bacs/src/main/res/values-pl-rPL/strings.xml @@ -17,6 +17,10 @@ Nieprawidłowy numer rozliczeniowy SORT Niepoprawny adres email + Potwierdzam, że konto jest zarejestrowane na moje nazwisko i jestem jedynym sygnatariuszem wymaganym do autoryzacji polecenia zapłaty na tym koncie. + Wyrażam zgodę na pobranie powyższej kwoty z mojego rachunku bankowego. + Wyrażam zgodę na pobranie kwoty %s z mojego rachunku bankowego. + Kontynuuj Potwierdź i zapłać \ No newline at end of file diff --git a/bacs/src/main/res/values-pt-rBR/strings.xml b/bacs/src/main/res/values-pt-rBR/strings.xml index 63a220928c..19380e8ead 100644 --- a/bacs/src/main/res/values-pt-rBR/strings.xml +++ b/bacs/src/main/res/values-pt-rBR/strings.xml @@ -17,6 +17,10 @@ Código de classificação inválido Endereço de e-mail inválido + Confirmo que a conta está em meu nome e que sou o único signatário que deve autorizar o débito direto nessa conta. + Concordo que o valor acima seja deduzido da minha conta bancária. + Concordo que o valor de %s seja deduzido da minha conta bancária. + Continuar Confirmar e pagar \ No newline at end of file diff --git a/bacs/src/main/res/values-ro-rRO/strings.xml b/bacs/src/main/res/values-ro-rRO/strings.xml index 5b7b3a80ec..ceac883863 100644 --- a/bacs/src/main/res/values-ro-rRO/strings.xml +++ b/bacs/src/main/res/values-ro-rRO/strings.xml @@ -17,6 +17,10 @@ Cod de identificare bancară incorect Adresă de e-mail incorectă + Confirm că sunt titularul acestui cont și că sunt singurul semnatar necesar pentru autorizarea debitului direct pentru acest cont. + Sunt de acord ca suma menționată mai sus să fie dedusă din contul meu bancar. + Sunt de acord să se deducă %s din contul meu bancar. + Continuare Confirmați și plătiți \ No newline at end of file diff --git a/bacs/src/main/res/values-ru-rRU/strings.xml b/bacs/src/main/res/values-ru-rRU/strings.xml index 5ceedafbab..83996ecb14 100644 --- a/bacs/src/main/res/values-ru-rRU/strings.xml +++ b/bacs/src/main/res/values-ru-rRU/strings.xml @@ -17,6 +17,10 @@ Неверный код банка Недействительный адрес эл. почты + Подтверждаю, что счет оформлен на мое имя и что я – единственное лицо, имеющее право подписи, разрешающей прямое дебетование средств со счета. + Выражаю согласие на списание вышеуказанной суммы с моего банковского счета. + Выражаю согласие на списание %s с моего банковского счета. + Продолжить Подтвердить и оплатить \ No newline at end of file diff --git a/bacs/src/main/res/values-sk-rSK/strings.xml b/bacs/src/main/res/values-sk-rSK/strings.xml index 84047e0d48..56cbad8cc7 100644 --- a/bacs/src/main/res/values-sk-rSK/strings.xml +++ b/bacs/src/main/res/values-sk-rSK/strings.xml @@ -17,6 +17,10 @@ Neplatný variabilný symbol Neplatná emailová adresa + Potvrdzujem, že účet je na moje meno a som jediný podpisovateľ, ktorý je povinný autorizovať inkaso v tomto účte. + Súhlasím s tým, že nižšie uvedená čiastka bude odpísaná z môjho bankového účtu. + Súhlasím s úhradou čiastky %s z môjho bankového účtu. + Pokračovať Potvrdiť a zaplatiť \ No newline at end of file diff --git a/bacs/src/main/res/values-sl-rSI/strings.xml b/bacs/src/main/res/values-sl-rSI/strings.xml index ef13a8c0b9..51c9afa057 100644 --- a/bacs/src/main/res/values-sl-rSI/strings.xml +++ b/bacs/src/main/res/values-sl-rSI/strings.xml @@ -17,6 +17,10 @@ Neveljavna številka banke Neveljaven elektronski naslov + Potrjujem, da je račun ustvarjen v mojem imenu in sem edini podpisnik za odobritev neposredne bremenitve za ta račun. + Soglašam s tem, da bo zgornji znesek odtegnjen z mojega bančnega računa. + Soglašam, da bo znesek %s odtegnjen z mojega bančnega računa. + Nadaljuj Potrdi in plačaj \ No newline at end of file diff --git a/bacs/src/main/res/values-sv-rSE/strings.xml b/bacs/src/main/res/values-sv-rSE/strings.xml index 5ac5b970ae..f4b7e58801 100644 --- a/bacs/src/main/res/values-sv-rSE/strings.xml +++ b/bacs/src/main/res/values-sv-rSE/strings.xml @@ -17,6 +17,10 @@ Ogiltigt clearingnummer Ogiltig e-postadress + Jag bekräftar att jag är kontoinnehavare och att jag är den enda person vars godkännande krävs för att auktorisera autogiro från detta konto. + Jag godkänner att ovanstående belopp dras från mitt bankkonto. + Jag godkänner att %s kommer att dras från mitt bankkonto. + Fortsätt Bekräfta och betala \ No newline at end of file diff --git a/bacs/src/main/res/values-zh-rCN/strings.xml b/bacs/src/main/res/values-zh-rCN/strings.xml index 32c9a2e30f..83986331d2 100644 --- a/bacs/src/main/res/values-zh-rCN/strings.xml +++ b/bacs/src/main/res/values-zh-rCN/strings.xml @@ -17,6 +17,10 @@ 无效的分类代码 无效的邮件地址 + 我确认该账户为我名下的账户,并且我是授权该账户直接借记的唯一签署人。 + 我同意从银行账户中扣除上述金额。 + 我同意从我的银行账户中扣除以下金额:%s。 + 继续 确认并支付 \ No newline at end of file diff --git a/bacs/src/main/res/values-zh-rTW/strings.xml b/bacs/src/main/res/values-zh-rTW/strings.xml index 7f09205ee9..04abb5ff67 100644 --- a/bacs/src/main/res/values-zh-rTW/strings.xml +++ b/bacs/src/main/res/values-zh-rTW/strings.xml @@ -17,6 +17,10 @@ 銀行代碼無效 電子郵件地址無效 + 我確認該帳戶以我的名義開設,並且我是授權從該帳戶直接扣款的唯一簽署人。 + 我同意從我的銀行帳戶扣除上述金額。 + 我同意從我的銀行帳戶扣除 %s。 + 繼續 確認並支付 \ No newline at end of file diff --git a/bacs/src/main/res/values/strings.xml b/bacs/src/main/res/values/strings.xml index 15e11311e3..bb0eea3246 100644 --- a/bacs/src/main/res/values/strings.xml +++ b/bacs/src/main/res/values/strings.xml @@ -17,6 +17,10 @@ Invalid sort code Invalid email address + I confirm the account is in my name and I am the only signatory required to authorise the Direct Debit on this account. + I agree that the above amount will be deducted from my bank account. + I agree that %s will be deducted from my bank account. + Continue Confirm and pay \ No newline at end of file diff --git a/bacs/src/main/res/values/styles.xml b/bacs/src/main/res/values/styles.xml index d3f6852e4b..0e0e5b7358 100644 --- a/bacs/src/main/res/values/styles.xml +++ b/bacs/src/main/res/values/styles.xml @@ -31,13 +31,11 @@ textEmailAddress - - \ No newline at end of file From 6f7cff5fd69739bd10a88e128988ceda40f58b91 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 14 Dec 2021 11:22:48 +0100 Subject: [PATCH 094/102] Voucher: Remove unused field paymentMethodType --- .../src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt index eaa9d25505..bfb473faeb 100644 --- a/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt +++ b/voucher/src/main/java/com/adyen/checkout/voucher/VoucherComponent.kt @@ -32,7 +32,6 @@ class VoucherComponent( private val mOutputLiveData = MutableLiveData() private var url: String? = null - private var paymentMethodType: String? = null override fun canHandleAction(action: Action): Boolean { return PROVIDER.canHandleAction(action) From 165801d1eaea558b1869127b7d281c45bc93818e Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 14 Dec 2021 11:45:13 +0100 Subject: [PATCH 095/102] BACS: Update input data when input view gets recreated --- .../adyen/checkout/bacs/BacsDirectDebitInputView.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt index 57ca2c6ae7..aac334a87a 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitInputView.kt @@ -45,6 +45,8 @@ class BacsDirectDebitInputView @JvmOverloads constructor(context: Context, attrs override fun onComponentAttached() { component.outputData?.let { + updateInputData(it) + binding.editTextHolderName.setText(it.holderNameState.value) binding.editTextBankAccountNumber.setText(it.bankAccountNumberState.value) binding.editTextSortCode.setText(it.sortCodeState.value) @@ -225,6 +227,17 @@ class BacsDirectDebitInputView @JvmOverloads constructor(context: Context, attrs } } + private fun updateInputData(outputData: BacsDirectDebitOutputData) { + mBacsDirectDebitInputData.apply { + holderName = outputData.holderNameState.value + bankAccountNumber = outputData.bankAccountNumberState.value + sortCode = outputData.sortCodeState.value + shopperEmail = outputData.shopperEmailState.value + isAccountConsentChecked = outputData.isAccountConsentChecked + isAmountConsentChecked = outputData.isAmountConsentChecked + } + } + private fun onBankAccountNumberValidated(bankAccountNumberFieldState: FieldState) { if (bankAccountNumberFieldState.validation.isValid()) { goToNextInputIfFocus(binding.editTextBankAccountNumber) From 575cc992ab8f341f3c95768c72cbdcdb117e6577 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 14 Dec 2021 13:42:26 +0100 Subject: [PATCH 096/102] BACS: Hide bottom sheet indicator --- .../main/res/layout/fragment_bacs_direct_debit_component.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml index 91a277f539..c1c48d730c 100644 --- a/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml +++ b/drop-in/src/main/res/layout/fragment_bacs_direct_debit_component.xml @@ -13,11 +13,6 @@ android:orientation="vertical" android:paddingBottom="@dimen/standard_margin"> - - Date: Thu, 16 Dec 2021 13:14:10 +0100 Subject: [PATCH 097/102] BACS: Code fixes --- .../checkout/bacs/BacsDirectDebitComponent.kt | 8 ++++---- .../checkout/dropin/ComponentParsingProvider.kt | 14 +++++++------- .../com/adyen/checkout/dropin/ui/DropInActivity.kt | 1 - 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt index 359129c811..4039e8d0f4 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/BacsDirectDebitComponent.kt @@ -55,10 +55,10 @@ class BacsDirectDebitComponent( } return BacsDirectDebitComponentState( - paymentComponentData, - outputData?.isValid ?: false, - true, - mLatestInputData?.mode ?: BacsDirectDebitMode.INPUT + paymentComponentData = paymentComponentData, + isInputValid = outputData?.isValid ?: false, + isReady = true, + mode = mLatestInputData?.mode ?: BacsDirectDebitMode.INPUT ) } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt index 151629999f..78395baccf 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ComponentParsingProvider.kt @@ -106,6 +106,9 @@ internal fun getDefaultConfigForPaymentMethod( // get default builder for Configuration type val builder: BaseConfigurationBuilder = when (paymentMethod) { + PaymentMethodTypes.BACS -> BacsDirectDebitConfiguration.Builder(shopperLocale, environment, clientKey).apply { + if (!dropInConfiguration.amount.isEmpty) setAmount(dropInConfiguration.amount) + } PaymentMethodTypes.BCMC -> BcmcConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.BLIK -> BlikConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.DOTPAY -> DotpayConfiguration.Builder(shopperLocale, environment, clientKey) @@ -125,9 +128,6 @@ internal fun getDefaultConfigForPaymentMethod( PaymentMethodTypes.MOLPAY_VIETNAM -> MolpayConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.OPEN_BANKING -> OpenBankingConfiguration.Builder(shopperLocale, environment, clientKey) PaymentMethodTypes.SEPA -> SepaConfiguration.Builder(shopperLocale, environment, clientKey) - PaymentMethodTypes.BACS -> BacsDirectDebitConfiguration.Builder(shopperLocale, environment, clientKey).apply { - if (!dropInConfiguration.amount.isEmpty) setAmount(dropInConfiguration.amount) - } PaymentMethodTypes.SCHEME -> CardConfiguration.Builder(shopperLocale, environment, clientKey) else -> throw CheckoutException("Unable to find component configuration for paymentMethod - $paymentMethod") } @@ -238,6 +238,10 @@ internal fun getComponentFor( ): PaymentComponent, Configuration> { val component = when (paymentMethod.type) { + PaymentMethodTypes.BACS -> { + val bacsConfiguration: BacsDirectDebitConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.BACS) + BacsDirectDebitComponent.PROVIDER.get(fragment, paymentMethod, bacsConfiguration) + } PaymentMethodTypes.BCMC -> { val bcmcConfiguration: BcmcConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.BCMC) BcmcComponent.PROVIDER.get(fragment, paymentMethod, bcmcConfiguration) @@ -304,10 +308,6 @@ internal fun getComponentFor( val sepaConfiguration: SepaConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.SEPA) SepaComponent.PROVIDER.get(fragment, paymentMethod, sepaConfiguration) } - PaymentMethodTypes.BACS -> { - val bacsConfiguration: BacsDirectDebitConfiguration = dropInConfiguration.getConfigurationForPaymentMethod(PaymentMethodTypes.BACS) - BacsDirectDebitComponent.PROVIDER.get(fragment, paymentMethod, bacsConfiguration) - } else -> { throw CheckoutException("Unable to find component for type - ${paymentMethod.type}") } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt index 622a04c004..d9df20a854 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/DropInActivity.kt @@ -354,7 +354,6 @@ class DropInActivity : AppCompatActivity(), DropInBottomSheetDialogFragment.Prot hideAllScreens() val dialogFragment = when (storedPaymentMethod.type) { PaymentMethodTypes.SCHEME -> CardComponentDialogFragment - PaymentMethodTypes.BACS -> BacsDirectDebitDialogFragment else -> GenericComponentDialogFragment }.newInstance(storedPaymentMethod, dropInViewModel.dropInConfiguration, fromPreselected) From 5140ebf70eccb7954d046041ea005ed7f60850b0 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 16 Dec 2021 13:25:39 +0100 Subject: [PATCH 098/102] BACS: Fix state not being preserved on rotation --- .../ui/component/BacsDirectDebitDialogFragment.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt index ebc364bd24..2772832940 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/component/BacsDirectDebitDialogFragment.kt @@ -57,16 +57,20 @@ class BacsDirectDebitDialogFragment : BaseComponentDialogFragment() { component.observe(viewLifecycleOwner, this) bacsDirectDebitComponent.observeErrors(viewLifecycleOwner, createErrorHandlerObserver()) - val bacsDirectDebitInputView = BacsDirectDebitInputView(requireContext()) - binding.viewContainer.addView(bacsDirectDebitInputView) - bacsDirectDebitInputView.attach(bacsDirectDebitComponent, viewLifecycleOwner) + val bacsView = when ((bacsDirectDebitComponent.state as? BacsDirectDebitComponentState)?.mode) { + BacsDirectDebitMode.CONFIRMATION -> BacsDirectDebitConfirmationView(requireContext()) + else -> BacsDirectDebitInputView(requireContext()) + } + + binding.viewContainer.addView(bacsView) + bacsView.attach(bacsDirectDebitComponent, viewLifecycleOwner) - if (bacsDirectDebitInputView.isConfirmationRequired) { + if (bacsView.isConfirmationRequired) { binding.payButton.setOnClickListener { handleContinueClick() } setInitViewState(BottomSheetBehavior.STATE_EXPANDED) - bacsDirectDebitInputView.requestFocus() + bacsView.requestFocus() } else { binding.payButton.isVisible = false } From 15a395d17015e4196da2a3984ce31c80c785012d Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 20 Dec 2021 10:08:24 +0100 Subject: [PATCH 099/102] DropIn: Finish drop in with action if action component does not provide details --- .../action/ActionComponentDialogFragment.kt | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt index ebd75f252e..f337a88005 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/ui/action/ActionComponentDialogFragment.kt @@ -82,8 +82,7 @@ class ActionComponentDialogFragment : DropInBottomSheetDialogFragment(), Observe actionComponent = getComponent(action) attachComponent(actionComponent, componentView) - val shouldShowFinishButton = getActionProviderFor(action)?.providesDetails() == false - if (shouldShowFinishButton) { + if (shouldFinishWithAction()) { with(binding.buttonFinish) { isVisible = true setOnClickListener { protocol.finishWithAction() } @@ -102,14 +101,23 @@ class ActionComponentDialogFragment : DropInBottomSheetDialogFragment(), Observe } override fun onBackPressed(): Boolean { - protocol.terminateDropIn() + // polling will be canceled by lifecycle event + when { + shouldFinishWithAction() -> { protocol.finishWithAction() } + dropInViewModel.shouldSkipToSinglePaymentMethod() -> { protocol.terminateDropIn() } + else -> { protocol.showPaymentMethodsDialog() } + } return true } override fun onCancel(dialog: DialogInterface) { super.onCancel(dialog) Logger.d(TAG, "onCancel") - protocol.terminateDropIn() + if (shouldFinishWithAction()) { + protocol.finishWithAction() + } else { + protocol.terminateDropIn() + } } override fun onChanged(actionComponentData: ActionComponentData?) { @@ -165,4 +173,8 @@ class ActionComponentDialogFragment : DropInBottomSheetDialogFragment(), Observe Logger.e(TAG, componentError.errorMessage) protocol.showError(getString(R.string.action_failed), componentError.errorMessage, true) } + + private fun shouldFinishWithAction(): Boolean { + return getActionProviderFor(action)?.providesDetails() == false + } } From 97dee1888a5052d20c53e5e2878ec6025fe1392a Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 20 Dec 2021 12:16:15 +0100 Subject: [PATCH 100/102] Release 4.4.0 --- README.md | 4 ++-- RELEASE_NOTES.md | 20 ++------------------ build.gradle | 2 +- example-app/build.gradle | 2 +- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index d52598a146..70cd571d97 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,11 @@ If you are upgrading from 3.x.x to a current release, check out our [migration g Import the Component module for the Payment Method you want to use by adding it to your `build.gradle` file. For example, for the Drop-in solution you should add: ```groovy -implementation "com.adyen.checkout:drop-in:4.3.0" +implementation "com.adyen.checkout:drop-in:4.4.0" ``` For a Credit Card component you should add: ```groovy -implementation "com.adyen.checkout:card:4.3.0" +implementation "com.adyen.checkout:card:4.4.0" ``` ### Client Key diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 1d8be83e08..7402690cd1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -8,24 +8,8 @@ [//]: # ( # Deprecated) [//]: # ( - Configurations public constructor are deprecated, please use each Configuration's builder to make a Configuration object) -## WARNING -Make sure you explicitly set your LIVE environment on release builds when initializing Drop-in; `DropInConfiguration` is now initialized with `Environment.TEST` by default instead of `Environment.EUROPE`. - -## Deprecated -- `saveState` and `restoreState` methods in action components. We rely on `SavedStateHandle` in all components and providers so these methods can be safely removed now. -- `requiresConfiguration` method in action component providers. All components require configurations therefore this method will always return true. - ## Added -- Card component shows a more specific error message when the user enters a card belonging to an unsupported brand. -- `DropInConfiguration.Builder.setSkipListWhenSinglePaymentMethod` to allow skipping payment methods screen when single payment method exists. This only applies to payment methods that require a component (user input). Redirect payment methods, SDK payment methods, and so on will not be skipped. -- Provide `fundingSource` when present in payment methods response. -- Support for installments in card component. -- `Environment.LIVE`, identical to the `Environment.EUROPE`. - -## Changed -- Update 3DS2 SDK to version `2.2.5`. +- BACS Direct Debit Component. ## Fixed -- Use `ApplicationInfo.FLAG_DEBUGGABLE` instead of `BuildConfig.DEBUG` to figure out whether it's a debug or release build. -- `NoClassDefFoundError` crash with Card component, if 3DS2 is not included in the project. -- Handle Google Pay cancellation and failure callbacks on initialisation. +- Google Pay Environment being set incorrectly to `WalletConstants.ENVIRONMENT_PRODUCTION`. diff --git a/build.gradle b/build.gradle index bb8ad4f870..3336010b42 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ allprojects { // just for example app, don't need to increment ext.version_code = 1 // The version_name format is "major.minor.patch(-(alpha|beta|rc)[0-9]{2}){0,1}" (e.g. 3.0.0, 3.1.1-alpha04 or 3.1.4-rc01 etc). - ext.version_name = "4.3.0" + ext.version_name = "4.4.0" // Code quality ext.ktlint_version = '0.40.0' diff --git a/example-app/build.gradle b/example-app/build.gradle index 8cbdbb6b1d..51e062f0c7 100644 --- a/example-app/build.gradle +++ b/example-app/build.gradle @@ -74,7 +74,7 @@ android { dependencies { // Checkout implementation project(':drop-in') -// implementation "com.adyen.checkout:drop-in:4.3.0" +// implementation "com.adyen.checkout:drop-in:4.4.0" // Dependencies implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinx_version" From 9a5921b702ab4dd9c03b5bced4a995bba7007b77 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 20 Dec 2021 13:25:42 +0100 Subject: [PATCH 101/102] Update release notes --- RELEASE_NOTES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7402690cd1..7f93a6c7d7 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -13,3 +13,6 @@ ## Fixed - Google Pay Environment being set incorrectly to `WalletConstants.ENVIRONMENT_PRODUCTION`. + +##Deprecated +- `DropInServiceResult.Action(actionJSON: String)` is deprecated in favor of `DropInServiceResult.Action(action: com.adyen.checkout.components.model.payments.response.Action)`. Use `com.adyen.checkout.components.model.payments.response.Action.SERIALIZER` to serialize your JSON response string. \ No newline at end of file From e77323ba72a0b03f7a4880a5674b74759654f583 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 20 Dec 2021 13:49:13 +0100 Subject: [PATCH 102/102] Fix release notes --- RELEASE_NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7f93a6c7d7..f06213e1ad 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -14,5 +14,5 @@ ## Fixed - Google Pay Environment being set incorrectly to `WalletConstants.ENVIRONMENT_PRODUCTION`. -##Deprecated +## Deprecated - `DropInServiceResult.Action(actionJSON: String)` is deprecated in favor of `DropInServiceResult.Action(action: com.adyen.checkout.components.model.payments.response.Action)`. Use `com.adyen.checkout.components.model.payments.response.Action.SERIALIZER` to serialize your JSON response string. \ No newline at end of file