Files
Termind/TFM/Features/Commerce/ProPaywallView.swift
T

102 lines
3.7 KiB
Swift

import SwiftUI
import TermindApplication
import TermindDomain
import TermindInfrastructure
import TermindPresentation
struct ProPaywallView: View {
@Environment(AppModel.self) private var app
@Environment(\.dismiss) private var dismiss
@Environment(\.openURL) private var openURL
@State private var selectedPlan: ProPurchasePlan = .annual
private var pro: ProAccessController { app.proAccess }
var body: some View {
ProPaywallContent(
presentation: presentation, selectedPlan: $selectedPlan,
background: TermindColor.windowSurface, cardBackground: TermindColor.contentSurface, purchase: purchase,
restorePurchases: { Task { await pro.restorePurchases() } },
reloadProducts: { Task { await pro.reloadProducts() } },
manageSubscription: { openURL(URL(string: "https://apps.apple.com/account/subscriptions")!) }
)
.frame(width: 604, height: 640)
.overlay(alignment: .topLeading) {
closeButton.padding(16)
}
.task {
await pro.reloadProducts()
if pro.annualProduct == nil, pro.product != nil { selectedPlan = .lifetime }
}
}
private var closeButton: some View {
Button {
dismiss()
} label: {
Label(AppStrings.Common.close, systemImage: "xmark")
.labelStyle(.iconOnly)
.frame(width: 30, height: 30)
.contentShape(.circle)
}
.buttonStyle(.plain)
.termindGlassCircle(isInteractive: true)
.termindInputAwareFocusEffect()
.keyboardShortcut(.cancelAction)
.help(AppStrings.Common.close)
.accessibilityLabel(Text(AppStrings.Common.close))
}
private var presentation: ProPaywallPresentation {
ProPaywallPresentation(
status: pro.status, annualPrice: pro.annualDisplayPrice, lifetimePrice: pro.displayPrice,
billingPeriod: pro.annualBillingPeriod, trialDuration: pro.annualIntroOfferDuration,
canStartTrial: pro.canStartTrial, canPurchaseAnnual: pro.canPurchase(.annual),
canPurchaseLifetime: pro.canPurchase(.lifetime), isProcessing: pro.isProcessing,
message: pro.message, requestedFeature: pro.requestedFeature, supportsMCPServer: true)
}
private func purchase(_ plan: ProPurchasePlan) {
Task {
switch plan {
case .annual: await pro.purchaseAnnual()
case .lifetime: await pro.purchaseLifetime()
}
}
}
}
struct ProPaywallPresenter: ViewModifier {
let app: AppModel
let window: WindowModel
func body(content: Content) -> some View {
content
.onChange(of: app.proAccess.isPaywallPresented, initial: true) {
app.mainWindows.synchronizePaywall()
}
.sheet(
isPresented: Binding(
get: {
app.proAccess.isPaywallPresented
&& app.mainWindows.paywallOwnerID == ObjectIdentifier(window)
},
set: { presented in
guard app.mainWindows.paywallOwnerID == ObjectIdentifier(window) else { return }
app.proAccess.isPaywallPresented = presented
app.mainWindows.synchronizePaywall()
}
)
) {
ProPaywallView().environment(app)
.allowsApplicationTerminationWhenModal()
}
}
}
extension View {
func proPaywallPresenter(app: AppModel, window: WindowModel) -> some View {
modifier(ProPaywallPresenter(app: app, window: window))
}
}