From 5fce96257ad7266f2e771f7249f3825682a60486 Mon Sep 17 00:00:00 2001 From: Simon Duchastel <163092709+simond-stripe@users.noreply.github.com> Date: Mon, 7 Oct 2024 12:15:04 -0700 Subject: [PATCH] [Connect SDK] UI for Connect SDK Example App (#9276) * Build UI of example app # Conflicts: # gradle.properties * Update build.gradle to use version catalog * Update EmbeddedComponentService.kt * Update PayoutsExampleActivity.kt * Update AccountOnboardingExampleActivity.kt * Fix dependencies * Fix lint * Fix fetch client secret * Fix lint * Fix lint * Move to color/string res * fix color values --- stripe-connect-example/build.gradle | 2 + .../dependencies/dependencies.txt | 19 ++ .../src/main/AndroidManifest.xml | 13 +- .../connectsdk/example/MainActivity.kt | 188 ++++++++++++++---- .../android/connectsdk/example/Theme.kt | 56 ++++++ .../networking/EmbeddedComponentService.kt | 15 ++ .../AccountOnboardingExampleActivity.kt | 52 +++++ .../AccountOnboardingExampleViewModel.kt | 25 +++ .../ui/payouts/PayoutsExampleActivity.kt | 52 +++++ .../ui/payouts/PayoutsExampleViewModel.kt | 25 +++ .../src/main/res/values/colors.xml | 6 + .../src/main/res/values/strings.xml | 8 + .../connectsdk/FetchClientSecretCallback.kt | 2 +- 13 files changed, 419 insertions(+), 44 deletions(-) create mode 100644 stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/Theme.kt create mode 100644 stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/networking/EmbeddedComponentService.kt create mode 100644 stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleActivity.kt create mode 100644 stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleViewModel.kt create mode 100644 stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleActivity.kt create mode 100644 stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleViewModel.kt create mode 100644 stripe-connect-example/src/main/res/values/colors.xml create mode 100644 stripe-connect-example/src/main/res/values/strings.xml diff --git a/stripe-connect-example/build.gradle b/stripe-connect-example/build.gradle index 8f9021c9d84..8170e7b781c 100644 --- a/stripe-connect-example/build.gradle +++ b/stripe-connect-example/build.gradle @@ -24,6 +24,7 @@ dependencies { // Compose implementation libs.compose.ui + implementation libs.compose.uiToolingPreview implementation libs.compose.uiViewBinding implementation libs.compose.foundation implementation libs.compose.material @@ -31,6 +32,7 @@ dependencies { implementation libs.compose.activity implementation libs.compose.navigation implementation libs.accompanist.systemUiController + debugImplementation libs.compose.uiTooling // Test testImplementation testLibs.androidx.archCore diff --git a/stripe-connect-example/dependencies/dependencies.txt b/stripe-connect-example/dependencies/dependencies.txt index f0f0488a057..53a2c34ae04 100644 --- a/stripe-connect-example/dependencies/dependencies.txt +++ b/stripe-connect-example/dependencies/dependencies.txt @@ -376,12 +376,14 @@ | | | | +--- androidx.compose.ui:ui-geometry:1.5.4 (c) | | | | +--- androidx.compose.ui:ui-graphics:1.5.4 (c) | | | | +--- androidx.compose.ui:ui-text:1.5.4 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.5.4 (c) | | | | +--- androidx.compose.ui:ui-unit:1.5.4 (c) | | | | \--- androidx.compose.ui:ui-viewbinding:1.5.4 (c) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 1.9.24 (*) | | | +--- androidx.compose.ui:ui:1.5.4 (c) | | | +--- androidx.compose.ui:ui-graphics:1.5.4 (c) | | | +--- androidx.compose.ui:ui-text:1.5.4 (c) +| | | +--- androidx.compose.ui:ui-tooling-preview:1.5.4 (c) | | | +--- androidx.compose.ui:ui-unit:1.5.4 (c) | | | +--- androidx.compose.ui:ui-util:1.5.4 (c) | | | \--- androidx.compose.ui:ui-viewbinding:1.5.4 (c) @@ -400,12 +402,14 @@ | | | | +--- androidx.compose.ui:ui-geometry:1.5.4 (c) | | | | +--- androidx.compose.ui:ui-graphics:1.5.4 (c) | | | | +--- androidx.compose.ui:ui-text:1.5.4 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.5.4 (c) | | | | +--- androidx.compose.ui:ui-util:1.5.4 (c) | | | | \--- androidx.compose.ui:ui-viewbinding:1.5.4 (c) | | | +--- androidx.compose.ui:ui-util:1.5.4 (*) | | | +--- androidx.compose.ui:ui:1.5.4 (c) | | | +--- androidx.compose.ui:ui-geometry:1.5.4 (c) | | | +--- androidx.compose.ui:ui-text:1.5.4 (c) +| | | +--- androidx.compose.ui:ui-tooling-preview:1.5.4 (c) | | | +--- androidx.compose.ui:ui-unit:1.5.4 (c) | | | +--- androidx.compose.ui:ui-util:1.5.4 (c) | | | \--- androidx.compose.ui:ui-viewbinding:1.5.4 (c) @@ -425,6 +429,7 @@ | | | +--- androidx.compose.ui:ui:1.5.4 (c) | | | +--- androidx.compose.ui:ui-geometry:1.5.4 (c) | | | +--- androidx.compose.ui:ui-graphics:1.5.4 (c) +| | | +--- androidx.compose.ui:ui-tooling-preview:1.5.4 (c) | | | +--- androidx.compose.ui:ui-unit:1.5.4 (c) | | | +--- androidx.compose.ui:ui-util:1.5.4 (c) | | | \--- androidx.compose.ui:ui-viewbinding:1.5.4 (c) @@ -446,6 +451,7 @@ | | +--- androidx.compose.ui:ui-geometry:1.5.4 (c) | | +--- androidx.compose.ui:ui-graphics:1.5.4 (c) | | +--- androidx.compose.ui:ui-text:1.5.4 (c) +| | +--- androidx.compose.ui:ui-tooling-preview:1.5.4 (c) | | +--- androidx.compose.ui:ui-unit:1.5.4 (c) | | +--- androidx.compose.ui:ui-util:1.5.4 (c) | | +--- androidx.compose.ui:ui-viewbinding:1.5.4 (c) @@ -457,6 +463,7 @@ | | +--- androidx.fragment:fragment-ktx:1.3.2 -> 1.6.2 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 1.9.24 (*) | | +--- androidx.compose.ui:ui:1.5.4 (c) +| | +--- androidx.compose.ui:ui-tooling-preview:1.5.4 (c) | | +--- androidx.compose.ui:ui-util:1.5.4 (c) | | +--- androidx.compose.ui:ui-geometry:1.5.4 (c) | | +--- androidx.compose.ui:ui-graphics:1.5.4 (c) @@ -646,6 +653,18 @@ +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (*) +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (*) +--- androidx.compose.ui:ui:1.5.4 (*) ++--- androidx.compose.ui:ui-tooling-preview:1.5.4 +| \--- androidx.compose.ui:ui-tooling-preview-android:1.5.4 +| +--- androidx.annotation:annotation:1.2.0 -> 1.7.1 (*) +| +--- androidx.compose.runtime:runtime:1.5.4 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21 -> 1.9.24 (*) +| +--- androidx.compose.ui:ui:1.5.4 (c) +| +--- androidx.compose.ui:ui-geometry:1.5.4 (c) +| +--- androidx.compose.ui:ui-graphics:1.5.4 (c) +| +--- androidx.compose.ui:ui-text:1.5.4 (c) +| +--- androidx.compose.ui:ui-unit:1.5.4 (c) +| +--- androidx.compose.ui:ui-util:1.5.4 (c) +| \--- androidx.compose.ui:ui-viewbinding:1.5.4 (c) +--- androidx.compose.ui:ui-viewbinding:1.5.4 (*) +--- androidx.compose.foundation:foundation:1.5.4 (*) +--- androidx.compose.material:material:1.5.4 (*) diff --git a/stripe-connect-example/src/main/AndroidManifest.xml b/stripe-connect-example/src/main/AndroidManifest.xml index 8934fd2d324..eaae5a28c77 100644 --- a/stripe-connect-example/src/main/AndroidManifest.xml +++ b/stripe-connect-example/src/main/AndroidManifest.xml @@ -1,14 +1,23 @@ - + android:exported="true" + android:theme="@style/Theme.AppCompat.Light.NoActionBar"> + + + diff --git a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/MainActivity.kt b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/MainActivity.kt index dee57e83a70..cfce1f953b0 100644 --- a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/MainActivity.kt +++ b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/MainActivity.kt @@ -1,69 +1,175 @@ package com.stripe.android.connectsdk.example +import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyItemScope +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Divider +import androidx.compose.material.Icon import androidx.compose.material.Text -import com.stripe.android.connectsdk.EmbeddedComponentManager -import com.stripe.android.connectsdk.FetchClientSecretCallback -import com.stripe.android.connectsdk.FetchClientSecretCallback.ClientSecretResultCallback -import com.stripe.android.connectsdk.PrivateBetaConnectSDK +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.KeyboardArrowRight +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.stripe.android.connectsdk.example.ui.accountonboarding.AccountOnboardingExampleActivity +import com.stripe.android.connectsdk.example.ui.payouts.PayoutsExampleActivity -@OptIn(PrivateBetaConnectSDK::class) class MainActivity : ComponentActivity() { - private lateinit var embeddedComponentManager: EmbeddedComponentManager + private data class MenuItem( + val title: String, + val subtitle: String, + val activity: Class, + val isBeta: Boolean = false, + ) + + private val menuItems = listOf( + MenuItem( + title = resources.getString(R.string.account_onboarding), + subtitle = resources.getString(R.string.account_onboarding_menu_subtitle), + activity = AccountOnboardingExampleActivity::class.java, + isBeta = true, + ), + MenuItem( + title = resources.getString(R.string.payouts), + subtitle = resources.getString(R.string.payouts_menu_subtitle), + activity = PayoutsExampleActivity::class.java, + isBeta = true, + ), + ) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - embeddedComponentManager = EmbeddedComponentManager( - activity = this, - configuration = EmbeddedComponentManager.Configuration( - publishableKey = "" - ), - fetchClientSecret = object : FetchClientSecretCallback { - override fun fetchClientSecret(resultCallback: ClientSecretResultCallback) { - // Make a network call to fetch your client secret here - resultCallback.onResult("") + setContent { + ConnectSdkExampleTheme { + MainContent(title = stringResource(R.string.connect_sdk_example)) { + ComponentList(menuItems) } } - ) - - setContent { - Text("Not yet built...") } } - fun launchPayouts() { - // launch the payouts activity - embeddedComponentManager.presentPayouts() + @Composable + private fun ComponentList(components: List) { + LazyColumn { + items(components) { menuItem -> + MenuRowItem(menuItem) + } + } } - fun launchAccountOnboardingActivity() { - // launch the account onboarding activity - embeddedComponentManager.presentAccountOnboarding() + @Composable + private fun LazyItemScope.MenuRowItem(menuItem: MenuItem) { + val context = LocalContext.current + Row( + modifier = Modifier + .fillParentMaxWidth() + .clickable { context.startActivity(Intent(context, menuItem.activity)) }, + verticalAlignment = Alignment.CenterVertically, + ) { + Column(modifier = Modifier.weight(1f)) { + Column(modifier = Modifier.padding(8.dp)) { + Spacer(modifier = Modifier.height(8.dp)) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + Text( + text = menuItem.title, + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, + ) + if (menuItem.isBeta) { + BetaBadge() + } + } + Spacer(modifier = Modifier.height(8.dp)) + Text( + + text = menuItem.subtitle, + fontSize = 16.sp, + ) + } + Spacer(modifier = Modifier.height(8.dp)) + Divider() + } + + Icon( + modifier = Modifier + .size(36.dp) + .padding(start = 8.dp), + contentDescription = null, + imageVector = Icons.Default.KeyboardArrowRight, + ) + } } - fun updateAppearance() { - // update the appearance - embeddedComponentManager.update( - EmbeddedComponentManager.Appearance( - typography = EmbeddedComponentManager.Appearance.Typography(), - colors = EmbeddedComponentManager.Appearance.Colors(), - buttonPrimary = EmbeddedComponentManager.Appearance.Button(), - buttonSecondary = EmbeddedComponentManager.Appearance.Button(), - badgeNeutral = EmbeddedComponentManager.Appearance.Badge(), - badgeSuccess = EmbeddedComponentManager.Appearance.Badge(), - badgeWarning = EmbeddedComponentManager.Appearance.Badge(), - badgeDanger = EmbeddedComponentManager.Appearance.Badge(), - cornerRadius = EmbeddedComponentManager.Appearance.CornerRadius() + @Composable + private fun BetaBadge() { + val shape = RoundedCornerShape(4.dp) + val labelMediumEmphasized = TextStyle.Default.copy( + fontSize = 14.sp, + fontWeight = FontWeight.SemiBold, + lineHeight = 20.sp, + lineHeightStyle = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Center, + trim = LineHeightStyle.Trim.None ) ) + Text( + modifier = Modifier + .border(1.dp, colorResource(R.color.default_border_color), shape) + .background( + color = colorResource(R.color.default_background_color), + shape = shape + ) + .padding(horizontal = 6.dp, vertical = 1.dp), + color = colorResource(R.color.default_text_color), + fontSize = 12.sp, + lineHeight = 16.sp, + style = labelMediumEmphasized, + text = "BETA" + ) } - fun logout() { - // log out the user - embeddedComponentManager.logout() + @Composable + @Preview(showBackground = true) + fun ComponentListPreview() { + ConnectSdkExampleTheme { + ComponentList(menuItems) + } + } + + @Composable + @Preview(showBackground = true) + fun BetaBadgePreview() { + ConnectSdkExampleTheme { + BetaBadge() + } } } diff --git a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/Theme.kt b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/Theme.kt new file mode 100644 index 00000000000..64774ddcef1 --- /dev/null +++ b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/Theme.kt @@ -0,0 +1,56 @@ +package com.stripe.android.connectsdk.example + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Divider +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun ConnectSdkExampleTheme( + content: @Composable () -> Unit, +) { + MaterialTheme( + colors = if (isSystemInDarkTheme()) darkColors() else lightColors(), + content = content, + ) +} + +@Composable +fun MainContent( + title: String, + content: @Composable () -> Unit, +) { + Scaffold( + topBar = { + Column { + Text( + modifier = Modifier.padding(8.dp), + text = title, + fontSize = 24.sp, + fontWeight = FontWeight.SemiBold, + ) + Divider() + } + } + ) { contentPadding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(contentPadding), + ) { + content() + } + } +} diff --git a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/networking/EmbeddedComponentService.kt b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/networking/EmbeddedComponentService.kt new file mode 100644 index 00000000000..f54e308e7c5 --- /dev/null +++ b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/networking/EmbeddedComponentService.kt @@ -0,0 +1,15 @@ +package com.stripe.android.connectsdk.example.networking + +import kotlinx.coroutines.delay + +class EmbeddedComponentService { + suspend fun fetchClientSecret(): String? { + // TODO MXMOBILE-2511 - add backend call + delay(ARTIFICIAL_DELAY_MS) + return null + } + + companion object { + private const val ARTIFICIAL_DELAY_MS = 3000L + } +} diff --git a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleActivity.kt b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleActivity.kt new file mode 100644 index 00000000000..651a757d73f --- /dev/null +++ b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleActivity.kt @@ -0,0 +1,52 @@ +package com.stripe.android.connectsdk.example.ui.accountonboarding + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.lifecycle.viewmodel.compose.viewModel +import com.stripe.android.connectsdk.EmbeddedComponentManager +import com.stripe.android.connectsdk.PrivateBetaConnectSDK +import com.stripe.android.connectsdk.example.ConnectSdkExampleTheme +import com.stripe.android.connectsdk.example.MainContent + +class AccountOnboardingExampleActivity : ComponentActivity() { + + @OptIn(PrivateBetaConnectSDK::class) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + ConnectSdkExampleTheme { + val viewModel: AccountOnboardingExampleViewModel = viewModel() + val embeddedComponentManager = remember { + EmbeddedComponentManager( + activity = this@AccountOnboardingExampleActivity, + // TODO MXMOBILE-2511 - pass publishable key from backend to SDK + configuration = EmbeddedComponentManager.Configuration(""), + fetchClientSecret = viewModel::fetchClientSecret, + ) + } + + MainContent(title = "Account Onboarding Example") { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Button( + onClick = embeddedComponentManager::presentAccountOnboarding, + ) { + Text("Launch onboarding") + } + } + } + } + } + } +} diff --git a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleViewModel.kt b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleViewModel.kt new file mode 100644 index 00000000000..16b2b84b43c --- /dev/null +++ b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleViewModel.kt @@ -0,0 +1,25 @@ +package com.stripe.android.connectsdk.example.ui.accountonboarding + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.stripe.android.connectsdk.FetchClientSecretCallback.ClientSecretResultCallback +import com.stripe.android.connectsdk.PrivateBetaConnectSDK +import com.stripe.android.connectsdk.example.networking.EmbeddedComponentService +import kotlinx.coroutines.launch + +class AccountOnboardingExampleViewModel( + private val embeddedComponentService: EmbeddedComponentService = EmbeddedComponentService(), +) : ViewModel() { + + @OptIn(PrivateBetaConnectSDK::class) + fun fetchClientSecret(resultCallback: ClientSecretResultCallback) { + viewModelScope.launch { + val clientSecret = embeddedComponentService.fetchClientSecret() + if (clientSecret != null) { + resultCallback.onResult(clientSecret) + } else { + resultCallback.onError() + } + } + } +} diff --git a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleActivity.kt b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleActivity.kt new file mode 100644 index 00000000000..201c5579e8d --- /dev/null +++ b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleActivity.kt @@ -0,0 +1,52 @@ +package com.stripe.android.connectsdk.example.ui.payouts + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.lifecycle.viewmodel.compose.viewModel +import com.stripe.android.connectsdk.EmbeddedComponentManager +import com.stripe.android.connectsdk.PrivateBetaConnectSDK +import com.stripe.android.connectsdk.example.ConnectSdkExampleTheme +import com.stripe.android.connectsdk.example.MainContent + +@OptIn(PrivateBetaConnectSDK::class) +class PayoutsExampleActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + ConnectSdkExampleTheme { + val viewModel: PayoutsExampleViewModel = viewModel() + val embeddedComponentManager = remember { + EmbeddedComponentManager( + activity = this@PayoutsExampleActivity, + // TODO MXMOBILE-2511 - pass publishable key from backend to SDK + configuration = EmbeddedComponentManager.Configuration(""), + fetchClientSecret = viewModel::fetchClientSecret, + ) + } + + MainContent(title = "Payouts Example") { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Button( + onClick = embeddedComponentManager::presentPayouts, + ) { + Text("Launch payouts") + } + } + } + } + } + } +} diff --git a/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleViewModel.kt b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleViewModel.kt new file mode 100644 index 00000000000..9ed20446a58 --- /dev/null +++ b/stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleViewModel.kt @@ -0,0 +1,25 @@ +package com.stripe.android.connectsdk.example.ui.payouts + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.stripe.android.connectsdk.FetchClientSecretCallback.ClientSecretResultCallback +import com.stripe.android.connectsdk.PrivateBetaConnectSDK +import com.stripe.android.connectsdk.example.networking.EmbeddedComponentService +import kotlinx.coroutines.launch + +class PayoutsExampleViewModel( + private val embeddedComponentService: EmbeddedComponentService = EmbeddedComponentService(), +) : ViewModel() { + + @OptIn(PrivateBetaConnectSDK::class) + fun fetchClientSecret(resultCallback: ClientSecretResultCallback) { + viewModelScope.launch { + val clientSecret = embeddedComponentService.fetchClientSecret() + if (clientSecret != null) { + resultCallback.onResult(clientSecret) + } else { + resultCallback.onError() + } + } + } +} diff --git a/stripe-connect-example/src/main/res/values/colors.xml b/stripe-connect-example/src/main/res/values/colors.xml new file mode 100644 index 00000000000..21c6d431e13 --- /dev/null +++ b/stripe-connect-example/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #A7E7FC + #CBF5FD + #CBF5FD + \ No newline at end of file diff --git a/stripe-connect-example/src/main/res/values/strings.xml b/stripe-connect-example/src/main/res/values/strings.xml new file mode 100644 index 00000000000..3ea180ed0c6 --- /dev/null +++ b/stripe-connect-example/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ + + + Account Onboarding + Show a localized onboarding form that validates data + Payouts + Show payout information and allow your users to perform payouts + Connect SDK Example + \ No newline at end of file diff --git a/stripe-connect/src/main/java/com/stripe/android/connectsdk/FetchClientSecretCallback.kt b/stripe-connect/src/main/java/com/stripe/android/connectsdk/FetchClientSecretCallback.kt index 569086f718d..a5dda3536d5 100644 --- a/stripe-connect/src/main/java/com/stripe/android/connectsdk/FetchClientSecretCallback.kt +++ b/stripe-connect/src/main/java/com/stripe/android/connectsdk/FetchClientSecretCallback.kt @@ -1,7 +1,7 @@ package com.stripe.android.connectsdk @PrivateBetaConnectSDK -interface FetchClientSecretCallback { +fun interface FetchClientSecretCallback { fun fetchClientSecret(resultCallback: ClientSecretResultCallback) interface ClientSecretResultCallback {