wip
This commit is contained in:
@ -31,11 +31,16 @@ struct DraggableSplitItem: View {
|
|||||||
.aspectRatio(1.618, contentMode: .fit)
|
.aspectRatio(1.618, contentMode: .fit)
|
||||||
.shadow(radius: 2)
|
.shadow(radius: 2)
|
||||||
|
|
||||||
VStack {
|
GeometryReader { geometry in
|
||||||
// Icon in the center
|
VStack(spacing: 4) {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
// Icon in the center - now using dynamic sizing
|
||||||
Image(systemName: systemImageName)
|
Image(systemName: systemImageName)
|
||||||
.font(.system(size: 40, weight: .bold))
|
.font(.system(size: min(geometry.size.width * 0.3, 40), weight: .bold))
|
||||||
.offset(y: -15)
|
.scaledToFit()
|
||||||
|
.frame(maxWidth: geometry.size.width * 0.6, maxHeight: geometry.size.height * 0.4)
|
||||||
|
.padding(.bottom, 4)
|
||||||
|
|
||||||
// Name at the bottom inside the rectangle
|
// Name at the bottom inside the rectangle
|
||||||
Text(name)
|
Text(name)
|
||||||
@ -48,9 +53,9 @@ struct DraggableSplitItem: View {
|
|||||||
.padding(.bottom, 8)
|
.padding(.bottom, 8)
|
||||||
}
|
}
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
|
.frame(width: geometry.size.width, height: geometry.size.height)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
Text("No exercises added yet.")
|
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
|
.navigationDestination(item: $createdWorkout, destination: { workout in
|
||||||
WorkoutLogView(workout: workout)
|
WorkoutLogView(workout: workout)
|
||||||
})
|
})
|
||||||
// .sheet(item: $createdWorkout) { workout in
|
|
||||||
// NavigationStack {
|
|
||||||
// WorkoutLogView(workout: workout)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// .toolbar {
|
// .toolbar {
|
||||||
// ToolbarItem(placement: .navigationBarTrailing) {
|
// ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
// Button(action: { showingAddSheet.toggle() }) {
|
// Button(action: { showingAddSheet.toggle() }) {
|
||||||
@ -110,18 +115,18 @@ struct SplitExercisesListView: View {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// .sheet (isPresented: $showingAddSheet) {
|
.sheet (isPresented: $showingAddSheet) {
|
||||||
// ExercisePickerView { exerciseName in
|
ExercisePickerView { exerciseName in
|
||||||
// itemToEdit = SplitExerciseAssignment(
|
itemToEdit = SplitExerciseAssignment(
|
||||||
// split: model,
|
split: model,
|
||||||
// exerciseName: exerciseName,
|
exerciseName: exerciseName,
|
||||||
// order: 0,
|
order: 0,
|
||||||
// sets: 3,
|
sets: 3,
|
||||||
// reps: 10,
|
reps: 10,
|
||||||
// weight: 40
|
weight: 40
|
||||||
// )
|
)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
.sheet(item: $itemToEdit) { item in
|
.sheet(item: $itemToEdit) { item in
|
||||||
SplitExerciseAssignmentAddEditView(model: item)
|
SplitExerciseAssignmentAddEditView(model: item)
|
||||||
}
|
}
|
||||||
|
@ -34,17 +34,14 @@ struct WorkoutLogView: View {
|
|||||||
Section (header: Text("\(workout.label)")) {
|
Section (header: Text("\(workout.label)")) {
|
||||||
List {
|
List {
|
||||||
ForEach (sortedWorkoutLogs) { log in
|
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)
|
let workoutLogStatus = log.status?.checkboxStatus ?? (log.completed ? CheckboxStatus.checked : CheckboxStatus.unchecked)
|
||||||
|
|
||||||
|
NavigationLink(destination: ExerciseView(workoutLog: log, allLogs: sortedWorkoutLogs)) {
|
||||||
CheckboxListItem(
|
CheckboxListItem(
|
||||||
status: workoutLogStatus,
|
status: workoutLogStatus,
|
||||||
title: log.exerciseName,
|
title: log.exerciseName,
|
||||||
subtitle: "\(log.sets) sets × \(log.reps) reps × \(log.weight) lbs"
|
subtitle: "\(log.sets) sets × \(log.reps) reps × \(log.weight) lbs"
|
||||||
)
|
)
|
||||||
|
|
||||||
.swipeActions(edge: .leading, allowsFullSwipe: false) {
|
.swipeActions(edge: .leading, allowsFullSwipe: false) {
|
||||||
let status = log.status ?? WorkoutStatus.notStarted
|
let status = log.status ?? WorkoutStatus.notStarted
|
||||||
|
|
||||||
@ -99,6 +96,8 @@ struct WorkoutLogView: View {
|
|||||||
.tint(.indigo)
|
.tint(.indigo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user