- 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>
95 lines
2.9 KiB
Swift
95 lines
2.9 KiB
Swift
import Foundation
|
|
import SwiftUI
|
|
|
|
@MainActor
|
|
class BeginnerModeViewModel: ObservableObject {
|
|
@Published var config: BeginnerConfig?
|
|
@Published var milestones: [Milestone] = []
|
|
@Published var currentLevel: BeginnerLevel = .justStarted
|
|
@Published var isLoading: Bool = false
|
|
@Published var error: BeginnerModeError?
|
|
|
|
private let service: BeginnerModeServiceProtocol
|
|
|
|
init(service: BeginnerModeServiceProtocol = BeginnerModeService()) {
|
|
self.service = service
|
|
}
|
|
|
|
func fetchConfig() async {
|
|
isLoading = true
|
|
error = nil
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
config = try await service.getConfig()
|
|
currentLevel = config?.currentLevel ?? .justStarted
|
|
} catch let error as BeginnerModeError {
|
|
self.error = error
|
|
} catch {
|
|
print("Failed to fetch beginner config: \(error)")
|
|
}
|
|
}
|
|
|
|
func fetchMilestoneProgress() async {
|
|
isLoading = true
|
|
error = nil
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
let result = try await service.getMilestoneProgress()
|
|
milestones = result.milestones
|
|
currentLevel = result.level
|
|
} catch let error as BeginnerModeError {
|
|
self.error = error
|
|
} catch {
|
|
print("Failed to fetch milestone progress: \(error)")
|
|
}
|
|
}
|
|
|
|
func toggleBeginnerMode(isEnabled: Bool) async {
|
|
do {
|
|
let request = UpdateBeginnerConfigRequest(isEnabled: isEnabled)
|
|
let updatedConfig = try await service.updateConfig(request: request)
|
|
config = updatedConfig
|
|
objectWillChange.send()
|
|
} catch {
|
|
print("Failed to toggle beginner mode: \(error)")
|
|
}
|
|
}
|
|
|
|
func completeOnboardingStep(_ step: OnboardingStep) async {
|
|
guard var currentConfig = config else { return }
|
|
currentConfig.completedOnboardingSteps.append(step)
|
|
|
|
do {
|
|
let request = UpdateBeginnerConfigRequest(completedOnboardingSteps: currentConfig.completedOnboardingSteps)
|
|
let updatedConfig = try await service.updateConfig(request: request)
|
|
config = updatedConfig
|
|
objectWillChange.send()
|
|
} catch {
|
|
print("Failed to complete onboarding step: \(error)")
|
|
}
|
|
}
|
|
|
|
var onboardingSteps: [OnboardingStep] { OnboardingStep.allCases }
|
|
|
|
var completedOnboardingCount: Int {
|
|
config?.completedOnboardingSteps.count ?? 0
|
|
}
|
|
|
|
var remainingOnboardingSteps: [OnboardingStep] {
|
|
let completed = config?.completedOnboardingSteps ?? []
|
|
return onboardingSteps.filter { !completed.contains($0) }
|
|
}
|
|
|
|
var completedMilestoneCount: Int {
|
|
milestones.filter { $0.isCompleted }.count
|
|
}
|
|
|
|
var totalMilestoneCount: Int {
|
|
milestones.count
|
|
}
|
|
|
|
var levels: [BeginnerLevel] { BeginnerLevel.allCases }
|
|
}
|