Adyen / adyen-android

Adyen Android Drop-in and Components
https://docs.adyen.com/checkout/android
MIT License
119 stars 66 forks source link

Compose support for components #1210

Closed kataRebuy closed 10 months ago

kataRebuy commented 11 months ago

Is your feature request related to a problem? Please describe. I want to fully migrate to compose and get rid of my fragments. Currently, it is not possible because of Adyen Components. The following line is preventing me from doing so: val cardComponent = CardComponent.PROVIDER.get(this@YourActivity, paymentMethod, cardConfiguration)

Describe the solution you'd like Creating a fully compose component library

Describe alternatives you've considered Maybe it would be possible to just use the context instead of the activity.

jreij commented 11 months ago

Hi @kataRebuy, thank you for reaching out! Compatibility with Compose is indeed something we're looking into. However at the moment I'm afraid the only way to integrate with our drop-in and components is through an activity or fragment (technically a ViewModelStoreOwner and a SavedStateRegistryOwner). Once we have any updates on that we'll post them here 🙂

jreij commented 11 months ago

Hi again @kataRebuy , can you try this code and let us know if it works?

val cardComponent = CardComponent.PROVIDER.get(
    LocalSavedStateRegistryOwner.current,
    LocalViewModelStoreOwner.current
    paymentMethod,
    cardConfiguration,
    null,
)
kataRebuy commented 11 months ago

@jreij Thank you, this seems to work I could get rid of the reference of the fragment. But I have to mention that I still use the compose view inside a fragment, I hope it will also work without it.

jreij commented 11 months ago

Good to hear it works! For the view, can you wrap it in an AndroidView? Something like this:

@Composable
fun CardViewComposable(cardComponent: CardComponent){
    val lifecycleOwner = LocalLifecycleOwner.current
    return AndroidView(factory = {
        CardView(it).apply {
            attach(cardComponent, lifecycleOwner)
        }
    })
}
kataRebuy commented 11 months ago

Yes this works, however, I tried to get rid of the fragment and use it inside a Dialog and then this problem appears: https://github.com/Adyen/adyen-android/issues/656 that is why we started to wrap it around a fragment

jreij commented 11 months ago

Ah yes you will face this issue indeed. I don't think this can be solved in the current version but we will investigate how we can improve this for the next major release (v5) and hopefully we'll have a proper solution for Compose apps.

kataRebuy commented 11 months ago

@jreij Until this is fixed would it be possible to have a workaround for this issue? Maybe having a function call like cardComponent.reset()

kataRebuy commented 10 months ago

@OscarSpruit will your PR(https://github.com/Adyen/adyen-android/pull/1237/files) solve this issue?

OscarSpruit commented 10 months ago

Hi @kataRebuy! Yes, I believe it should resolve all the issues you have been running into and also integration with compose should be easier. However, this change is only for the next 5.x.x release. Meaning you would have to migrate to this new major version

jreij commented 9 months ago

hi @kataRebuy, we just released 5.0.0-alpha02 which improves support for Jetpack compose with 2 new modules: drop-in-compose and components-compose.

kataRebuy commented 9 months ago

I just checked the release. I couldn't really find the documentation so I just tried working based on the code. I exchanged the provider from this:

CardComponent.PROVIDER.get( fragment, paymentMethod, cardConfiguration)

to the following:

 val savedState = LocalSavedStateRegistryOwner.current
val storeOwner = LocalViewModelStoreOwner.current
val lifecycleOwner = LocalLifecycleOwner.current
val callback = remember {
    object : ComponentCallback<CardComponentState> {
        override fun onAdditionalDetails(actionComponentData: ActionComponentData) {
            TODO("Not yet implemented")
        }
        override fun onError(componentError: ComponentError) {
            TODO("Not yet implemented")
        }
        override fun onSubmit(state: CardComponentState) {
            TODO("Not yet implemented")
        }
    }
}
CardComponent.PROVIDER.get(
    savedState,
    storeOwner!!,
    lifecycleOwner,
    paymentMethod,
    cardConfiguration,
    application,
    callback,
    null,
    null
)

Is this correct?

I noticed that now you added a button to the component, is there a way to change the text on the button? Also, I would be happy to get a documentation on how can I customize the button and all the colors in the component. It would be really nice if it could be done through the compose view that you created and not with an XML.

BREAKING: In the end, I tested the case reported with this issue: https://github.com/Adyen/adyen-android/issues/656, and seems like this issue is still not solved which makes it impossible to use the view without a fragment. Would it be possible to reopen this issue or the original one(https://github.com/Adyen/adyen-android/issues/656) to keep track of the issue?

jreij commented 9 months ago

Hi again @kataRebuy, the lack of documentation doesn't help indeed, we wanted to get the compose modules out quickly so you can get the chance to try them out but we'll try to document them a bit more. The code you need is basically in these 2 files: drop-in and components.

Here's a code sample you can try out:

    import com.adyen.checkout.components.compose.get

    @Composable
    private fun ComposableCardComponent() {
        // keep a reference to this component in case you need to access it later
        val cardComponent = CardComponent.PROVIDER.get(
            paymentMethod = paymentMethod,
            configuration = configuration,
            componentCallback = callback,
            // this key is necessary to ensure a new component gets created for each different screen/payment session
            // generate a new value for this key every time you need to "reset" the component
            key = "UNIQUE_KEY_PER_COMPONENT",
        )

        // this is your composable, a wrapper around our xml view
        AdyenComponent(
            component = cardComponent,
            modifier = YOUR_MODIFIER,
        )
    }

As for customizing the button there are 2 ways:

I hope I haven't missed anything, let me know if you have any more questions. And please let us know whether this works or not and if you think it's a nice way to integrate our components with compose. We're still in alpha and we have lots of room for feedback and improvement 😉

kataRebuy commented 9 months ago

Thank you for the good explanation. I just tried it out the way you suggested and it works. It would be super nice if the AdyenComponent could use compose themes in the future. I am looking forward to the production release.

jreij commented 9 months ago

Great to hear that, thanks for the feedback!