Skip to content
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

Add Internal support for draft paywall previews #4761

Merged
merged 11 commits into from
Feb 13, 2025
5 changes: 5 additions & 0 deletions RevenueCatUI/Data/PaywallViewConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct PaywallViewConfiguration {
var mode: PaywallViewMode
var fonts: PaywallFontProvider
var displayCloseButton: Bool
let useDraftPaywall: Bool
var introEligibility: TrialOrIntroEligibilityChecker?
var purchaseHandler: PurchaseHandler
var locale: Locale
Expand All @@ -29,6 +30,7 @@ struct PaywallViewConfiguration {
mode: PaywallViewMode = .default,
fonts: PaywallFontProvider = DefaultPaywallFontProvider(),
displayCloseButton: Bool = false,
useDraftPaywall: Bool = false,
introEligibility: TrialOrIntroEligibilityChecker? = nil,
purchaseHandler: PurchaseHandler,
locale: Locale = .current
Expand All @@ -38,6 +40,7 @@ struct PaywallViewConfiguration {
self.mode = mode
self.fonts = fonts
self.displayCloseButton = displayCloseButton
self.useDraftPaywall = useDraftPaywall
self.introEligibility = introEligibility
self.purchaseHandler = purchaseHandler
self.locale = locale
Expand Down Expand Up @@ -72,6 +75,7 @@ extension PaywallViewConfiguration {
mode: PaywallViewMode = .default,
fonts: PaywallFontProvider = DefaultPaywallFontProvider(),
displayCloseButton: Bool = false,
useDraftPaywall: Bool = false,
introEligibility: TrialOrIntroEligibilityChecker? = nil,
purchaseHandler: PurchaseHandler = PurchaseHandler.default(),
locale: Locale = .current
Expand All @@ -84,6 +88,7 @@ extension PaywallViewConfiguration {
mode: mode,
fonts: fonts,
displayCloseButton: displayCloseButton,
useDraftPaywall: useDraftPaywall,
introEligibility: introEligibility,
purchaseHandler: handler,
locale: locale
Expand Down
30 changes: 27 additions & 3 deletions RevenueCatUI/PaywallView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//
// Created by Nacho Soto.

import RevenueCat
@_spi(Internal) import RevenueCat
import SwiftUI

#if !os(macOS) && !os(tvOS)
Expand All @@ -31,6 +31,7 @@ public struct PaywallView: View {
private let fonts: PaywallFontProvider
private let displayCloseButton: Bool
private let paywallViewOwnsPurchaseHandler: Bool
private let useDraftPaywall: Bool

private var locale: Locale

Expand Down Expand Up @@ -104,13 +105,33 @@ public struct PaywallView: View {
displayCloseButton: Bool = false,
performPurchase: PerformPurchase? = nil,
performRestore: PerformRestore? = nil
) {
self.init(
offering: offering,
fonts: fonts,
displayCloseButton: displayCloseButton,
useDraftPaywall: false,
performPurchase: performPurchase,
performRestore: performRestore
)
}

// swiftlint:disable:next missing_docs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idk if we should be documenting these public-but-not-public APIs 🤔 WDYT @RevenueCat/coresdk?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm IMO, I think it's fine to not document them. It's not meant for public usage yeah.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be more inclined to documenting since it's quick, and particularly adding a - warn: this API is meant for internal use

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure... I would actually hide them from the reference docs if possible, but maybe we should have a note for people finding it through autocomplete?

Copy link
Member Author

@ajpallares ajpallares Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't appear in the autocomplete because of the @_spi(Internal) attribute. And based on the existing v5.16.1 release, which contains @_spi-protected APIs in DangerousSettings, it does not appear in the reference docs either (see https://revenuecat.github.io/purchases-ios-docs/5.16.1/documentation/revenuecat/dangeroussettings)

I'd be more inclined to documenting since it's quick, and particularly adding a - warn: this API is meant for internal use

@aboedo for all the above, I think that we don't need to document this and that its being internal should be clear thanks to @_spi(Internal) attribute

@_spi(Internal) public init(
offering: Offering,
fonts: PaywallFontProvider = DefaultPaywallFontProvider(),
displayCloseButton: Bool = false,
useDraftPaywall: Bool,
performPurchase: PerformPurchase? = nil,
performRestore: PerformRestore? = nil
) {
let purchaseHandler = PurchaseHandler.default(performPurchase: performPurchase, performRestore: performRestore)
self.init(
configuration: .init(
offering: offering,
fonts: fonts,
displayCloseButton: displayCloseButton,
useDraftPaywall: useDraftPaywall,
purchaseHandler: purchaseHandler
)
)
Expand Down Expand Up @@ -142,6 +163,7 @@ public struct PaywallView: View {
self.mode = configuration.mode
self.fonts = configuration.fonts
self.displayCloseButton = configuration.displayCloseButton
self.useDraftPaywall = configuration.useDraftPaywall

self.initializationError = Self.checkForConfigurationConsistency(purchaseHandler: configuration.purchaseHandler)

Expand Down Expand Up @@ -198,6 +220,7 @@ public struct PaywallView: View {
} else if self.introEligibility.isConfigured, self.purchaseHandler.isConfigured {
if let offering = self.offering, let customerInfo = self.customerInfo {
self.paywallView(for: offering,
useDraftPaywall: self.useDraftPaywall,
activelySubscribedProductIdentifiers: customerInfo.activeSubscriptions,
fonts: self.fonts,
checker: self.introEligibility,
Expand Down Expand Up @@ -240,9 +263,10 @@ public struct PaywallView: View {
}

@ViewBuilder
// swiftlint:disable:next function_body_length
// swiftlint:disable:next function_body_length function_parameter_count
private func paywallView(
for offering: Offering,
useDraftPaywall: Bool,
activelySubscribedProductIdentifiers: Set<String>,
fonts: PaywallFontProvider,
checker: TrialOrIntroEligibilityChecker,
Expand All @@ -253,7 +277,7 @@ public struct PaywallView: View {
countries: offering.paywall?.zeroDecimalPlaceCountries
)

if let paywallComponents = offering.paywallComponents {
if let paywallComponents = useDraftPaywall ? offering.draftPaywallComponents : offering.paywallComponents {

// For fallback view or footer
let paywall: PaywallData = .createDefault(with: offering.availablePackages,
Expand Down
2 changes: 1 addition & 1 deletion Sources/Networking/Responses/OfferingsResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct OfferingsResponse {
@DefaultDecodable.EmptyDictionary
var metadata: [String: AnyDecodable]
var paywallComponents: PaywallComponentsData?

var draftPaywallComponents: PaywallComponentsData?
}

struct Placements {
Expand Down
28 changes: 27 additions & 1 deletion Sources/Purchasing/Offering.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ import Foundation
*/
public let paywallComponents: PaywallComponents?

/**
Draft paywall components configuration defined in RevenueCat dashboard.
*/
@_spi(Internal) public let draftPaywallComponents: PaywallComponents?

/**
Array of ``Package`` objects available for purchase.
*/
Expand Down Expand Up @@ -176,12 +181,32 @@ import Foundation
}

/// Initialize an ``Offering`` given a list of ``Package``s.
public init(
public convenience init(
identifier: String,
serverDescription: String,
metadata: [String: Any] = [:],
paywall: PaywallData? = nil,
paywallComponents: PaywallComponents? = nil,
availablePackages: [Package]
) {
self.init(
identifier: identifier,
serverDescription: serverDescription,
metadata: metadata,
paywall: paywall,
paywallComponents: paywallComponents,
draftPaywallComponents: nil,
availablePackages: availablePackages
)
}

init(
identifier: String,
serverDescription: String,
metadata: [String: Any] = [:],
paywall: PaywallData? = nil,
paywallComponents: PaywallComponents? = nil,
draftPaywallComponents: PaywallComponents?,
availablePackages: [Package]
) {
self.identifier = identifier
Expand All @@ -190,6 +215,7 @@ import Foundation
self._metadata = Metadata(data: metadata)
self.paywall = paywall
self.paywallComponents = paywallComponents
self.draftPaywallComponents = draftPaywallComponents

var foundPackages: [PackageType: Package] = [:]

Expand Down
11 changes: 11 additions & 0 deletions Sources/Purchasing/OfferingsFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,22 @@ class OfferingsFactory {
return nil
}()

let paywallDraftComponents: Offering.PaywallComponents? = {
if let uiConfig, let paywallDraftComponents = offering.draftPaywallComponents {
return .init(
uiConfig: uiConfig,
data: paywallDraftComponents
)
}
return nil
}()

return Offering(identifier: offering.identifier,
serverDescription: offering.description,
metadata: offering.metadata.mapValues(\.asAny),
paywall: offering.paywall,
paywallComponents: paywallComponents,
draftPaywallComponents: paywallDraftComponents,
availablePackages: availablePackages)
}

Expand Down