// // SettingsView.swift // SportsTime // import SwiftUI struct SettingsView: View { @Environment(\.colorScheme) private var colorScheme @State private var viewModel = SettingsViewModel() @State private var showResetConfirmation = false @State private var showPaywall = false @State private var showOnboardingPaywall = false var body: some View { List { // Subscription subscriptionSection // Appearance Mode (Light/Dark/System) appearanceSection // Theme Selection themeSection // UI Design Style designStyleSection // Sports Preferences sportsSection // Travel Preferences travelSection // About aboutSection // Reset resetSection #if DEBUG // Debug debugSection #endif } .scrollContentBackground(.hidden) .themedBackground() .alert("Reset Settings", isPresented: $showResetConfirmation) { Button("Cancel", role: .cancel) { } Button("Reset", role: .destructive) { viewModel.resetToDefaults() } } message: { Text("This will reset all settings to their default values.") } .sheet(isPresented: $showOnboardingPaywall) { OnboardingPaywallView(isPresented: $showOnboardingPaywall) } } // MARK: - Appearance Section private var appearanceSection: some View { Section { ForEach(AppearanceMode.allCases) { mode in Button { withAnimation(.easeInOut(duration: 0.2)) { AppearanceManager.shared.currentMode = mode } } label: { HStack(spacing: 12) { // Icon ZStack { Circle() .fill(Theme.warmOrange.opacity(0.15)) .frame(width: 32, height: 32) Image(systemName: mode.iconName) .font(.system(size: 16)) .foregroundStyle(Theme.warmOrange) } VStack(alignment: .leading, spacing: 2) { Text(mode.displayName) .font(.body) .foregroundStyle(.primary) Text(mode.description) .font(.caption) .foregroundStyle(.secondary) } Spacer() if AppearanceManager.shared.currentMode == mode { Image(systemName: "checkmark.circle.fill") .foregroundStyle(Theme.warmOrange) .font(.title3) } } .contentShape(Rectangle()) } .buttonStyle(.plain) } } header: { Text("Appearance") } footer: { Text("Choose light, dark, or follow your device settings.") } .listRowBackground(Theme.cardBackground(colorScheme)) } // MARK: - Theme Section private var themeSection: some View { Section { ForEach(AppTheme.allCases) { theme in Button { withAnimation(.easeInOut(duration: 0.2)) { viewModel.selectedTheme = theme } } label: { HStack(spacing: 12) { // Color preview circles HStack(spacing: -6) { ForEach(Array(theme.previewColors.enumerated()), id: \.offset) { _, color in Circle() .fill(color) .frame(width: 24, height: 24) .overlay( Circle() .stroke(Color.primary.opacity(0.1), lineWidth: 1) ) } } VStack(alignment: .leading, spacing: 2) { Text(theme.displayName) .font(.body) .foregroundStyle(.primary) Text(theme.description) .font(.caption) .foregroundStyle(.secondary) } Spacer() if viewModel.selectedTheme == theme { Image(systemName: "checkmark.circle.fill") .foregroundStyle(Theme.warmOrange) .font(.title3) } } .contentShape(Rectangle()) } .buttonStyle(.plain) } } header: { Text("Theme") } footer: { Text("Choose a color scheme for the app.") } .listRowBackground(Theme.cardBackground(colorScheme)) } // MARK: - Design Style Section private var designStyleSection: some View { Section { ForEach(UIDesignStyle.allCases) { style in Button { withAnimation(.easeInOut(duration: 0.2)) { DesignStyleManager.shared.setStyle(style) } } label: { HStack(spacing: 12) { // Icon with accent color ZStack { Circle() .fill(style.accentColor.opacity(0.15)) .frame(width: 36, height: 36) Image(systemName: style.iconName) .font(.system(size: 16)) .foregroundStyle(style.accentColor) } VStack(alignment: .leading, spacing: 2) { Text(style.rawValue) .font(.body) .foregroundStyle(.primary) Text(style.description) .font(.caption) .foregroundStyle(.secondary) .lineLimit(1) } Spacer() if DesignStyleManager.shared.currentStyle == style { Image(systemName: "checkmark.circle.fill") .foregroundStyle(style.accentColor) .font(.title3) } } .contentShape(Rectangle()) } .buttonStyle(.plain) } } header: { Text("Home Screen Style") } footer: { Text("Choose a visual aesthetic for the home screen.") } .listRowBackground(Theme.cardBackground(colorScheme)) } // MARK: - Sports Section private var sportsSection: some View { Section { ForEach(Sport.supported) { sport in Toggle(isOn: Binding( get: { viewModel.selectedSports.contains(sport) }, set: { _ in viewModel.toggleSport(sport) } )) { Label { Text(sport.displayName) } icon: { Image(systemName: sport.iconName) .foregroundStyle(sportColor(for: sport)) } } } } header: { Text("Favorite Sports") } footer: { Text("Selected sports will be shown by default in schedules and trip planning.") } .listRowBackground(Theme.cardBackground(colorScheme)) } // MARK: - Travel Section private var travelSection: some View { Section { VStack(alignment: .leading, spacing: 8) { HStack { Text("Max Driving Per Day") Spacer() Text("\(viewModel.maxDrivingHoursPerDay) hours") .foregroundStyle(.secondary) } Slider( value: Binding( get: { Double(viewModel.maxDrivingHoursPerDay) }, set: { viewModel.maxDrivingHoursPerDay = Int($0) } ), in: 2...12, step: 1 ) } } header: { Text("Travel Preferences") } footer: { Text("Trips will be optimized to keep daily driving within this limit.") } .listRowBackground(Theme.cardBackground(colorScheme)) } // MARK: - About Section private var aboutSection: some View { Section { HStack { Text("Version") Spacer() Text("\(viewModel.appVersion) (\(viewModel.buildNumber))") .foregroundStyle(.secondary) } Link(destination: URL(string: "https://88oakapps.com/privacy")!) { Label("Privacy Policy", systemImage: "hand.raised") } Link(destination: URL(string: "https://88oakapps.com/terms")!) { Label("Terms of Service", systemImage: "doc.text") } Link(destination: URL(string: "mailto:support@88oakapps.com")!) { Label("Contact Support", systemImage: "envelope") } } header: { Text("About") } .listRowBackground(Theme.cardBackground(colorScheme)) } // MARK: - Reset Section private var resetSection: some View { Section { Button(role: .destructive) { showResetConfirmation = true } label: { Label("Reset to Defaults", systemImage: "arrow.counterclockwise") } } .listRowBackground(Theme.cardBackground(colorScheme)) } // MARK: - Debug Section #if DEBUG private var debugSection: some View { Section { Toggle(isOn: Binding( get: { StoreManager.shared.debugProOverride }, set: { StoreManager.shared.debugProOverride = $0 } )) { Label("Override Pro Status", systemImage: "star.fill") } Button { showOnboardingPaywall = true } label: { Label("Show Onboarding Flow", systemImage: "play.circle") } Button { UserDefaults.standard.removeObject(forKey: "hasSeenOnboardingPaywall") } label: { Label("Reset Onboarding Flag", systemImage: "arrow.counterclockwise") } } header: { Text("Debug") } footer: { Text("These options are only visible in debug builds.") } .listRowBackground(Theme.cardBackground(colorScheme)) } #endif // MARK: - Subscription Section private var subscriptionSection: some View { Section { if StoreManager.shared.isPro { // Pro user - show manage option HStack { Label { VStack(alignment: .leading, spacing: 4) { Text("SportsTime Pro") .foregroundStyle(Theme.textPrimary(colorScheme)) Text("Active subscription") .font(.caption) .foregroundStyle(.green) } } icon: { Image(systemName: "star.fill") .foregroundStyle(Theme.warmOrange) } Spacer() Image(systemName: "checkmark.circle.fill") .foregroundStyle(.green) } Button { if let url = URL(string: "https://apps.apple.com/account/subscriptions") { UIApplication.shared.open(url) } } label: { Label("Manage Subscription", systemImage: "gear") } } else { // Free user - show upgrade option Button { showPaywall = true } label: { HStack { Label { VStack(alignment: .leading, spacing: 4) { Text("Upgrade to Pro") .foregroundStyle(Theme.textPrimary(colorScheme)) Text("Unlimited trips, PDF export, progress tracking") .font(.caption) .foregroundStyle(Theme.textSecondary(colorScheme)) } } icon: { Image(systemName: "star.fill") .foregroundStyle(Theme.warmOrange) } Spacer() Image(systemName: "chevron.right") .foregroundStyle(Theme.textMuted(colorScheme)) } } .buttonStyle(.plain) Button { Task { await StoreManager.shared.restorePurchases() } } label: { Label("Restore Purchases", systemImage: "arrow.clockwise") } } } header: { Text("Subscription") } .listRowBackground(Theme.cardBackground(colorScheme)) .sheet(isPresented: $showPaywall) { PaywallView() } } // MARK: - Helpers private func sportColor(for sport: Sport) -> Color { sport.themeColor } } #Preview { NavigationStack { SettingsView() } }