Skip to content

Commit

Permalink
Merge pull request #1331 from Adyen/refactor/bcmc
Browse files Browse the repository at this point in the history
Refactor BCMC
  • Loading branch information
ozgur00 authored Nov 10, 2023
2 parents bb39b78 + 8e12f47 commit d6bf88c
Show file tree
Hide file tree
Showing 43 changed files with 473 additions and 1,422 deletions.
90 changes: 10 additions & 80 deletions bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponent.kt
Original file line number Diff line number Diff line change
@@ -1,106 +1,36 @@
/*
* Copyright (c) 2019 Adyen N.V.
* Copyright (c) 2023 Adyen N.V.
*
* This file is open source and available under the MIT license. See the LICENSE file for more info.
*
* Created by arman on 18/9/2019.
* Created by ozgur on 22/8/2023.
*/

package com.adyen.checkout.bcmc

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.adyen.checkout.action.core.internal.ActionHandlingComponent
import com.adyen.checkout.action.core.internal.DefaultActionHandlingComponent
import com.adyen.checkout.action.core.internal.ui.GenericActionDelegate
import com.adyen.checkout.bcmc.internal.provider.BcmcComponentProvider
import com.adyen.checkout.bcmc.internal.ui.BcmcDelegate
import com.adyen.checkout.card.CardBrand
import com.adyen.checkout.card.CardType
import com.adyen.checkout.card.CardComponent
import com.adyen.checkout.card.internal.ui.CardDelegate
import com.adyen.checkout.components.core.PaymentMethodTypes
import com.adyen.checkout.components.core.internal.ButtonComponent
import com.adyen.checkout.components.core.internal.ComponentEventHandler
import com.adyen.checkout.components.core.internal.PaymentComponent
import com.adyen.checkout.components.core.internal.PaymentComponentEvent
import com.adyen.checkout.components.core.internal.toActionCallback
import com.adyen.checkout.components.core.internal.ui.ComponentDelegate
import com.adyen.checkout.core.internal.util.LogUtil
import com.adyen.checkout.core.internal.util.Logger
import com.adyen.checkout.ui.core.internal.ui.ButtonDelegate
import com.adyen.checkout.ui.core.internal.ui.ComponentViewType
import com.adyen.checkout.ui.core.internal.ui.ViewableComponent
import com.adyen.checkout.ui.core.internal.util.mergeViewFlows
import kotlinx.coroutines.flow.Flow

