From f14e8f4717a1180253dcbaa3ec4ed33834dc9731 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 10:58:19 +0100 Subject: [PATCH 1/8] add shouldDisplayDismissButton --- .../purchases/hybridcommon/ui/PaywallFragment.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt index 0ebe4b46..0b66dc97 100644 --- a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt +++ b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.lifecycle.ViewModelProvider +import com.revenuecat.purchases.Offering import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallActivityLauncher import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallResult @@ -13,6 +14,7 @@ import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallResultHandler internal class PaywallFragment : Fragment(), PaywallResultHandler { companion object { private const val requiredEntitlementIdentifierKey = "requiredEntitlementIdentifier" + private const val shouldDisplayDismissButtonKey = "shouldDisplayDismissButton" const val tag: String = "revenuecat-paywall-fragment" @JvmStatic @@ -20,12 +22,14 @@ internal class PaywallFragment : Fragment(), PaywallResultHandler { activity: FragmentActivity, requiredEntitlementIdentifier: String? = null, paywallResultListener: PaywallResultListener? = null, + shouldDisplayDismissButton: Boolean? = null, ): PaywallFragment { val paywallFragmentViewModel = ViewModelProvider(activity)[PaywallFragmentViewModel::class.java] paywallFragmentViewModel.paywallResultListener = paywallResultListener return PaywallFragment().apply { arguments = Bundle().apply { putString(requiredEntitlementIdentifierKey, requiredEntitlementIdentifier) + shouldDisplayDismissButton?.let { putBoolean(shouldDisplayDismissButtonKey, it) } } } } @@ -37,6 +41,9 @@ internal class PaywallFragment : Fragment(), PaywallResultHandler { private val requiredEntitlementIdentifier: String? get() = arguments?.getString(requiredEntitlementIdentifierKey) + private val shouldDisplayDismissButton: Boolean? + get() = arguments?.getBoolean(shouldDisplayDismissButtonKey) + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -46,8 +53,13 @@ internal class PaywallFragment : Fragment(), PaywallResultHandler { ) viewModel = ViewModelProvider(requireActivity())[PaywallFragmentViewModel::class.java] - requiredEntitlementIdentifier?.let { - launcher.launchIfNeeded(requiredEntitlementIdentifier = it) + requiredEntitlementIdentifier?.let { requiredEntitlementIdentifier -> + shouldDisplayDismissButton?.let { shouldDisplayDismissButton -> + launcher.launchIfNeeded( + requiredEntitlementIdentifier = requiredEntitlementIdentifier, + shouldDisplayDismissButton = shouldDisplayDismissButton, + ) + } ?: launcher.launchIfNeeded(requiredEntitlementIdentifier = requiredEntitlementIdentifier) } ?: launcher.launch() } From 0913068faf50b2dd4664eaf33abe0ec1ac66f74d Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 11:19:16 +0100 Subject: [PATCH 2/8] add displayCloseButton to iOS --- .../PurchasesHybridCommon/PaywallProxy.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift index be405dd7..156b8b34 100644 --- a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift +++ b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift @@ -26,13 +26,15 @@ import UIKit } @objc - public func presentPaywall() { + public func presentPaywall( + displayCloseButton: Bool = false + ) { guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { NSLog("Unable to find root UIViewController") return } - let controller = PaywallViewController(displayCloseButton: true) + let controller = PaywallViewController(displayCloseButton: displayCloseButton) controller.delegate = self controller.modalPresentationStyle = .pageSheet From 0cdb021101c3dd620b302785c8530159644d1821 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 14:05:36 +0100 Subject: [PATCH 3/8] make it optional in iOS --- .../ObjCAPITester/RCPaywallProxyAPITest.m | 1 + .../PurchasesHybridCommon/PaywallProxy.swift | 26 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m b/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m index a9f1c00b..4d386fc8 100644 --- a/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m +++ b/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m @@ -21,6 +21,7 @@ - (void)testAPI { if (@available(iOS 15.0, *)) { PaywallProxy *proxy = [PaywallProxy new]; [proxy presentPaywall]; + [proxy presentPaywallWithDisplayCloseButton:true]; [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@""]; } } diff --git a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift index 156b8b34..6ec2a53e 100644 --- a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift +++ b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift @@ -26,19 +26,25 @@ import UIKit } @objc - public func presentPaywall( - displayCloseButton: Bool = false - ) { + public func presentPaywall() { guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { NSLog("Unable to find root UIViewController") return } - let controller = PaywallViewController(displayCloseButton: displayCloseButton) - controller.delegate = self - controller.modalPresentationStyle = .pageSheet + let controller = PaywallViewController() + configureAndPresentPaywall(controller, rootController: rootController) + } - rootController.present(controller, animated: true) + @objc + public func presentPaywall(displayCloseButton: Bool) { + guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { + NSLog("Unable to find root UIViewController") + return + } + + let controller = PaywallViewController(displayCloseButton: displayCloseButton) + configureAndPresentPaywall(controller, rootController: rootController) } @objc @@ -55,6 +61,12 @@ import UIKit } } + private func configureAndPresentPaywall(_ viewController: PaywallViewController, rootController: UIViewController) { + viewController.delegate = self + viewController.modalPresentationStyle = .pageSheet + rootController.present(viewController, animated: true) + } + } @available(iOS 15.0, *) From 17a475f08f7da4b8b1ae5ebca622f894492f5f00 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 14:08:03 +0100 Subject: [PATCH 4/8] add to helpers --- .../java/com/revenuecat/apitests/java/PaywallApiTests.java | 6 +++++- .../java/com/revenuecat/apitests/kotlin/PaywallApiTests.kt | 7 +++++++ .../revenuecat/purchases/hybridcommon/ui/PaywallHelpers.kt | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/android/api-tests/src/test/java/com/revenuecat/apitests/java/PaywallApiTests.java b/android/api-tests/src/test/java/com/revenuecat/apitests/java/PaywallApiTests.java index a776d6af..866ef8cb 100644 --- a/android/api-tests/src/test/java/com/revenuecat/apitests/java/PaywallApiTests.java +++ b/android/api-tests/src/test/java/com/revenuecat/apitests/java/PaywallApiTests.java @@ -21,7 +21,8 @@ public void onPaywallResult(@NonNull PaywallResult paywallResult) { private void checkPresentPaywall( FragmentActivity fragmentActivity, String requiredEntitlementIdentifier, - PaywallResultListener listener + PaywallResultListener listener, + Boolean shouldDisplayDismissButton ) { PaywallHelpersKt.presentPaywallFromFragment( fragmentActivity @@ -32,5 +33,8 @@ private void checkPresentPaywall( PaywallHelpersKt.presentPaywallFromFragment( fragmentActivity, requiredEntitlementIdentifier, listener ); + PaywallHelpersKt.presentPaywallFromFragment( + fragmentActivity, requiredEntitlementIdentifier, listener, shouldDisplayDismissButton + ); } } diff --git a/android/api-tests/src/test/java/com/revenuecat/apitests/kotlin/PaywallApiTests.kt b/android/api-tests/src/test/java/com/revenuecat/apitests/kotlin/PaywallApiTests.kt index 17a485bd..17868f5a 100644 --- a/android/api-tests/src/test/java/com/revenuecat/apitests/kotlin/PaywallApiTests.kt +++ b/android/api-tests/src/test/java/com/revenuecat/apitests/kotlin/PaywallApiTests.kt @@ -21,6 +21,7 @@ private class PaywallApiTests { fragmentActivity: FragmentActivity, requiredEntitlementIdentifier: String?, paywallResultListener: PaywallResultListener?, + shouldDisplayDismissButton: Boolean?, ) { presentPaywallFromFragment( fragment = fragmentActivity, @@ -34,5 +35,11 @@ private class PaywallApiTests { requiredEntitlementIdentifier = requiredEntitlementIdentifier, paywallResultListener = paywallResultListener, ) + presentPaywallFromFragment( + fragment = fragmentActivity, + requiredEntitlementIdentifier = requiredEntitlementIdentifier, + paywallResultListener = paywallResultListener, + shouldDisplayDismissButton = shouldDisplayDismissButton, + ) } } diff --git a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallHelpers.kt b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallHelpers.kt index abd9ec91..d494e906 100644 --- a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallHelpers.kt +++ b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallHelpers.kt @@ -7,6 +7,7 @@ fun presentPaywallFromFragment( fragment: FragmentActivity, requiredEntitlementIdentifier: String? = null, paywallResultListener: PaywallResultListener? = null, + shouldDisplayDismissButton: Boolean? = null, ) { fragment .supportFragmentManager @@ -16,6 +17,7 @@ fun presentPaywallFromFragment( fragment, requiredEntitlementIdentifier, paywallResultListener, + shouldDisplayDismissButton, ), PaywallFragment.tag, ) From 1c10d5451b90a63511c1e515fdcc3b4205df2f33 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 14:20:28 +0100 Subject: [PATCH 5/8] add missing call --- .../hybridcommon/ui/PaywallFragment.kt | 24 +++++++++++++------ .../PurchasesHybridCommon/PaywallProxy.swift | 14 +++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt index 0b66dc97..fc3949f2 100644 --- a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt +++ b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt @@ -54,16 +54,26 @@ internal class PaywallFragment : Fragment(), PaywallResultHandler { viewModel = ViewModelProvider(requireActivity())[PaywallFragmentViewModel::class.java] requiredEntitlementIdentifier?.let { requiredEntitlementIdentifier -> - shouldDisplayDismissButton?.let { shouldDisplayDismissButton -> - launcher.launchIfNeeded( - requiredEntitlementIdentifier = requiredEntitlementIdentifier, - shouldDisplayDismissButton = shouldDisplayDismissButton, - ) - } ?: launcher.launchIfNeeded(requiredEntitlementIdentifier = requiredEntitlementIdentifier) - } ?: launcher.launch() + launchPaywallIfNeeded(requiredEntitlementIdentifier) + } ?: launchPaywall() } override fun onActivityResult(result: PaywallResult) { viewModel.paywallResultListener?.onPaywallResult(result) } + + private fun launchPaywallIfNeeded(requiredEntitlementIdentifier: String) { + shouldDisplayDismissButton?.let { shouldDisplayDismissButton -> + launcher.launchIfNeeded( + requiredEntitlementIdentifier = requiredEntitlementIdentifier, + shouldDisplayDismissButton = shouldDisplayDismissButton, + ) + } ?: launcher.launchIfNeeded(requiredEntitlementIdentifier = requiredEntitlementIdentifier) + } + + private fun launchPaywall() { + shouldDisplayDismissButton?.let { + launcher.launch(shouldDisplayDismissButton = it) + } ?: launcher.launch() + } } diff --git a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift index 6ec2a53e..61019f42 100644 --- a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift +++ b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift @@ -61,6 +61,20 @@ import UIKit } } + @objc + public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, displayCloseButton: Bool) { + _ = Task { @MainActor in + do { + let customerInfo = try await Purchases.shared.customerInfo() + if !customerInfo.entitlements.active.keys.contains(requiredEntitlementIdentifier) { + self.presentPaywall(displayCloseButton: displayCloseButton) + } + } catch { + NSLog("Failed presenting paywall: \(error)") + } + } + } + private func configureAndPresentPaywall(_ viewController: PaywallViewController, rootController: UIViewController) { viewController.delegate = self viewController.modalPresentationStyle = .pageSheet From abb31cc7f510f943f9ab091db5a88f6e2f1625af Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 14:21:24 +0100 Subject: [PATCH 6/8] remove unused import --- .../com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt index fc3949f2..411b5f27 100644 --- a/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt +++ b/android/hybridcommon-ui/src/main/java/com/revenuecat/purchases/hybridcommon/ui/PaywallFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.lifecycle.ViewModelProvider -import com.revenuecat.purchases.Offering import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallActivityLauncher import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallResult From 92a7f109e97b43e70bfc4e20ae65dd04f83a49e4 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 16:34:49 +0100 Subject: [PATCH 7/8] cleanup by using private functions --- .../PurchasesHybridCommon/PaywallProxy.swift | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift index 61019f42..faa07c91 100644 --- a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift +++ b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift @@ -27,47 +27,37 @@ import UIKit @objc public func presentPaywall() { - guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { - NSLog("Unable to find root UIViewController") - return - } - - let controller = PaywallViewController() - configureAndPresentPaywall(controller, rootController: rootController) + presentPaywall(optionalDisplayCloseButton: nil) } @objc public func presentPaywall(displayCloseButton: Bool) { - guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { - NSLog("Unable to find root UIViewController") - return - } - - let controller = PaywallViewController(displayCloseButton: displayCloseButton) - configureAndPresentPaywall(controller, rootController: rootController) + presentPaywall(optionalDisplayCloseButton: displayCloseButton) } @objc public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String) { - _ = Task { @MainActor in - do { - let customerInfo = try await Purchases.shared.customerInfo() - if !customerInfo.entitlements.active.keys.contains(requiredEntitlementIdentifier) { - self.presentPaywall() - } - } catch { - NSLog("Failed presenting paywall: \(error)") - } - } + presentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, + optionalDisplayCloseButton: nil) } @objc public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, displayCloseButton: Bool) { + presentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, + optionalDisplayCloseButton: displayCloseButton) + } + + private func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, optionalDisplayCloseButton: Bool?) { _ = Task { @MainActor in do { let customerInfo = try await Purchases.shared.customerInfo() if !customerInfo.entitlements.active.keys.contains(requiredEntitlementIdentifier) { - self.presentPaywall(displayCloseButton: displayCloseButton) + if let displayCloseButton = optionalDisplayCloseButton { + self.presentPaywall(displayCloseButton: displayCloseButton) + } else { + self.presentPaywall() + } + } } catch { NSLog("Failed presenting paywall: \(error)") @@ -75,10 +65,22 @@ import UIKit } } - private func configureAndPresentPaywall(_ viewController: PaywallViewController, rootController: UIViewController) { - viewController.delegate = self - viewController.modalPresentationStyle = .pageSheet - rootController.present(viewController, animated: true) + private func presentPaywall(optionalDisplayCloseButton: Bool?) { + guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { + NSLog("Unable to find root UIViewController") + return + } + + let controller: PaywallViewController + if let displayCloseButton = optionalDisplayCloseButton { + controller = PaywallViewController(displayCloseButton: displayCloseButton) + } else { + controller = PaywallViewController() + } + + controller.delegate = self + controller.modalPresentationStyle = .pageSheet + rootController.present(controller, animated: true) } } From b4baf09911cf37e5feae66f57b94a2422c008488 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 22 Dec 2023 16:35:53 +0100 Subject: [PATCH 8/8] add to API test --- ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m b/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m index 4d386fc8..cc76bf69 100644 --- a/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m +++ b/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m @@ -23,6 +23,7 @@ - (void)testAPI { [proxy presentPaywall]; [proxy presentPaywallWithDisplayCloseButton:true]; [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@""]; + [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@"" displayCloseButton:YES]; } }