From 7948e733f301ec6ce464d6060d9f167bf298780d Mon Sep 17 00:00:00 2001 From: Rektoooooo Date: Mon, 20 Oct 2025 10:47:16 +0200 Subject: [PATCH] FEAT: Add premium subscription tier with 10 features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create comprehensive premium subscription UI and infrastructure: Premium Features (2.99€/month or 29.99€/year): 1. Smart Progression Coach - AI weight increase suggestions 2. Automatic PR Tracking - Never miss personal records 3. Progress Photo Timeline - Visual transformation tracking 4. Extended Analytics - Week/month/all-time graphs 5. AI Workout Summary - Weekly insights & recommendations 6. Workout Templates - Pre-built programs for goals 7. Advanced Streak Analytics - Motivation & predictions 8. Export Your Data - CSV/PDF reports 9. Unlimited History - Lifetime workout access 10. Custom App Appearance - Choose themes & colors Changes: - Create PremiumSubscriptionView with feature list - Add monthly (2.99€) and yearly (29.99€, save 17%) plans - Design 7-day free trial CTA button - Create premium FloatingClouds theme (deep purple/violet) - Link premium upgrade from Settings tab - Add FeatureRow and PlanCard components - Include Terms, Privacy, and Restore Purchase links - Add sophisticated purple gradient background for luxury feel Design: - Deep indigo/purple-black background (Apple-style sophistication) - Royal purple, violet, plum, and lavender accents - Clean, modern layout with feature icons - Selectable plan cards with visual feedback - Professional pricing presentation Result: Complete premium tier foundation ready for StoreKit integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Gymly/Settings/FloatingClouds.swift | 29 ++ Gymly/Settings/NewSettingsView.swift | 7 +- Gymly/Settings/PremiumSubscriptionView.swift | 297 +++++++++++++++++++ 3 files changed, 327 insertions(+), 6 deletions(-) create mode 100644 Gymly/Settings/PremiumSubscriptionView.swift diff --git a/Gymly/Settings/FloatingClouds.swift b/Gymly/Settings/FloatingClouds.swift index c925de4..ed117b9 100644 --- a/Gymly/Settings/FloatingClouds.swift +++ b/Gymly/Settings/FloatingClouds.swift @@ -141,6 +141,35 @@ struct CloudsTheme { bottomTrailing: Color(red: 0.3, green: 0.7, blue: 1.0, opacity: 0.75) ) } + + static func premium(_ scheme: ColorScheme) -> CloudsTheme { + CloudsTheme( + // Deep indigo/purple-black background for sophisticated luxury + background: scheme == .dark + ? Color(red: 0.05, green: 0.03, blue: 0.10) // Deep indigo black + : Color(red: 0.08, green: 0.06, blue: 0.12), // Dark purple charcoal + + // Royal purple shimmer - top left + topLeading: scheme == .dark + ? Color(red: 0.45, green: 0.20, blue: 0.75, opacity: 0.80) // Royal purple + : Color(red: 0.50, green: 0.25, blue: 0.70, opacity: 0.70), + + // Deep violet glow - top right + topTrailing: scheme == .dark + ? Color(red: 0.60, green: 0.30, blue: 0.85, opacity: 0.70) // Deep violet + : Color(red: 0.55, green: 0.30, blue: 0.75, opacity: 0.60), + + // Rich plum warmth - bottom left + bottomLeading: scheme == .dark + ? Color(red: 0.35, green: 0.15, blue: 0.55, opacity: 0.65) // Rich plum + : Color(red: 0.40, green: 0.20, blue: 0.55, opacity: 0.55), + + // Lavender/light purple - bottom right + bottomTrailing: scheme == .dark + ? Color(red: 0.65, green: 0.45, blue: 0.90, opacity: 0.75) // Lavender purple + : Color(red: 0.60, green: 0.40, blue: 0.80, opacity: 0.65) + ) + } } class CloudProvider: ObservableObject { diff --git a/Gymly/Settings/NewSettingsView.swift b/Gymly/Settings/NewSettingsView.swift index a8dc52b..c06603f 100644 --- a/Gymly/Settings/NewSettingsView.swift +++ b/Gymly/Settings/NewSettingsView.swift @@ -78,9 +78,7 @@ struct NewSettingsView: View { // Premium Section Section("Premium") { - Button(action: { - // TODO: Show premium upgrade flow - }) { + NavigationLink(destination: PremiumSubscriptionView()) { HStack { Image(systemName: "star.fill") .foregroundColor(.yellow) @@ -93,9 +91,6 @@ struct NewSettingsView: View { .font(.caption) } Spacer() - Image(systemName: "chevron.right") - .foregroundColor(.secondary) - .font(.caption) } } .frame(width: 300) diff --git a/Gymly/Settings/PremiumSubscriptionView.swift b/Gymly/Settings/PremiumSubscriptionView.swift new file mode 100644 index 0000000..bcb8759 --- /dev/null +++ b/Gymly/Settings/PremiumSubscriptionView.swift @@ -0,0 +1,297 @@ +// +// PremiumSubscriptionView.swift +// Gymly +// +// Created by Sebastián Kučera on 20.10.2025. +// + +import SwiftUI + +struct PremiumSubscriptionView: View { + @Environment(\.dismiss) var dismiss + @Environment(\.colorScheme) private var scheme + @State private var selectedPlan: SubscriptionPlan = .monthly + + enum SubscriptionPlan { + case monthly + case yearly + + var price: String { + switch self { + case .monthly: return "2.99€" + case .yearly: return "29.99€" + } + } + + var period: String { + switch self { + case .monthly: return "month" + case .yearly: return "year" + } + } + + var savings: String? { + switch self { + case .monthly: return nil + case .yearly: return "Save 17%" + } + } + } + + var body: some View { + NavigationView { + ZStack { + FloatingClouds(theme: CloudsTheme.premium(scheme)) + .ignoresSafeArea() + + ScrollView { + VStack(spacing: 24) { + // Header + VStack(spacing: 12) { + Image(systemName: "star.fill") + .font(.system(size: 60)) + .foregroundColor(.yellow) + + Text("Gymly Pro") + .font(.largeTitle) + .fontWeight(.bold) + + Text("Unlock your full potential") + .font(.subheadline) + .foregroundStyle(.secondary) + } + .padding(.top, 40) + .padding(.bottom, 20) + + // Features List + VStack(spacing: 16) { + FeatureRow( + icon: "brain.head.profile", + title: "Smart Progression Coach", + description: "AI suggests optimal weight increases" + ) + + FeatureRow( + icon: "trophy.fill", + title: "Automatic PR Tracking", + description: "Never miss a personal record" + ) + + FeatureRow( + icon: "camera.fill", + title: "Progress Photo Timeline", + description: "Track your visual transformation" + ) + + FeatureRow( + icon: "chart.line.uptrend.xyaxis", + title: "Extended Analytics", + description: "Week, month, and all-time graphs" + ) + + FeatureRow( + icon: "apple.intelligence", + title: "AI Workout Summary", + description: "Weekly insights & recommendations" + ) + + FeatureRow( + icon: "book.fill", + title: "Workout Templates", + description: "Pre-built programs for your goals" + ) + + FeatureRow( + icon: "flame.fill", + title: "Advanced Streak Analytics", + description: "Motivation & predictions" + ) + + FeatureRow( + icon: "square.and.arrow.up", + title: "Export Your Data", + description: "CSV/PDF reports anytime" + ) + + FeatureRow( + icon: "calendar", + title: "Unlimited History", + description: "Lifetime workout access" + ) + + FeatureRow( + icon: "paintbrush.fill", + title: "Custom App Appearance", + description: "Choose your theme & colors" + ) + } + .padding(.horizontal, 24) + + // Pricing Plans + VStack(spacing: 12) { + Text("Choose Your Plan") + .font(.headline) + .padding(.top, 20) + + // Monthly Plan + PlanCard( + plan: .monthly, + isSelected: selectedPlan == .monthly + ) { + selectedPlan = .monthly + } + + // Yearly Plan + PlanCard( + plan: .yearly, + isSelected: selectedPlan == .yearly + ) { + selectedPlan = .yearly + } + } + .padding(.horizontal, 24) + + // CTA Button + Button(action: { + // TODO: Implement subscription purchase + print("Starting subscription: \(selectedPlan)") + }) { + VStack(spacing: 8) { + Text("Start 7-Day Free Trial") + .font(.headline) + .foregroundColor(.white) + + Text("Then \(selectedPlan.price)/\(selectedPlan.period)") + .font(.caption) + .foregroundColor(.white.opacity(0.8)) + } + .frame(maxWidth: .infinity) + .padding() + .background(Color.red) + .cornerRadius(12) + } + .padding(.horizontal, 24) + .padding(.top, 8) + + // Fine Print + VStack(spacing: 8) { + Text("Cancel anytime. No commitment.") + .font(.caption) + .foregroundStyle(.secondary) + + HStack(spacing: 16) { + Button("Terms of Service") { + // TODO: Open terms + } + .font(.caption2) + .foregroundStyle(.secondary) + + Button("Privacy Policy") { + // TODO: Open privacy + } + .font(.caption2) + .foregroundStyle(.secondary) + + Button("Restore Purchase") { + // TODO: Restore purchase + } + .font(.caption2) + .foregroundStyle(.secondary) + } + } + .padding(.bottom, 40) + } + } + } + .navigationBarTitleDisplayMode(.inline) + } + } +} + +// MARK: - Feature Row Component +struct FeatureRow: View { + let icon: String + let title: String + let description: String + + var body: some View { + HStack(spacing: 16) { + Image(systemName: icon) + .font(.system(size: 28)) + .foregroundColor(.red) + .frame(width: 40) + + VStack(alignment: .leading, spacing: 4) { + Text(title) + .font(.headline) + .foregroundColor(.primary) + + Text(description) + .font(.caption) + .foregroundStyle(.secondary) + } + + Spacer() + } + .padding(.vertical, 8) + } +} + +// MARK: - Plan Card Component +struct PlanCard: View { + let plan: PremiumSubscriptionView.SubscriptionPlan + let isSelected: Bool + let action: () -> Void + + var body: some View { + Button(action: action) { + HStack { + VStack(alignment: .leading, spacing: 4) { + HStack { + Text(plan.period.capitalized) + .font(.headline) + .foregroundColor(.primary) + + if let savings = plan.savings { + Text(savings) + .font(.caption) + .fontWeight(.semibold) + .foregroundColor(.green) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background(Color.green.opacity(0.2)) + .cornerRadius(6) + } + } + + Text("\(plan.price)/\(plan.period)") + .font(.title2) + .fontWeight(.bold) + .foregroundColor(.primary) + } + + Spacer() + + if isSelected { + Image(systemName: "checkmark.circle.fill") + .font(.system(size: 24)) + .foregroundColor(.red) + } + } + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.black.opacity(0.3)) + .overlay( + RoundedRectangle(cornerRadius: 12) + .stroke(isSelected ? Color.red : Color.clear, lineWidth: 2) + ) + ) + } + .buttonStyle(.plain) + } +} + +#Preview { + PremiumSubscriptionView() +}