wip
This commit is contained in:
		@@ -31,26 +31,31 @@ struct DraggableSplitItem: View {
 | 
			
		||||
                    .aspectRatio(1.618, contentMode: .fit)
 | 
			
		||||
                    .shadow(radius: 2)
 | 
			
		||||
                
 | 
			
		||||
                VStack {
 | 
			
		||||
                    // Icon in the center
 | 
			
		||||
                    Image(systemName: systemImageName)
 | 
			
		||||
                        .font(.system(size: 40, weight: .bold))
 | 
			
		||||
                        .offset(y: -15)
 | 
			
		||||
                    
 | 
			
		||||
                    // Name at the bottom inside the rectangle
 | 
			
		||||
                    Text(name)
 | 
			
		||||
                        .font(.headline)
 | 
			
		||||
                        .lineLimit(1)
 | 
			
		||||
                        .padding(.horizontal, 8)
 | 
			
		||||
                GeometryReader { geometry in
 | 
			
		||||
                    VStack(spacing: 4) {
 | 
			
		||||
                        Spacer()
 | 
			
		||||
                        
 | 
			
		||||
                        // Icon in the center - now using dynamic sizing
 | 
			
		||||
                        Image(systemName: systemImageName)
 | 
			
		||||
                            .font(.system(size: min(geometry.size.width * 0.3, 40), weight: .bold))
 | 
			
		||||
                            .scaledToFit()
 | 
			
		||||
                            .frame(maxWidth: geometry.size.width * 0.6, maxHeight: geometry.size.height * 0.4)
 | 
			
		||||
                            .padding(.bottom, 4)
 | 
			
		||||
                        
 | 
			
		||||
                        // Name at the bottom inside the rectangle
 | 
			
		||||
                        Text(name)
 | 
			
		||||
                            .font(.headline)
 | 
			
		||||
                            .lineLimit(1)
 | 
			
		||||
                            .padding(.horizontal, 8)
 | 
			
		||||
 | 
			
		||||
                    Text("\(exerciseCount) exercises")
 | 
			
		||||
                        .font(.caption)
 | 
			
		||||
                        .padding(.bottom, 8)
 | 
			
		||||
                        Text("\(exerciseCount) exercises")
 | 
			
		||||
                            .font(.caption)
 | 
			
		||||
                            .padding(.bottom, 8)
 | 
			
		||||
                    }
 | 
			
		||||
                    .foregroundColor(.white)
 | 
			
		||||
                    .frame(width: geometry.size.width, height: geometry.size.height)
 | 
			
		||||
                }
 | 
			
		||||
                .foregroundColor(.white)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										129
									
								
								Workouts/Views/Splits/ExerciseView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								Workouts/Views/Splits/ExerciseView.swift
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
//
 | 
			
		||||
// ExerciseView.swift
 | 
			
		||||
// Workouts
 | 
			
		||||
//
 | 
			
		||||
// Created by rzen on 7/18/25 at 5:44 PM.
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2025 Rouslan Zenetl. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
import SwiftUI
 | 
			
		||||
import SwiftData
 | 
			
		||||
 | 
			
		||||
struct ExerciseView: View {
 | 
			
		||||
    @Environment(\.modelContext) private var modelContext
 | 
			
		||||
    @Environment(\.dismiss) private var dismiss
 | 
			
		||||
    
 | 
			
		||||
    @Bindable var workoutLog: WorkoutLog
 | 
			
		||||
    
 | 
			
		||||
    @State var allLogs: [WorkoutLog]
 | 
			
		||||
    var currentIndex: Int = 0
 | 
			
		||||
    
 | 
			
		||||
    @State private var progress: Int = 0
 | 
			
		||||
    @State private var navigateTo: WorkoutLog? = nil
 | 
			
		||||
 | 
			
		||||
    let notStartedColor = Color.white
 | 
			
		||||
    let completedColor = Color.green
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        Form {
 | 
			
		||||
            Section(header: Text("Navigation")) {
 | 
			
		||||
                HStack {
 | 
			
		||||
                    Button(action: navigateToPrevious) {
 | 
			
		||||
                        HStack {
 | 
			
		||||
                            Image(systemName: "chevron.left")
 | 
			
		||||
                            Text("Previous")
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    .disabled(currentIndex <= 0)
 | 
			
		||||
                    
 | 
			
		||||
                    Spacer()
 | 
			
		||||
                    Text("\(currentIndex)")
 | 
			
		||||
                    Spacer()
 | 
			
		||||
                    
 | 
			
		||||
                    Button(action: navigateToNext) {
 | 
			
		||||
                        HStack {
 | 
			
		||||
                            Text("Next")
 | 
			
		||||
                            Image(systemName: "chevron.right")
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    .disabled(currentIndex >= allLogs.count - 1)
 | 
			
		||||
                }
 | 
			
		||||
                .padding(.vertical, 8)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Section (header: Text("Progress")) {
 | 
			
		||||
                LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: workoutLog.sets), spacing: 2) {
 | 
			
		||||
                    ForEach (1...workoutLog.sets, id: \.self) { index in
 | 
			
		||||
                        ZStack {
 | 
			
		||||
                            let completed = index <= progress
 | 
			
		||||
                            let color = completed ? completedColor : notStartedColor
 | 
			
		||||
                            RoundedRectangle(cornerRadius: 8)
 | 
			
		||||
                                .fill(
 | 
			
		||||
                                    LinearGradient(
 | 
			
		||||
                                        gradient: Gradient(colors: [color, color.darker(by: 0.2)]),
 | 
			
		||||
                                        startPoint: .topLeading,
 | 
			
		||||
                                        endPoint: .bottomTrailing
 | 
			
		||||
                                    )
 | 
			
		||||
                                )
 | 
			
		||||
                                .aspectRatio(0.618, contentMode: .fit)
 | 
			
		||||
                                .shadow(radius: 2)
 | 
			
		||||
                            Text("\(index)")
 | 
			
		||||
                                .foregroundColor(.primary)
 | 
			
		||||
                                .colorInvert()
 | 
			
		||||
                        }
 | 
			
		||||
                        .onTapGesture {
 | 
			
		||||
                            if progress == index {
 | 
			
		||||
                                progress = 0
 | 
			
		||||
                            } else {
 | 
			
		||||
                                progress = index
 | 
			
		||||
                            }
 | 
			
		||||
                            let _ = print("progress set to \(progress)")
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Section (header: Text("Plan")) {
 | 
			
		||||
                Stepper("\(workoutLog.sets) sets", value: $workoutLog.sets, in: 1...10)
 | 
			
		||||
                    .font(.title)
 | 
			
		||||
                Stepper("\(workoutLog.reps) reps", value: $workoutLog.reps, in: 1...25)
 | 
			
		||||
                    .font(.title)
 | 
			
		||||
                HStack {
 | 
			
		||||
                    Text("\(workoutLog.weight) lbs")
 | 
			
		||||
                    VStack (alignment: .trailing) {
 | 
			
		||||
                        Stepper("", value: $workoutLog.weight, in: 1...200)
 | 
			
		||||
                        Stepper("", value: $workoutLog.weight, in: 1...200, step: 5)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                    .font(.title)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .navigationTitle("\(workoutLog.exerciseName)")
 | 
			
		||||
        .navigationDestination(item: $navigateTo) { nextLog in
 | 
			
		||||
            ExerciseView(
 | 
			
		||||
                workoutLog: nextLog,
 | 
			
		||||
                allLogs: allLogs,
 | 
			
		||||
                currentIndex: allLogs.firstIndex(of: nextLog) ?? 0
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
//        .onAppear {
 | 
			
		||||
//            allLogs = modelContext.fetch(FetchDescriptor(sortBy: [
 | 
			
		||||
//                SortDescriptor(\WorkoutLog.order),
 | 
			
		||||
//                SortDescriptor(\WorkoutLog.name)
 | 
			
		||||
//            ]))
 | 
			
		||||
//        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private func navigateToPrevious() {
 | 
			
		||||
        guard currentIndex > 0 else { return }
 | 
			
		||||
        let previousIndex = currentIndex - 1
 | 
			
		||||
        navigateTo = allLogs[previousIndex]
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private func navigateToNext() {
 | 
			
		||||
        guard currentIndex < allLogs.count - 1 else { return }
 | 
			
		||||
        let nextIndex = currentIndex + 1
 | 
			
		||||
        navigateTo = allLogs[nextIndex]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -61,8 +61,18 @@ struct SplitExercisesListView: View {
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        })
 | 
			
		||||
                        
 | 
			
		||||
                        Button {
 | 
			
		||||
                            showingAddSheet = true
 | 
			
		||||
                        } label: {
 | 
			
		||||
                            ListItem(title: "Add Exercise")
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Text("No exercises added yet.")
 | 
			
		||||
                        Button(action: { showingAddSheet.toggle() }) {
 | 
			
		||||
                            ListItem(title: "Add Exercise")
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -98,11 +108,6 @@ struct SplitExercisesListView: View {
 | 
			
		||||
        .navigationDestination(item: $createdWorkout, destination: { workout in
 | 
			
		||||
            WorkoutLogView(workout: workout)
 | 
			
		||||
        })
 | 
			
		||||
//        .sheet(item: $createdWorkout) { workout in
 | 
			
		||||
//            NavigationStack {
 | 
			
		||||
//                WorkoutLogView(workout: workout)
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
//        .toolbar {
 | 
			
		||||
//            ToolbarItem(placement: .navigationBarTrailing) {
 | 
			
		||||
//                Button(action: { showingAddSheet.toggle() }) {
 | 
			
		||||
@@ -110,18 +115,18 @@ struct SplitExercisesListView: View {
 | 
			
		||||
//                }
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
//        .sheet (isPresented: $showingAddSheet) {
 | 
			
		||||
//            ExercisePickerView { exerciseName in
 | 
			
		||||
//                itemToEdit = SplitExerciseAssignment(
 | 
			
		||||
//                    split: model,
 | 
			
		||||
//                    exerciseName: exerciseName,
 | 
			
		||||
//                    order: 0,
 | 
			
		||||
//                    sets: 3,
 | 
			
		||||
//                    reps: 10,
 | 
			
		||||
//                    weight: 40
 | 
			
		||||
//                )
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
        .sheet (isPresented: $showingAddSheet) {
 | 
			
		||||
            ExercisePickerView { exerciseName in
 | 
			
		||||
                itemToEdit = SplitExerciseAssignment(
 | 
			
		||||
                    split: model,
 | 
			
		||||
                    exerciseName: exerciseName,
 | 
			
		||||
                    order: 0,
 | 
			
		||||
                    sets: 3,
 | 
			
		||||
                    reps: 10,
 | 
			
		||||
                    weight: 40
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .sheet(item: $itemToEdit) { item in
 | 
			
		||||
            SplitExerciseAssignmentAddEditView(model: item)
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -34,70 +34,69 @@ struct WorkoutLogView: View {
 | 
			
		||||
            Section (header: Text("\(workout.label)")) {
 | 
			
		||||
                List {
 | 
			
		||||
                    ForEach (sortedWorkoutLogs) { log in
 | 
			
		||||
                        // Handle optional status, defaulting to a status based on completed flag if nil
 | 
			
		||||
                        let _ = print("DEBUG: workoutLog.status=\(log.status)")
 | 
			
		||||
                        
 | 
			
		||||
                        let workoutLogStatus = log.status?.checkboxStatus ?? (log.completed ? CheckboxStatus.checked : CheckboxStatus.unchecked)
 | 
			
		||||
                        
 | 
			
		||||
                        CheckboxListItem(
 | 
			
		||||
                            status: workoutLogStatus,
 | 
			
		||||
                            title: log.exerciseName,
 | 
			
		||||
                            subtitle: "\(log.sets) sets × \(log.reps) reps × \(log.weight) lbs"
 | 
			
		||||
                        )
 | 
			
		||||
                        NavigationLink(destination: ExerciseView(workoutLog: log, allLogs: sortedWorkoutLogs)) {
 | 
			
		||||
                            CheckboxListItem(
 | 
			
		||||
                                status: workoutLogStatus,
 | 
			
		||||
                                title: log.exerciseName,
 | 
			
		||||
                                subtitle: "\(log.sets) sets × \(log.reps) reps × \(log.weight) lbs"
 | 
			
		||||
                            )
 | 
			
		||||
                            .swipeActions(edge: .leading, allowsFullSwipe: false) {
 | 
			
		||||
                                let status = log.status ?? WorkoutStatus.notStarted
 | 
			
		||||
                                
 | 
			
		||||
                                if [.inProgress,.completed].contains(status) {
 | 
			
		||||
                                    Button {
 | 
			
		||||
                                        withAnimation {
 | 
			
		||||
                                            log.status = .notStarted
 | 
			
		||||
                                            try? modelContext.save()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    } label: {
 | 
			
		||||
                                        Label("Not Started", systemImage: WorkoutStatus.notStarted.checkboxStatus.systemName)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    .tint(WorkoutStatus.notStarted.checkboxStatus.color)
 | 
			
		||||
                                }
 | 
			
		||||
                                
 | 
			
		||||
                                if [.notStarted,.completed].contains(status) {
 | 
			
		||||
                                    Button {
 | 
			
		||||
                                        withAnimation {
 | 
			
		||||
                                            log.status = .inProgress
 | 
			
		||||
                                            try? modelContext.save()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    } label: {
 | 
			
		||||
                                        Label("In Progress", systemImage: WorkoutStatus.inProgress.checkboxStatus.systemName)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    .tint(WorkoutStatus.inProgress.checkboxStatus.color)
 | 
			
		||||
                                }
 | 
			
		||||
                                
 | 
			
		||||
                                if [.notStarted,.inProgress].contains(status) {
 | 
			
		||||
                                    Button {
 | 
			
		||||
                                        withAnimation {
 | 
			
		||||
                                            log.status = .completed
 | 
			
		||||
                                            try? modelContext.save()
 | 
			
		||||
                                        }
 | 
			
		||||
                                    } label: {
 | 
			
		||||
                                        Label("Complete", systemImage: WorkoutStatus.completed.checkboxStatus.systemName)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    .tint(WorkoutStatus.completed.checkboxStatus.color)
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            .swipeActions(edge: .trailing, allowsFullSwipe: false) {
 | 
			
		||||
                                Button {
 | 
			
		||||
                                    itemToDelete = log
 | 
			
		||||
                                } label: {
 | 
			
		||||
                                    Label("Delete", systemImage: "trash")
 | 
			
		||||
                                }
 | 
			
		||||
                                .tint(.secondary)
 | 
			
		||||
                                Button {
 | 
			
		||||
                                    itemToEdit = log
 | 
			
		||||
                                } label: {
 | 
			
		||||
                                    Label("Edit", systemImage: "pencil")
 | 
			
		||||
                                }
 | 
			
		||||
                                .tint(.indigo)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                        .swipeActions(edge: .leading, allowsFullSwipe: false) {
 | 
			
		||||
                            let status = log.status ?? WorkoutStatus.notStarted
 | 
			
		||||
                            
 | 
			
		||||
                            if [.inProgress,.completed].contains(status) {
 | 
			
		||||
                                Button {
 | 
			
		||||
                                    withAnimation {
 | 
			
		||||
                                        log.status = .notStarted
 | 
			
		||||
                                        try? modelContext.save()
 | 
			
		||||
                                    }
 | 
			
		||||
                                } label: {
 | 
			
		||||
                                    Label("Not Started", systemImage: WorkoutStatus.notStarted.checkboxStatus.systemName)
 | 
			
		||||
                                }
 | 
			
		||||
                                .tint(WorkoutStatus.notStarted.checkboxStatus.color)
 | 
			
		||||
                            }
 | 
			
		||||
                            
 | 
			
		||||
                            if [.notStarted,.completed].contains(status) {
 | 
			
		||||
                                Button {
 | 
			
		||||
                                    withAnimation {
 | 
			
		||||
                                        log.status = .inProgress
 | 
			
		||||
                                        try? modelContext.save()
 | 
			
		||||
                                    }
 | 
			
		||||
                                } label: {
 | 
			
		||||
                                    Label("In Progress", systemImage: WorkoutStatus.inProgress.checkboxStatus.systemName)
 | 
			
		||||
                                }
 | 
			
		||||
                                .tint(WorkoutStatus.inProgress.checkboxStatus.color)
 | 
			
		||||
                            }
 | 
			
		||||
                            
 | 
			
		||||
                            if [.notStarted,.inProgress].contains(status) {
 | 
			
		||||
                                Button {
 | 
			
		||||
                                    withAnimation {
 | 
			
		||||
                                        log.status = .completed
 | 
			
		||||
                                        try? modelContext.save()
 | 
			
		||||
                                    }
 | 
			
		||||
                                } label: {
 | 
			
		||||
                                    Label("Complete", systemImage: WorkoutStatus.completed.checkboxStatus.systemName)
 | 
			
		||||
                                }
 | 
			
		||||
                                .tint(WorkoutStatus.completed.checkboxStatus.color)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        .swipeActions(edge: .trailing, allowsFullSwipe: false) {
 | 
			
		||||
                            Button {
 | 
			
		||||
                                itemToDelete = log
 | 
			
		||||
                            } label: {
 | 
			
		||||
                                Label("Delete", systemImage: "trash")
 | 
			
		||||
                            }
 | 
			
		||||
                            .tint(.secondary)
 | 
			
		||||
                            Button {
 | 
			
		||||
                                itemToEdit = log
 | 
			
		||||
                            } label: {
 | 
			
		||||
                                Label("Edit", systemImage: "pencil")
 | 
			
		||||
                            }
 | 
			
		||||
                            .tint(.indigo)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user