diff --git a/RevenueCatUI/Templates/Components/Button/ButtonComponentView.swift b/RevenueCatUI/Templates/Components/Button/ButtonComponentView.swift index c07c8ff9b5..1e17ff413a 100644 --- a/RevenueCatUI/Templates/Components/Button/ButtonComponentView.swift +++ b/RevenueCatUI/Templates/Components/Button/ButtonComponentView.swift @@ -35,10 +35,11 @@ struct ButtonComponentView: View { } var body: some View { - AsyncButton( - action: { try await performAction() }, - label: { StackComponentView(viewModel: viewModel.stackViewModel, onDismiss: self.onDismiss) } - ) + AsyncButton { + try await performAction() + } label: { + StackComponentView(viewModel: viewModel.stackViewModel, onDismiss: self.onDismiss) + } #if canImport(SafariServices) && canImport(UIKit) .sheet(isPresented: .isNotNil($inAppBrowserURL)) { SafariView(url: inAppBrowserURL!) diff --git a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift index f1a51113e0..6df2201f39 100644 --- a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift +++ b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift @@ -46,19 +46,8 @@ struct PurchaseButtonComponentView: View { _ = try await self.purchaseHandler.purchase(package: selectedPackage) } label: { - // WIP: Need to add logic for intro offer - Text(viewModel.cta) - .font(viewModel.textStyle) - .fontWeight(viewModel.fontWeight) - .fixedSize(horizontal: false, vertical: true) - .multilineTextAlignment(viewModel.horizontalAlignment) - .foregroundStyle(viewModel.color) - .padding(viewModel.padding) - .background(viewModel.backgroundColor) - .shape(viewModel.clipShape) - .cornerBorder(border: nil, - radiuses: viewModel.cornerRadiuses) - .padding(viewModel.margin) + // Not passing an onDismiss - nothing in this stack should be able to dismiss + StackComponentView(viewModel: viewModel.stackViewModel, onDismiss: {}) } } @@ -96,22 +85,29 @@ struct PurchaseButtonComponentView_Previews: PreviewProvider { PurchaseButtonComponentView( // swiftlint:disable:next force_try viewModel: try! .init( + packageValidator: PackageValidator(), localizedStrings: [ "id_1": .string("Hello, world"), "id_2": .string("Hello, world intro offer") ], component: .init( - cta: "id_1", - ctaIntroOffer: "id_2", - fontWeight: .bold, - color: .init(light: "#ffffff"), - backgroundColor: .init(light: "#ff0000"), - padding: .init(top: 10, - bottom: 10, - leading: 30, - trailing: 30), - shape: .pill - ) + stack: .init(components: [ + // WIP: Intro offer state with "id_2", + .text(.init( + text: "id_1", + fontWeight: .bold, + color: .init(light: "#ffffff"), + backgroundColor: .init(light: "#ff0000"), + padding: .init(top: 10, + bottom: 10, + leading: 30, + trailing: 30) + )) + ]) + ), + offering: Offering(identifier: "", + serverDescription: "", + availablePackages: []) ) ) .previewLayout(.sizeThatFits) @@ -121,26 +117,37 @@ struct PurchaseButtonComponentView_Previews: PreviewProvider { PurchaseButtonComponentView( // swiftlint:disable:next force_try viewModel: try! .init( + packageValidator: PackageValidator(), localizedStrings: [ "id_1": .string("Hello, world"), "id_2": .string("Hello, world intro offer") ], component: .init( - cta: "id_1", - ctaIntroOffer: "id_2", - fontWeight: .bold, - color: .init(light: "#ffffff"), - backgroundColor: .init(light: "#ff0000"), - padding: .init(top: 10, - bottom: 10, - leading: 30, - trailing: 30), - shape: .rectangle, - cornerRadiuses: .init(topLeading: 8, - topTrailing: 8, - bottomLeading: 8, - bottomTrailing: 8) - ) + stack: .init( + components: [ + // WIP: Intro offer state with "id_2", + .text(.init( + text: "id_1", + fontWeight: .bold, + color: .init(light: "#ffffff") + )) + ], + backgroundColor: .init(light: "#ff0000"), + padding: .init(top: 8, + bottom: 8, + leading: 8, + trailing: 8), + cornerRadiuses: PaywallComponent.CornerRadiuses( + topLeading: 8, + topTrailing: 8, + bottomLeading: 8, + bottomTrailing: 8 + ) + ) + ), + offering: Offering(identifier: "", + serverDescription: "", + availablePackages: []) ) ) .previewLayout(.sizeThatFits) diff --git a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift index 8356a2803c..68ac764e45 100644 --- a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift +++ b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift @@ -23,65 +23,23 @@ class PurchaseButtonComponentViewModel { private let localizedStrings: PaywallComponent.LocalizationDictionary private let component: PaywallComponent.PurchaseButtonComponent - let cta: String - let ctaIntroOffer: String? - - init(localizedStrings: PaywallComponent.LocalizationDictionary, - component: PaywallComponent.PurchaseButtonComponent) throws { + let stackViewModel: StackComponentViewModel + + init( + packageValidator: PackageValidator, + localizedStrings: PaywallComponent.LocalizationDictionary, + component: PaywallComponent.PurchaseButtonComponent, + offering: Offering + ) throws { self.localizedStrings = localizedStrings self.component = component - self.cta = try localizedStrings.string(key: component.cta) - self.ctaIntroOffer = try component.ctaIntroOffer.flatMap { - try localizedStrings.string(key: $0) - } - } - - var fontFamily: String? { - component.fontFamily - } - - var fontWeight: Font.Weight { - component.fontWeight.fontWeight - } - - var color: Color { - component.color.toDyanmicColor() - } - - var textStyle: Font { - component.textStyle.font - } - - var horizontalAlignment: TextAlignment { - component.horizontalAlignment.textAlignment - } - - var backgroundColor: Color { - component.backgroundColor?.toDyanmicColor() ?? Color.clear - } - - var padding: EdgeInsets { - component.padding.edgeInsets - } - - var margin: EdgeInsets { - component.margin.edgeInsets - } - - var clipShape: PaywallComponent.Shape { - component.shape - } - - var cornerRadiuses: CornerBorderModifier.RaidusInfo? { - component.cornerRadiuses.flatMap { cornerRadiuses in - CornerBorderModifier.RaidusInfo( - topLeft: cornerRadiuses.topLeading, - topRight: cornerRadiuses.topTrailing, - bottomLeft: cornerRadiuses.bottomLeading, - bottomRight: cornerRadiuses.bottomLeading - ) - } + self.stackViewModel = try StackComponentViewModel( + packageValidator: packageValidator, + component: component.stack, + localizedStrings: localizedStrings, + offering: offering + ) } } diff --git a/RevenueCatUI/Templates/Components/PaywallComponentViewModel.swift b/RevenueCatUI/Templates/Components/PaywallComponentViewModel.swift index 3477e5c9f6..21950edda4 100644 --- a/RevenueCatUI/Templates/Components/PaywallComponentViewModel.swift +++ b/RevenueCatUI/Templates/Components/PaywallComponentViewModel.swift @@ -82,14 +82,17 @@ extension PaywallComponent { return .package(viewModel) case .purchaseButton(let component): return .purchaseButton( - try PurchaseButtonComponentViewModel(localizedStrings: localizedStrings, - component: component) + try PurchaseButtonComponentViewModel(packageValidator: packageValidator, + localizedStrings: localizedStrings, + component: component, + offering: offering) ) case .stickyFooter(let component): return .stickyFooter( try StickyFooterComponentViewModel( component: component, stackViewModel: StackComponentViewModel( + packageValidator: packageValidator, component: component.stack, localizedStrings: localizedStrings, offering: offering diff --git a/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template1Preview.swift b/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template1Preview.swift index 6d90bb56da..465fb938a4 100644 --- a/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template1Preview.swift +++ b/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template1Preview.swift @@ -93,16 +93,19 @@ private enum Template1Preview { ) static let purchaseButton = PaywallComponent.PurchaseButtonComponent( - cta: "cta", - ctaIntroOffer: "cta_intro", - fontWeight: .bold, - color: .init(light: "#ffffff"), - backgroundColor: .init(light: "#e89d89"), - padding: .init(top: 10, - bottom: 10, - leading: 30, - trailing: 30), - shape: .pill + stack: .init(components: [ + // WIP: Intro offer state with "cta_intro", + .text(.init( + text: "cta", + fontWeight: .bold, + color: .init(light: "#ffffff"), + backgroundColor: .init(light: "#e89d89"), + padding: .init(top: 10, + bottom: 10, + leading: 30, + trailing: 30) + )) + ]) ) static let contentStack = PaywallComponent.StackComponent( diff --git a/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template5Preview.swift b/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template5Preview.swift index d17773c813..a080ba0af7 100644 --- a/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template5Preview.swift +++ b/RevenueCatUI/Templates/Components/TemplateComponentsViewPreviews/Template5Preview.swift @@ -146,16 +146,25 @@ private enum Template5Preview { ) static let purchaseButton = PaywallComponent.PurchaseButtonComponent( - cta: "cta", - ctaIntroOffer: "cta_intro", - fontWeight: .bold, - color: .init(light: "#ffffff"), - backgroundColor: .init(light: "#e89d89"), - padding: .init(top: 15, - bottom: 15, - leading: 50, - trailing: 50), - shape: .pill + stack: .init( + components: [ + // WIP: Intro offer state with "cta_intro", + .text(.init( + text: "cta", + fontWeight: .bold, + color: .init(light: "#ffffff") + )) + ], + backgroundColor: .init(light: "#e89d89"), + padding: .init(top: 15, + bottom: 15, + leading: 50, + trailing: 50), + cornerRadiuses: .init(topLeading: 16, + topTrailing: 16, + bottomLeading: 16, + bottomTrailing: 16) + ) ) static let purchaseButtonStack = PaywallComponent.StackComponent( @@ -199,11 +208,14 @@ private enum Template5Preview { templateName: "components", assetBaseURL: URL(string: "https://assets.pawwalls.com")!, componentsConfigs: .init( - base: .init(stack: .init( - components: [ - .stack(stack) - ] - )) + base: .init( + stack: .init( + components: [ + .stack(stack) + ] + ), + stickyFooter: nil + ) ), componentsLocalizations: ["en_US": [ "title": .string("Ignite your cat's curiosity"), diff --git a/RevenueCatUI/Templates/Components/Text/TextComponentViewModel.swift b/RevenueCatUI/Templates/Components/Text/TextComponentViewModel.swift index a4cd3900fc..7af88acc8c 100644 --- a/RevenueCatUI/Templates/Components/Text/TextComponentViewModel.swift +++ b/RevenueCatUI/Templates/Components/Text/TextComponentViewModel.swift @@ -11,7 +11,6 @@ // // Created by Josh Holtz on 6/11/24. -import Foundation import RevenueCat import SwiftUI @@ -64,4 +63,5 @@ class TextComponentViewModel { } } + #endif diff --git a/Sources/Paywalls/Components/PaywallPurchaseButtonComponent.swift b/Sources/Paywalls/Components/PaywallPurchaseButtonComponent.swift index 0bed25ff30..3cb231da16 100644 --- a/Sources/Paywalls/Components/PaywallPurchaseButtonComponent.swift +++ b/Sources/Paywalls/Components/PaywallPurchaseButtonComponent.swift @@ -15,70 +15,17 @@ public extension PaywallComponent { struct PurchaseButtonComponent: PaywallComponentBase { let type: ComponentType - public let cta: LocalizationKey - public let ctaIntroOffer: LocalizationKey? - public let fontFamily: String? - public let fontWeight: FontWeight - public let color: ColorInfo - public let textStyle: TextStyle - public let horizontalAlignment: HorizontalAlignment - public let backgroundColor: ColorInfo? - public let padding: Padding - public let margin: Padding - public let shape: Shape - public let cornerRadiuses: CornerRadiuses? + public let stack: PaywallComponent.StackComponent public init( - cta: LocalizationKey, - ctaIntroOffer: LocalizationKey? = nil, - fontFamily: String? = nil, - fontWeight: FontWeight = .regular, - color: ColorInfo, - backgroundColor: ColorInfo? = nil, - padding: Padding = .default, - margin: Padding = .default, - textStyle: TextStyle = .body, - horizontalAlignment: HorizontalAlignment = .center, - shape: Shape = .pill, - cornerRadiuses: CornerRadiuses? = nil + stack: PaywallComponent.StackComponent ) { - self.type = .purchaseButton - self.cta = cta - self.ctaIntroOffer = ctaIntroOffer - self.fontFamily = fontFamily - self.fontWeight = fontWeight - self.color = color - self.backgroundColor = backgroundColor - self.padding = padding - self.margin = margin - self.textStyle = textStyle - self.horizontalAlignment = horizontalAlignment - self.shape = shape - self.cornerRadiuses = cornerRadiuses + self.type = .button + self.stack = stack } } } -extension PaywallComponent.PurchaseButtonComponent { - - enum CodingKeys: String, CodingKey { - case type - case cta = "cta_lid" - case ctaIntroOffer = "cta_intro_offer_lid" - case fontFamily - case fontWeight - case color - case textStyle - case horizontalAlignment - case backgroundColor - case padding - case margin - case shape - case cornerRadiuses - } - -} - #endif diff --git a/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/SamplePaywalls.swift b/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/SamplePaywalls.swift index 3cf472c7a3..7910a13efd 100644 --- a/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/SamplePaywalls.swift +++ b/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/SamplePaywalls.swift @@ -795,20 +795,25 @@ private extension SamplePaywallLoader { margin: .init(top: 20, bottom: 20, leading: 20, trailing: 20) )), .purchaseButton(.init( - cta: "cta", - ctaIntroOffer: "cta_intro", - fontWeight: .bold, - color: .init(light: "#ffffff"), - backgroundColor: .init(light: "#ff0000"), - padding: .init(top: 10, - bottom: 10, - leading: 30, - trailing: 30), - shape: .rectangle, - cornerRadiuses: .init(topLeading: 10, - topTrailing: 10, - bottomLeading: 10, - bottomTrailing: 10) + stack: .init( + components: [ + // WIP: Intro offer state with "cta_intro", + .text(.init( + text: "cta", + fontWeight: .bold, + color: .init(light: "#ffffff") + )) + ], + backgroundColor: .init(light: "#ff0000"), + padding: .init(top: 15, + bottom: 15, + leading: 30, + trailing: 30), + cornerRadiuses: .init(topLeading: 16, + topTrailing: 16, + bottomLeading: 16, + bottomTrailing: 16) + ) )) ], width: .init(type: .fill, value: nil),