Skip to content

Commit

Permalink
Cleaned up hacks
Browse files Browse the repository at this point in the history
  • Loading branch information
NachoSoto committed Aug 22, 2023
1 parent ee48037 commit 39e5c9a
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 77 deletions.
2 changes: 0 additions & 2 deletions RevenueCatUI/Data/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ enum Constants {

static let defaultCornerRadius: CGFloat = 20

static let maxFooterHeight: CGFloat = 400

/// For UI elements that wouldn't make sense to keep scaling up forever
static let maximumDynamicTypeSize: DynamicTypeSize = .accessibility3

Expand Down
18 changes: 12 additions & 6 deletions RevenueCatUI/Modifiers/FooterHidingModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,25 @@ private struct FooterHidingModifier: ViewModifier {

func body(content: Content) -> some View {
switch self.configuration.mode {
case .fullScreen, .footer:
case .fullScreen:
// These modes don't support hiding the content
content
.padding(.vertical)

case .footer:
content

case .condensedFooter:
content
.onSizeChange(.vertical) { self.height = $0 }
.onSizeChange(.vertical) { if $0 > 0 { self.height = $0 } }
.opacity(self.hide ? 0 : 1)
.frame(height: self.hide ? 0 : nil, alignment: .top)
.clipped()
.transition(.move(edge: .bottom))

.offset(
y: self.hide
? self.height
: 0
)
.frame(height: self.hide ? 0 : nil)
.blur(radius: self.hide ? Self.blurRadius : 0)
}
}

Expand Down
25 changes: 11 additions & 14 deletions RevenueCatUI/PaywallFooterView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,27 @@ import SwiftUI
@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 PaywallFooterView: View {
internal struct PaywallFooterView: View {

private let mode: PaywallViewMode
private let condensed: Bool
private let fonts: PaywallFontProvider
private let introEligibility: TrialOrIntroEligibilityChecker?
private let purchaseHandler: PurchaseHandler?

@State
private var offering: Offering?
@State
private var error: NSError?

/// Create a view that loads the `Offerings.current`.
/// - Note: If loading the current `Offering` fails (if the user is offline, for example),
/// an error will be displayed.
/// - Warning: `Purchases` must have been configured prior to displaying it.
/// If you want to handle that, you can use ``init(offering:mode:)`` instead.
public init(
init(
condensed: Bool = false,
fonts: PaywallFontProvider = DefaultPaywallFontProvider()
) {
self.init(
offering: nil,
condensed: condensed,
fonts: fonts,
introEligibility: .default(),
purchaseHandler: .default()
Expand All @@ -50,7 +48,7 @@ public struct PaywallFooterView: View {
/// - Note: if `offering` does not have a current paywall, or it fails to load due to invalid data,
/// a default paywall will be displayed.
/// - Warning: `Purchases` must have been configured prior to displaying it.
public init(
init(
offering: Offering,
condensed: Bool = false,
fonts: PaywallFontProvider = DefaultPaywallFontProvider()
Expand All @@ -64,25 +62,24 @@ public struct PaywallFooterView: View {
)
}

init(
internal init(
offering: Offering?,
condensed: Bool = false,
condensed: Bool,
fonts: PaywallFontProvider = DefaultPaywallFontProvider(),
introEligibility: TrialOrIntroEligibilityChecker?,
purchaseHandler: PurchaseHandler?
) {
self._offering = .init(initialValue: offering)
self.offering = offering
self.introEligibility = introEligibility
self.purchaseHandler = purchaseHandler
self.mode = condensed ? .condensedFooter : .footer
self.condensed = condensed
self.fonts = fonts
}

// swiftlint:disable:next missing_docs
public var body: some View {
var body: some View {
PaywallView(
offering: self.offering,
mode: self.mode,
mode: self.condensed ? .condensedFooter : .footer,
fonts: self.fonts,
introEligibility: self.introEligibility,
purchaseHandler: self.purchaseHandler
Expand Down
39 changes: 9 additions & 30 deletions RevenueCatUI/Templates/Template2View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ struct Template2View: TemplateViewType {
@State
private var displayingAllPlans: Bool

@State
private var containerHeight: CGFloat = 10

@EnvironmentObject
private var introEligibilityViewModel: IntroEligibilityViewModel
@EnvironmentObject
Expand All @@ -41,10 +38,7 @@ struct Template2View: TemplateViewType {
Spacer()

self.scrollableContent
// Disabling in overlay mode here because of animation issues with ViewThatFits
// Scrolling is enabled in overlay mode in the packages
// Bonus is that CTA stays visible and doesn't scroll
.scrollableIfNecessary(enabled: configuration.mode == .fullScreen)
.scrollableIfNecessary(enabled: self.configuration.mode.shouldDisplayPackages)

if self.configuration.mode.shouldDisplayInlineOfferDetails {
self.offerDetails(package: self.selectedPackage, selected: false)
Expand Down Expand Up @@ -86,35 +80,18 @@ struct Template2View: TemplateViewType {
Spacer()
}

VStack {
self.packagesScrollHack

Spacer()
}
// Sets a max footer height so there is enough room for paywall content above
.frame(maxHeight: configuration.mode == .fullScreen ? nil : Constants.maxFooterHeight)
.hideFooterContent(self.configuration,
hide: !self.configuration.mode.shouldDisplayPackages && !self.displayingAllPlans)
}
.frame(maxHeight: .infinity)
}

/// Hack because scrollableIfNecessary() doesn't work on iOS 15 because of unknown reason
private var packagesScrollHack: some View {
Group {
if #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *) {
if self.configuration.mode.shouldDisplayPackages {
self.packages
// Another hack because bounce animation temporarily clips top package a little bits
.padding(.top, 5)
.scrollableIfNecessary()
} else {
ScrollView {
self.packages
}
self.packages
.hideFooterContent(self.configuration,
hide: !self.displayingAllPlans)
}
}
.frame(maxHeight: .infinity)
}

@ViewBuilder
private var packages: some View {
VStack(spacing: 8) {
ForEach(self.configuration.packages.all, id: \.content.id) { package in
Expand All @@ -130,6 +107,8 @@ struct Template2View: TemplateViewType {
}
}
.padding(.horizontal)

Spacer()
}

@ViewBuilder
Expand Down
1 change: 1 addition & 0 deletions RevenueCatUI/Templates/Template4View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct Template4View: TemplateViewType {
self.packagesScrollView
} else {
self.packagesScrollView
.padding(.vertical)
.hideFooterContent(self.configuration,
hide: !self.displayingAllPlans)
}
Expand Down
4 changes: 1 addition & 3 deletions RevenueCatUI/Templates/TemplateViewType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ extension PaywallData {
.task(id: offering) {
await introEligibility.computeEligibility(for: configuration.packages)
}
.background(
configuration.backgroundView
)
.background(configuration.backgroundView)

case let .failure(error):
DebugErrorView(error, releaseBehavior: .emptyView)
Expand Down
30 changes: 13 additions & 17 deletions RevenueCatUI/View+PresentPaywallFooter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ extension View {
/// .paywallFooter()
/// }
/// ```
/// - Note: If loading the `CustomerInfo` fails (for example, if Internet is offline),
/// the paywall won't be displayed.
///
/// ### Related Articles
/// [Documentation](https://rev.cat/paywalls)
Expand All @@ -46,8 +44,6 @@ extension View {
/// .paywallFooter(offering: offering)
/// }
/// ```
/// - Note: If loading the `CustomerInfo` fails (for example, if Internet is offline),
/// the paywall won't be displayed.
///
/// ### Related Articles
/// [Documentation](https://rev.cat/paywalls)
Expand Down Expand Up @@ -89,29 +85,29 @@ extension View {
@available(iOS 15.0, macOS 12.0, tvOS 15.0, *)
@available(macOS, unavailable)
@available(tvOS, unavailable)
struct PresentingPaywallFooterModifier: ViewModifier {
private struct PresentingPaywallFooterModifier: ViewModifier {

let offering: Offering?
let condensed: Bool

let purchaseCompleted: PurchaseCompletedHandler?
let fontProvider: PaywallFontProvider

let introEligibility: TrialOrIntroEligibilityChecker?
let purchaseHandler: PurchaseHandler?

func body(content: Content) -> some View {
content.safeAreaInset(edge: .bottom) {
PaywallFooterView(
offering: self.offering,
condensed: self.condensed,
fonts: self.fontProvider,
introEligibility: self.introEligibility ?? .default(),
purchaseHandler: self.purchaseHandler ?? .default()
)
.onPurchaseCompleted {
self.purchaseCompleted?($0)
}
content
.safeAreaInset(edge: .bottom) {
PaywallFooterView(
offering: self.offering,
condensed: self.condensed,
fonts: self.fontProvider,
introEligibility: self.introEligibility ?? .default(),
purchaseHandler: self.purchaseHandler ?? .default()
)
.onPurchaseCompleted {
self.purchaseCompleted?($0)
}
}
}
}
10 changes: 5 additions & 5 deletions Tests/TestingApps/SimpleApp/SimpleApp/Views/CustomPaywall.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,28 +66,28 @@ struct CustomPaywall: View {
struct CustomPaywall_Previews: PreviewProvider {

static var previews: some View {
ForEach(Self.modes, id: \.self) { mode in
ForEach(Self.condensedOptions, id: \.self) { mode in
CustomPaywall(
offering: TestData.offeringWithMultiPackagePaywall,
condensed: mode,
introEligibility: .producing(eligibility: .eligible),
purchaseHandler: .mock()
)
.previewDisplayName("\(mode)")
.previewDisplayName("Template2\(mode ? " condensed" : "")")
}

ForEach(Self.modes, id: \.self) { mode in
ForEach(Self.condensedOptions, id: \.self) { mode in
CustomPaywall(
offering: TestData.offeringWithMultiPackageHorizontalPaywall,
condensed: mode,
introEligibility: .producing(eligibility: .eligible),
purchaseHandler: .mock()
)
.previewDisplayName("\(mode)")
.previewDisplayName("Template4\(mode ? " condensed" : "")")
}
}

private static let modes: [Bool] = [
private static let condensedOptions: [Bool] = [
true,
false
]
Expand Down

0 comments on commit 39e5c9a

Please sign in to comment.