Skip to content

Commit

Permalink
Paywalls: added support for PackageType.custom (#2959)
Browse files Browse the repository at this point in the history
Fixes [PWL-80].
  • Loading branch information
NachoSoto committed Sep 8, 2023
1 parent c1804a0 commit 9735d57
Show file tree
Hide file tree
Showing 20 changed files with 152 additions and 86 deletions.
2 changes: 1 addition & 1 deletion RevenueCatUI/Data/Errors/TemplateError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ enum TemplateError: Error {
case emptyPackageList

/// No packages from the `PackageType` list could be found.
case couldNotFindAnyPackages(expectedTypes: [PackageType])
case couldNotFindAnyPackages(expectedTypes: [String])

}

Expand Down
6 changes: 3 additions & 3 deletions RevenueCatUI/Data/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import RevenueCat
enum Strings {

case package_not_subscription(Package)
case found_multiple_packages_of_same_type(PackageType)
case found_multiple_packages_of_same_identifier(String)
case could_not_find_content_for_variable(variableName: String)

case determining_whether_to_display_paywall
Expand All @@ -30,8 +30,8 @@ extension Strings: CustomStringConvertible {
return "Expected package '\(package.identifier)' to be a subscription. " +
"Type: \(package.packageType.debugDescription)"

case let .found_multiple_packages_of_same_type(type):
return "Found multiple \(type) packages. Will use the first one."
case let .found_multiple_packages_of_same_identifier(identifier):
return "Found multiple packages with same identifier '\(identifier)'. Will use the first one."

case let .could_not_find_content_for_variable(variableName):
return "Couldn't find content for variable '\(variableName)'"
Expand Down
18 changes: 9 additions & 9 deletions RevenueCatUI/Data/TemplateViewConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ extension TemplateViewConfiguration.PackageConfiguration {
/// - Throws: `TemplateError`
static func create(
with packages: [RevenueCat.Package],
filter: [PackageType],
default: PackageType?,
filter: [String],
default: String?,
localization: PaywallData.LocalizedConfiguration,
setting: TemplateViewConfiguration.PackageSetting,
locale: Locale = .current
Expand Down Expand Up @@ -150,7 +150,7 @@ extension TemplateViewConfiguration.PackageConfiguration {
return .single(firstPackage)
case .multiple:
let defaultPackage = filteredPackages
.first { $0.content.packageType == `default` }
.first { $0.content.identifier == `default` }
?? firstPackage

return .multiple(first: firstPackage,
Expand Down Expand Up @@ -189,20 +189,20 @@ extension TemplateViewConfiguration.PackageConfiguration {
@available(iOS 16.0, macOS 13.0, tvOS 16.0, *)
extension TemplateViewConfiguration {

/// Filters `packages`, extracting only the values corresponding to `list`.
static func filter(packages: [RevenueCat.Package], with list: [PackageType]) -> [RevenueCat.Package] {
let map = Dictionary(grouping: packages) { $0.packageType }
/// Filters `packages`, extracting only the values corresponding to `identifiers`.
static func filter(packages: [RevenueCat.Package], with identifiers: [String]) -> [RevenueCat.Package] {
let map = Dictionary(grouping: packages) { $0.identifier }

return list.compactMap { type in
if let packages = map[type] {
return identifiers.compactMap { identifier in
if let packages = map[identifier] {
switch packages.count {
case 0:
// This isn't actually possible because of `Dictionary(grouping:by:)
return nil
case 1:
return packages.first
default:
Logger.warning(Strings.found_multiple_packages_of_same_type(type))
Logger.warning(Strings.found_multiple_packages_of_same_identifier(identifier))
return packages.first
}
} else {
Expand Down
30 changes: 19 additions & 11 deletions RevenueCatUI/Data/TestData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ internal enum TestData {
price: 119.49,
localizedPriceString: "$119.49",
productIdentifier: "com.revenuecat.product_lifetime",
productType: .consumable,
productType: .nonConsumable,
localizedDescription: "Lifetime purchase",
subscriptionGroupIdentifier: "group",
subscriptionPeriod: nil
Expand Down Expand Up @@ -90,38 +90,38 @@ internal enum TestData {
discounts: []
)
static let weeklyPackage = Package(
identifier: "weekly",
identifier: PackageType.weekly.identifier,
packageType: .weekly,
storeProduct: Self.weeklyProduct.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
)
static let monthlyPackage = Package(
identifier: "monthly",
identifier: PackageType.monthly.identifier,
packageType: .monthly,
storeProduct: Self.monthlyProduct.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
)
static let annualPackage = Package(
identifier: "annual",
identifier: PackageType.annual.identifier,
packageType: .annual,
storeProduct: Self.annualProduct.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
)

static let packageWithIntroOffer = Package(
identifier: "monthly",
identifier: PackageType.monthly.identifier,
packageType: .monthly,
storeProduct: productWithIntroOffer.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
)
static let packageWithNoIntroOffer = Package(
identifier: "annual",
identifier: PackageType.annual.identifier,
packageType: .annual,
storeProduct: productWithNoIntroOffer.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
)
static let lifetimePackage = Package(
identifier: "lifetime",
identifier: PackageType.lifetime.identifier,
packageType: .lifetime,
storeProduct: Self.lifetimeProduct.toStoreProduct(),
offeringIdentifier: Self.offeringIdentifier
Expand All @@ -135,7 +135,7 @@ internal enum TestData {
static let paywallWithIntroOffer = PaywallData(
template: .onePackageStandard,
config: .init(
packages: [.monthly],
packages: [PackageType.monthly.identifier],
images: Self.images,
colors: .init(light: Self.lightColors, dark: Self.darkColors),
termsOfServiceURL: URL(string: "https://revenuecat.com/tos")!,
Expand All @@ -147,7 +147,7 @@ internal enum TestData {
static let paywallWithNoIntroOffer = PaywallData(
template: .onePackageStandard,
config: .init(
packages: [.annual],
packages: [PackageType.annual.identifier],
images: Self.images,
colors: .init(light: Self.lightColors, dark: Self.darkColors)
),
Expand Down Expand Up @@ -178,7 +178,7 @@ internal enum TestData {
paywall: .init(
template: .multiPackageBold,
config: .init(
packages: [.annual, .monthly],
packages: [PackageType.annual.identifier, PackageType.monthly.identifier],
images: Self.images,
colors: .init(
light: .init(
Expand Down Expand Up @@ -217,7 +217,7 @@ internal enum TestData {
paywall: .init(
template: .onePackageWithFeatures,
config: .init(
packages: [.annual],
packages: [PackageType.annual.identifier],
images: Self.images,
colors: .init(
light: .init(
Expand Down Expand Up @@ -438,4 +438,12 @@ extension PaywallColor: ExpressibleByStringLiteral {

}

extension PackageType {

var identifier: String {
return Package.string(from: self)!
}

}

#endif
6 changes: 5 additions & 1 deletion RevenueCatUI/Helpers/PaywallData+Default.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ extension PaywallData {
public static let `default`: Self = .init(
template: .multiPackageBold,
config: .init(
packages: [.weekly, .monthly, .annual],
packages: [
Package.string(from: .weekly)!,
Package.string(from: .monthly)!,
Package.string(from: .annual)!
],
images: .init(background: Self.backgroundImage),
colors: Self.colors,
blurredBackgroundImage: true,
Expand Down
10 changes: 5 additions & 5 deletions Sources/Paywalls/PaywallData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@ extension PaywallData {
/// Generic configuration for any paywall.
public struct Configuration {

/// The list of package types this paywall will display
public var packages: [PackageType]
/// The list of package identifiers this paywall will display
public var packages: [String]

/// The package to be selected by default.
public var defaultPackage: PackageType?
public var defaultPackage: String?

/// The images for this template.
public var images: Images
Expand Down Expand Up @@ -217,8 +217,8 @@ extension PaywallData {

// swiftlint:disable:next missing_docs
public init(
packages: [PackageType],
defaultPackage: PackageType? = nil,
packages: [String],
defaultPackage: String? = nil,
images: Images,
colors: ColorInformation,
blurredBackgroundImage: Bool = false,
Expand Down
1 change: 1 addition & 0 deletions Sources/Purchasing/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import Foundation
}

/// Initialize a ``Package``.
@objc
public init(
identifier: String,
packageType: PackageType,
Expand Down
2 changes: 1 addition & 1 deletion Sources/Purchasing/Purchases/Purchases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1627,7 +1627,7 @@ private extension Purchases {
let products: Set<String> = .init(
offering.availablePackages
.lazy
.filter { packageTypes.contains($0.packageType) }
.filter { packageTypes.contains($0.identifier) }
.map(\.storeProduct.productIdentifier)
)

Expand Down
6 changes: 6 additions & 0 deletions Tests/APITesters/ObjCAPITester/ObjCAPITester/RCPackageAPI.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ + (void)checkAPI {
RCStoreProduct *storeProduct = p.storeProduct;
NSString *i = p.identifier;
RCPackageType t = p.packageType;
NSString *oid = p.offeringIdentifier;
NSString *lps = p.localizedPriceString;
NSString *lips = p.localizedIntroductoryPriceString;

NSLog(p, storeProduct, i, t, lps, lips);

RCPackage *package __unused = [[RCPackage alloc] initWithIdentifier:i
packageType:RCPackageTypeAnnual
storeProduct:storeProduct
offeringIdentifier:oid];
}

+ (void)checkEnums {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ func checkPackageAPI() {
let ident: String = pack.identifier
let pType: PackageType = pack.packageType
let prod: StoreProduct = pack.storeProduct
let oID: String = pack.offeringIdentifier
let lps: String = pack.localizedPriceString
let lips: String? = pack.localizedIntroductoryPriceString

print(pack!, ident, pType, prod, lps, lips!)
print(pack!, ident, pType, prod, oID, lps, lips!)
}

private func checkCreatePackageAPI(product: StoreProduct) {
_ = Package(
identifier: "", packageType: PackageType.annual,
identifier: "",
packageType: PackageType.annual,
storeProduct: product,
offeringIdentifier: ""
)
Expand Down
10 changes: 5 additions & 5 deletions Tests/APITesters/SwiftAPITester/SwiftAPITester/PaywallAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ func checkPaywallData(_ data: PaywallData) {
func checkPaywallConfiguration(_ config: PaywallData.Configuration,
_ images: PaywallData.Configuration.Images,
_ colors: PaywallData.Configuration.ColorInformation) {
let _: PaywallData.Configuration = .init(packages: [.monthly, .annual],
let _: PaywallData.Configuration = .init(packages: ["$rc_monthly", "$rc_annual"],
images: images,
colors: colors)
let _: PaywallData.Configuration = .init(packages: [.monthly, .annual],
defaultPackage: .monthly,
let _: PaywallData.Configuration = .init(packages: ["$rc_monthly", "custom"],
defaultPackage: "custom",
images: images,
colors: colors,
blurredBackgroundImage: true,
displayRestorePurchases: true,
termsOfServiceURL: URL(string: ""),
privacyURL: URL(string: ""))
let _: [PackageType] = config.packages
let _: PackageType? = config.defaultPackage
let _: [String] = config.packages
let _: String? = config.defaultPackage
let _: PaywallData.Configuration.Images = config.images
let _: PaywallData.Configuration.ColorInformation = config.colors
let _: Bool = config.blurredBackgroundImage
Expand Down
Loading

0 comments on commit 9735d57

Please sign in to comment.