-
Notifications
You must be signed in to change notification settings - Fork 338
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Paywall Components Initial Commit (#4224)
Initial components merge. Notes: - Linting enabled except for public documentation which will come as the API matures and stabilizes. - Took out unused files (tier-related ones), which will come back in a future version. The comments were useful and will be referenced when they come back so thank you for the comments on these. - Left in tvOS and watchOS availability checks for now - may revisit this later. - Everything is codable. - Features added: - Layout components allow other components to be laid out along x/y/z axes. - Text component supports font weight. (Changing actual font will come later.) - LinkButton component links out to external website of choice. - RemoteImage allows the image to be arbitrarily styled by the calling code by passing the image back in a closure. - Image component supports corner rounding an overlaid gradient. (These will likely be pulled out into common code somewhere in a future PR.) - Support for OfferingResponse that includes a separate `PaywallComponentsData` structure, which is separate from `PaywallData` used for template-based paywalls. --------- Co-authored-by: Josh Holtz <[email protected]>
- Loading branch information
Showing
25 changed files
with
1,645 additions
and
42 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
RevenueCatUI/Templates/Components/ImageComponentView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// | ||
// Copyright RevenueCat Inc. All Rights Reserved. | ||
// | ||
// Licensed under the MIT License (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://opensource.org/licenses/MIT | ||
// | ||
// ImageComponentView.swift | ||
// | ||
// Created by Josh Holtz on 6/11/24. | ||
|
||
import Foundation | ||
import RevenueCat | ||
import SwiftUI | ||
|
||
#if PAYWALL_COMPONENTS | ||
|
||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||
struct ImageComponentView: View { | ||
|
||
let locale: Locale | ||
let component: PaywallComponent.ImageComponent | ||
|
||
var cornerRadius: CGFloat { | ||
component.cornerRadius | ||
} | ||
|
||
var gradientColors: [Color] { | ||
component.gradientColors.compactMap { try? $0.toColor() } | ||
} | ||
|
||
var body: some View { | ||
RemoteImage(url: component.url) { image in | ||
image | ||
.resizable() | ||
.aspectRatio(contentMode: .fit) | ||
.overlay( | ||
LinearGradient( | ||
gradient: Gradient(colors: gradientColors), | ||
startPoint: .top, | ||
endPoint: .bottom | ||
) | ||
) | ||
.cornerRadius(cornerRadius) | ||
} | ||
.clipped() | ||
} | ||
|
||
} | ||
|
||
#endif |
33 changes: 33 additions & 0 deletions
33
RevenueCatUI/Templates/Components/LinkButtonComponentView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// | ||
// LinkButtonComponentView.swift | ||
// | ||
// | ||
// Created by James Borthwick on 2024-08-21. | ||
// | ||
|
||
import Foundation | ||
import RevenueCat | ||
import SwiftUI | ||
|
||
#if PAYWALL_COMPONENTS | ||
|
||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||
struct LinkButtonComponentView: View { | ||
|
||
let locale: Locale | ||
let component: PaywallComponent.LinkButtonComponent | ||
|
||
var url: URL { | ||
component.url | ||
} | ||
|
||
var body: some View { | ||
Link(destination: url) { | ||
TextComponentView(locale: locale, component: component.textComponent) | ||
.cornerRadius(25) | ||
} | ||
} | ||
|
||
} | ||
|
||
#endif |
32 changes: 32 additions & 0 deletions
32
RevenueCatUI/Templates/Components/SpacerComponentView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// | ||
// Copyright RevenueCat Inc. All Rights Reserved. | ||
// | ||
// Licensed under the MIT License (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://opensource.org/licenses/MIT | ||
// | ||
// SpacerComponentView.swift | ||
// | ||
// Created by James Borthwick on 2024-08-19. | ||
|
||
import Foundation | ||
import RevenueCat | ||
import SwiftUI | ||
|
||
#if PAYWALL_COMPONENTS | ||
|
||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||
struct SpacerComponentView: View { | ||
|
||
let locale: Locale | ||
let component: PaywallComponent.SpacerComponent | ||
|
||
var body: some View { | ||
Spacer() | ||
} | ||
|
||
} | ||
|
||
#endif |
71 changes: 71 additions & 0 deletions
71
RevenueCatUI/Templates/Components/StackComponentView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// | ||
// Copyright RevenueCat Inc. All Rights Reserved. | ||
// | ||
// Licensed under the MIT License (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://opensource.org/licenses/MIT | ||
// | ||
// StackComponentView.swift | ||
// | ||
// Created by James Borthwick on 2024-08-20. | ||
|
||
import RevenueCat | ||
import SwiftUI | ||
|
||
#if PAYWALL_COMPONENTS | ||
|
||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||
struct StackComponentView: View { | ||
|
||
let component: PaywallComponent.StackComponent | ||
|
||
var dimension: PaywallComponent.StackComponent.Dimension { | ||
component.dimension | ||
} | ||
var components: [PaywallComponent] { | ||
component.components | ||
} | ||
|
||
var spacing: CGFloat? { | ||
component.spacing | ||
} | ||
|
||
var backgroundColor: Color { | ||
if let lightColor = component.backgroundColor?.light { | ||
return (try? PaywallColor(stringRepresentation: lightColor).underlyingColor) ?? Color.clear | ||
} | ||
return Color.clear | ||
} | ||
|
||
let locale: Locale | ||
|
||
init(component: PaywallComponent.StackComponent, locale: Locale) { | ||
self.component = component | ||
self.locale = locale | ||
} | ||
|
||
var body: some View { | ||
switch dimension { | ||
case .vertical(let horizontalAlignment): | ||
VStack(alignment: horizontalAlignment.stackAlignment, spacing: spacing) { | ||
ComponentsView(locale: locale, components: components) | ||
} | ||
.background(backgroundColor) | ||
case .horizontal(let verticalAlignment): | ||
HStack(alignment: verticalAlignment.stackAlignment, spacing: spacing) { | ||
ComponentsView(locale: locale, components: components) | ||
} | ||
.background(backgroundColor) | ||
case .zlayer(let alignment): | ||
ZStack(alignment: alignment.stackAlignment) { | ||
ComponentsView(locale: locale, components: components) | ||
} | ||
.background(backgroundColor) | ||
} | ||
} | ||
|
||
} | ||
|
||
#endif |
85 changes: 85 additions & 0 deletions
85
RevenueCatUI/Templates/Components/TemplateComponentsView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// | ||
// File.swift | ||
// | ||
// | ||
// Created by Josh Holtz on 6/11/24. | ||
// | ||
|
||
import RevenueCat | ||
import SwiftUI | ||
|
||
#if PAYWALL_COMPONENTS | ||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||
struct TemplateComponentsView: View { | ||
|
||
@Environment(\.locale) | ||
var locale | ||
|
||
let paywallComponentsData: PaywallComponentsData | ||
|
||
init(paywallComponentsData: PaywallComponentsData) { | ||
self.paywallComponentsData = paywallComponentsData | ||
} | ||
|
||
var body: some View { | ||
VStack(spacing: 0) { | ||
ComponentsView( | ||
locale: self.locale, | ||
components: paywallComponentsData.componentsConfig.components | ||
) | ||
} | ||
.edgesIgnoringSafeArea(.top) | ||
} | ||
|
||
} | ||
|
||
func getLocalization(_ locale: Locale, _ displayString: DisplayString) -> String { | ||
if let found = displayString.value[locale.identifier] { | ||
return found | ||
} | ||
|
||
return displayString.value.values.first! | ||
} | ||
|
||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||
// @PublicForExternalTesting | ||
struct ComponentsView: View { | ||
|
||
let locale: Locale | ||
let components: [PaywallComponent] | ||
|
||
// @PublicForExternalTesting | ||
init(locale: Locale, components: [PaywallComponent]) { | ||
self.locale = locale | ||
self.components = components | ||
} | ||
|
||
// @PublicForExternalTesting | ||
var body: some View { | ||
self.layoutComponents(self.components) | ||
} | ||
|
||
@ViewBuilder | ||
func layoutComponents(_ layoutComponentsArray: [PaywallComponent]) -> some View { | ||
ForEach(Array(layoutComponentsArray.enumerated()), id: \.offset) { _, item in | ||
switch item { | ||
case .text(let component): | ||
TextComponentView(locale: locale, component: component) | ||
case .image(let component): | ||
ImageComponentView(locale: locale, component: component) | ||
case .spacer(let component): | ||
SpacerComponentView( | ||
locale: locale, | ||
component: component | ||
) | ||
case .stack(let component): | ||
StackComponentView(component: component, locale: locale) | ||
case .linkButton(let component): | ||
LinkButtonComponentView(locale: locale, component: component) | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// | ||
// Copyright RevenueCat Inc. All Rights Reserved. | ||
// | ||
// Licensed under the MIT License (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://opensource.org/licenses/MIT | ||
// | ||
// TextComponentView.swift | ||
// | ||
// Created by Josh Holtz on 6/11/24. | ||
|
||
import Foundation | ||
import RevenueCat | ||
import SwiftUI | ||
|
||
#if PAYWALL_COMPONENTS | ||
|
||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||
struct TextComponentView: View { | ||
|
||
let locale: Locale | ||
let component: PaywallComponent.TextComponent | ||
|
||
var backgroundColor: Color? { | ||
if let thing = component.backgroundColor?.light { | ||
return (try? PaywallColor(stringRepresentation: thing).underlyingColor) ?? Color.clear | ||
} | ||
return nil | ||
} | ||
|
||
var body: some View { | ||
Text(getLocalization(locale, component.text)) | ||
.font(component.textStyle.font) | ||
.fontWeight(component.fontWeight.fontWeight) | ||
.multilineTextAlignment(component.horizontalAlignment.textAlignment) | ||
.foregroundStyle( | ||
(try? PaywallColor(stringRepresentation: component.color.light).underlyingColor) ?? Color.clear | ||
) | ||
.padding(.top, component.padding.top) | ||
.padding(.bottom, component.padding.bottom) | ||
.padding(.leading, component.padding.leading) | ||
.padding(.trailing, component.padding.trailing) | ||
.background(self.backgroundColor) | ||
} | ||
|
||
} | ||
|
||
#endif |
Oops, something went wrong.