- Add VoiceOver labels, hints, and element grouping across all 60+ views - Add Reduce Motion support (Theme.Animation.prefersReducedMotion) to all animations - Replace fixed font sizes with semantic Dynamic Type styles - Hide decorative elements from VoiceOver with .accessibilityHidden(true) - Add .minimumHitTarget() modifier ensuring 44pt touch targets - Add AccessibilityAnnouncer utility for VoiceOver announcements - Improve color contrast values in Theme.swift for WCAG AA compliance - Extract CloudKitContainerConfig for explicit container identity - Remove PostHog debug console log from AnalyticsManager Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
74 lines
2.1 KiB
Swift
74 lines
2.1 KiB
Swift
//
|
|
// ProGate.swift
|
|
// SportsTime
|
|
//
|
|
// View modifier that gates Pro-only features.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct ProGateModifier: ViewModifier {
|
|
let feature: ProFeature
|
|
|
|
@State private var showPaywall = false
|
|
|
|
func body(content: Content) -> some View {
|
|
content
|
|
.onTapGesture {
|
|
if !StoreManager.shared.isPro {
|
|
showPaywall = true
|
|
}
|
|
}
|
|
.allowsHitTesting(!StoreManager.shared.isPro ? true : true)
|
|
.overlay {
|
|
if !StoreManager.shared.isPro {
|
|
Color.clear
|
|
.contentShape(Rectangle())
|
|
.onTapGesture {
|
|
showPaywall = true
|
|
}
|
|
.accessibilityLabel("Pro feature locked")
|
|
.accessibilityHint("Double-tap to view upgrade options")
|
|
}
|
|
}
|
|
.sheet(isPresented: $showPaywall) {
|
|
PaywallView(source: "pro_gate_\(feature.rawValue)")
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Modifier for buttons that should show paywall when tapped by free users
|
|
struct ProGateButtonModifier: ViewModifier {
|
|
let feature: ProFeature
|
|
let action: () -> Void
|
|
|
|
@State private var showPaywall = false
|
|
|
|
func body(content: Content) -> some View {
|
|
Button {
|
|
if StoreManager.shared.isPro {
|
|
action()
|
|
} else {
|
|
showPaywall = true
|
|
}
|
|
} label: {
|
|
content
|
|
}
|
|
.sheet(isPresented: $showPaywall) {
|
|
PaywallView(source: "pro_gate_\(feature.rawValue)")
|
|
}
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
/// Gates entire view - tapping shows paywall if not Pro
|
|
func proGate(feature: ProFeature) -> some View {
|
|
modifier(ProGateModifier(feature: feature))
|
|
}
|
|
|
|
/// Gates a button action - shows paywall instead of performing action if not Pro
|
|
func proGateButton(feature: ProFeature, action: @escaping () -> Void) -> some View {
|
|
modifier(ProGateButtonModifier(feature: feature, action: action))
|
|
}
|
|
}
|