feat(#2236): EmbeddedPaymentElement example screen and rendering polish#2419
feat(#2236): EmbeddedPaymentElement example screen and rendering polish#2419realmeylisdev wants to merge 1 commit into
Conversation
…rendering polish PR flutter-stripe#2239 shipped the EmbeddedPaymentElement widget, but issue flutter-stripe#2236 stayed open because (a) the example app had no demo, (b) the widget reserved a 400pt blank area until the first onHeightChanged fired, and (c) the Android build.gradle carried dead duplicate compose config that confused readers debugging Kotlin/Compose failures. - Adds example/lib/screens/payment_sheet/embedded/embedded_payment_element_screen.dart demonstrating PaymentIntent and SetupIntent modes with the deferred confirm-handler pattern. - Registers the demo in screens.dart under the existing "Payment Sheet" section, restricted to iOS and Android. - Replaces the 400pt initial-render placeholder with a 60pt area plus a centered CircularProgressIndicator overlay; AnimatedSize smoothly expands to the measured height once the native side reports it. - Adds explicit dartdoc clarifying that web and desktop throw UnsupportedError. - Removes the dead duplicate buildFeatures { compose true } block and the legacy kotlinCompilerExtensionVersion = '1.5.1' (irrelevant once org.jetbrains.kotlin.plugin.compose is applied). - Documents the Kotlin/compose-compiler coupling in stripe_android/README.md. - Adds CHANGELOG entry under Unreleased citing issue flutter-stripe#2236 and PR flutter-stripe#2239. - Adds a wire-format contract test in stripe_platform_interface for IntentConfiguration and EmbeddedPaymentElementAppearance JSON shape.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR adds Embedded Payment Element support to the Flutter Stripe SDK through a complete example implementation, core widget loading UX improvements, Android platform configuration, and test coverage for serialization contracts. ChangesEmbedded Payment Element example and UX improvements
Sequence DiagramsequenceDiagram
participant User
participant EmbeddedPaymentElement
participant ExampleScreen
participant Backend
participant StripeCallback
User->>ExampleScreen: Select payment method & confirm
ExampleScreen->>EmbeddedPaymentElement: controller.confirm()
EmbeddedPaymentElement->>ExampleScreen: confirmHandler triggered
ExampleScreen->>Backend: POST selected payment method
Backend->>ExampleScreen: Return clientSecret
ExampleScreen->>StripeCallback: intentCreationCallback(clientSecret)
StripeCallback->>User: Display result message
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
remonh87
left a comment
There was a problem hiding this comment.
Thanks for adding the screen left a few comments. Also check the merge issues
| child: Stack( | ||
| children: [ | ||
| Positioned.fill(child: platformView), | ||
| if (_currentHeight == 0) |
There was a problem hiding this comment.
I am not a big fan of adding a circular progress indicator here. Two problems: every app has its own loading conventions (branded spinner, shimmer/skeleton, nothing at all), and the magic 60.0 placeholder height will clip any loader taller than 60pt.
Proposed API
inal isLoading = _currentHeight == 0;
return AnimatedSize(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
alignment: Alignment.topCenter,
child: isLoading
? Stack(
children: [
// Keep the platform view mounted so it can initialize and
// report its height; the loading widget (the only non-positioned
// child) sizes the Stack.
Positioned.fill(child: platformView),
widget.loadingBuilder?.call(context) ?? const _DefaultEmbeddedLoading(),
],
)
: SizedBox(height: _currentHeight, child: platformView),
);| @@ -1,3 +1,15 @@ | |||
| ## Unreleased | |||
There was a problem hiding this comment.
Remove the change log changes here
|
|
||
| This is an implementation of the [`stripe_platform_interface`](https://github.com/flutter-stripe/flutter_stripe/tree/main/packages/stripe_platform_interface) package for Android. | ||
|
|
||
| ### Kotlin / Compose requirement |
There was a problem hiding this comment.
this should be added to the main readme as well
| ); | ||
| } | ||
|
|
||
| // Use a small placeholder height until the native element reports its |
| if (_mode == _PaymentMode.paymentIntent) { | ||
| return IntentConfiguration( | ||
| mode: IntentMode.paymentMode(currencyCode: 'USD', amount: 1500), | ||
| confirmHandler: _handlePaymentIntentConfirm, |
There was a problem hiding this comment.
I think we can collapse _handlePaymentIntentConform and _handleSetupIntentConfirm into one function.
Summary
Closes the remaining gaps from issue #2236 after PR #2239 shipped the
EmbeddedPaymentElementwidget. The implementation was merged but the issue stayed open because the example app had no demo, the widget reserved a 400pt blank area while loading, and the Androidbuild.gradlecarried dead duplicate Compose config that confused readers debugging Kotlin/Compose failures.example/lib/screens/payment_sheet/embedded/embedded_payment_element_screen.dartcovers bothPaymentIntentandSetupIntentmodes using the deferred confirm-handler pattern. Registered under the existing "Payment Sheet" section, restricted to iOS and Android.embedded_payment_element.dartwith a 60pt area plus a centeredCircularProgressIndicatoroverlay;AnimatedSizesmoothly expands to the measured height once the native side reports it.UnsupportedError.buildFeatures { compose true }block and the legacykotlinCompilerExtensionVersion = '1.5.1'(irrelevant onceorg.jetbrains.kotlin.plugin.composeis applied), and adds a one-line comment explaining the Kotlin/Compose coupling.packages/stripe_android/README.mddocumenting the Kotlin/compose-compiler plugin requirement.## Unreleasedstanza citing issue Add support for Embedded Payment Element #2236 and PR Add EmbeddedPaymentElement support for Flutter #2239.packages/stripe_platform_interface/test/embedded_payment_element_wire_contract_test.dartlocks theIntentConfigurationandEmbeddedPaymentElementAppearanceJSON shape (in the spirit of test: lock down PaymentSheet wire-format contract for @JsonKey renames #2418).Reproducing steps (manual verification)
Run the example app on each platform and walk through the demo:
cd example && flutter pub getexample/server/README.md) so the deferredconfirmHandlercan hit/payment-intent-for-payment-sheetand/create-setup-intent.flutter run -d ios. Tap Payment Sheet → Embedded Payment Element.controller.confirm()and shows the result string at the bottom./create-setup-intent.flutter run -d emulator-5554. Repeat steps 3 and 4. Verify the spinner placeholder also appears on Android before the Compose view reports its first height.Test plan
flutter testinpackages/stripe_platform_interface— 29/29 pass, including 3 new wire-contract tests.flutter analyzeon touched files — clean (pre-existing warnings in_parseLoadingErrorlines remain; not touched by this PR).Out of scope
_StripeMethodChannel._confirmHandleris a single global slot written by bothinitPaymentSheetand the embedded widget'sStripe.instance.setConfirmHandler(...). If a host app keeps an activePaymentSheetand mounts anEmbeddedPaymentElementat the same time, the embedded widget overwrites the sheet's handler oninitStateand nulls it ondispose. Fixing this requires a platform-interface contract change and is a separate concern from the example/UX gaps this PR addresses. Happy to file a follow-up issue.UnsupportedError(now explicitly documented in the dartdoc).EmbeddedPaymentElementAppearance. The Dart model exposes onlyrowtoday; broader styling (primaryButton, etc.) lives onPaymentSheetAppearance. Out of scope here.Closes #2236.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation