141 lines
5.6 KiB
Swift
141 lines
5.6 KiB
Swift
import SwiftUI
|
|
import RevenueCat
|
|
import Bedrock
|
|
|
|
struct ProPaywallView: View {
|
|
@State private var manager = PremiumManager()
|
|
@Environment(\.dismiss) private var dismiss
|
|
@ScaledMetric(relativeTo: .body) private var bodyFontSize: CGFloat = Design.FontSize.body
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
ScrollView {
|
|
VStack(spacing: Design.Spacing.xLarge) {
|
|
// Crown icon
|
|
Image(systemName: "crown.fill")
|
|
.font(.system(size: Design.FontSize.hero))
|
|
.foregroundStyle(.yellow)
|
|
|
|
Text(String(localized: "Go Pro"))
|
|
.font(.system(size: Design.FontSize.title, weight: .bold))
|
|
|
|
// Benefits list
|
|
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
|
BenefitRow(image: "paintpalette.fill", text: String(localized: "Premium Colors + Custom Color Picker"))
|
|
BenefitRow(image: "sparkles", text: String(localized: "Skin Smoothing Beauty Filter"))
|
|
BenefitRow(image: "arrow.left.and.right.righttriangle.left.righttriangle.right.fill", text: String(localized: "True Mirror Mode"))
|
|
BenefitRow(image: "bolt.fill", text: String(localized: "Flash Sync with Ring Light"))
|
|
BenefitRow(image: "camera.filters", text: String(localized: "HDR Mode for Better Photos"))
|
|
BenefitRow(image: "person.crop.rectangle.fill", text: String(localized: "Center Stage Auto-Framing"))
|
|
BenefitRow(image: "timer", text: String(localized: "Extended Self-Timers (5s, 10s)"))
|
|
BenefitRow(image: "star.fill", text: String(localized: "High Quality Photo Export"))
|
|
}
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
|
|
// Product packages
|
|
if manager.availablePackages.isEmpty {
|
|
ProgressView()
|
|
.padding()
|
|
} else {
|
|
ForEach(manager.availablePackages, id: \.identifier) { package in
|
|
ProductPackageButton(
|
|
package: package,
|
|
isPremiumUnlocked: manager.isPremiumUnlocked,
|
|
onPurchase: {
|
|
Task {
|
|
_ = try? await manager.purchase(package)
|
|
if manager.isPremiumUnlocked {
|
|
dismiss()
|
|
}
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
// Restore purchases
|
|
Button(String(localized: "Restore Purchases")) {
|
|
Task { try? await manager.restorePurchases() }
|
|
}
|
|
.font(.footnote)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
.padding(Design.Spacing.large)
|
|
}
|
|
.background(AppSurface.overlay)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button(String(localized: "Cancel")) { dismiss() }
|
|
.foregroundStyle(.white)
|
|
}
|
|
}
|
|
}
|
|
.font(.system(size: bodyFontSize))
|
|
.task { try? await manager.loadProducts() }
|
|
}
|
|
}
|
|
|
|
// MARK: - Product Package Button
|
|
|
|
private struct ProductPackageButton: View {
|
|
let package: Package
|
|
let isPremiumUnlocked: Bool
|
|
let onPurchase: () -> Void
|
|
|
|
var body: some View {
|
|
Button(action: onPurchase) {
|
|
VStack(spacing: Design.Spacing.small) {
|
|
Text(package.storeProduct.localizedTitle)
|
|
.font(.headline)
|
|
.foregroundStyle(.white)
|
|
|
|
Text(package.localizedPriceString)
|
|
.font(.title2.bold())
|
|
.foregroundStyle(.white)
|
|
|
|
if package.packageType == .annual {
|
|
Text(String(localized: "Best Value • Save 33%"))
|
|
.font(.caption)
|
|
.foregroundStyle(.white.opacity(Design.Opacity.accent))
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
.padding(Design.Spacing.large)
|
|
.background(AppAccent.primary.opacity(Design.Opacity.medium))
|
|
.clipShape(.rect(cornerRadius: Design.CornerRadius.large))
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: Design.CornerRadius.large)
|
|
.strokeBorder(AppAccent.primary, lineWidth: Design.LineWidth.thin)
|
|
)
|
|
}
|
|
.accessibilityLabel(String(localized: "Subscribe to \(package.storeProduct.localizedTitle) for \(package.localizedPriceString)"))
|
|
}
|
|
}
|
|
|
|
// MARK: - Benefit Row
|
|
|
|
struct BenefitRow: View {
|
|
let image: String
|
|
let text: String
|
|
|
|
var body: some View {
|
|
HStack(spacing: Design.Spacing.medium) {
|
|
Image(systemName: image)
|
|
.font(.title2)
|
|
.foregroundStyle(AppAccent.primary)
|
|
.frame(width: Design.IconSize.xLarge)
|
|
|
|
Text(text)
|
|
.foregroundStyle(.white)
|
|
|
|
Spacer()
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
ProPaywallView()
|
|
.preferredColorScheme(.dark)
|
|
}
|