From 97c06565de9fa13cfa1b71911047ebff69a5e40f Mon Sep 17 00:00:00 2001 From: NachoSoto Date: Fri, 25 Aug 2023 10:21:33 -0700 Subject: [PATCH] `Paywalls`: enabled `Catalyst` support (#3087) ![Screenshot 2023-08-24 at 15 18 51](https://github.com/RevenueCat/purchases-ios/assets/685609/7a243aad-1558-419b-b2f8-b39f620794f4) With "native" design: ![Screenshot 2023-08-25 at 10 11 10](https://github.com/RevenueCat/purchases-ios/assets/685609/8d0c529d-0b5a-4ca5-b7b0-7462187f6864) --- .../Helpers/PaywallData+Default.swift | 1 - RevenueCatUI/Helpers/PreviewHelpers.swift | 1 - RevenueCatUI/PaywallView.swift | 2 - RevenueCatUI/Templates/Template1View.swift | 1 - RevenueCatUI/Templates/Template2View.swift | 1 - RevenueCatUI/Templates/Template3View.swift | 1 - RevenueCatUI/Templates/Template4View.swift | 1 - RevenueCatUI/Views/FooterView.swift | 4 +- RevenueCatUI/Views/LoadingPaywallView.swift | 1 - .../SimpleApp.xcodeproj/project.pbxproj | 8 +- .../SimpleApp/Views/CustomPaywall.swift | 6 +- .../SimpleApp/Views/OfferingsList.swift | 15 ++- .../SimpleApp/Views/SamplePaywallsList.swift | 96 +++++++++++-------- 13 files changed, 80 insertions(+), 58 deletions(-) diff --git a/RevenueCatUI/Helpers/PaywallData+Default.swift b/RevenueCatUI/Helpers/PaywallData+Default.swift index 747b89a711..5f61f02e48 100644 --- a/RevenueCatUI/Helpers/PaywallData+Default.swift +++ b/RevenueCatUI/Helpers/PaywallData+Default.swift @@ -110,7 +110,6 @@ private extension PaywallData { @available(watchOS, unavailable) @available(macOS, unavailable) @available(tvOS, unavailable) -@available(macCatalyst, unavailable) struct DefaultPaywall_Previews: PreviewProvider { static var previews: some View { diff --git a/RevenueCatUI/Helpers/PreviewHelpers.swift b/RevenueCatUI/Helpers/PreviewHelpers.swift index cfa2687ec9..4471570047 100644 --- a/RevenueCatUI/Helpers/PreviewHelpers.swift +++ b/RevenueCatUI/Helpers/PreviewHelpers.swift @@ -19,7 +19,6 @@ import SwiftUI @available(iOS 16.0, macOS 13.0, tvOS 16.0, *) @available(watchOS, unavailable) @available(macOS, unavailable) -@available(macCatalyst, unavailable) @MainActor enum PreviewHelpers { diff --git a/RevenueCatUI/PaywallView.swift b/RevenueCatUI/PaywallView.swift index 31074d081d..71348d0fc6 100644 --- a/RevenueCatUI/PaywallView.swift +++ b/RevenueCatUI/PaywallView.swift @@ -22,7 +22,6 @@ import SwiftUI @available(watchOS, unavailable, message: "RevenueCatUI does not support watchOS yet") @available(macOS, unavailable, message: "RevenueCatUI does not support macOS yet") @available(tvOS, unavailable, message: "RevenueCatUI does not support tvOS yet") -@available(macCatalyst, unavailable, message: "RevenueCatUI does not support Catalyst yet") public struct PaywallView: View { private let mode: PaywallViewMode @@ -250,7 +249,6 @@ struct LoadedOfferingPaywallView: View { @available(watchOS, unavailable) @available(macOS, unavailable) @available(tvOS, unavailable) -@available(macCatalyst, unavailable) struct PaywallView_Previews: PreviewProvider { static var previews: some View { diff --git a/RevenueCatUI/Templates/Template1View.swift b/RevenueCatUI/Templates/Template1View.swift index d95bcf8be0..e9002f747c 100644 --- a/RevenueCatUI/Templates/Template1View.swift +++ b/RevenueCatUI/Templates/Template1View.swift @@ -165,7 +165,6 @@ private struct CircleMaskModifier: ViewModifier { @available(watchOS, unavailable) @available(macOS, unavailable) @available(tvOS, unavailable) -@available(macCatalyst, unavailable) struct Template1View_Previews: PreviewProvider { static var previews: some View { diff --git a/RevenueCatUI/Templates/Template2View.swift b/RevenueCatUI/Templates/Template2View.swift index c7a94b08c7..ff9e3a7e1b 100644 --- a/RevenueCatUI/Templates/Template2View.swift +++ b/RevenueCatUI/Templates/Template2View.swift @@ -324,7 +324,6 @@ private extension Bundle { @available(watchOS, unavailable) @available(macOS, unavailable) @available(tvOS, unavailable) -@available(macCatalyst, unavailable) struct Template2View_Previews: PreviewProvider { static var previews: some View { diff --git a/RevenueCatUI/Templates/Template3View.swift b/RevenueCatUI/Templates/Template3View.swift index 4e69f47f72..d7b5be68e0 100644 --- a/RevenueCatUI/Templates/Template3View.swift +++ b/RevenueCatUI/Templates/Template3View.swift @@ -189,7 +189,6 @@ private struct FeatureView: View { @available(watchOS, unavailable) @available(macOS, unavailable) @available(tvOS, unavailable) -@available(macCatalyst, unavailable) struct Template3View_Previews: PreviewProvider { static var previews: some View { diff --git a/RevenueCatUI/Templates/Template4View.swift b/RevenueCatUI/Templates/Template4View.swift index 1a942ca60a..93e1b75fb2 100644 --- a/RevenueCatUI/Templates/Template4View.swift +++ b/RevenueCatUI/Templates/Template4View.swift @@ -370,7 +370,6 @@ private extension PaywallViewMode { @available(iOS 16.0, macOS 13.0, tvOS 16.0, *) @available(watchOS, unavailable) @available(macOS, unavailable) -@available(macCatalyst, unavailable) struct Template4View_Previews: PreviewProvider { static var previews: some View { diff --git a/RevenueCatUI/Views/FooterView.swift b/RevenueCatUI/Views/FooterView.swift index b167c6616d..5d285566cc 100644 --- a/RevenueCatUI/Views/FooterView.swift +++ b/RevenueCatUI/Views/FooterView.swift @@ -101,6 +101,9 @@ struct FooterView: View { .padding(.horizontal) .padding(.bottom, 5) .dynamicTypeSize(...Constants.maximumDynamicTypeSize) + #if targetEnvironment(macCatalyst) + .buttonStyle(.plain) + #endif } private static func allPlansButton(_ binding: Binding) -> some View { @@ -229,7 +232,6 @@ private struct LinkButton: View { @available(iOS 16.0, macOS 13.0, tvOS 16.0, *) @available(watchOS, unavailable) @available(macOS, unavailable) -@available(macCatalyst, unavailable) struct Footer_Previews: PreviewProvider { static var previews: some View { diff --git a/RevenueCatUI/Views/LoadingPaywallView.swift b/RevenueCatUI/Views/LoadingPaywallView.swift index 5422514731..d95898271d 100644 --- a/RevenueCatUI/Views/LoadingPaywallView.swift +++ b/RevenueCatUI/Views/LoadingPaywallView.swift @@ -133,7 +133,6 @@ private extension LoadingPaywallView { @available(watchOS, unavailable) @available(macOS, unavailable) @available(tvOS, unavailable) -@available(macCatalyst, unavailable) struct LoadingPaywallView_Previews: PreviewProvider { static var previews: some View { diff --git a/Tests/TestingApps/SimpleApp/SimpleApp.xcodeproj/project.pbxproj b/Tests/TestingApps/SimpleApp/SimpleApp.xcodeproj/project.pbxproj index f2e0d95c35..7576cc9d2d 100644 --- a/Tests/TestingApps/SimpleApp/SimpleApp.xcodeproj/project.pbxproj +++ b/Tests/TestingApps/SimpleApp/SimpleApp.xcodeproj/project.pbxproj @@ -390,13 +390,13 @@ PRODUCT_BUNDLE_IDENTIFIER = com.revenuecat.PaywallsTester; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,7"; + TARGETED_DEVICE_FAMILY = "1,2,6,7"; }; name = Debug; }; @@ -434,13 +434,13 @@ PRODUCT_BUNDLE_IDENTIFIER = com.revenuecat.PaywallsTester; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,7"; + TARGETED_DEVICE_FAMILY = "1,2,6,7"; }; name = Release; }; diff --git a/Tests/TestingApps/SimpleApp/SimpleApp/Views/CustomPaywall.swift b/Tests/TestingApps/SimpleApp/SimpleApp/Views/CustomPaywall.swift index 1faa156121..99f4008d8c 100644 --- a/Tests/TestingApps/SimpleApp/SimpleApp/Views/CustomPaywall.swift +++ b/Tests/TestingApps/SimpleApp/SimpleApp/Views/CustomPaywall.swift @@ -18,10 +18,8 @@ struct CustomPaywall: View { var purchaseHandler: PurchaseHandler? var body: some View { - NavigationView { - self.content - .navigationTitle("Custom paywall") - } + self.content + .navigationTitle("Custom paywall") } private var content: some View { diff --git a/Tests/TestingApps/SimpleApp/SimpleApp/Views/OfferingsList.swift b/Tests/TestingApps/SimpleApp/SimpleApp/Views/OfferingsList.swift index 0e24343f23..232df6af11 100644 --- a/Tests/TestingApps/SimpleApp/SimpleApp/Views/OfferingsList.swift +++ b/Tests/TestingApps/SimpleApp/SimpleApp/Views/OfferingsList.swift @@ -42,7 +42,20 @@ struct OfferingsList: View { case let .success(offerings): self.list(with: offerings) .sheet(item: self.$selectedOffering) { offering in - PaywallView(offering: offering) + NavigationView { + PaywallView(offering: offering) + #if targetEnvironment(macCatalyst) + .toolbar { + ToolbarItem(placement: .destructiveAction) { + Button { + self.selectedOffering = nil + } label: { + Image(systemName: "xmark") + } + } + } + #endif + } } case let .failure(error): diff --git a/Tests/TestingApps/SimpleApp/SimpleApp/Views/SamplePaywallsList.swift b/Tests/TestingApps/SimpleApp/SimpleApp/Views/SamplePaywallsList.swift index 5ca59c4e48..1dc4b15185 100644 --- a/Tests/TestingApps/SimpleApp/SimpleApp/Views/SamplePaywallsList.swift +++ b/Tests/TestingApps/SimpleApp/SimpleApp/Views/SamplePaywallsList.swift @@ -22,45 +22,19 @@ struct SamplePaywallsList: View { .navigationTitle("Test Paywalls") } .sheet(item: self.$display) { display in - switch display { - case let .template(template, mode): - switch mode { - case .fullScreen: - PaywallView(offering: Self.loader.offering(for: template), - customerInfo: Self.loader.customerInfo, - introEligibility: Self.introEligibility, - purchaseHandler: .default()) - - case .footer, .condensedFooter: - CustomPaywall(offering: Self.loader.offering(for: template), - customerInfo: Self.loader.customerInfo, - condensed: mode == .condensedFooter, - introEligibility: Self.introEligibility, - purchaseHandler: .default()) - } - - case let .customFont(template): - PaywallView(offering: Self.loader.offering(for: template), - customerInfo: Self.loader.customerInfo, - fonts: Self.customFontProvider, - introEligibility: Self.introEligibility, - purchaseHandler: .default()) - - case let .customPaywall(mode): - CustomPaywall(customerInfo: Self.loader.customerInfo, - condensed: mode == .condensedFooter) - - case .missingPaywall: - PaywallView(offering: Self.loader.offeringWithDefaultPaywall(), - customerInfo: Self.loader.customerInfo, - introEligibility: Self.introEligibility, - purchaseHandler: .default()) - - case .unrecognizedPaywall: - PaywallView(offering: Self.loader.offeringWithUnrecognizedPaywall(), - customerInfo: Self.loader.customerInfo, - introEligibility: Self.introEligibility, - purchaseHandler: .default()) + NavigationView { + self.view(for: display) + #if targetEnvironment(macCatalyst) + .toolbar { + ToolbarItem(placement: .destructiveAction) { + Button { + self.display = nil + } label: { + Image(systemName: "xmark") + } + } + } + #endif } } .onPurchaseCompleted { _ in @@ -69,6 +43,50 @@ struct SamplePaywallsList: View { .navigationTitle("Paywalls") } + @ViewBuilder + private func view(for display: Display) -> some View { + switch display { + case let .template(template, mode): + switch mode { + case .fullScreen: + PaywallView(offering: Self.loader.offering(for: template), + customerInfo: Self.loader.customerInfo, + introEligibility: Self.introEligibility, + purchaseHandler: .default()) + + case .footer, .condensedFooter: + CustomPaywall(offering: Self.loader.offering(for: template), + customerInfo: Self.loader.customerInfo, + condensed: mode == .condensedFooter, + introEligibility: Self.introEligibility, + purchaseHandler: .default()) + } + + case let .customFont(template): + PaywallView(offering: Self.loader.offering(for: template), + customerInfo: Self.loader.customerInfo, + fonts: Self.customFontProvider, + introEligibility: Self.introEligibility, + purchaseHandler: .default()) + + case let .customPaywall(mode): + CustomPaywall(customerInfo: Self.loader.customerInfo, + condensed: mode == .condensedFooter) + + case .missingPaywall: + PaywallView(offering: Self.loader.offeringWithDefaultPaywall(), + customerInfo: Self.loader.customerInfo, + introEligibility: Self.introEligibility, + purchaseHandler: .default()) + + case .unrecognizedPaywall: + PaywallView(offering: Self.loader.offeringWithUnrecognizedPaywall(), + customerInfo: Self.loader.customerInfo, + introEligibility: Self.introEligibility, + purchaseHandler: .default()) + } + } + private func list(with loader: SamplePaywallLoader) -> some View { List { ForEach(PaywallTemplate.allCases, id: \.rawValue) { template in