Files
Reflect/Shared/Views/SettingsView/PaywallPreviewSettingsView.swift
Trey t 0442eab1f8 Rebrand entire project from Feels to Reflect
Complete rename across all bundle IDs, App Groups, CloudKit containers,
StoreKit product IDs, data store filenames, URL schemes, logger subsystems,
Swift identifiers, user-facing strings (7 languages), file names, directory
names, Xcode project, schemes, assets, and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:47:16 -06:00

929 lines
30 KiB
Swift

//
// PaywallPreviewSettingsView.swift
// Reflect
//
// Debug view for previewing and switching paywall styles.
//
import SwiftUI
#if DEBUG
struct PaywallPreviewSettingsView: View {
@Environment(\.dismiss) private var dismiss
@State private var selectedStyle: PaywallStyle = .celestial
@State private var showFullPreview = false
@EnvironmentObject var iapManager: IAPManager
var body: some View {
ScrollView {
VStack(spacing: 24) {
headerSection
stylePicker
previewCard
fullPreviewButton
}
.padding()
}
.background(Color(.systemGroupedBackground))
.navigationTitle("Paywall Styles")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button("Done") {
dismiss()
}
}
}
.sheet(isPresented: $showFullPreview) {
ReflectSubscriptionStoreView(source: "paywall_preview", style: selectedStyle)
.environmentObject(iapManager)
}
}
private var headerSection: some View {
VStack(spacing: 8) {
Image(systemName: "paintpalette.fill")
.font(.system(size: 40))
.foregroundStyle(
LinearGradient(
colors: [.purple, .pink, .orange],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
Text("Paywall Theme Lab")
.font(.title2.bold())
Text("Preview and test different subscription paywall designs")
.font(.subheadline)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
}
.padding(.vertical)
}
private var stylePicker: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Select Style")
.font(.headline)
ForEach(PaywallStyle.allCases, id: \.self) { style in
StyleOptionRow(
style: style,
isSelected: selectedStyle == style,
onTap: { selectedStyle = style }
)
}
}
}
private var previewCard: some View {
VStack(spacing: 0) {
// Mini preview header
HStack {
Text("Preview")
.font(.caption.weight(.semibold))
.foregroundStyle(.secondary)
Spacer()
Text(selectedStyle.displayName)
.font(.caption.weight(.medium))
.foregroundStyle(.secondary)
}
.padding(.horizontal, 16)
.padding(.vertical, 10)
.background(Color(.secondarySystemGroupedBackground))
// Mini preview content
miniPreview
.frame(height: 280)
.clipped()
}
.clipShape(RoundedRectangle(cornerRadius: 16))
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color(.separator), lineWidth: 0.5)
)
}
@ViewBuilder
private var miniPreview: some View {
switch selectedStyle {
case .celestial:
CelestialMiniPreview()
case .garden:
GardenMiniPreview()
case .neon:
NeonMiniPreview()
case .minimal:
MinimalMiniPreview()
case .zen:
ZenMiniPreview()
case .editorial:
EditorialMiniPreview()
case .mixtape:
MixtapeMiniPreview()
case .heartfelt:
HeartfeltMiniPreview()
case .luxe:
LuxeMiniPreview()
case .forecast:
ForecastMiniPreview()
case .playful:
PlayfulMiniPreview()
case .journal:
JournalMiniPreview()
}
}
private var fullPreviewButton: some View {
Button {
showFullPreview = true
} label: {
HStack {
Image(systemName: "arrow.up.left.and.arrow.down.right")
Text("View Full Paywall")
.fontWeight(.semibold)
}
.frame(maxWidth: .infinity)
.padding()
.background(
LinearGradient(
colors: gradientColors,
startPoint: .leading,
endPoint: .trailing
)
)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: 14))
}
}
private var gradientColors: [Color] {
switch selectedStyle {
case .celestial:
return [Color(red: 1.0, green: 0.4, blue: 0.5), Color(red: 0.6, green: 0.4, blue: 0.9)]
case .garden:
return [Color(red: 0.4, green: 0.75, blue: 0.45), Color(red: 0.3, green: 0.6, blue: 0.4)]
case .neon:
return [Color(red: 0.0, green: 0.9, blue: 0.7), Color(red: 0.9, green: 0.0, blue: 0.7)]
case .minimal:
return [Color(red: 0.85, green: 0.6, blue: 0.5), Color(red: 0.7, green: 0.5, blue: 0.45)]
case .zen:
return [Color(red: 0.6, green: 0.7, blue: 0.6), Color(red: 0.5, green: 0.6, blue: 0.55)]
case .editorial:
return [Color(red: 0.15, green: 0.15, blue: 0.15), Color(red: 0.3, green: 0.3, blue: 0.3)]
case .mixtape:
return [Color(red: 0.95, green: 0.45, blue: 0.35), Color(red: 0.95, green: 0.65, blue: 0.25)]
case .heartfelt:
return [Color(red: 0.9, green: 0.45, blue: 0.55), Color(red: 0.95, green: 0.6, blue: 0.65)]
case .luxe:
return [Color(red: 0.75, green: 0.6, blue: 0.35), Color(red: 0.55, green: 0.45, blue: 0.25)]
case .forecast:
return [Color(red: 0.4, green: 0.65, blue: 0.85), Color(red: 0.3, green: 0.5, blue: 0.75)]
case .playful:
return [Color(red: 0.95, green: 0.55, blue: 0.35), Color(red: 0.95, green: 0.75, blue: 0.35)]
case .journal:
return [Color(red: 0.55, green: 0.45, blue: 0.35), Color(red: 0.4, green: 0.35, blue: 0.3)]
}
}
}
// MARK: - Style Option Row
struct StyleOptionRow: View {
let style: PaywallStyle
let isSelected: Bool
let onTap: () -> Void
var body: some View {
Button(action: onTap) {
HStack(spacing: 14) {
// Style icon
ZStack {
Circle()
.fill(iconGradient)
.frame(width: 44, height: 44)
Image(systemName: iconName)
.font(.system(size: 18, weight: .semibold))
.foregroundColor(.white)
}
// Text
VStack(alignment: .leading, spacing: 2) {
Text(style.displayName)
.font(.body.weight(.medium))
.foregroundColor(.primary)
Text(style.description)
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
// Selection indicator
if isSelected {
Image(systemName: "checkmark.circle.fill")
.font(.title3)
.foregroundColor(.accentColor)
}
}
.padding(12)
.background(Color(.secondarySystemGroupedBackground))
.clipShape(RoundedRectangle(cornerRadius: 12))
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(isSelected ? Color.accentColor : Color.clear, lineWidth: 2)
)
}
.buttonStyle(.plain)
}
private var iconName: String {
switch style {
case .celestial: return "sparkles"
case .garden: return "leaf.fill"
case .neon: return "bolt.fill"
case .minimal: return "circle.grid.2x2"
case .zen: return "circle"
case .editorial: return "textformat"
case .mixtape: return "opticaldisc.fill"
case .heartfelt: return "heart.fill"
case .luxe: return "diamond.fill"
case .forecast: return "cloud.fill"
case .playful: return "face.smiling.fill"
case .journal: return "book.closed.fill"
}
}
private var iconGradient: LinearGradient {
switch style {
case .celestial:
return LinearGradient(
colors: [Color(red: 1.0, green: 0.4, blue: 0.5), Color(red: 0.6, green: 0.4, blue: 0.9)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .garden:
return LinearGradient(
colors: [Color(red: 0.4, green: 0.75, blue: 0.45), Color(red: 0.3, green: 0.6, blue: 0.4)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .neon:
return LinearGradient(
colors: [Color(red: 0.0, green: 0.9, blue: 0.7), Color(red: 0.9, green: 0.0, blue: 0.7)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .minimal:
return LinearGradient(
colors: [Color(red: 0.85, green: 0.6, blue: 0.5), Color(red: 0.7, green: 0.5, blue: 0.45)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .zen:
return LinearGradient(
colors: [Color(red: 0.6, green: 0.7, blue: 0.6), Color(red: 0.5, green: 0.6, blue: 0.55)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .editorial:
return LinearGradient(
colors: [Color(red: 0.15, green: 0.15, blue: 0.15), Color(red: 0.3, green: 0.3, blue: 0.3)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .mixtape:
return LinearGradient(
colors: [Color(red: 0.95, green: 0.45, blue: 0.35), Color(red: 0.95, green: 0.65, blue: 0.25)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .heartfelt:
return LinearGradient(
colors: [Color(red: 0.9, green: 0.45, blue: 0.55), Color(red: 0.95, green: 0.6, blue: 0.65)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .luxe:
return LinearGradient(
colors: [Color(red: 0.75, green: 0.6, blue: 0.35), Color(red: 0.55, green: 0.45, blue: 0.25)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .forecast:
return LinearGradient(
colors: [Color(red: 0.4, green: 0.65, blue: 0.85), Color(red: 0.3, green: 0.5, blue: 0.75)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .playful:
return LinearGradient(
colors: [Color(red: 0.95, green: 0.55, blue: 0.35), Color(red: 0.95, green: 0.75, blue: 0.35)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
case .journal:
return LinearGradient(
colors: [Color(red: 0.55, green: 0.45, blue: 0.35), Color(red: 0.4, green: 0.35, blue: 0.3)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
}
}
// MARK: - Mini Previews
struct CelestialMiniPreview: View {
@State private var animate = false
var body: some View {
ZStack {
// Background
LinearGradient(
colors: [
Color(red: 0.05, green: 0.05, blue: 0.12),
Color(red: 0.08, green: 0.06, blue: 0.15)
],
startPoint: .top,
endPoint: .bottom
)
// Glow
Circle()
.fill(Color(red: 1.0, green: 0.4, blue: 0.5).opacity(0.3))
.frame(width: 200, height: 200)
.blur(radius: 60)
.offset(y: animate ? -20 : 0)
// Content
VStack(spacing: 12) {
// Mini orbs
HStack(spacing: -10) {
ForEach(0..<3, id: \.self) { i in
Circle()
.fill(orbColors[i])
.frame(width: 24, height: 24)
.shadow(color: orbColors[i].opacity(0.5), radius: 8)
}
}
Text("Understand\nYourself Deeper")
.font(.system(size: 18, weight: .bold, design: .serif))
.multilineTextAlignment(.center)
.foregroundColor(.white)
}
}
.onAppear {
withAnimation(.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
animate = true
}
}
.onDisappear {
animate = false
}
}
private var orbColors: [Color] {
[
Color(red: 1.0, green: 0.8, blue: 0.3),
Color(red: 1.0, green: 0.5, blue: 0.5),
Color(red: 0.6, green: 0.5, blue: 0.9)
]
}
}
struct GardenMiniPreview: View {
@State private var bloom = false
var body: some View {
ZStack {
// Background
LinearGradient(
colors: [
Color(red: 0.05, green: 0.12, blue: 0.08),
Color(red: 0.08, green: 0.18, blue: 0.1)
],
startPoint: .top,
endPoint: .bottom
)
// Glow
Circle()
.fill(Color(red: 0.3, green: 0.7, blue: 0.4).opacity(0.25))
.frame(width: 200, height: 200)
.blur(radius: 60)
// Content
VStack(spacing: 12) {
// Mini flower
ZStack {
ForEach(0..<6, id: \.self) { i in
Ellipse()
.fill(Color(red: 1.0, green: 0.6, blue: 0.7))
.frame(width: 14, height: bloom ? 28 : 20)
.offset(y: bloom ? -22 : -16)
.rotationEffect(.degrees(Double(i) * 60))
}
Circle()
.fill(Color(red: 1.0, green: 0.9, blue: 0.6))
.frame(width: 20, height: 20)
}
Text("Watch Yourself\nBloom")
.font(.system(size: 18, weight: .bold, design: .serif))
.multilineTextAlignment(.center)
.foregroundColor(.white)
}
}
.onAppear {
withAnimation(.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
bloom = true
}
}
.onDisappear {
bloom = false
}
}
}
struct NeonMiniPreview: View {
@State private var pulse = false
var body: some View {
ZStack {
// Background
Color(red: 0.02, green: 0.02, blue: 0.05)
// Grid
Canvas { context, size in
let spacing: CGFloat = 20
for y in stride(from: 0, to: size.height, by: spacing) {
var path = Path()
path.move(to: CGPoint(x: 0, y: y))
path.addLine(to: CGPoint(x: size.width, y: y))
context.stroke(path, with: .color(Color.cyan.opacity(0.1)), lineWidth: 0.5)
}
}
// Glows
Circle()
.fill(Color.cyan.opacity(pulse ? 0.3 : 0.15))
.frame(width: 150, height: 150)
.blur(radius: 50)
.offset(y: -40)
Circle()
.fill(Color.pink.opacity(pulse ? 0.2 : 0.1))
.frame(width: 120, height: 120)
.blur(radius: 40)
.offset(x: 30, y: 40)
// Content
VStack(spacing: 12) {
// Neon ring
Circle()
.stroke(
LinearGradient(
colors: [.cyan, .pink],
startPoint: .topLeading,
endPoint: .bottomTrailing
),
lineWidth: 3
)
.frame(width: 50, height: 50)
.shadow(color: .cyan.opacity(0.5), radius: pulse ? 15 : 8)
Text("UNLOCK YOUR\nFULL SIGNAL")
.font(.system(size: 14, weight: .black, design: .monospaced))
.multilineTextAlignment(.center)
.foregroundStyle(
LinearGradient(colors: [.cyan, .pink], startPoint: .leading, endPoint: .trailing)
)
}
}
.onAppear {
withAnimation(.easeInOut(duration: 1.5).repeatForever(autoreverses: true)) {
pulse = true
}
}
.onDisappear {
pulse = false
}
}
}
struct MinimalMiniPreview: View {
@State private var breathe = false
var body: some View {
ZStack {
// Background
LinearGradient(
colors: [
Color(red: 0.98, green: 0.96, blue: 0.92),
Color(red: 0.95, green: 0.93, blue: 0.88)
],
startPoint: .top,
endPoint: .bottom
)
// Content
VStack(spacing: 16) {
// Breathing circles
ZStack {
Circle()
.stroke(Color(red: 0.8, green: 0.7, blue: 0.6).opacity(0.3), lineWidth: 1)
.frame(width: breathe ? 60 : 50, height: breathe ? 60 : 50)
Circle()
.fill(Color(red: 0.95, green: 0.6, blue: 0.5).opacity(0.4))
.frame(width: 30, height: 30)
.scaleEffect(breathe ? 1.1 : 0.95)
}
Text("Simply\nKnow Yourself")
.font(.system(size: 18, weight: .light, design: .serif))
.italic()
.multilineTextAlignment(.center)
.foregroundColor(Color(red: 0.2, green: 0.15, blue: 0.1))
}
}
.onAppear {
withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) {
breathe = true
}
}
.onDisappear {
breathe = false
}
}
}
struct ZenMiniPreview: View {
@State private var breathe = false
var body: some View {
ZStack {
// Warm paper background
LinearGradient(
colors: [
Color(red: 0.96, green: 0.94, blue: 0.90),
Color(red: 0.92, green: 0.90, blue: 0.86)
],
startPoint: .top,
endPoint: .bottom
)
// Content
VStack(spacing: 16) {
// Enso circle
Circle()
.stroke(
Color(red: 0.3, green: 0.35, blue: 0.3),
style: StrokeStyle(lineWidth: 3, lineCap: .round)
)
.frame(width: breathe ? 55 : 50, height: breathe ? 55 : 50)
.rotationEffect(.degrees(-30))
Text("Find Your\nInner Peace")
.font(.system(size: 18, weight: .light, design: .serif))
.multilineTextAlignment(.center)
.foregroundColor(Color(red: 0.25, green: 0.25, blue: 0.2))
}
}
.onAppear {
withAnimation(.easeInOut(duration: 4).repeatForever(autoreverses: true)) {
breathe = true
}
}
.onDisappear {
breathe = false
}
}
}
struct EditorialMiniPreview: View {
var body: some View {
ZStack {
// Deep black background
Color.black
// Content
VStack(spacing: 16) {
// Simple geometric element
Rectangle()
.fill(Color.white)
.frame(width: 40, height: 2)
Text("THE ART\nOF FEELING")
.font(.system(size: 16, weight: .bold, design: .serif))
.tracking(3)
.multilineTextAlignment(.center)
.foregroundColor(.white)
Rectangle()
.fill(Color.white)
.frame(width: 40, height: 2)
}
}
}
}
struct MixtapeMiniPreview: View {
@State private var spin = false
var body: some View {
ZStack {
// Warm gradient background
LinearGradient(
colors: [
Color(red: 0.95, green: 0.45, blue: 0.35),
Color(red: 0.95, green: 0.65, blue: 0.25)
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
// Content
VStack(spacing: 12) {
// Mini cassette
ZStack {
RoundedRectangle(cornerRadius: 4)
.fill(Color.black.opacity(0.8))
.frame(width: 50, height: 32)
HStack(spacing: 10) {
Circle()
.fill(Color.white.opacity(0.9))
.frame(width: 14, height: 14)
.rotationEffect(.degrees(spin ? 360 : 0))
Circle()
.fill(Color.white.opacity(0.9))
.frame(width: 14, height: 14)
.rotationEffect(.degrees(spin ? 360 : 0))
}
}
Text("YOUR MOOD\nMIXTAPE")
.font(.system(size: 14, weight: .black))
.multilineTextAlignment(.center)
.foregroundColor(.white)
}
}
.onAppear {
withAnimation(.linear(duration: 3).repeatForever(autoreverses: false)) {
spin = true
}
}
.onDisappear {
spin = false
}
}
}
struct HeartfeltMiniPreview: View {
@State private var beat = false
var body: some View {
ZStack {
// Soft pink gradient
LinearGradient(
colors: [
Color(red: 1.0, green: 0.95, blue: 0.95),
Color(red: 0.98, green: 0.9, blue: 0.92)
],
startPoint: .top,
endPoint: .bottom
)
// Content
VStack(spacing: 12) {
// Floating hearts
HStack(spacing: -8) {
ForEach(0..<3, id: \.self) { i in
Image(systemName: "heart.fill")
.font(.system(size: 20 - CGFloat(i * 4)))
.foregroundColor(Color(red: 0.9, green: 0.45, blue: 0.55))
.scaleEffect(beat ? 1.1 : 0.95)
}
}
Text("Feel With\nAll Your Heart")
.font(.system(size: 17, weight: .medium, design: .serif))
.italic()
.multilineTextAlignment(.center)
.foregroundColor(Color(red: 0.4, green: 0.25, blue: 0.3))
}
}
.onAppear {
withAnimation(.easeInOut(duration: 0.8).repeatForever(autoreverses: true)) {
beat = true
}
}
.onDisappear {
beat = false
}
}
}
struct LuxeMiniPreview: View {
@State private var shimmer = false
var body: some View {
ZStack {
// Deep rich background
LinearGradient(
colors: [
Color(red: 0.12, green: 0.1, blue: 0.08),
Color(red: 0.08, green: 0.06, blue: 0.04)
],
startPoint: .top,
endPoint: .bottom
)
// Content
VStack(spacing: 14) {
// Diamond icon
Image(systemName: "diamond.fill")
.font(.system(size: 36))
.foregroundStyle(
LinearGradient(
colors: [
Color(red: 0.85, green: 0.7, blue: 0.45),
Color(red: 0.65, green: 0.5, blue: 0.3)
],
startPoint: shimmer ? .topLeading : .bottomTrailing,
endPoint: shimmer ? .bottomTrailing : .topLeading
)
)
Text("Elevate Your\nEmotional Life")
.font(.system(size: 16, weight: .light, design: .serif))
.tracking(1)
.multilineTextAlignment(.center)
.foregroundColor(Color(red: 0.85, green: 0.8, blue: 0.7))
}
}
.onAppear {
withAnimation(.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
shimmer = true
}
}
.onDisappear {
shimmer = false
}
}
}
struct ForecastMiniPreview: View {
@State private var drift = false
var body: some View {
ZStack {
// Sky gradient
LinearGradient(
colors: [
Color(red: 0.55, green: 0.75, blue: 0.95),
Color(red: 0.4, green: 0.6, blue: 0.85)
],
startPoint: .top,
endPoint: .bottom
)
// Floating clouds
HStack(spacing: 20) {
Image(systemName: "cloud.fill")
.font(.system(size: 28))
.foregroundColor(.white.opacity(0.8))
.offset(x: drift ? 5 : -5)
Image(systemName: "sun.max.fill")
.font(.system(size: 24))
.foregroundColor(Color(red: 1.0, green: 0.85, blue: 0.4))
}
.offset(y: -30)
// Content
VStack(spacing: 8) {
Text("Your Emotional\nForecast")
.font(.system(size: 17, weight: .semibold, design: .rounded))
.multilineTextAlignment(.center)
.foregroundColor(.white)
}
.offset(y: 30)
}
.onAppear {
withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) {
drift = true
}
}
.onDisappear {
drift = false
}
}
}
struct PlayfulMiniPreview: View {
@State private var bounce = false
var body: some View {
ZStack {
// Warm playful gradient
LinearGradient(
colors: [
Color(red: 1.0, green: 0.98, blue: 0.94),
Color(red: 0.98, green: 0.95, blue: 0.9)
],
startPoint: .top,
endPoint: .bottom
)
// Bouncing emojis
HStack(spacing: 8) {
Text("😊")
.font(.system(size: 28))
.offset(y: bounce ? -8 : 0)
Text("🎉")
.font(.system(size: 24))
.offset(y: bounce ? 0 : -8)
Text("")
.font(.system(size: 20))
.offset(y: bounce ? -8 : 0)
}
.offset(y: -30)
// Content
VStack(spacing: 8) {
Text("Make Tracking\nFun Again!")
.font(.system(size: 17, weight: .bold, design: .rounded))
.multilineTextAlignment(.center)
.foregroundColor(Color(red: 0.3, green: 0.25, blue: 0.2))
}
.offset(y: 35)
}
.onAppear {
withAnimation(.easeInOut(duration: 0.6).repeatForever(autoreverses: true)) {
bounce = true
}
}
.onDisappear {
bounce = false
}
}
}
struct JournalMiniPreview: View {
var body: some View {
ZStack {
// Paper texture background
LinearGradient(
colors: [
Color(red: 0.95, green: 0.92, blue: 0.88),
Color(red: 0.92, green: 0.88, blue: 0.82)
],
startPoint: .top,
endPoint: .bottom
)
// Horizontal lines like notebook paper
VStack(spacing: 18) {
ForEach(0..<6, id: \.self) { _ in
Rectangle()
.fill(Color(red: 0.7, green: 0.65, blue: 0.6).opacity(0.3))
.frame(height: 1)
}
}
.padding(.horizontal, 30)
// Content
VStack(spacing: 12) {
Image(systemName: "book.closed.fill")
.font(.system(size: 32))
.foregroundColor(Color(red: 0.5, green: 0.4, blue: 0.35))
Text("Write Your\nEmotional Story")
.font(.system(size: 16, weight: .medium, design: .serif))
.italic()
.multilineTextAlignment(.center)
.foregroundColor(Color(red: 0.35, green: 0.3, blue: 0.25))
}
}
}
}
#Preview {
NavigationStack {
PaywallPreviewSettingsView()
.environmentObject(IAPManager())
}
}
#endif