Code

Create CartUiState.kt — client secret and PaymentSheet

In the code column — CartUiState.kt. The new clientSecret field is a switch: when it becomes non-null, the screen presents the PaymentSheet. totalCents is the amount in Stripe's format (cents).

How does clientSecret turn into a payment dialog? CartScreen uses Stripe's composables:

// 1) prepare the PaymentSheet and describe what to do with the result
val paymentSheet = rememberPaymentSheet { result ->
    when (result) {
        is PaymentSheetResult.Completed -> viewModel.onEvent(CartEvent.PaymentSucceeded)
        is PaymentSheetResult.Canceled  -> viewModel.onEvent(CartEvent.PaymentCanceled)
        is PaymentSheetResult.Failed    -> viewModel.onEvent(CartEvent.PaymentFailed(result.error.message))
    }
}

// 2) when a clientSecret appears → present the payment dialog
LaunchedEffect(state.clientSecret) {
    state.clientSecret?.let { secret ->
        paymentSheet.presentWithPaymentIntent(
            secret,
            PaymentSheet.Configuration(merchantDisplayName = "Pica")
        )
    }
}

// 3) order recorded → snackbar and go back
LaunchedEffect(state.orderPlaced) {
    if (state.orderPlaced) {
        snackbarHostState.showSnackbar("Payment complete! 🍕")
        viewModel.onEvent(CartEvent.ClearOrderPlaced)
        onOrderPlaced()
    }
}

The full cycle: CheckoutstartPayment()clientSecretLaunchedEffect presents PaymentSheet → the user enters a card → CompletedPaymentSucceededcompleteOrder()orderPlaced → snackbar.

Verify. Test mode, test card 4242 4242 4242 4242, any future date, any CVC:

1. Cart → "Pay" → briefly ⟳ (a PaymentIntent is created).
2. The Stripe PaymentSheet pops up → enter 4242… → "Pay €X".
3. "Payment complete! 🍕" → the order appears in history (status "paid"/"created").

Gotcha (initialization). If you don't call PaymentConfiguration.init(...) in Application.onCreate (or you call it after PaymentSheet), the app crashes:

java.lang.IllegalStateException: PaymentConfiguration was not initialized.
Call PaymentConfiguration.init(context, publishableKey)

Without the publishable key, PaymentSheet has no idea which Stripe account to talk to. Initialize it once, early — in the Application class (right where startKoin lives).