Skip to content

Commit

Permalink
BottomSheet for PaymentSheet
Browse files Browse the repository at this point in the history
  • Loading branch information
tillh-stripe committed Aug 10, 2023
1 parent 63e17ee commit 454a64a
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 116 deletions.
25 changes: 6 additions & 19 deletions paymentsheet/res/layout/stripe_activity_payment_options.xml
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="match_parent">

<LinearLayout
android:id="@+id/bottom_sheet"
<androidx.compose.ui.platform.ComposeView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:background="?colorSurface"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
android:layout_height="match_parent" />

<androidx.compose.ui.platform.ComposeView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>
25 changes: 6 additions & 19 deletions paymentsheet/res/layout/stripe_activity_payment_sheet.xml
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="match_parent">

<LinearLayout
android:id="@+id/bottom_sheet"
<androidx.compose.ui.platform.ComposeView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:background="?colorSurface"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
android:layout_height="match_parent" />

<androidx.compose.ui.platform.ComposeView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsBottomHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ModalBottomSheetDefaults
import androidx.compose.material.ModalBottomSheetLayout
Expand All @@ -26,7 +27,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.stripe.android.uicore.StripeThemeDefaults
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.first

Expand Down Expand Up @@ -147,11 +150,19 @@ internal fun BottomSheet(
)
}

// TODO Recognize taps outside the sheet for dismissal

ModalBottomSheetLayout(
modifier = modifier
.statusBarsPadding()
.imePadding(),
sheetState = state.modalBottomSheetState,
sheetShape = RoundedCornerShape(
topStart = StripeThemeDefaults.shapes.cornerRadius.dp,
topEnd = StripeThemeDefaults.shapes.cornerRadius.dp,
bottomStart = 0.dp,
bottomEnd = 0.dp,
),
sheetContent = {
sheetContent()
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import android.os.Bundle
import android.view.ViewGroup
import androidx.activity.viewModels
import androidx.annotation.VisibleForTesting
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.ViewModelProvider
import com.stripe.android.common.ui.BottomSheet
import com.stripe.android.common.ui.rememberBottomSheetState
import com.stripe.android.paymentsheet.databinding.StripeActivityPaymentOptionsBinding
import com.stripe.android.paymentsheet.ui.BaseSheetActivity
import com.stripe.android.paymentsheet.ui.PaymentOptionsScreen
Expand Down Expand Up @@ -33,8 +39,8 @@ internal class PaymentOptionsActivity : BaseSheetActivity<PaymentOptionResult>()
}

override val rootView: ViewGroup by lazy { viewBinding.root }
override val bottomSheet: ViewGroup by lazy { viewBinding.bottomSheet }

@OptIn(ExperimentalMaterialApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
val starterArgs = initializeStarterArgs()
super.onCreate(savedInstanceState)
Expand All @@ -52,7 +58,27 @@ internal class PaymentOptionsActivity : BaseSheetActivity<PaymentOptionResult>()

viewBinding.content.setContent {
StripeTheme {
PaymentOptionsScreen(viewModel)
val isProcessing by viewModel.processing.collectAsState()
val result by viewModel.paymentOptionResult.collectAsState(initial = null)

val bottomSheetState = rememberBottomSheetState(
confirmValueChange = { !isProcessing },
)

result?.let { sheetResult ->
LaunchedEffect(sheetResult) {
setActivityResult(sheetResult)
bottomSheetState.hide()
finish()
}
}

BottomSheet(
state = bottomSheetState,
onDismissed = viewModel::onUserCancel,
) {
PaymentOptionsScreen(viewModel)
}
}
}
}
Expand All @@ -69,8 +95,4 @@ internal class PaymentOptionsActivity : BaseSheetActivity<PaymentOptionResult>()
Intent().putExtras(result.toBundle()),
)
}

internal companion object {
internal const val EXTRA_STARTER_ARGS = BaseSheetActivity.EXTRA_STARTER_ARGS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ import android.os.Bundle
import android.view.ViewGroup
import androidx.activity.viewModels
import androidx.annotation.VisibleForTesting
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.stripe.android.common.ui.BottomSheet
import com.stripe.android.common.ui.rememberBottomSheetState
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContractV2
import com.stripe.android.paymentsheet.databinding.StripeActivityPaymentSheetBinding
import com.stripe.android.paymentsheet.ui.BaseSheetActivity
Expand Down Expand Up @@ -35,8 +41,8 @@ internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {
}

override val rootView: ViewGroup by lazy { viewBinding.root }
override val bottomSheet: ViewGroup by lazy { viewBinding.bottomSheet }

@OptIn(ExperimentalMaterialApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
val validationResult = initializeArgs()
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -64,7 +70,27 @@ internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {

viewBinding.content.setContent {
StripeTheme {
PaymentSheetScreen(viewModel)
val isProcessing by viewModel.processing.collectAsState()
val result by viewModel.paymentSheetResult.collectAsState(initial = null)

val bottomSheetState = rememberBottomSheetState(
confirmValueChange = { !isProcessing },
)

result?.let { sheetResult ->
LaunchedEffect(sheetResult) {
setActivityResult(sheetResult)
bottomSheetState.hide()
finish()
}
}

BottomSheet(
state = bottomSheetState,
onDismissed = viewModel::onUserCancel,
) {
PaymentSheetScreen(viewModel)
}
}
}

Expand Down Expand Up @@ -109,8 +135,4 @@ internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {
private fun defaultInitializationError(): IllegalArgumentException {
return IllegalArgumentException("PaymentSheet started without arguments.")
}

internal companion object {
internal const val EXTRA_STARTER_ARGS = BaseSheetActivity.EXTRA_STARTER_ARGS
}
}
Original file line number Diff line number Diff line change
@@ -1,53 +1,31 @@
package com.stripe.android.paymentsheet.ui

import android.animation.LayoutTransition
import android.content.pm.ActivityInfo
import android.graphics.Insets
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.Gravity
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowMetrics
import androidx.activity.addCallback
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat.Type
import androidx.core.view.updateLayoutParams
import androidx.core.view.updateMargins
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.stripe.android.paymentsheet.BottomSheetController
import com.stripe.android.paymentsheet.LinkHandler
import com.stripe.android.paymentsheet.R
import com.stripe.android.paymentsheet.utils.doOnApplyWindowInsets
import com.stripe.android.paymentsheet.utils.launchAndCollectIn
import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel
import com.stripe.android.uicore.isSystemDarkTheme
import com.stripe.android.utils.AnimationConstants
import kotlin.math.roundToInt

internal abstract class BaseSheetActivity<ResultType> : AppCompatActivity() {
abstract val viewModel: BaseSheetViewModel

val linkHandler: LinkHandler
get() = viewModel.linkHandler

@VisibleForTesting
internal val bottomSheetBehavior by lazy { BottomSheetBehavior.from(bottomSheet) }

private val bottomSheetController: BottomSheetController by lazy {
BottomSheetController(bottomSheetBehavior = bottomSheetBehavior)
}

abstract val rootView: ViewGroup
abstract val bottomSheet: ViewGroup

protected var earlyExitDueToIllegalState: Boolean = false

Expand All @@ -66,16 +44,16 @@ internal abstract class BaseSheetActivity<ResultType> : AppCompatActivity() {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}

bottomSheet.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
// bottomSheet.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
renderEdgeToEdge()

bottomSheetController.setup(bottomSheet)
// bottomSheetController.setup(bottomSheet)

bottomSheetController.shouldFinish.launchAndCollectIn(this) { shouldFinish ->
if (shouldFinish) {
finish()
}
}
// bottomSheetController.shouldFinish.launchAndCollectIn(this) { shouldFinish ->
// if (shouldFinish) {
// finish()
// }
// }

onBackPressedDispatcher.addCallback {
viewModel.handleBackPressed()
Expand All @@ -87,14 +65,14 @@ internal abstract class BaseSheetActivity<ResultType> : AppCompatActivity() {

// Make `bottomSheet` clickable to prevent clicks on the bottom sheet from triggering
// `rootView`'s click listener
bottomSheet.isClickable = true
// bottomSheet.isClickable = true

val isDark = baseContext.isSystemDarkTheme()
viewModel.config?.let {
bottomSheet.setBackgroundColor(
Color(it.appearance.getColors(isDark).surface).toArgb()
)
}
// val isDark = baseContext.isSystemDarkTheme()
// viewModel.config?.let {
// bottomSheet.setBackgroundColor(
// Color(it.appearance.getColors(isDark).surface).toArgb()
// )
// }

setSheetWidthForTablets()
}
Expand All @@ -109,7 +87,7 @@ internal abstract class BaseSheetActivity<ResultType> : AppCompatActivity() {
) {
// TODO(mlb): Consider if this needs to be an abstract function
setActivityResult(result)
bottomSheetController.hide()
// bottomSheetController.hide()
}

private fun renderEdgeToEdge() {
Expand All @@ -119,14 +97,14 @@ internal abstract class BaseSheetActivity<ResultType> : AppCompatActivity() {

WindowCompat.setDecorFitsSystemWindows(window, false)

bottomSheet.doOnApplyWindowInsets { view, insets, initialState ->
// Status bar inset
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
updateMargins(
top = initialState.top + insets.getInsets(Type.systemBars()).top,
)
}
}
// bottomSheet.doOnApplyWindowInsets { view, insets, initialState ->
// // Status bar inset
// view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
// updateMargins(
// top = initialState.top + insets.getInsets(Type.systemBars()).top,
// )
// }
// }
}

private fun updateRootViewClickHandling(isProcessing: Boolean) {
Expand Down Expand Up @@ -160,11 +138,11 @@ internal abstract class BaseSheetActivity<ResultType> : AppCompatActivity() {
displayMetrics.widthPixels
}

val params = bottomSheet.layoutParams
val clParams = params as CoordinatorLayout.LayoutParams
clParams.gravity = clParams.gravity or Gravity.CENTER_HORIZONTAL
clParams.width = (screenWidth * TABLET_WIDTH_RATIO).roundToInt()
bottomSheet.layoutParams = clParams
// val params = bottomSheet.layoutParams
// val clParams = params as CoordinatorLayout.LayoutParams
// clParams.gravity = clParams.gravity or Gravity.CENTER_HORIZONTAL
// clParams.width = (screenWidth * TABLET_WIDTH_RATIO).roundToInt()
// bottomSheet.layoutParams = clParams
}

internal companion object {
Expand Down
Loading

0 comments on commit 454a64a

Please sign in to comment.