Skip to content

Commit

Permalink
[connect] Add component event listeners (#9690)
Browse files Browse the repository at this point in the history
* refactor `onSetterFunctionCalled` message handling

* add component listening and events

* tests and ergonomics

* show toast on error for demo
  • Loading branch information
lng-stripe authored Dec 3, 2024
1 parent 98f5f85 commit 2edfbfb
Show file tree
Hide file tree
Showing 14 changed files with 413 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class AppearanceViewModel @Inject constructor(
) : ViewModel() {

private val logger: Logger = Logger.getInstance(enableLogging = BuildConfig.DEBUG)
private val loggingTag = this::class.java.name
private val loggingTag = this::class.java.simpleName

private val _state = MutableStateFlow(AppearanceState())
val state = _state.asStateFlow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.stripe.android.connect.example.ui.features.payouts

import android.content.Context
import android.view.View
import android.widget.Toast
import com.stripe.android.connect.PayoutsListener
import com.stripe.android.connect.PrivateBetaConnectSDK
import com.stripe.android.connect.example.R
import com.stripe.android.connect.example.ui.common.BasicComponentExampleActivity
Expand All @@ -13,6 +15,15 @@ class PayoutsExampleActivity : BasicComponentExampleActivity() {
override val titleRes: Int = R.string.payouts

override fun createComponentView(context: Context): View {
return embeddedComponentManager.createPayoutsView(context)
return embeddedComponentManager.createPayoutsView(
context = context,
listener = Listener(),
)
}

private inner class Listener : PayoutsListener {
override fun onLoadError(error: Throwable) {
Toast.makeText(this@PayoutsExampleActivity, error.message, Toast.LENGTH_LONG).show()
}
}
}
28 changes: 28 additions & 0 deletions connect/api/connect.api
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
public abstract interface class com/stripe/android/connect/AccountOnboardingListener : com/stripe/android/connect/StripeEmbeddedComponentListener {
public abstract fun onExit ()V
}

public final class com/stripe/android/connect/AccountOnboardingListener$DefaultImpls {
public static fun onExit (Lcom/stripe/android/connect/AccountOnboardingListener;)V
public static fun onLoadError (Lcom/stripe/android/connect/AccountOnboardingListener;Ljava/lang/Throwable;)V
public static fun onLoaderStart (Lcom/stripe/android/connect/AccountOnboardingListener;)V
}

public final class com/stripe/android/connect/BuildConfig {
public static final field BUILD_TYPE Ljava/lang/String;
public static final field DEBUG Z
Expand All @@ -13,6 +23,24 @@ public final class com/stripe/android/connect/EmbeddedComponentManager$Configura
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public abstract interface class com/stripe/android/connect/PayoutsListener : com/stripe/android/connect/StripeEmbeddedComponentListener {
}

public final class com/stripe/android/connect/PayoutsListener$DefaultImpls {
public static fun onLoadError (Lcom/stripe/android/connect/PayoutsListener;Ljava/lang/Throwable;)V
public static fun onLoaderStart (Lcom/stripe/android/connect/PayoutsListener;)V
}

public abstract interface class com/stripe/android/connect/StripeEmbeddedComponentListener {
public abstract fun onLoadError (Ljava/lang/Throwable;)V
public abstract fun onLoaderStart ()V
}

public final class com/stripe/android/connect/StripeEmbeddedComponentListener$DefaultImpls {
public static fun onLoadError (Lcom/stripe/android/connect/StripeEmbeddedComponentListener;Ljava/lang/Throwable;)V
public static fun onLoaderStart (Lcom/stripe/android/connect/StripeEmbeddedComponentListener;)V
}

public final class com/stripe/android/connect/appearance/Appearance : android/os/Parcelable {
public static final field $stable I
public static final field CREATOR Landroid/os/Parcelable$Creator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,59 @@ import android.widget.FrameLayout
import androidx.annotation.RestrictTo
import com.stripe.android.connect.webview.StripeConnectWebViewContainer
import com.stripe.android.connect.webview.StripeConnectWebViewContainerImpl
import com.stripe.android.connect.webview.serialization.SetOnExit
import com.stripe.android.connect.webview.serialization.SetterFunctionCalledMessage

@PrivateBetaConnectSDK
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class AccountOnboardingView private constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
webViewContainerBehavior: StripeConnectWebViewContainerImpl,
webViewContainerBehavior: StripeConnectWebViewContainerImpl<AccountOnboardingListener>,
) : FrameLayout(context, attrs, defStyleAttr),
StripeConnectWebViewContainer by webViewContainerBehavior {
StripeConnectWebViewContainer<AccountOnboardingListener> by webViewContainerBehavior {

@JvmOverloads
constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
embeddedComponentManager: EmbeddedComponentManager? = null,
listener: AccountOnboardingListener? = null,
) : this(
context,
attrs,
defStyleAttr,
StripeConnectWebViewContainerImpl(
embeddedComponent = StripeEmbeddedComponent.ACCOUNT_ONBOARDING,
embeddedComponentManager = embeddedComponentManager
embeddedComponentManager = embeddedComponentManager,
listener = listener,
listenerDelegate = AccountOnboardingListenerDelegate
)
)

init {
webViewContainerBehavior.initializeView(this)
}
}

@PrivateBetaConnectSDK
interface AccountOnboardingListener : StripeEmbeddedComponentListener {
/**
* The connected account has exited the onboarding process.
*/
fun onExit() {}
}

@OptIn(PrivateBetaConnectSDK::class)
internal object AccountOnboardingListenerDelegate : ComponentListenerDelegate<AccountOnboardingListener> {
override fun AccountOnboardingListener.delegate(message: SetterFunctionCalledMessage) {
when (message.value) {
is SetOnExit -> onExit()
else -> {
// Ignore.
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,29 @@ class EmbeddedComponentManager(
/**
* Create a new [AccountOnboardingView] for inclusion in the view hierarchy.
*/
fun createAccountOnboardingView(context: Context): AccountOnboardingView {
return AccountOnboardingView(context = context, embeddedComponentManager = this)
fun createAccountOnboardingView(
context: Context,
listener: AccountOnboardingListener? = null
): AccountOnboardingView {
return AccountOnboardingView(
context = context,
embeddedComponentManager = this,
listener = listener
)
}

/**
* Create a new [PayoutsView] for inclusion in the view hierarchy.
*/
fun createPayoutsView(context: Context): PayoutsView {
return PayoutsView(context = context, embeddedComponentManager = this)
fun createPayoutsView(
context: Context,
listener: PayoutsListener? = null
): PayoutsView {
return PayoutsView(
context = context,
embeddedComponentManager = this,
listener = listener
)
}

internal fun getInitialParams(context: Context): ConnectInstanceJs {
Expand Down
12 changes: 9 additions & 3 deletions connect/src/main/java/com/stripe/android/connect/PayoutsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,33 @@ class PayoutsView private constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
webViewContainerBehavior: StripeConnectWebViewContainerImpl,
webViewContainerBehavior: StripeConnectWebViewContainerImpl<PayoutsListener>,
) : FrameLayout(context, attrs, defStyleAttr),
StripeConnectWebViewContainer by webViewContainerBehavior {
StripeConnectWebViewContainer<PayoutsListener> by webViewContainerBehavior {

@JvmOverloads
constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
embeddedComponentManager: EmbeddedComponentManager? = null,
listener: PayoutsListener? = null,
) : this(
context,
attrs,
defStyleAttr,
StripeConnectWebViewContainerImpl(
embeddedComponent = StripeEmbeddedComponent.PAYOUTS,
embeddedComponentManager = embeddedComponentManager
embeddedComponentManager = embeddedComponentManager,
listener = listener,
listenerDelegate = ComponentListenerDelegate.ignore(),
)
)

init {
webViewContainerBehavior.initializeView(this)
}
}

@PrivateBetaConnectSDK
interface PayoutsListener : StripeEmbeddedComponentListener
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.stripe.android.connect

import com.stripe.android.connect.webview.serialization.SetterFunctionCalledMessage

@PrivateBetaConnectSDK
interface StripeEmbeddedComponentListener {
/**
* The component executes this callback function before any UI is displayed to the user.
*/
fun onLoaderStart() {}

/**
* The component executes this callback function when a load failure occurs.
*/
fun onLoadError(error: Throwable) {}
}

@OptIn(PrivateBetaConnectSDK::class)
internal fun interface ComponentListenerDelegate<Listener : StripeEmbeddedComponentListener> {
fun Listener.delegate(message: SetterFunctionCalledMessage)

companion object {
internal fun <Listener : StripeEmbeddedComponentListener> ignore(): ComponentListenerDelegate<Listener> {
return ComponentListenerDelegate { _ -> }
}
}
}
Loading

0 comments on commit 2edfbfb

Please sign in to comment.