Repository navigation
Add the BTPayPalSavedPaymentMethodView checkout component 4/6 #1888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import SwiftUI | ||
| import SafariServices | ||
|
|
||
| /// Presents the credit-messaging "Learn more" lander (`click_url`) in an | ||
| /// `SFSafariViewController`, giving buyers Safari's built-in security and reader chrome | ||
| /// without pulling in a new dependency or triggering an app-switch consent alert. | ||
| struct PayPalCreditMessagingLanderView: UIViewControllerRepresentable { | ||
|
|
||
| let url: URL | ||
|
|
||
| /// Called when the buyer taps Safari's "Done" button, so the presenter can clear its state. | ||
| let onFinish: () -> Void | ||
|
|
||
| func makeUIViewController(context: Context) -> SFSafariViewController { | ||
| let controller = SFSafariViewController(url: url) | ||
| controller.delegate = context.coordinator | ||
| return controller | ||
| } | ||
|
|
||
| func updateUIViewController(_ controller: SFSafariViewController, context: Context) { | ||
| context.coordinator.onFinish = onFinish | ||
| } | ||
|
|
||
| func makeCoordinator() -> Coordinator { | ||
| Coordinator(onFinish: onFinish) | ||
| } | ||
|
|
||
| // MARK: - Coordinator | ||
|
|
||
| final class Coordinator: NSObject, SFSafariViewControllerDelegate { | ||
|
|
||
| var onFinish: () -> Void | ||
|
|
||
| init(onFinish: @escaping () -> Void) { | ||
| self.onFinish = onFinish | ||
| } | ||
|
|
||
| func safariViewControllerDidFinish(_ controller: SFSafariViewController) { | ||
| onFinish() | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+7
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems like there's no
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added an |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| import SwiftUI | ||
|
|
||
| /// A left-to-right shimmer sweep, masked to the content's silhouette. Used for the skeleton loading state. | ||
| struct ShimmerModifier: ViewModifier { | ||
|
|
||
| @State private var animating = false | ||
|
|
||
| func body(content: Content) -> some View { | ||
| content | ||
| .overlay( | ||
| GeometryReader { geo in | ||
| let highlightWidth = geo.size.width * EditFIStyleDefaultConstants.shimmerHighlightWidthRatio | ||
| LinearGradient( | ||
| gradient: Gradient( | ||
| colors: [.clear, Color.white.opacity(EditFIStyleDefaultConstants.shimmerHighlightOpacity), .clear] | ||
| ), | ||
| startPoint: .leading, | ||
| endPoint: .trailing | ||
| ) | ||
| .frame(width: highlightWidth) | ||
| .offset(x: animating ? geo.size.width : -highlightWidth) | ||
| } | ||
| ) | ||
| .mask(content) | ||
| .onAppear { | ||
| withAnimation(.linear(duration: EditFIStyleDefaultConstants.shimmerDuration).repeatForever(autoreverses: false)) { | ||
| animating = true | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| extension View { | ||
|
|
||
| /// Applies an animated shimmer sweep, masked to this view. Use on placeholder shapes. | ||
| func shimmering() -> some View { | ||
| modifier(ShimmerModifier()) | ||
| } | ||
| } | ||
|
|
||
| /// A rounded shimmer placeholder bar that fills the available width and stops short of the trailing edge. | ||
| struct ShimmerBar: View { | ||
|
|
||
| var body: some View { | ||
| RoundedRectangle(cornerRadius: EditFIStyleDefaultConstants.shimmerBarCornerRadius) | ||
| .fill(Color(uiColor: EditFIStyleDefaultConstants.shimmerBarColor)) | ||
| .frame(height: EditFIStyleDefaultConstants.shimmerBarHeight) | ||
| .frame(maxWidth: .infinity) | ||
| .padding(.trailing, EditFIStyleDefaultConstants.shimmerBarTrailingGap) | ||
| .shimmering() | ||
| } | ||
| } | ||
|
|
||
| /// Loading placeholder for the FI row: the real PayPal brand mark stays visible while a | ||
| /// shimmer bar fills the space where the FI pill will appear. | ||
| struct PayPalSavedPaymentMethodSkeletonRow: View { | ||
|
|
||
| let style: PayPalSavedPaymentMethodViewStyle | ||
|
|
||
| private var fundingInstrumentGap: CGFloat { | ||
| EditFIStyleGuard.dimension( | ||
| style.container?.fundingInstrument?.leadingGap, | ||
| default: EditFIStyleDefaultConstants.fundingInstrumentLeadingGap | ||
| ) | ||
| } | ||
|
|
||
| var body: some View { | ||
| HStack(spacing: 0) { | ||
| // A hidden brand mark would still take the gap, so it is left out entirely. | ||
| if style.showPayPalLogo || style.showPayPalLabel { | ||
| PayPalBrandCluster(style: style) | ||
| .padding(.trailing, fundingInstrumentGap) | ||
| } | ||
| ShimmerBar() | ||
| } | ||
| .accessibilityElement() | ||
| .accessibilityLabel("Loading saved payment method") | ||
| } | ||
| } | ||
|
|
||
| /// Loading placeholder for the credit-messaging line: a shimmer bar that stops short of the edge. | ||
| struct CreditMessageSkeleton: View { | ||
|
|
||
| var body: some View { | ||
| ShimmerBar() | ||
| .accessibilityHidden(true) | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.