- Models: TrainingPlan, Race, FamilyPlan, BeginnerMode, CommunityEvent - Services: 5 service layers with protocol-based architecture - ViewModels: 5 view models with @MainActor ObservableObject pattern - Views: 10 SwiftUI views for all Phase 3 features - Updated README with full Phase 3 documentation Co-Authored-By: Paperclip <noreply@paperclip.ing>
202 lines
5.0 KiB
Swift
202 lines
5.0 KiB
Swift
import Foundation
|
|
import SwiftUI
|
|
|
|
// MARK: - Beginner Configuration
|
|
|
|
struct BeginnerConfig: Codable {
|
|
var isEnabled: Bool
|
|
var currentLevel: BeginnerLevel
|
|
var completedOnboardingSteps: [OnboardingStep]
|
|
var milestones: [Milestone]
|
|
var shownTips: Set<String>
|
|
var preferredMetric: MetricType
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case isEnabled, currentLevel, completedOnboardingSteps, milestones, shownTips, preferredMetric
|
|
}
|
|
}
|
|
|
|
// MARK: - Beginner Level
|
|
|
|
enum BeginnerLevel: String, CaseIterable, Codable {
|
|
case justStarted
|
|
case gettingComfortable
|
|
case buildingConsistency
|
|
case progressing
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .justStarted: return "Just Started"
|
|
case .gettingComfortable: return "Getting Comfortable"
|
|
case .buildingConsistency: return "Building Consistency"
|
|
case .progressing: return "Progressing"
|
|
}
|
|
}
|
|
|
|
var requiredWorkouts: Int {
|
|
switch self {
|
|
case .justStarted: return 0
|
|
case .gettingComfortable: return 5
|
|
case .buildingConsistency: return 15
|
|
case .progressing: return 30
|
|
}
|
|
}
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .justStarted: return "sparkles"
|
|
case .gettingComfortable: return "leaf.fill"
|
|
case .buildingConsistency: return "chart.bar.fill"
|
|
case .progressing: return "bolt.fill"
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Onboarding Step
|
|
|
|
enum OnboardingStep: String, CaseIterable, Codable {
|
|
case profileSetup
|
|
case goalSelection
|
|
case firstActivity
|
|
case inviteFriends
|
|
case enableNotifications
|
|
case choosePlan
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .profileSetup: return "Profile Setup"
|
|
case .goalSelection: return "Set Goals"
|
|
case .firstActivity: return "First Activity"
|
|
case .inviteFriends: return "Invite Friends"
|
|
case .enableNotifications: return "Enable Notifications"
|
|
case .choosePlan: return "Choose a Plan"
|
|
}
|
|
}
|
|
|
|
var description: String {
|
|
switch self {
|
|
case .profileSetup: return "Complete your profile with your name and photo"
|
|
case .goalSelection: return "Tell us what you want to achieve"
|
|
case .firstActivity: return "Record your first workout"
|
|
case .inviteFriends: return "Invite friends to join Nessa"
|
|
case .enableNotifications: return "Get reminders and updates"
|
|
case .choosePlan: return "Pick a training plan to follow"
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Milestone
|
|
|
|
struct Milestone: Identifiable, Codable {
|
|
let id: String
|
|
let title: String
|
|
let description: String
|
|
let icon: String
|
|
let requirement: MilestoneRequirement
|
|
var isCompleted: Bool
|
|
var completedAt: Date?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case id, title, description, icon, requirement, isCompleted, completedAt
|
|
}
|
|
|
|
init(
|
|
id: String,
|
|
title: String,
|
|
description: String,
|
|
icon: String,
|
|
requirement: MilestoneRequirement,
|
|
isCompleted: Bool,
|
|
completedAt: Date?
|
|
) {
|
|
self.id = id
|
|
self.title = title
|
|
self.description = description
|
|
self.icon = icon
|
|
self.requirement = requirement
|
|
self.isCompleted = isCompleted
|
|
self.completedAt = completedAt
|
|
}
|
|
}
|
|
|
|
// MARK: - Milestone Requirement
|
|
|
|
struct MilestoneRequirement: Codable {
|
|
let type: RequirementType
|
|
let targetValue: Double
|
|
}
|
|
|
|
enum RequirementType: String, CaseIterable, Codable {
|
|
case totalDistanceKm
|
|
case totalWorkouts
|
|
case consecutiveDays
|
|
case weeklyConsistency
|
|
case firstWorkout
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .totalDistanceKm: return "Total Distance"
|
|
case .totalWorkouts: return "Total Workouts"
|
|
case .consecutiveDays: return "Streak"
|
|
case .weeklyConsistency: return "Weekly Consistency"
|
|
case .firstWorkout: return "First Workout"
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Tip
|
|
|
|
struct BeginnerTip: Identifiable, Codable {
|
|
let id: String
|
|
let context: TipContext
|
|
let title: String
|
|
let message: String
|
|
var isShown: Bool
|
|
}
|
|
|
|
enum TipContext: String, CaseIterable, Codable {
|
|
case beforeWorkout
|
|
case afterWorkout
|
|
case dailyReminder
|
|
case progressUpdate
|
|
case restDay
|
|
}
|
|
|
|
// MARK: - Metric Type
|
|
|
|
enum MetricType: String, CaseIterable, Codable {
|
|
case distance
|
|
case duration
|
|
case pace
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .distance: return "Distance"
|
|
case .duration: return "Duration"
|
|
case .pace: return "Pace"
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - API Response Types
|
|
|
|
struct BeginnerConfigResponse: Decodable {
|
|
let config: BeginnerConfig
|
|
}
|
|
|
|
struct UpdateBeginnerConfigRequest: Encodable {
|
|
var isEnabled: Bool?
|
|
var completedOnboardingSteps: [OnboardingStep]?
|
|
var preferredMetric: MetricType?
|
|
}
|
|
|
|
struct UpdateBeginnerConfigResponse: Decodable {
|
|
let success: Bool
|
|
let config: BeginnerConfig
|
|
}
|
|
|
|
struct MilestoneProgressResponse: Decodable {
|
|
let milestones: [Milestone]
|
|
let currentLevel: BeginnerLevel
|
|
}
|