// // WeightProgressionChartView.swift // Workouts // // Created on 7/20/25. // // Copyright 2025 Rouslan Zenetl. All Rights Reserved. // import SwiftUI import Charts import CoreData struct WeightProgressionChartView: View { @Environment(\.managedObjectContext) private var viewContext let exerciseName: String @State private var weightData: [WeightDataPoint] = [] @State private var isLoading: Bool = true @State private var motivationalMessage: String = "" var body: some View { VStack(alignment: .leading) { if isLoading { ProgressView("Loading data...") } else if weightData.isEmpty { Text("No weight history available yet.") .foregroundColor(.secondary) .frame(maxWidth: .infinity, alignment: .center) .padding() } else { Text("Weight Progression") .font(.headline) .padding(.bottom, 4) Chart { ForEach(weightData) { dataPoint in LineMark( x: .value("Date", dataPoint.date), y: .value("Weight", dataPoint.weight) ) .foregroundStyle(Color.blue.gradient) .interpolationMethod(.catmullRom) PointMark( x: .value("Date", dataPoint.date), y: .value("Weight", dataPoint.weight) ) .foregroundStyle(Color.blue) } } .chartYScale(domain: .automatic(includesZero: false)) .chartXAxis { AxisMarks(values: .automatic) { _ in AxisGridLine() AxisValueLabel(format: .dateTime.month().day()) } } .frame(height: 200) .padding(.bottom, 8) if !motivationalMessage.isEmpty { Text(motivationalMessage) .font(.subheadline) .foregroundColor(.primary) .padding() .background(Color.blue.opacity(0.1)) .cornerRadius(8) } } } .padding() .onAppear { loadWeightData() } } private func loadWeightData() { isLoading = true let request: NSFetchRequest = WorkoutLog.fetchRequest() request.predicate = NSPredicate(format: "exerciseName == %@ AND completed == YES", exerciseName) request.sortDescriptors = [NSSortDescriptor(keyPath: \WorkoutLog.date, ascending: true)] if let logs = try? viewContext.fetch(request) { weightData = logs.map { log in WeightDataPoint(date: log.date, weight: Int(log.weight)) } generateMotivationalMessage() } isLoading = false } private func generateMotivationalMessage() { guard weightData.count >= 2 else { motivationalMessage = "Complete more workouts to track your progress!" return } let firstWeight = weightData.first?.weight ?? 0 let currentWeight = weightData.last?.weight ?? 0 let weightDifference = currentWeight - firstWeight if weightDifference > 0 { let percentIncrease = Int((Double(weightDifference) / Double(firstWeight)) * 100) if percentIncrease >= 20 { motivationalMessage = "Amazing progress! You've increased your weight by \(weightDifference) lbs (\(percentIncrease)%)!" } else if percentIncrease >= 10 { motivationalMessage = "Great job! You've increased your weight by \(weightDifference) lbs (\(percentIncrease)%)!" } else { motivationalMessage = "You're making progress! Weight increased by \(weightDifference) lbs. Keep it up!" } } else if weightDifference == 0 { motivationalMessage = "You're maintaining consistent weight. Focus on form and consider increasing when ready!" } else { motivationalMessage = "Your current weight is lower than when you started. Adjust your training as needed and keep pushing!" } } } // Data structure for chart points struct WeightDataPoint: Identifiable { let id = UUID() let date: Date let weight: Int }