160 lines
5.8 KiB
Swift
160 lines
5.8 KiB
Swift
//
|
|
// OnboardingSoftPaywallView.swift
|
|
// SelfieCam
|
|
//
|
|
// Soft paywall shown to free users during onboarding.
|
|
// Presents premium benefits with options to upgrade or continue with free version.
|
|
// Supports landscape and iPad layouts with max width constraints.
|
|
//
|
|
|
|
import SwiftUI
|
|
import Bedrock
|
|
|
|
struct OnboardingSoftPaywallView: View {
|
|
@Bindable var viewModel: OnboardingViewModel
|
|
@Bindable var settingsViewModel: SettingsViewModel
|
|
@Binding var showPaywall: Bool
|
|
let onComplete: () -> Void
|
|
|
|
/// Premium manager for restore purchases
|
|
@State private var premiumManager = PremiumManager()
|
|
|
|
/// Whether a restore is in progress
|
|
@State private var isRestoring = false
|
|
|
|
var body: some View {
|
|
OnboardingContentContainer {
|
|
VStack(spacing: Design.Spacing.large) {
|
|
Spacer()
|
|
|
|
// Header
|
|
VStack(spacing: Design.Spacing.medium) {
|
|
SymbolIcon("crown.fill", size: .hero, color: AppStatus.warning)
|
|
|
|
OnboardingSectionTitle(
|
|
title: String(localized: "Unlock Pro Features"),
|
|
subtitle: String(localized: "Get the most out of SelfieCam")
|
|
)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
// Benefits list
|
|
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
|
OnboardingBenefitRow(
|
|
image: "paintpalette.fill",
|
|
text: String(localized: "Premium Colors + Custom Color Picker")
|
|
)
|
|
|
|
OnboardingBenefitRow(
|
|
image: "sparkles",
|
|
text: String(localized: "Skin Smoothing Beauty Filter")
|
|
)
|
|
|
|
OnboardingBenefitRow(
|
|
image: "arrow.left.and.right.righttriangle.left.righttriangle.right.fill",
|
|
text: String(localized: "True Mirror Mode")
|
|
)
|
|
|
|
OnboardingBenefitRow(
|
|
image: "camera.filters",
|
|
text: String(localized: "HDR Mode for Better Photos")
|
|
)
|
|
|
|
OnboardingBenefitRow(
|
|
image: "timer",
|
|
text: String(localized: "Extended Self-Timers (5s, 10s)")
|
|
)
|
|
|
|
OnboardingBenefitRow(
|
|
image: "star.fill",
|
|
text: String(localized: "High Quality Photo Export")
|
|
)
|
|
}
|
|
.padding(.horizontal, Design.Spacing.large)
|
|
|
|
Spacer()
|
|
|
|
// Action buttons
|
|
VStack(spacing: Design.Spacing.medium) {
|
|
// Upgrade button
|
|
OnboardingPrimaryButton(
|
|
title: String(localized: "Upgrade to Pro"),
|
|
action: { showPaywall = true },
|
|
icon: "crown.fill",
|
|
style: .premium
|
|
)
|
|
|
|
// Maybe Later button
|
|
OnboardingSecondaryButton(
|
|
title: String(localized: "Maybe Later"),
|
|
action: {
|
|
viewModel.completeOnboarding(settingsViewModel: settingsViewModel)
|
|
onComplete()
|
|
}
|
|
)
|
|
|
|
// Restore Purchases button
|
|
Button {
|
|
Task {
|
|
isRestoring = true
|
|
try? await premiumManager.restorePurchases()
|
|
isRestoring = false
|
|
|
|
// Check if premium was restored
|
|
if premiumManager.isPremiumUnlocked {
|
|
viewModel.completeOnboarding(settingsViewModel: settingsViewModel)
|
|
onComplete()
|
|
}
|
|
}
|
|
} label: {
|
|
if isRestoring {
|
|
ProgressView()
|
|
.tint(.secondary)
|
|
} else {
|
|
Text(String(localized: "Restore Purchases"))
|
|
}
|
|
}
|
|
.font(.footnote)
|
|
.foregroundStyle(.secondary)
|
|
.disabled(isRestoring)
|
|
}
|
|
.padding(.horizontal, Design.Spacing.xLarge)
|
|
.padding(.bottom, Design.Spacing.xLarge)
|
|
}
|
|
.padding(.horizontal, Design.Spacing.medium)
|
|
}
|
|
.onChange(of: viewModel.isPremiumUser) { _, isPremium in
|
|
// If user subscribed during paywall, complete onboarding
|
|
if isPremium {
|
|
viewModel.completeOnboarding(settingsViewModel: settingsViewModel)
|
|
onComplete()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Preview
|
|
|
|
#Preview {
|
|
OnboardingSoftPaywallView(
|
|
viewModel: OnboardingViewModel(),
|
|
settingsViewModel: SettingsViewModel(),
|
|
showPaywall: .constant(false),
|
|
onComplete: {}
|
|
)
|
|
.background(AppSurface.primary)
|
|
.preferredColorScheme(.dark)
|
|
}
|
|
|
|
#Preview("Landscape", traits: .landscapeLeft) {
|
|
OnboardingSoftPaywallView(
|
|
viewModel: OnboardingViewModel(),
|
|
settingsViewModel: SettingsViewModel(),
|
|
showPaywall: .constant(false),
|
|
onComplete: {}
|
|
)
|
|
.background(AppSurface.primary)
|
|
.preferredColorScheme(.dark)
|
|
}
|