diff --git a/Workouts/Models/WorkoutStatus.swift b/Workouts/Models/WorkoutStatus.swift index f2c6943..c249f40 100644 --- a/Workouts/Models/WorkoutStatus.swift +++ b/Workouts/Models/WorkoutStatus.swift @@ -11,12 +11,14 @@ enum WorkoutStatus: Int, Codable { case notStarted = 1 case inProgress = 2 case completed = 3 + case skipped = 4 var checkboxStatus: CheckboxStatus { switch (self) { case .notStarted: .unchecked case .inProgress: .intermediate case .completed: .checked + case .skipped: .cancelled } } } diff --git a/Workouts/Resources/exercises.yaml b/Workouts/Resources/exercises.yaml new file mode 100644 index 0000000..327fa6a --- /dev/null +++ b/Workouts/Resources/exercises.yaml @@ -0,0 +1,180 @@ +- name: Lat Pull Down + setup: 'Seat: 3, Thigh Pad: 4' + descr: Sit upright with your knees secured under the pad. Grip the bar wider than + shoulder-width. Pull the bar down to your chest, squeezing your shoulder blades + together. Avoid leaning back excessively or using momentum. + sets: 3 + reps: 10 + weight: 60 + type: Machine-Based + muscles: + - Latissimus Dorsi + - Trapezius + - Rhomboids + - Biceps Brachii +- name: Seated Row + setup: 'Seat: 2, Chest Pad: 3' + descr: With your chest firmly against the pad, grip the handles and pull straight + back while keeping your elbows close to your body. Focus on retracting your shoulder + blades and avoid rounding your back. + sets: 3 + reps: 10 + weight: 60 + type: Machine-Based + muscles: + - Latissimus Dorsi + - Rhomboids + - Trapezius + - Biceps Brachii +- name: Shoulder Press + setup: 'Seat: 4' + descr: Sit with your back against the pad, grip the handles just outside shoulder-width. + Press upward without locking out your elbows. Keep your neck relaxed and avoid + shrugging your shoulders. + sets: 3 + reps: 10 + weight: 30 + type: Machine-Based + muscles: + - Deltoid (Anterior) + - Deltoid (Lateral) + - Triceps Brachii +- name: Chest Press + setup: 'Seat: 3' + descr: Adjust the seat so the handles are at mid-chest height. Push forward until + arms are nearly extended, then return slowly. Keep wrists straight and don’t let + your elbows drop too low. + sets: 3 + reps: 10 + weight: 40 + type: Machine-Based + muscles: + - Pectoralis Major + - Triceps Brachii + - Deltoid (Anterior) +- name: Tricep Press + setup: 'Seat: 2' + descr: With elbows close to your sides, press the handles downward in a controlled + motion. Avoid flaring your elbows or using your shoulders to assist the motion. + sets: 3 + reps: 10 + weight: 60 + type: Machine-Based + muscles: + - Triceps Brachii +- name: Arm Curl + setup: 'Seat: 3' + descr: Position your arms over the pad and grip the handles. Curl the weight upward + while keeping your upper arms stationary. Avoid using momentum and fully control + the lowering phase. + sets: 3 + reps: 10 + weight: 30 + type: Machine-Based + muscles: + - Biceps Brachii + - Brachialis +- name: Abdominal + setup: 'Seat: 2, Back Pad: 3' + descr: Sit with the pads resting against your chest. Contract your abs to curl forward, + keeping your lower back in contact with the pad. Avoid pulling with your arms + or hips. + sets: 3 + reps: 10 + weight: 60 + type: Machine-Based + muscles: + - Rectus Abdominis + - Internal Obliques +- name: Rotary + setup: 'Seat: 3, Start Angle: Centered' + descr: Rotate your torso from side to side in a controlled motion, keeping your + hips still. Focus on using your obliques to generate the twist, not momentum or + the arms. + sets: 3 + reps: 10 + weight: 60 + type: Machine-Based + muscles: + - Internal Obliques + - External Obliques +- name: Leg Press + setup: 'Seat Angle: 4, Platform: Middle' + descr: Place your feet shoulder-width on the platform. Press upward through your + heels without locking your knees. Keep your back flat against the pad throughout + the motion. + sets: 3 + reps: 10 + weight: 130 + type: Machine-Based + muscles: + - Gluteus Maximus + - Rectus Femoris + - Vastus Lateralis + - Vastus Medialis + - Vastus Intermedius + - Biceps Femoris + - Semitendinosus + - Semimembranosus +- name: Leg Extension + setup: 'Seat: 3, Pad: Above ankle' + descr: Sit upright and align your knees with the pivot point. Extend your legs to + a straightened position, then lower with control. Avoid jerky movements or lifting + your hips off the seat. + sets: 3 + reps: 10 + weight: 70 + type: Machine-Based + muscles: + - Rectus Femoris + - Vastus Lateralis + - Vastus Medialis + - Vastus Intermedius +- name: Leg Curl + setup: 'Seat: 2, Pad: Above ankle' + descr: Lie face down or sit depending on the version. Curl your legs toward your + glutes, focusing on hamstring engagement. Avoid arching your back or using momentum. + sets: 3 + reps: 10 + weight: 60 + type: Machine-Based + muscles: + - Biceps Femoris + - Semitendinosus + - Semimembranosus +- name: Adductor + setup: 'Seat: 3, Start Position: Wide' + descr: Sit with legs placed outside the pads. Bring your legs together using inner + thigh muscles. Control the motion both in and out, avoiding fast swings. + sets: 3 + reps: 10 + weight: 110 + type: Machine-Based + muscles: + - Adductor Longus + - Adductor Brevis + - Adductor Magnus + - Gracilis +- name: Abductor + setup: 'Seat: 3, Start Position: Narrow' + descr: Sit with legs inside the pads and push outward to engage outer thighs and + glutes. Avoid leaning forward and keep the motion controlled throughout. + sets: 3 + reps: 10 + weight: 110 + type: Machine-Based + muscles: + - Gluteus Medius + - Tensor Fasciae Latae +- name: Calfs + setup: 'Seat: 3, Toe Bar: Midfoot' + descr: Place the balls of your feet on the platform with heels hanging off. Raise + your heels by contracting your calves, then slowly lower them below the platform + level for a full stretch. + sets: 3 + reps: 10 + weight: 60 + type: Machine-Based + muscles: + - Gastrocnemius + - Soleus diff --git a/Workouts/Utils/CheckboxListItem.swift b/Workouts/Utils/CheckboxListItem.swift index 863a60c..79af1db 100644 --- a/Workouts/Utils/CheckboxListItem.swift +++ b/Workouts/Utils/CheckboxListItem.swift @@ -13,12 +13,14 @@ enum CheckboxStatus { case checked case unchecked case intermediate + case cancelled var color: Color { switch (self) { case .checked: .green case .unchecked: .gray case .intermediate: .yellow + case .cancelled: .red } } @@ -27,6 +29,7 @@ enum CheckboxStatus { case .checked: "checkmark.circle.fill" case .unchecked: "circle" case .intermediate: "ellipsis.circle" + case .cancelled: "cross.circle" } } } diff --git a/Workouts/Utils/Color+darker.swift b/Workouts/Utils/Color+darker.swift new file mode 100644 index 0000000..7a460c0 --- /dev/null +++ b/Workouts/Utils/Color+darker.swift @@ -0,0 +1,30 @@ +// +// Color+darker.swift +// Workouts +// +// Created by rzen on 7/17/25 at 9:20 AM. +// +// Copyright 2025 Rouslan Zenetl. All Rights Reserved. +// + +import SwiftUI +import UIKit + +extension Color { + func darker(by percentage: CGFloat) -> Color { + let uiColor = UIColor(self) + var hue: CGFloat = 0 + var saturation: CGFloat = 0 + var brightness: CGFloat = 0 + var alpha: CGFloat = 0 + + if uiColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) { + let newBrightness = max(brightness * (1 - percentage), 0) + let darkerUIColor = UIColor(hue: hue, saturation: saturation, brightness: newBrightness, alpha: alpha) + return Color(darkerUIColor) + } + + return self // Fallback if color can't be converted + } +} + diff --git a/Workouts/Utils/Date+Extensions.swift b/Workouts/Utils/Date+formatDateET.swift similarity index 100% rename from Workouts/Utils/Date+Extensions.swift rename to Workouts/Utils/Date+formatDateET.swift diff --git a/Workouts/Views/Workouts/SplitPickerView.swift b/Workouts/Views/Workouts/SplitPickerView.swift index e6b17fd..c1fb0c8 100644 --- a/Workouts/Views/Workouts/SplitPickerView.swift +++ b/Workouts/Views/Workouts/SplitPickerView.swift @@ -30,21 +30,37 @@ struct SplitPickerView: View { dismiss() }) { VStack { - ZStack { + ZStack(alignment: .bottom) { + // Golden ratio rectangle (1:1.618) RoundedRectangle(cornerRadius: 12) - .fill(split.getColor()) - .aspectRatio(1, contentMode: .fit) + .fill( + LinearGradient( + gradient: Gradient(colors: [split.getColor(), split.getColor().darker(by: 0.2)]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + ) + .aspectRatio(1.618, contentMode: .fit) .shadow(radius: 2) - Image(systemName: split.systemImage) - .font(.system(size: 30)) - .foregroundColor(.white) + VStack { + // Icon in the center + Image(systemName: split.systemImage) + .font(.system(size: 40, weight: .medium)) + .foregroundColor(.white) + .offset(y: -15) + + // Name at the bottom inside the rectangle + Text(split.name) + .font(.headline) + .foregroundColor(.white) + .lineLimit(1) + .padding(.horizontal, 8) + .padding(.bottom, 8) + } } - Text(split.name) - .font(.headline) - .lineLimit(1) - + // Exercise count below the rectangle Text("\(split.exercises?.count ?? 0) exercises") .font(.caption) .foregroundColor(.secondary) diff --git a/Workouts/Views/Workouts/WorkoutsView.swift b/Workouts/Views/Workouts/WorkoutsView.swift index 5b0ecbe..d2dec20 100644 --- a/Workouts/Views/Workouts/WorkoutsView.swift +++ b/Workouts/Views/Workouts/WorkoutsView.swift @@ -40,11 +40,12 @@ struct WorkoutsView: View { ) } .swipeActions(edge: .trailing, allowsFullSwipe: false) { - Button(role: .destructive) { + Button { itemToDelete = workout } label: { Label("Delete", systemImage: "trash") } + .tint(.red) Button { itemToEdit = workout } label: { @@ -77,9 +78,11 @@ struct WorkoutsView: View { ) { Button("Delete", role: .destructive) { if let item = itemToDelete { - modelContext.delete(item) - try? modelContext.save() - itemToDelete = nil + withAnimation { + modelContext.delete(item) + try? modelContext.save() + itemToDelete = nil + } } } Button("Cancel", role: .cancel) {