Skip to content

Commit

Permalink
Paywalls: extracted IntroEligibilityStateView (#2837)
Browse files Browse the repository at this point in the history
Small refactor, starting to take views out of `Example1Template` so
they're usable by other templates. This also removes some of the
duplicate code.
  • Loading branch information
NachoSoto committed Sep 6, 2023
1 parent 9627fef commit e012acc
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 61 deletions.
75 changes: 14 additions & 61 deletions RevenueCatUI/Templates/Example1Template.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,14 @@ private struct Example1TemplateContent: View {
Spacer()
}

self.offerDetails
IntroEligibilityStateView(
textWithNoIntroOffer: self.localization.offerDetails,
textWithIntroOffer: self.localization.offerDetailsWithIntroOffer,
introEligibility: self.introEligibility
)
.font(self.configuration.mode.offerDetailsFont)
.foregroundColor(self.configuration.colors.text1Color)

self.button
.padding(.horizontal)
}
Expand Down Expand Up @@ -138,49 +145,6 @@ private struct Example1TemplateContent: View {
}
}

private var offerDetails: some View {
let detailsWithIntroOffer = self.localization.offerDetailsWithIntroOffer

func text() -> String {
if let detailsWithIntroOffer = detailsWithIntroOffer, self.isEligibleForIntro {
return detailsWithIntroOffer
} else {
return self.localization.offerDetails
}
}

return Text(verbatim: text())
// Hide until we've determined intro eligibility
// only if there is a custom intro offer string.
.withPendingData(self.needsToWaitForIntroEligibility(detailsWithIntroOffer != nil))
.font(self.configuration.mode.offerDetailsFont)
}

private var ctaText: some View {
let ctaWithIntroOffer = self.localization.callToActionWithIntroOffer

func text() -> String {
if let ctaWithIntroOffer = ctaWithIntroOffer, self.isEligibleForIntro {
return ctaWithIntroOffer
} else {
return self.localization.callToAction
}
}

return Text(verbatim: text())
// Hide until we've determined intro eligibility
// only if there is a custom intro offer string.
.withPendingData(self.needsToWaitForIntroEligibility(ctaWithIntroOffer != nil))
}

private var isEligibleForIntro: Bool {
return self.introEligibility?.isEligible != false
}

private func needsToWaitForIntroEligibility(_ hasCustomString: Bool) -> Bool {
return self.introEligibility == nil && hasCustomString && self.isEligibleForIntro
}

@ViewBuilder
private var button: some View {
let package = self.configuration.packages.single.content
Expand All @@ -192,8 +156,13 @@ private struct Example1TemplateContent: View {
self.dismiss()
}
} label: {
self.ctaText
IntroEligibilityStateView(
textWithNoIntroOffer: self.localization.callToAction,
textWithIntroOffer: self.localization.callToActionWithIntroOffer,
introEligibility: self.introEligibility
)
.foregroundColor(self.configuration.colors.callToActionForegroundColor)
.tint(self.configuration.colors.callToActionForegroundColor)
.frame(
maxWidth: self.configuration.mode.fullWidthButton
? .infinity
Expand Down Expand Up @@ -289,19 +258,3 @@ private extension PaywallViewMode {
}

}

@available(iOS 16.0, macOS 13.0, tvOS 16.0, *)
private extension View {

func withPendingData(_ pending: Bool) -> some View {
self
.hidden(if: pending)
.overlay {
if pending {
ProgressView()
}
}
.transition(.opacity.animation(Constants.defaultAnimation))
}

}
76 changes: 76 additions & 0 deletions RevenueCatUI/Views/IntroEligibilityStateView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// IntroEligibilityStateView.swift
//
//
// Created by Nacho Soto on 7/18/23.
//

import RevenueCat
import SwiftUI

/// A view that can process intro eligibility and display different data based on the result.
@available(iOS 16.0, macOS 13.0, tvOS 16.0, *)
struct IntroEligibilityStateView: View {

var textWithNoIntroOffer: String
var textWithIntroOffer: String?
var introEligibility: IntroEligibilityStatus?

init(
textWithNoIntroOffer: String,
textWithIntroOffer: String?,
introEligibility: IntroEligibilityStatus?
) {
self.textWithNoIntroOffer = textWithNoIntroOffer
self.textWithIntroOffer = textWithIntroOffer
self.introEligibility = introEligibility
}

var body: some View {
Text(self.text)
// Hide until we've determined intro eligibility
// only if there is a custom intro text.
.withPendingData(self.needsToWaitForIntroEligibility)
}

private var text: String {
if let textWithIntroOffer = self.textWithIntroOffer, self.isEligibleForIntro {
return textWithIntroOffer
} else {
return self.textWithNoIntroOffer
}
}

}

// MARK: - Extensions

@available(iOS 16.0, macOS 13.0, tvOS 16.0, *)
private extension IntroEligibilityStateView {

var isEligibleForIntro: Bool {
return self.introEligibility?.isEligible != false
}

var needsToWaitForIntroEligibility: Bool {
return self.introEligibility == nil && self.textWithIntroOffer != nil
}

}

@available(iOS 16.0, macOS 13.0, tvOS 16.0, *)
private extension View {

func withPendingData(_ pending: Bool) -> some View {
self
.hidden(if: pending)
.overlay {
if pending {
ProgressView()
.progressViewStyle(.circular)
}
}
.transition(.opacity.animation(Constants.defaultAnimation))
}

}

0 comments on commit e012acc

Please sign in to comment.