/**
* A [PaymentComponent] that supports the [PaymentMethodTypes.BCMC] payment method.
*/
class BcmcComponent internal constructor(
private val bcmcDelegate: BcmcDelegate,
private val genericActionDelegate: GenericActionDelegate,
private val actionHandlingComponent: DefaultActionHandlingComponent,
class BcmcComponent(
cardDelegate: CardDelegate,
genericActionDelegate: GenericActionDelegate,
actionHandlingComponent: DefaultActionHandlingComponent,
internal val componentEventHandler: ComponentEventHandler<BcmcComponentState>,
) : ViewModel(),
PaymentComponent,
ViewableComponent,
ButtonComponent,
ActionHandlingComponent by actionHandlingComponent {

override val delegate: ComponentDelegate get() = actionHandlingComponent.activeDelegate

override val viewFlow: Flow<ComponentViewType?> = mergeViewFlows(
viewModelScope,
bcmcDelegate.viewFlow,
genericActionDelegate.viewFlow,
)

init {
bcmcDelegate.initialize(viewModelScope)
genericActionDelegate.initialize(viewModelScope)
componentEventHandler.initialize(viewModelScope)
}

internal fun observe(
lifecycleOwner: LifecycleOwner,
callback: (PaymentComponentEvent<BcmcComponentState>) -> Unit
) {
bcmcDelegate.observe(lifecycleOwner, viewModelScope, callback)
genericActionDelegate.observe(lifecycleOwner, viewModelScope, callback.toActionCallback())
}

internal fun removeObserver() {
bcmcDelegate.removeObserver()
genericActionDelegate.removeObserver()
}

override fun isConfirmationRequired(): Boolean = bcmcDelegate.isConfirmationRequired()

override fun submit() {
(delegate as? ButtonDelegate)?.onSubmit() ?: Logger.e(TAG, "Component is currently not submittable, ignoring.")
}

override fun setInteractionBlocked(isInteractionBlocked: Boolean) {
(delegate as? BcmcDelegate)?.setInteractionBlocked(isInteractionBlocked)
?: Logger.e(TAG, "Payment component is not interactable, ignoring.")
}

override fun onCleared() {
super.onCleared()
Logger.d(TAG, "onCleared")
bcmcDelegate.onCleared()
genericActionDelegate.onCleared()
componentEventHandler.onCleared()
}

) : CardComponent(cardDelegate, genericActionDelegate, actionHandlingComponent, componentEventHandler) {
companion object {
private val TAG = LogUtil.getTag()

@JvmField
val PROVIDER = BcmcComponentProvider()

@JvmField
val PAYMENT_METHOD_TYPES = listOf(PaymentMethodTypes.BCMC)

internal val SUPPORTED_CARD_TYPE = CardBrand(cardType = CardType.BCMC)
}
}
15 changes: 3 additions & 12 deletions bcmc/src/main/java/com/adyen/checkout/bcmc/BcmcComponentState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,11 @@
*
* This file is open source and available under the MIT license. See the LICENSE file for more info.
*
* Created by ozgur on 20/2/2023.
* Created by ozgur on 27/9/2023.
*/

package com.adyen.checkout.bcmc

import com.adyen.checkout.components.core.PaymentComponentData
import com.adyen.checkout.components.core.PaymentComponentState
import com.adyen.checkout.components.core.paymentmethod.CardPaymentMethod
import com.adyen.checkout.card.CardComponentState

/**
* Represents the state of [BcmcComponent].
*/
data class BcmcComponentState(
override val data: PaymentComponentData<CardPaymentMethod>,
override val isInputValid: Boolean,
override val isReady: Boolean
) : PaymentComponentState<CardPaymentMethod>
typealias BcmcComponentState = CardComponentState
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
* Copyright (c) 2019 Adyen N.V.
* Copyright (c) 2023 Adyen N.V.
*
* This file is open source and available under the MIT license. See the LICENSE file for more info.
*
* Created by arman on 18/9/2019.
* Created by ozgur on 22/8/2023.
*/

package com.adyen.checkout.bcmc.internal.provider
Expand All @@ -19,9 +19,11 @@ import com.adyen.checkout.action.core.internal.provider.GenericActionComponentPr
import com.adyen.checkout.bcmc.BcmcComponent
import com.adyen.checkout.bcmc.BcmcComponentState
import com.adyen.checkout.bcmc.BcmcConfiguration
import com.adyen.checkout.bcmc.internal.ui.DefaultBcmcDelegate
import com.adyen.checkout.bcmc.internal.ui.model.BcmcComponentParamsMapper
import com.adyen.checkout.card.internal.data.api.BinLookupService
import com.adyen.checkout.card.internal.data.api.DefaultDetectCardTypeRepository
import com.adyen.checkout.card.internal.ui.CardValidationMapper
import com.adyen.checkout.card.internal.ui.DefaultCardDelegate
import com.adyen.checkout.components.core.ComponentCallback
import com.adyen.checkout.components.core.Order
import com.adyen.checkout.components.core.PaymentMethod
Expand Down Expand Up @@ -54,6 +56,8 @@ import com.adyen.checkout.sessions.core.internal.data.api.SessionRepository
import com.adyen.checkout.sessions.core.internal.data.api.SessionService
import com.adyen.checkout.sessions.core.internal.provider.SessionPaymentComponentProvider
import com.adyen.checkout.sessions.core.internal.ui.model.SessionParamsFactory
import com.adyen.checkout.ui.core.internal.data.api.AddressService
import com.adyen.checkout.ui.core.internal.data.api.DefaultAddressRepository
import com.adyen.checkout.ui.core.internal.ui.SubmitHandler

class BcmcComponentProvider
Expand All @@ -78,6 +82,7 @@ constructor(

private val componentParamsMapper = BcmcComponentParamsMapper(overrideComponentParams, overrideSessionParams)

@Suppress("LongMethod")
override fun get(
savedStateRegistryOwner: SavedStateRegistryOwner,
viewModelStoreOwner: ViewModelStoreOwner,
Expand All @@ -90,39 +95,45 @@ constructor(
key: String?,
): BcmcComponent {
assertSupported(paymentMethod)
val bcmcFactory = viewModelFactory(savedStateRegistryOwner, null) { savedStateHandle ->
val componentParams = componentParamsMapper.mapToParams(configuration, null, paymentMethod)
val httpClient = HttpClientFactory.getHttpClient(componentParams.environment)
val publicKeyService = PublicKeyService(httpClient)
val publicKeyRepository = DefaultPublicKeyRepository(publicKeyService)
val cardValidationMapper = CardValidationMapper()
val dateGenerator = DateGenerator()
val clientSideEncrypter = ClientSideEncrypter()
val genericEncrypter = DefaultGenericEncrypter(clientSideEncrypter, dateGenerator)
val cardEncrypter = DefaultCardEncrypter(genericEncrypter)
val addressService = AddressService(httpClient)
val addressRepository = DefaultAddressRepository(addressService)
val binLookupService = BinLookupService(httpClient)
val detectCardTypeRepository = DefaultDetectCardTypeRepository(cardEncrypter, binLookupService)

val componentParams = componentParamsMapper.mapToParams(configuration, null)
val httpClient = HttpClientFactory.getHttpClient(componentParams.environment)
val publicKeyService = PublicKeyService(httpClient)
val publicKeyRepository = DefaultPublicKeyRepository(publicKeyService)
val cardValidationMapper = CardValidationMapper()
val dateGenerator = DateGenerator()
val clientSideEncrypter = ClientSideEncrypter()
val genericEncrypter = DefaultGenericEncrypter(clientSideEncrypter, dateGenerator)
val cardEncrypter = DefaultCardEncrypter(genericEncrypter)

val analyticsRepository = analyticsRepository ?: DefaultAnalyticsRepository(
analyticsRepositoryData = AnalyticsRepositoryData(
application = application,
componentParams = componentParams,
paymentMethod = paymentMethod,
),
analyticsService = AnalyticsService(
HttpClientFactory.getAnalyticsHttpClient(componentParams.environment)
),
analyticsMapper = AnalyticsMapper(),
)
val analyticsRepository = analyticsRepository ?: DefaultAnalyticsRepository(
analyticsRepositoryData = AnalyticsRepositoryData(
application = application,
componentParams = componentParams,
paymentMethod = paymentMethod,
),
analyticsService = AnalyticsService(
HttpClientFactory.getAnalyticsHttpClient(componentParams.environment)
),
analyticsMapper = AnalyticsMapper(),
)

val bcmcFactory = viewModelFactory(savedStateRegistryOwner, null) { savedStateHandle ->
val bcmcDelegate = DefaultBcmcDelegate(
val cardDelegate = DefaultCardDelegate(
observerRepository = PaymentObserverRepository(),
paymentMethod = paymentMethod,
order = order,
publicKeyRepository = publicKeyRepository,
componentParams = componentParams,
paymentMethod = paymentMethod,
order = order,
analyticsRepository = analyticsRepository,
addressRepository = addressRepository,
detectCardTypeRepository = detectCardTypeRepository,
cardValidationMapper = cardValidationMapper,
cardEncrypter = cardEncrypter,
analyticsRepository = analyticsRepository,
genericEncrypter = genericEncrypter,
submitHandler = SubmitHandler(savedStateHandle)
)

Expand All @@ -133,13 +144,16 @@ constructor(
)

BcmcComponent(
bcmcDelegate = bcmcDelegate,
cardDelegate = cardDelegate,
genericActionDelegate = genericActionDelegate,
actionHandlingComponent = DefaultActionHandlingComponent(genericActionDelegate, bcmcDelegate),
actionHandlingComponent = DefaultActionHandlingComponent(genericActionDelegate, cardDelegate),
componentEventHandler = DefaultComponentEventHandler(),
)
}
return ViewModelProvider(viewModelStoreOwner, bcmcFactory)[key, BcmcComponent::class.java].also { component ->
return ViewModelProvider(
viewModelStoreOwner,
bcmcFactory
)[key, BcmcComponent::class.java].also { component ->
component.observe(lifecycleOwner) {
component.componentEventHandler.onPaymentComponentEvent(it, componentCallback)
}
Expand All @@ -159,43 +173,50 @@ constructor(
key: String?
): BcmcComponent {
assertSupported(paymentMethod)
val bcmcFactory = viewModelFactory(savedStateRegistryOwner, null) { savedStateHandle ->
val componentParams = componentParamsMapper.mapToParams(
bcmcConfiguration = configuration,
sessionParams = SessionParamsFactory.create(checkoutSession),
paymentMethod = paymentMethod
)
val httpClient = HttpClientFactory.getHttpClient(componentParams.environment)
val publicKeyService = PublicKeyService(httpClient)
val publicKeyRepository = DefaultPublicKeyRepository(publicKeyService)
val cardValidationMapper = CardValidationMapper()
val dateGenerator = DateGenerator()
val clientSideEncrypter = ClientSideEncrypter()
val genericEncrypter = DefaultGenericEncrypter(clientSideEncrypter, dateGenerator)
val cardEncrypter = DefaultCardEncrypter(genericEncrypter)
val addressService = AddressService(httpClient)
val addressRepository = DefaultAddressRepository(addressService)
val binLookupService = BinLookupService(httpClient)
val detectCardTypeRepository = DefaultDetectCardTypeRepository(cardEncrypter, binLookupService)

val componentParams = componentParamsMapper.mapToParams(
bcmcConfiguration = configuration,
sessionParams = SessionParamsFactory.create(checkoutSession)
)
val httpClient = HttpClientFactory.getHttpClient(componentParams.environment)
val publicKeyService = PublicKeyService(httpClient)
val publicKeyRepository = DefaultPublicKeyRepository(publicKeyService)
val cardValidationMapper = CardValidationMapper()
val dateGenerator = DateGenerator()
val clientSideEncrypter = ClientSideEncrypter()
val genericEncrypter = DefaultGenericEncrypter(clientSideEncrypter, dateGenerator)
val cardEncrypter = DefaultCardEncrypter(genericEncrypter)

val analyticsRepository = analyticsRepository ?: DefaultAnalyticsRepository(
analyticsRepositoryData = AnalyticsRepositoryData(
application = application,
componentParams = componentParams,
paymentMethod = paymentMethod,
sessionId = checkoutSession.sessionSetupResponse.id,
),
analyticsService = AnalyticsService(
HttpClientFactory.getAnalyticsHttpClient(componentParams.environment)
),
analyticsMapper = AnalyticsMapper(),
)
val analyticsRepository = analyticsRepository ?: DefaultAnalyticsRepository(
analyticsRepositoryData = AnalyticsRepositoryData(
application = application,
componentParams = componentParams,
paymentMethod = paymentMethod,
sessionId = checkoutSession.sessionSetupResponse.id,
),
analyticsService = AnalyticsService(
HttpClientFactory.getAnalyticsHttpClient(componentParams.environment)
),
analyticsMapper = AnalyticsMapper(),
)

val bcmcFactory = viewModelFactory(savedStateRegistryOwner, null) { savedStateHandle ->
val bcmcDelegate = DefaultBcmcDelegate(
val cardDelegate = DefaultCardDelegate(
observerRepository = PaymentObserverRepository(),
paymentMethod = paymentMethod,
order = checkoutSession.order,
publicKeyRepository = publicKeyRepository,
componentParams = componentParams,
paymentMethod = paymentMethod,
order = checkoutSession.order,
analyticsRepository = analyticsRepository,
addressRepository = addressRepository,
detectCardTypeRepository = detectCardTypeRepository,
cardValidationMapper = cardValidationMapper,
cardEncrypter = cardEncrypter,
analyticsRepository = analyticsRepository,
genericEncrypter = genericEncrypter,
submitHandler = SubmitHandler(savedStateHandle)
)

Expand Down Expand Up @@ -225,13 +246,17 @@ constructor(
)

BcmcComponent(
bcmcDelegate = bcmcDelegate,
cardDelegate = cardDelegate,
genericActionDelegate = genericActionDelegate,
actionHandlingComponent = DefaultActionHandlingComponent(genericActionDelegate, bcmcDelegate),
actionHandlingComponent = DefaultActionHandlingComponent(genericActionDelegate, cardDelegate),
componentEventHandler = sessionComponentEventHandler,
)
}
return ViewModelProvider(viewModelStoreOwner, bcmcFactory)[key, BcmcComponent::class.java].also { component ->

return ViewModelProvider(
viewModelStoreOwner,
bcmcFactory
)[key, BcmcComponent::class.java].also { component ->
component.observe(lifecycleOwner) {
component.componentEventHandler.onPaymentComponentEvent(it, componentCallback)
}
Expand Down
Loading

0 comments on commit d6bf88c

Please sign in to comment.