WIP
This commit is contained in:
@@ -17,6 +17,10 @@
|
|||||||
1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A822A42347D0042FFBD /* Extensions.swift */; };
|
1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A822A42347D0042FFBD /* Extensions.swift */; };
|
||||||
1C4AFF152A60F25F0027710B /* ThotStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF142A60F25E0027710B /* ThotStyle.swift */; };
|
1C4AFF152A60F25F0027710B /* ThotStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF142A60F25E0027710B /* ThotStyle.swift */; };
|
||||||
1C4AFF162A60F27E0027710B /* ThotStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF142A60F25E0027710B /* ThotStyle.swift */; };
|
1C4AFF162A60F27E0027710B /* ThotStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF142A60F25E0027710B /* ThotStyle.swift */; };
|
||||||
|
1C4AFF182A65CD290027710B /* Superset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF172A65CD290027710B /* Superset.swift */; };
|
||||||
|
1C4AFF192A65CD6F0027710B /* Superset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF172A65CD290027710B /* Superset.swift */; };
|
||||||
|
1C4AFF1B2A65FB190027710B /* CurrentWorkoutInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF1A2A65FB190027710B /* CurrentWorkoutInfo.swift */; };
|
||||||
|
1C4AFF1C2A65FB2B0027710B /* CurrentWorkoutInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4AFF1A2A65FB190027710B /* CurrentWorkoutInfo.swift */; };
|
||||||
1C5190C22A57CA5F00885849 /* OvalTextFieldStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C12A57CA5F00885849 /* OvalTextFieldStyle.swift */; };
|
1C5190C22A57CA5F00885849 /* OvalTextFieldStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C12A57CA5F00885849 /* OvalTextFieldStyle.swift */; };
|
||||||
1C5190C42A589CAC00885849 /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C32A589CAC00885849 /* InfoView.swift */; };
|
1C5190C42A589CAC00885849 /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C32A589CAC00885849 /* InfoView.swift */; };
|
||||||
1C5190C62A589CC100885849 /* ActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C52A589CC100885849 /* ActionsView.swift */; };
|
1C5190C62A589CC100885849 /* ActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C52A589CC100885849 /* ActionsView.swift */; };
|
||||||
@@ -129,6 +133,8 @@
|
|||||||
1C485C892A492BB400A6F896 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
1C485C892A492BB400A6F896 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
||||||
1C485C8B2A49D65600A6F896 /* WorkoutHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutHistoryView.swift; sourceTree = "<group>"; };
|
1C485C8B2A49D65600A6F896 /* WorkoutHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutHistoryView.swift; sourceTree = "<group>"; };
|
||||||
1C4AFF142A60F25E0027710B /* ThotStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThotStyle.swift; sourceTree = "<group>"; };
|
1C4AFF142A60F25E0027710B /* ThotStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThotStyle.swift; sourceTree = "<group>"; };
|
||||||
|
1C4AFF172A65CD290027710B /* Superset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Superset.swift; sourceTree = "<group>"; };
|
||||||
|
1C4AFF1A2A65FB190027710B /* CurrentWorkoutInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentWorkoutInfo.swift; sourceTree = "<group>"; };
|
||||||
1C5190C12A57CA5F00885849 /* OvalTextFieldStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OvalTextFieldStyle.swift; sourceTree = "<group>"; };
|
1C5190C12A57CA5F00885849 /* OvalTextFieldStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OvalTextFieldStyle.swift; sourceTree = "<group>"; };
|
||||||
1C5190C32A589CAC00885849 /* InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = "<group>"; };
|
1C5190C32A589CAC00885849 /* InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = "<group>"; };
|
||||||
1C5190C52A589CC100885849 /* ActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionsView.swift; sourceTree = "<group>"; };
|
1C5190C52A589CC100885849 /* ActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionsView.swift; sourceTree = "<group>"; };
|
||||||
@@ -269,6 +275,7 @@
|
|||||||
1CF65A822A42347D0042FFBD /* Extensions.swift */,
|
1CF65A822A42347D0042FFBD /* Extensions.swift */,
|
||||||
1CF65A272A3972840042FFBD /* Persistence.swift */,
|
1CF65A272A3972840042FFBD /* Persistence.swift */,
|
||||||
1CD0C6662A5CA19600970E52 /* BaseURLs.swift */,
|
1CD0C6662A5CA19600970E52 /* BaseURLs.swift */,
|
||||||
|
1C4AFF1A2A65FB190027710B /* CurrentWorkoutInfo.swift */,
|
||||||
1CF65A4F2A3A1EA90042FFBD /* BridgeModule.swift */,
|
1CF65A4F2A3A1EA90042FFBD /* BridgeModule.swift */,
|
||||||
1CF65A802A412AA30042FFBD /* DataStore.swift */,
|
1CF65A802A412AA30042FFBD /* DataStore.swift */,
|
||||||
1CF65AB92A4894430042FFBD /* UserStore.swift */,
|
1CF65AB92A4894430042FFBD /* UserStore.swift */,
|
||||||
@@ -314,6 +321,7 @@
|
|||||||
1CAF4D892A5132F900B00E50 /* PlannedWorkout.swift */,
|
1CAF4D892A5132F900B00E50 /* PlannedWorkout.swift */,
|
||||||
1CF65A462A39FB6C0042FFBD /* RegisteredUser.swift */,
|
1CF65A462A39FB6C0042FFBD /* RegisteredUser.swift */,
|
||||||
1CF65A422A39FB410042FFBD /* Workout.swift */,
|
1CF65A422A39FB410042FFBD /* Workout.swift */,
|
||||||
|
1C4AFF172A65CD290027710B /* Superset.swift */,
|
||||||
);
|
);
|
||||||
path = APIModels;
|
path = APIModels;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -583,6 +591,7 @@
|
|||||||
1CF65A852A43E8060042FFBD /* CompletedWorkout.swift in Sources */,
|
1CF65A852A43E8060042FFBD /* CompletedWorkout.swift in Sources */,
|
||||||
1CF65A6E2A3F60480042FFBD /* CreateViewModels.swift in Sources */,
|
1CF65A6E2A3F60480042FFBD /* CreateViewModels.swift in Sources */,
|
||||||
1CF65A4C2A39FDA20042FFBD /* WorkoutDetailView.swift in Sources */,
|
1CF65A4C2A39FDA20042FFBD /* WorkoutDetailView.swift in Sources */,
|
||||||
|
1C4AFF182A65CD290027710B /* Superset.swift in Sources */,
|
||||||
1CF65A8E2A44B78B0042FFBD /* CompletedWorkoutView.swift in Sources */,
|
1CF65A8E2A44B78B0042FFBD /* CompletedWorkoutView.swift in Sources */,
|
||||||
1CF65A432A39FB410042FFBD /* Workout.swift in Sources */,
|
1CF65A432A39FB410042FFBD /* Workout.swift in Sources */,
|
||||||
1CF65A502A3A1EA90042FFBD /* BridgeModule.swift in Sources */,
|
1CF65A502A3A1EA90042FFBD /* BridgeModule.swift in Sources */,
|
||||||
@@ -597,6 +606,7 @@
|
|||||||
1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */,
|
1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */,
|
||||||
1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */,
|
1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */,
|
||||||
1C485C8A2A492BB400A6F896 /* LoginView.swift in Sources */,
|
1C485C8A2A492BB400A6F896 /* LoginView.swift in Sources */,
|
||||||
|
1C4AFF1B2A65FB190027710B /* CurrentWorkoutInfo.swift in Sources */,
|
||||||
1CF65A732A3F60D20042FFBD /* CreateExerciseActionsView.swift in Sources */,
|
1CF65A732A3F60D20042FFBD /* CreateExerciseActionsView.swift in Sources */,
|
||||||
1CF65A832A42347D0042FFBD /* Extensions.swift in Sources */,
|
1CF65A832A42347D0042FFBD /* Extensions.swift in Sources */,
|
||||||
1CF65A282A3972840042FFBD /* Persistence.swift in Sources */,
|
1CF65A282A3972840042FFBD /* Persistence.swift in Sources */,
|
||||||
@@ -619,6 +629,7 @@
|
|||||||
files = (
|
files = (
|
||||||
1CF65A982A452D270042FFBD /* ContentView.swift in Sources */,
|
1CF65A982A452D270042FFBD /* ContentView.swift in Sources */,
|
||||||
1CF65A962A452D270042FFBD /* Werkout_watchApp.swift in Sources */,
|
1CF65A962A452D270042FFBD /* Werkout_watchApp.swift in Sources */,
|
||||||
|
1C4AFF192A65CD6F0027710B /* Superset.swift in Sources */,
|
||||||
1CF65AA92A452D9C0042FFBD /* Workout.swift in Sources */,
|
1CF65AA92A452D9C0042FFBD /* Workout.swift in Sources */,
|
||||||
1CF65AA62A452D9C0042FFBD /* Equipment.swift in Sources */,
|
1CF65AA62A452D9C0042FFBD /* Equipment.swift in Sources */,
|
||||||
1C4AFF162A60F27E0027710B /* ThotStyle.swift in Sources */,
|
1C4AFF162A60F27E0027710B /* ThotStyle.swift in Sources */,
|
||||||
@@ -627,6 +638,7 @@
|
|||||||
1CF65AB62A4532940042FFBD /* WatchMainViewModel.swift in Sources */,
|
1CF65AB62A4532940042FFBD /* WatchMainViewModel.swift in Sources */,
|
||||||
1CD0C6682A5CA1A200970E52 /* BaseURLs.swift in Sources */,
|
1CD0C6682A5CA1A200970E52 /* BaseURLs.swift in Sources */,
|
||||||
1CF65AA72A452D9C0042FFBD /* Muscle.swift in Sources */,
|
1CF65AA72A452D9C0042FFBD /* Muscle.swift in Sources */,
|
||||||
|
1C4AFF1C2A65FB2B0027710B /* CurrentWorkoutInfo.swift in Sources */,
|
||||||
1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */,
|
1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */,
|
||||||
1CF65AAB2A452DAC0042FFBD /* PreviewData.swift in Sources */,
|
1CF65AAB2A452DAC0042FFBD /* PreviewData.swift in Sources */,
|
||||||
1CF65AA52A452D9C0042FFBD /* CompletedWorkout.swift in Sources */,
|
1CF65AA52A452D9C0042FFBD /* CompletedWorkout.swift in Sources */,
|
||||||
|
|||||||
@@ -6,28 +6,18 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Equipment: Codable {
|
struct Equipment: Codable {
|
||||||
let id: Int
|
let id: Int
|
||||||
let createdAt, updatedAt: String
|
let name, createdAt, updatedAt: String
|
||||||
let category, name: String?
|
let is_weight: Bool?
|
||||||
|
let category: String?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case id
|
case id, name
|
||||||
case createdAt = "created_at"
|
case createdAt = "created_at"
|
||||||
case updatedAt = "updated_at"
|
case updatedAt = "updated_at"
|
||||||
case category, name
|
case is_weight
|
||||||
}
|
case category
|
||||||
}
|
|
||||||
|
|
||||||
struct ExerciseEquipment: Codable, Hashable {
|
|
||||||
let id: Int
|
|
||||||
let createdAt, updatedAt: String
|
|
||||||
let exercise, equipment: Int
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case id
|
|
||||||
case createdAt = "created_at"
|
|
||||||
case updatedAt = "updated_at"
|
|
||||||
case equipment, exercise
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,32 +7,39 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ExerciseElement: Codable, Equatable {
|
struct SupersetExercise: Identifiable, Codable, Equatable, Hashable {
|
||||||
let workout: Int
|
var id = UUID()
|
||||||
let exercise: ExerciseExercise
|
|
||||||
|
let workout: Int?
|
||||||
|
let exercise: Exercise
|
||||||
let weight: Int?
|
let weight: Int?
|
||||||
let reps: Int?
|
let reps: Int?
|
||||||
let duration: Int?
|
let duration: Int?
|
||||||
let durationAudio: String?
|
let durationAudio: String?
|
||||||
let weightAudio: String?
|
let weightAudio: String?
|
||||||
let createdAt: String
|
let createdAt: String
|
||||||
|
let order, superset: Int
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case workout, exercise, weight, reps, duration
|
case workout, exercise, weight, reps, duration, order, superset
|
||||||
case durationAudio = "duration_audio"
|
case durationAudio = "duration_audio"
|
||||||
case weightAudio = "weight_audio"
|
case weightAudio = "weight_audio"
|
||||||
case createdAt = "created_at"
|
case createdAt = "created_at"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func hash(into hasher: inout Hasher) {
|
||||||
|
return hasher.combine(id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExerciseExercise: Codable, Hashable, Identifiable {
|
struct Exercise: Identifiable, Codable, Equatable {
|
||||||
static func == (lhs: ExerciseExercise, rhs: ExerciseExercise) -> Bool {
|
static func == (lhs: Exercise, rhs: Exercise) -> Bool {
|
||||||
lhs.id == rhs.id
|
lhs.id == rhs.id
|
||||||
}
|
}
|
||||||
|
|
||||||
let id: Int
|
let id: Int
|
||||||
let muscles: [ExerciseMuscle]
|
let equipment: [Equipment]
|
||||||
let equipment: [ExerciseEquipment]
|
let muscles: [Muscle]
|
||||||
let audioURL, videoURL, createdAt, updatedAt: String
|
let audioURL, videoURL, createdAt, updatedAt: String
|
||||||
let name, description, side: String
|
let name, description, side: String
|
||||||
let isTwoDumbbells, isTrackableDistance, isAlternating, isWeight: Bool
|
let isTwoDumbbells, isTrackableDistance, isAlternating, isWeight: Bool
|
||||||
|
|||||||
@@ -9,18 +9,11 @@ import Foundation
|
|||||||
|
|
||||||
struct Muscle: Codable {
|
struct Muscle: Codable {
|
||||||
let id: Int
|
let id: Int
|
||||||
let name: String
|
let name, createdAt, updatedAt: String
|
||||||
}
|
|
||||||
|
|
||||||
struct ExerciseMuscle: Codable, Hashable {
|
|
||||||
let id: Int
|
|
||||||
let createdAt, updatedAt: String
|
|
||||||
let exercise, muscle: Int
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case id
|
case id, name
|
||||||
case createdAt = "created_at"
|
case createdAt = "created_at"
|
||||||
case updatedAt = "updated_at"
|
case updatedAt = "updated_at"
|
||||||
case exercise, muscle
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
Werkout_ios/APIModels/Superset.swift
Normal file
26
Werkout_ios/APIModels/Superset.swift
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Superset.swift
|
||||||
|
// Werkout_ios
|
||||||
|
//
|
||||||
|
// Created by Trey Tartt on 7/17/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct Superset: Codable, Identifiable, Hashable {
|
||||||
|
let id: Int
|
||||||
|
let exercises: [SupersetExercise]
|
||||||
|
let createdAt, updatedAt, name: String?
|
||||||
|
let rounds, order, workout: Int
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id, exercises
|
||||||
|
case createdAt = "created_at"
|
||||||
|
case updatedAt = "updated_at"
|
||||||
|
case name, rounds, order, workout
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hash(into hasher: inout Hasher) {
|
||||||
|
return hasher.combine(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,17 +15,15 @@ struct Workout: Codable, Identifiable, Equatable {
|
|||||||
let id: Int
|
let id: Int
|
||||||
let name: String
|
let name: String
|
||||||
let description: String?
|
let description: String?
|
||||||
let exercises: [ExerciseElement]
|
let supersets: [Superset]?
|
||||||
let registeredUser: RegisteredUser?
|
let registeredUser: RegisteredUser?
|
||||||
|
let femaleVideos, maleVideos, bothVideos: [String]?
|
||||||
let muscles: [String]?
|
let muscles: [String]?
|
||||||
let equipment: [String]?
|
let equipment: [String]?
|
||||||
let exercise_count: Int?
|
let exercise_count: Int?
|
||||||
let maleVideos: [String]?
|
|
||||||
let femaleVideos: [String]?
|
|
||||||
let bothVideos: [String]?
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case name, description, exercises, id, muscles, equipment, exercise_count
|
case id, name, description, supersets, exercise_count, muscles, equipment
|
||||||
case registeredUser = "registered_user"
|
case registeredUser = "registered_user"
|
||||||
case maleVideos = "male_videos"
|
case maleVideos = "male_videos"
|
||||||
case femaleVideos = "female_videos"
|
case femaleVideos = "female_videos"
|
||||||
@@ -34,31 +32,18 @@ struct Workout: Codable, Identifiable, Equatable {
|
|||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
if let exercises = try container.decodeIfPresent([ExerciseElement].self, forKey: .exercises) {
|
|
||||||
self.exercises = exercises
|
self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "NA"
|
||||||
} else {
|
|
||||||
self.exercises = [ExerciseElement]()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.name = try container.decode(String.self, forKey: .name)
|
|
||||||
self.description = try container.decodeIfPresent(String.self, forKey: .description)
|
self.description = try container.decodeIfPresent(String.self, forKey: .description)
|
||||||
self.registeredUser = try container.decodeIfPresent(RegisteredUser.self, forKey: .registeredUser)
|
self.registeredUser = try container.decodeIfPresent(RegisteredUser.self, forKey: .registeredUser)
|
||||||
self.id = try container.decode(Int.self, forKey: .id)
|
self.id = try container.decode(Int.self, forKey: .id)
|
||||||
self.muscles = try container.decodeIfPresent([String].self, forKey: .muscles)
|
|
||||||
self.equipment = try container.decodeIfPresent([String].self, forKey: .equipment)
|
|
||||||
self.exercise_count = try container.decodeIfPresent(Int.self, forKey: .exercise_count)
|
|
||||||
self.femaleVideos = try container.decodeIfPresent([String].self, forKey: .femaleVideos)
|
self.femaleVideos = try container.decodeIfPresent([String].self, forKey: .femaleVideos)
|
||||||
self.maleVideos = try container.decodeIfPresent([String].self, forKey: .maleVideos)
|
self.maleVideos = try container.decodeIfPresent([String].self, forKey: .maleVideos)
|
||||||
self.bothVideos = try container.decodeIfPresent([String].self, forKey: .bothVideos)
|
self.bothVideos = try container.decodeIfPresent([String].self, forKey: .bothVideos)
|
||||||
}
|
self.supersets = try container.decodeIfPresent([Superset].self, forKey: .supersets)
|
||||||
|
|
||||||
var exercisesSortedByCreated_at: [ExerciseElement] {
|
self.equipment = try container.decodeIfPresent([String].self, forKey: .equipment)
|
||||||
return self.exercises.sorted(by: {
|
self.muscles = try container.decodeIfPresent([String].self, forKey: .muscles)
|
||||||
if let lhsDate = $0.createdAt.dateFromServerDate,
|
self.exercise_count = try container.decodeIfPresent(Int.self, forKey: .exercise_count)
|
||||||
let rhsDate = $1.createdAt.dateFromServerDate {
|
|
||||||
return lhsDate < rhsDate
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ enum BaseURLs: String {
|
|||||||
case dev = "https://dev.werkout.fitness"
|
case dev = "https://dev.werkout.fitness"
|
||||||
|
|
||||||
static var currentBaseURL: String {
|
static var currentBaseURL: String {
|
||||||
return BaseURLs.dev.rawValue
|
return BaseURLs.local.rawValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,17 +36,14 @@ class BridgeModule: NSObject, ObservableObject {
|
|||||||
@Published var currentWorkoutRunTimeInSeconds: Int = -1
|
@Published var currentWorkoutRunTimeInSeconds: Int = -1
|
||||||
private var currentWorkoutRunTimer: Timer?
|
private var currentWorkoutRunTimer: Timer?
|
||||||
|
|
||||||
var currentWorkout: Workout?
|
|
||||||
public private(set) var workoutStartDate: Date?
|
public private(set) var workoutStartDate: Date?
|
||||||
|
|
||||||
private var currentExerciseTimer: Timer?
|
private var currentExerciseTimer: Timer?
|
||||||
public private(set) var currentExerciseIdx: Int = -1 {
|
|
||||||
didSet {
|
@Published public private(set) var currentExerciseInfo = CurrentWorkoutInfo()
|
||||||
self.currentExercisePositionString = "\(self.currentExerciseIdx+1)/\(self.currentWorkout?.exercises.count ?? 0)"
|
@Published var previewWorkout: Workout?
|
||||||
}
|
|
||||||
}
|
|
||||||
@Published var currentExerciseTimeLeft: Int = 0
|
@Published var currentExerciseTimeLeft: Int = 0
|
||||||
@Published var currentExercise: ExerciseElement?
|
|
||||||
var currentExercisePositionString: String?
|
var currentExercisePositionString: String?
|
||||||
|
|
||||||
private var isWatchConnected = false
|
private var isWatchConnected = false
|
||||||
@@ -59,33 +56,33 @@ class BridgeModule: NSObject, ObservableObject {
|
|||||||
var audioPlayer: AVAudioPlayer?
|
var audioPlayer: AVAudioPlayer?
|
||||||
|
|
||||||
func start(workout: Workout) {
|
func start(workout: Workout) {
|
||||||
self.currentWorkout = workout
|
currentExerciseInfo.complete = {
|
||||||
|
self.completeWorkout()
|
||||||
|
}
|
||||||
|
|
||||||
|
currentExerciseInfo.start(workout: workout)
|
||||||
currentWorkoutRunTimeInSeconds = 0
|
currentWorkoutRunTimeInSeconds = 0
|
||||||
currentWorkoutRunTimer?.invalidate()
|
currentWorkoutRunTimer?.invalidate()
|
||||||
currentWorkoutRunTimer = nil
|
currentWorkoutRunTimer = nil
|
||||||
|
|
||||||
currentExerciseIdx = 0
|
if let superetExercise = currentExerciseInfo.currentExercise {
|
||||||
let exercise = workout.exercises[currentExerciseIdx]
|
updateCurrent(exercise: superetExercise)
|
||||||
updateCurrent(exercise: exercise)
|
startWorkoutTimer()
|
||||||
startWorkoutTimer()
|
workoutStartDate = Date()
|
||||||
workoutStartDate = Date()
|
isInWorkout = true
|
||||||
isInWorkout = true
|
|
||||||
|
if WCSession.isSupported() {
|
||||||
if WCSession.isSupported() {
|
WCSession.default.delegate = self
|
||||||
WCSession.default.delegate = self
|
WCSession.default.activate()
|
||||||
WCSession.default.activate()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func goToExerciseAt(index: Int) {
|
func goToExerciseAt(section: Int, row: Int) {
|
||||||
guard let currentWorkout = currentWorkout else {
|
if let superetExercise = currentExerciseInfo.goToWorkoutAt(supersetIndex: section,
|
||||||
return
|
exerciseIndex: row) {
|
||||||
|
updateCurrent(exercise: superetExercise)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentExerciseIdx = index
|
|
||||||
let exercise = currentWorkout.exercises[index]
|
|
||||||
updateCurrent(exercise: exercise)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetCurrentWorkout() {
|
func resetCurrentWorkout() {
|
||||||
@@ -98,11 +95,8 @@ class BridgeModule: NSObject, ObservableObject {
|
|||||||
self.currentExerciseTimer = nil
|
self.currentExerciseTimer = nil
|
||||||
|
|
||||||
self.currentWorkoutRunTimeInSeconds = -1
|
self.currentWorkoutRunTimeInSeconds = -1
|
||||||
self.currentExerciseIdx = -1
|
self.currentExerciseInfo.reset()
|
||||||
|
|
||||||
self.currentExercise = nil
|
|
||||||
self.currentWorkout = nil
|
|
||||||
|
|
||||||
self.isInWorkout = false
|
self.isInWorkout = false
|
||||||
self.workoutStartDate = nil
|
self.workoutStartDate = nil
|
||||||
self.workoutEndDate = nil
|
self.workoutEndDate = nil
|
||||||
@@ -162,38 +156,24 @@ class BridgeModule: NSObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func nextExercise() {
|
func nextExercise() {
|
||||||
currentExerciseIdx += 1
|
if let nextSupersetExercise = currentExerciseInfo.nextExercise {
|
||||||
if let currentWorkout = currentWorkout {
|
updateCurrent(exercise: nextSupersetExercise)
|
||||||
if currentExerciseIdx < currentWorkout.exercises.count {
|
} else {
|
||||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
completeWorkout()
|
||||||
updateCurrent(exercise: nextExercise)
|
|
||||||
} else {
|
|
||||||
completeWorkout()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func previousExercise() {
|
func previousExercise() {
|
||||||
currentExerciseIdx -= 1
|
if let nextSupersetExercise = currentExerciseInfo.previousExercise {
|
||||||
if currentExerciseIdx < 0 {
|
updateCurrent(exercise: nextSupersetExercise)
|
||||||
currentExerciseIdx = 0
|
} else {
|
||||||
}
|
completeWorkout()
|
||||||
if let currentWorkout = currentWorkout {
|
|
||||||
if currentExerciseIdx < currentWorkout.exercises.count {
|
|
||||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
|
||||||
updateCurrent(exercise: nextExercise)
|
|
||||||
} else {
|
|
||||||
completeWorkout()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func restartExercise() {
|
func restartExercise() {
|
||||||
if let currentWorkout = currentWorkout {
|
if let currentExercise = currentExerciseInfo.currentExercise {
|
||||||
if currentExerciseIdx < currentWorkout.exercises.count {
|
updateCurrent(exercise: currentExercise)
|
||||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
|
||||||
updateCurrent(exercise: nextExercise)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,15 +181,12 @@ class BridgeModule: NSObject, ObservableObject {
|
|||||||
currentWorkoutRunTimeInSeconds += 1
|
currentWorkoutRunTimeInSeconds += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateCurrent(exercise: ExerciseElement) {
|
func updateCurrent(exercise: SupersetExercise) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.currentExerciseTimer?.invalidate()
|
self.currentExerciseTimer?.invalidate()
|
||||||
self.currentExerciseTimer = nil
|
self.currentExerciseTimer = nil
|
||||||
|
|
||||||
self.currentExercise = exercise
|
if let duration = exercise.duration, duration > 0 {
|
||||||
|
|
||||||
if let duration = exercise.duration,
|
|
||||||
duration > 0 {
|
|
||||||
self.startExerciseTimerWith(duration: duration)
|
self.startExerciseTimerWith(duration: duration)
|
||||||
}
|
}
|
||||||
self.sendCurrentExerciseToWatch()
|
self.sendCurrentExerciseToWatch()
|
||||||
@@ -281,25 +258,25 @@ extension BridgeModule: WCSessionDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sendCurrentExerciseToWatch() {
|
func sendCurrentExerciseToWatch() {
|
||||||
if let duration = currentExercise?.duration,
|
if let currentExercise = currentExerciseInfo.currentExercise,
|
||||||
|
let duration = currentExercise.duration ,
|
||||||
duration > 0 {
|
duration > 0 {
|
||||||
let watchModel = WatchPackageModel(currentExerciseName: currentExercise?.exercise.name ?? "-", currentTimeLeft: currentExerciseTimeLeft, workoutStartDate: workoutStartDate ?? Date())
|
let watchModel = WatchPackageModel(currentExerciseName: currentExercise.exercise.name, currentTimeLeft: currentExerciseTimeLeft, workoutStartDate: workoutStartDate ?? Date())
|
||||||
let model = PhoneToWatchActions.inExercise(watchModel)
|
let model = PhoneToWatchActions.inExercise(watchModel)
|
||||||
let data = try! JSONEncoder().encode(model)
|
let data = try! JSONEncoder().encode(model)
|
||||||
send(data)
|
send(data)
|
||||||
} else {
|
} else {
|
||||||
var intWatchDispaly = -1
|
if let currentExercise = currentExerciseInfo.currentExercise,
|
||||||
if let reps = self.currentExercise?.reps,
|
let reps = currentExercise.reps,
|
||||||
reps > 0 {
|
reps > 0 {
|
||||||
intWatchDispaly = reps
|
|
||||||
|
// if not a timer we need to set the watch display with number of reps
|
||||||
|
// if timer it will set when timer updates
|
||||||
|
let watchModel = WatchPackageModel(currentExerciseName: currentExercise.exercise.name, currentTimeLeft: reps, workoutStartDate: self.workoutStartDate ?? Date())
|
||||||
|
let model = PhoneToWatchActions.inExercise(watchModel)
|
||||||
|
let data = try! JSONEncoder().encode(model)
|
||||||
|
self.send(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not a timer we need to set the watch display with number of reps
|
|
||||||
// if timer it will set when timer updates
|
|
||||||
let watchModel = WatchPackageModel(currentExerciseName: self.currentExercise?.exercise.name ?? "-", currentTimeLeft: intWatchDispaly, workoutStartDate: self.workoutStartDate ?? Date())
|
|
||||||
let model = PhoneToWatchActions.inExercise(watchModel)
|
|
||||||
let data = try! JSONEncoder().encode(model)
|
|
||||||
self.send(data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
96
Werkout_ios/CurrentWorkoutInfo.swift
Normal file
96
Werkout_ios/CurrentWorkoutInfo.swift
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
//
|
||||||
|
// CurrentWorkoutInfo.swift
|
||||||
|
// Werkout_ios
|
||||||
|
//
|
||||||
|
// Created by Trey Tartt on 7/17/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class CurrentWorkoutInfo {
|
||||||
|
var supersetIndex: Int = 0
|
||||||
|
var exerciseIndex: Int = 0
|
||||||
|
var workout: Workout?
|
||||||
|
var complete: (() -> Void)?
|
||||||
|
|
||||||
|
var currentRound = 1
|
||||||
|
|
||||||
|
var superset: [Superset] {
|
||||||
|
return workout?.supersets?.sorted(by: { $0.order < $1.order }) ?? [Superset]()
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentExercise: SupersetExercise? {
|
||||||
|
guard let supersets = workout?.supersets else { return nil }
|
||||||
|
let superset = supersets[supersetIndex]
|
||||||
|
let exercise = superset.exercises[exerciseIndex]
|
||||||
|
return exercise
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextExercise: SupersetExercise? {
|
||||||
|
guard let workout = workout else { return nil }
|
||||||
|
guard let supersets = workout.supersets else { return nil }
|
||||||
|
|
||||||
|
exerciseIndex += 1
|
||||||
|
let currentSuperSet = supersets[supersetIndex]
|
||||||
|
|
||||||
|
if exerciseIndex >= currentSuperSet.exercises.count {
|
||||||
|
currentRound += 1
|
||||||
|
|
||||||
|
if currentRound > currentSuperSet.rounds {
|
||||||
|
supersetIndex += 1
|
||||||
|
currentRound = 1
|
||||||
|
|
||||||
|
if supersetIndex >= supersets.count {
|
||||||
|
complete?()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exerciseIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let superset = supersets[supersetIndex]
|
||||||
|
let exercise = superset.exercises[exerciseIndex]
|
||||||
|
return exercise
|
||||||
|
}
|
||||||
|
|
||||||
|
var previousExercise: SupersetExercise? {
|
||||||
|
guard let workout = workout else { return nil }
|
||||||
|
guard let supersets = workout.supersets else { return nil }
|
||||||
|
|
||||||
|
exerciseIndex -= 1
|
||||||
|
if exerciseIndex < 0 {
|
||||||
|
if currentRound > 1 {
|
||||||
|
currentRound -= 1
|
||||||
|
} else {
|
||||||
|
if supersetIndex > 1 {
|
||||||
|
supersetIndex -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exerciseIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let superset = supersets[supersetIndex]
|
||||||
|
let exercise = superset.exercises[exerciseIndex]
|
||||||
|
return exercise
|
||||||
|
}
|
||||||
|
|
||||||
|
func start(workout: Workout) {
|
||||||
|
reset()
|
||||||
|
self.workout = workout
|
||||||
|
}
|
||||||
|
|
||||||
|
func reset() {
|
||||||
|
supersetIndex = 0
|
||||||
|
exerciseIndex = 0
|
||||||
|
currentRound = 1
|
||||||
|
self.workout = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func goToWorkoutAt(supersetIndex: Int, exerciseIndex: Int) -> SupersetExercise? {
|
||||||
|
self.supersetIndex = supersetIndex
|
||||||
|
self.exerciseIndex = exerciseIndex
|
||||||
|
|
||||||
|
return currentExercise
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ class DataStore: ObservableObject {
|
|||||||
public private(set) var allWorkouts: [Workout]?
|
public private(set) var allWorkouts: [Workout]?
|
||||||
public private(set) var allMuscles: [Muscle]?
|
public private(set) var allMuscles: [Muscle]?
|
||||||
public private(set) var allEquipment: [Equipment]?
|
public private(set) var allEquipment: [Equipment]?
|
||||||
public private(set) var allExercise: [ExerciseExercise]?
|
public private(set) var allExercise: [Exercise]?
|
||||||
|
|
||||||
@Published public private(set) var status = DataStoreStatus.idle
|
@Published public private(set) var status = DataStoreStatus.idle
|
||||||
|
|
||||||
|
|||||||
@@ -2,151 +2,208 @@
|
|||||||
"id": 21,
|
"id": 21,
|
||||||
"name": "Ipad",
|
"name": "Ipad",
|
||||||
"description": "description",
|
"description": "description",
|
||||||
"exercises": [
|
"supersets": [
|
||||||
{
|
{
|
||||||
"workout": 21,
|
"id": 1,
|
||||||
"exercise": {
|
"exercises": [
|
||||||
"id": 520,
|
{
|
||||||
"muscles": [
|
"id": 1,
|
||||||
{
|
"exercise": {
|
||||||
"id": 7264,
|
"id": 520,
|
||||||
"created_at": "2023-06-14T17:05:39.760515Z",
|
"muscles": [
|
||||||
"updated_at": "2023-06-14T17:05:39.761372Z",
|
{
|
||||||
"exercise": 520,
|
"id": 7264,
|
||||||
"muscle": 16
|
"name": "hip flexor",
|
||||||
|
"created_at": "2023-06-14T17:05:39.760515Z",
|
||||||
|
"updated_at": "2023-06-14T17:05:39.761372Z",
|
||||||
|
"exercise": 520,
|
||||||
|
"muscle": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7265,
|
||||||
|
"name": "glutes",
|
||||||
|
"created_at": "2023-06-14T17:05:39.762342Z",
|
||||||
|
"updated_at": "2023-06-14T17:05:39.762814Z",
|
||||||
|
"exercise": 520,
|
||||||
|
"muscle": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"equipment": [
|
||||||
|
{
|
||||||
|
"id": 941,
|
||||||
|
"name": "Wall",
|
||||||
|
"created_at": "2023-06-13T02:28:04.289213Z",
|
||||||
|
"updated_at": "2023-06-13T02:28:04.290354Z",
|
||||||
|
"exercise": 520,
|
||||||
|
"equipment": 1106
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"audio_url": "exercise_audio/1-Step_Wall_March.m4a",
|
||||||
|
"video_url": "exercise_videos/1-Step_Wall_March.mp4",
|
||||||
|
"created_at": "2023-06-11T22:50:19.020826Z",
|
||||||
|
"updated_at": "2023-06-11T22:50:19.020834Z",
|
||||||
|
"name": "1-Step Wall March",
|
||||||
|
"description": "Keeping a tall posture, lean forward with both arms straight ahead, palms on the wall. While pushing your toes back through the floor, drive one knee up towards your ribs. Pause, then quickly repeat the same movement with the opposite leg. ",
|
||||||
|
"side": "",
|
||||||
|
"is_two_dumbbells": false,
|
||||||
|
"is_trackable_distance": false,
|
||||||
|
"is_alternating": true,
|
||||||
|
"is_weight": true,
|
||||||
|
"is_distance": false,
|
||||||
|
"is_duration": true,
|
||||||
|
"is_reps": true,
|
||||||
|
"joints_used": "ankle,knee,hip,wrist,shoulder,elbow",
|
||||||
|
"movement_patterns": "plyometric",
|
||||||
|
"equipment_required": "Wall",
|
||||||
|
"muscle_groups": "hip flexor,glutes",
|
||||||
|
"synonyms": ""
|
||||||
},
|
},
|
||||||
{
|
"created_at": "2023-07-17T18:56:36.984049Z",
|
||||||
"id": 7265,
|
"updated_at": "2023-07-17T19:06:00.534838Z",
|
||||||
"created_at": "2023-06-14T17:05:39.762342Z",
|
"weight": null,
|
||||||
"updated_at": "2023-06-14T17:05:39.762814Z",
|
"reps": null,
|
||||||
"exercise": 520,
|
"duration": 30,
|
||||||
"muscle": 4
|
"order": 1,
|
||||||
}
|
"superset": 1
|
||||||
],
|
},
|
||||||
"equipment": [
|
{
|
||||||
{
|
"id": 2,
|
||||||
"id": 941,
|
"exercise": {
|
||||||
"created_at": "2023-06-13T02:28:04.289213Z",
|
"id": 992,
|
||||||
"updated_at": "2023-06-13T02:28:04.290354Z",
|
"muscles": [
|
||||||
"exercise": 520,
|
{
|
||||||
"equipment": 1106
|
"id": 7270,
|
||||||
}
|
"name": "hamstrings",
|
||||||
],
|
"created_at": "2023-06-14T17:05:39.769351Z",
|
||||||
"audio_url": "exercise_audio/1-Step_Wall_March.m4a",
|
"updated_at": "2023-06-14T17:05:39.769758Z",
|
||||||
"video_url": "exercise_videos/1-Step_Wall_March.mp4",
|
"exercise": 992,
|
||||||
"created_at": "2023-06-11T22:50:19.020826Z",
|
"muscle": 6
|
||||||
"updated_at": "2023-06-11T22:50:19.020834Z",
|
},
|
||||||
"name": "1-Step Wall March",
|
{
|
||||||
"description": "Keeping a tall posture, lean forward with both arms straight ahead, palms on the wall. While pushing your toes back through the floor, drive one knee up towards your ribs. Pause, then quickly repeat the same movement with the opposite leg. ",
|
"id": 7271,
|
||||||
"side": "",
|
"name": "glutes",
|
||||||
"is_two_dumbbells": false,
|
"created_at": "2023-06-14T17:05:39.770480Z",
|
||||||
"is_trackable_distance": false,
|
"updated_at": "2023-06-14T17:05:39.771111Z",
|
||||||
"is_alternating": true,
|
"exercise": 992,
|
||||||
"is_weight": true,
|
"muscle": 4
|
||||||
"is_distance": false,
|
}
|
||||||
"is_duration": true,
|
],
|
||||||
"is_reps": true,
|
"equipment": [
|
||||||
"joints_used": "ankle,knee,hip,wrist,shoulder,elbow",
|
{
|
||||||
"movement_patterns": "plyometric",
|
"id": 944,
|
||||||
"equipment_required": "Wall",
|
"name": "Dumbbell",
|
||||||
"muscle_groups": "hip flexor,glutes",
|
"created_at": "2023-06-13T02:28:04.294180Z",
|
||||||
"synonyms": ""
|
"updated_at": "2023-06-13T02:28:04.294658Z",
|
||||||
},
|
"exercise": 992,
|
||||||
"weight": 0,
|
"equipment": 1091
|
||||||
"reps": 0,
|
}
|
||||||
"duration": null,
|
],
|
||||||
"duration_audio": null,
|
"audio_url": "exercise_audio/2_Dumbbell_Single-Leg_Deadlift.m4a",
|
||||||
"weight_audio": "/media/quantities_audio/for_0_pounds.m4a",
|
"video_url": "exercise_videos/2_Dumbbell_Single-Leg_Deadlift.mp4",
|
||||||
"created_at": "2023-06-20T21:03:00.127620Z"
|
"created_at": "2023-06-11T22:50:19.197099Z",
|
||||||
|
"updated_at": "2023-06-11T22:50:19.197105Z",
|
||||||
|
"name": "2 Dumbbell Single-Leg Deadlift",
|
||||||
|
"description": "Holding a dumbbell in each hand, with your right leg on the ground, hinge at your hips and let your body see-saw down until you are parallel with the ground. Snap back to a standing position.",
|
||||||
|
"side": "right_leg",
|
||||||
|
"is_two_dumbbells": true,
|
||||||
|
"is_trackable_distance": false,
|
||||||
|
"is_alternating": false,
|
||||||
|
"is_weight": true,
|
||||||
|
"is_distance": false,
|
||||||
|
"is_duration": true,
|
||||||
|
"is_reps": true,
|
||||||
|
"joints_used": "ankle,lumbar spine,hip,knee,wrist",
|
||||||
|
"movement_patterns": "lower pull,lower pull - hip hinge",
|
||||||
|
"equipment_required": "Dumbbell",
|
||||||
|
"muscle_groups": "hamstrings,glutes",
|
||||||
|
"synonyms": "2 Dumbbell Single Leg Deadlift"
|
||||||
|
},
|
||||||
|
"created_at": "2023-07-17T18:56:36.984523Z",
|
||||||
|
"updated_at": "2023-07-17T19:06:00.535334Z",
|
||||||
|
"weight": 30,
|
||||||
|
"reps": null,
|
||||||
|
"duration": null,
|
||||||
|
"order": 2,
|
||||||
|
"superset": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"created_at": "2023-07-17T18:56:36.983159Z",
|
||||||
|
"updated_at": "2023-07-17T19:06:00.534027Z",
|
||||||
|
"name": "test superste",
|
||||||
|
"rounds": 3,
|
||||||
|
"order": 1,
|
||||||
|
"workout": 21
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"workout": 21,
|
"id": 2,
|
||||||
"exercise": {
|
"exercises": [
|
||||||
"id": 37,
|
{
|
||||||
"muscles": [
|
"id": 3,
|
||||||
{
|
"exercise": {
|
||||||
"id": 7272,
|
"id": 992,
|
||||||
"created_at": "2023-06-14T17:05:39.772195Z",
|
"muscles": [
|
||||||
"updated_at": "2023-06-14T17:05:39.772765Z",
|
{
|
||||||
"exercise": 37,
|
"id": 7270,
|
||||||
"muscle": 4
|
"name": "hamstrings",
|
||||||
|
"created_at": "2023-06-14T17:05:39.769351Z",
|
||||||
|
"updated_at": "2023-06-14T17:05:39.769758Z",
|
||||||
|
"exercise": 992,
|
||||||
|
"muscle": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7271,
|
||||||
|
"name": "glutes",
|
||||||
|
"created_at": "2023-06-14T17:05:39.770480Z",
|
||||||
|
"updated_at": "2023-06-14T17:05:39.771111Z",
|
||||||
|
"exercise": 992,
|
||||||
|
"muscle": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"equipment": [
|
||||||
|
{
|
||||||
|
"id": 944,
|
||||||
|
"name": "Dumbbell",
|
||||||
|
"created_at": "2023-06-13T02:28:04.294180Z",
|
||||||
|
"updated_at": "2023-06-13T02:28:04.294658Z",
|
||||||
|
"exercise": 992,
|
||||||
|
"equipment": 1091
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"audio_url": "exercise_audio/2_Dumbbell_Single-Leg_Deadlift.m4a",
|
||||||
|
"video_url": "exercise_videos/2_Dumbbell_Single-Leg_Deadlift.mp4",
|
||||||
|
"created_at": "2023-06-11T22:50:19.197099Z",
|
||||||
|
"updated_at": "2023-06-11T22:50:19.197105Z",
|
||||||
|
"name": "2 Dumbbell Single-Leg Deadlift",
|
||||||
|
"description": "Holding a dumbbell in each hand, with your right leg on the ground, hinge at your hips and let your body see-saw down until you are parallel with the ground. Snap back to a standing position.",
|
||||||
|
"side": "right_leg",
|
||||||
|
"is_two_dumbbells": true,
|
||||||
|
"is_trackable_distance": false,
|
||||||
|
"is_alternating": false,
|
||||||
|
"is_weight": true,
|
||||||
|
"is_distance": false,
|
||||||
|
"is_duration": true,
|
||||||
|
"is_reps": true,
|
||||||
|
"joints_used": "ankle,lumbar spine,hip,knee,wrist",
|
||||||
|
"movement_patterns": "lower pull,lower pull - hip hinge",
|
||||||
|
"equipment_required": "Dumbbell",
|
||||||
|
"muscle_groups": "hamstrings,glutes",
|
||||||
|
"synonyms": "2 Dumbbell Single Leg Deadlift"
|
||||||
},
|
},
|
||||||
{
|
"created_at": "2023-07-17T18:58:35.585418Z",
|
||||||
"id": 7273,
|
"updated_at": "2023-07-17T18:58:35.585435Z",
|
||||||
"created_at": "2023-06-14T17:05:39.773621Z",
|
"weight": 11,
|
||||||
"updated_at": "2023-06-14T17:05:39.774079Z",
|
"reps": null,
|
||||||
"exercise": 37,
|
"duration": null,
|
||||||
"muscle": 6
|
"order": 1,
|
||||||
}
|
"superset": 2
|
||||||
],
|
}
|
||||||
"equipment": [
|
],
|
||||||
{
|
"created_at": "2023-07-17T18:58:35.584036Z",
|
||||||
"id": 945,
|
"updated_at": "2023-07-17T19:03:57.175639Z",
|
||||||
"created_at": "2023-06-13T02:28:04.295672Z",
|
"name": "two",
|
||||||
"updated_at": "2023-06-13T02:28:04.296237Z",
|
"rounds": 3,
|
||||||
"exercise": 37,
|
"order": 2,
|
||||||
"equipment": 1088
|
"workout": 21
|
||||||
}
|
|
||||||
],
|
|
||||||
"audio_url": "exercise_audio/2_Kettlebell_Clean.m4a",
|
|
||||||
"video_url": "exercise_videos/2_Kettlebell_Clean.mp4",
|
|
||||||
"created_at": "2023-06-11T22:50:18.813591Z",
|
|
||||||
"updated_at": "2023-06-11T22:50:18.813600Z",
|
|
||||||
"name": "2 Kettlebell Clean",
|
|
||||||
"description": "Standing with feet in a shoulder width stance, grab the handles of the bells and swing them back between the legs while keeping a neutral spine.\nExtend the hips, swing the bells forward, and allow them to flip around your wrists to end in the front rack position.",
|
|
||||||
"side": "",
|
|
||||||
"is_two_dumbbells": false,
|
|
||||||
"is_trackable_distance": false,
|
|
||||||
"is_alternating": false,
|
|
||||||
"is_weight": true,
|
|
||||||
"is_distance": false,
|
|
||||||
"is_duration": true,
|
|
||||||
"is_reps": true,
|
|
||||||
"joints_used": "shoulder,ankle,knee,hip,elbow",
|
|
||||||
"movement_patterns": "lower pull - hip hinge,upper pull",
|
|
||||||
"equipment_required": "Kettlebell",
|
|
||||||
"muscle_groups": "glutes,hamstrings",
|
|
||||||
"synonyms": ""
|
|
||||||
},
|
|
||||||
"weight": 0,
|
|
||||||
"reps": 0,
|
|
||||||
"duration": null,
|
|
||||||
"duration_audio": null,
|
|
||||||
"weight_audio": "/media/quantities_audio/for_0_pounds.m4a",
|
|
||||||
"created_at": "2023-06-20T21:03:00.131018Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"workout": 21,
|
|
||||||
"exercise": {
|
|
||||||
"id": 798,
|
|
||||||
"muscles": [],
|
|
||||||
"equipment": [],
|
|
||||||
"audio_url": "exercise_audio/Recover.m4a",
|
|
||||||
"video_url": "exercise_videos/Recover.mp4",
|
|
||||||
"created_at": "2023-06-11T22:50:19.127914Z",
|
|
||||||
"updated_at": "2023-06-11T22:50:19.127921Z",
|
|
||||||
"name": "Recover",
|
|
||||||
"description": "Use this time to catch your breath. It will help you get more out of what's next",
|
|
||||||
"side": "",
|
|
||||||
"is_two_dumbbells": false,
|
|
||||||
"is_trackable_distance": false,
|
|
||||||
"is_alternating": false,
|
|
||||||
"is_weight": false,
|
|
||||||
"is_distance": false,
|
|
||||||
"is_duration": true,
|
|
||||||
"is_reps": false,
|
|
||||||
"joints_used": "",
|
|
||||||
"movement_patterns": "",
|
|
||||||
"equipment_required": "",
|
|
||||||
"muscle_groups": "",
|
|
||||||
"synonyms": null
|
|
||||||
},
|
|
||||||
"weight": 0,
|
|
||||||
"reps": 0,
|
|
||||||
"duration": null,
|
|
||||||
"duration_audio": null,
|
|
||||||
"weight_audio": "/media/quantities_audio/for_0_pounds.m4a",
|
|
||||||
"created_at": "2023-06-20T21:03:00.134981Z"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"registered_user": {
|
"registered_user": {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class AllEquipmentFetchable: Fetchable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AllExerciseFetchable: Fetchable {
|
class AllExerciseFetchable: Fetchable {
|
||||||
typealias Response = [ExerciseExercise]
|
typealias Response = [Exercise]
|
||||||
var endPoint: String = "/exercise/all/"
|
var endPoint: String = "/exercise/all/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ class PreviewData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class func parseExercises() -> [ExerciseExercise] {
|
class func parseExercises() -> [Exercise] {
|
||||||
if let filepath = Bundle.main.path(forResource: "Exercises", ofType: "json") {
|
if let filepath = Bundle.main.path(forResource: "Exercises", ofType: "json") {
|
||||||
do {
|
do {
|
||||||
let data = try Data(NSData(contentsOfFile: filepath))
|
let data = try Data(NSData(contentsOfFile: filepath))
|
||||||
let exercises = try JSONDecoder().decode([ExerciseExercise].self, from: data)
|
let exercises = try JSONDecoder().decode([Exercise].self, from: data)
|
||||||
return exercises
|
return exercises
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
print(error)
|
||||||
|
|||||||
@@ -18,15 +18,15 @@ struct AddExerciseView: View {
|
|||||||
|
|
||||||
@State var selectedMuscles = [Muscle]()
|
@State var selectedMuscles = [Muscle]()
|
||||||
@State var selectedEquipment = [Equipment]()
|
@State var selectedEquipment = [Equipment]()
|
||||||
@State var filteredExercises = [ExerciseExercise]()
|
@State var filteredExercises = [Exercise]()
|
||||||
|
|
||||||
@StateObject var bridgeModule = BridgeModule.shared
|
@StateObject var bridgeModule = BridgeModule.shared
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
var selectedExercise: ((ExerciseExercise) -> Void)
|
var selectedExercise: ((Exercise) -> Void)
|
||||||
@State var createWorkoutItemPickerViewModel: CreateWorkoutItemPickerViewModel?
|
@State var createWorkoutItemPickerViewModel: CreateWorkoutItemPickerViewModel?
|
||||||
@State var createWorkoutItemPickerViewType: CreateWorkoutItemPickerViewType?
|
@State var createWorkoutItemPickerViewType: CreateWorkoutItemPickerViewType?
|
||||||
@State var searchString: String = ""
|
@State var searchString: String = ""
|
||||||
@State var videoExercise: ExerciseExercise? {
|
@State var videoExercise: Exercise? {
|
||||||
didSet {
|
didSet {
|
||||||
if let viddd = self.videoExercise?.videoURL,
|
if let viddd = self.videoExercise?.videoURL,
|
||||||
let url = URL(string: BaseURLs.currentBaseURL + viddd) {
|
let url = URL(string: BaseURLs.currentBaseURL + viddd) {
|
||||||
@@ -111,19 +111,19 @@ struct AddExerciseView: View {
|
|||||||
|
|
||||||
func filterExercises() {
|
func filterExercises() {
|
||||||
if selectedMuscles.count == 0 {
|
if selectedMuscles.count == 0 {
|
||||||
filteredExercises = [ExerciseExercise]()
|
filteredExercises = [Exercise]()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if selectedEquipment.count == 0 {
|
if selectedEquipment.count == 0 {
|
||||||
filteredExercises = [ExerciseExercise]()
|
filteredExercises = [Exercise]()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let exercises = DataStore.shared.allExercise,
|
guard let exercises = DataStore.shared.allExercise,
|
||||||
let muscles = DataStore.shared.allMuscles,
|
let muscles = DataStore.shared.allMuscles,
|
||||||
let equipment = DataStore.shared.allEquipment else {
|
let equipment = DataStore.shared.allEquipment else {
|
||||||
filteredExercises = [ExerciseExercise]()
|
filteredExercises = [Exercise]()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ struct AddExerciseView: View {
|
|||||||
if selectedMuscles.count == muscles.count {
|
if selectedMuscles.count == muscles.count {
|
||||||
hasCorrectMuscles = true
|
hasCorrectMuscles = true
|
||||||
} else {
|
} else {
|
||||||
let exerciseMuscleIds = exercise.muscles.map({ $0.muscle })
|
let exerciseMuscleIds = exercise.muscles.map({ $0.id })
|
||||||
let selctedMuscleIds = selectedMuscles.map({ $0.id })
|
let selctedMuscleIds = selectedMuscles.map({ $0.id })
|
||||||
// if one items match
|
// if one items match
|
||||||
if exerciseMuscleIds.contains(where: selctedMuscleIds.contains) {
|
if exerciseMuscleIds.contains(where: selctedMuscleIds.contains) {
|
||||||
@@ -146,7 +146,7 @@ struct AddExerciseView: View {
|
|||||||
if selectedEquipment.count == equipment.count {
|
if selectedEquipment.count == equipment.count {
|
||||||
hasCorrectEquipment = true
|
hasCorrectEquipment = true
|
||||||
} else {
|
} else {
|
||||||
let exerciseEquipmentIds = exercise.equipment.map({ $0.equipment })
|
let exerciseEquipmentIds = exercise.equipment.map({ $0.id })
|
||||||
let selctedEquipmentIds = selectedEquipment.map({ $0.id })
|
let selctedEquipmentIds = selectedEquipment.map({ $0.id })
|
||||||
// if one items match
|
// if one items match
|
||||||
if exerciseEquipmentIds.contains(where: selctedEquipmentIds.contains) {
|
if exerciseEquipmentIds.contains(where: selctedEquipmentIds.contains) {
|
||||||
@@ -198,7 +198,7 @@ struct AddExerciseView: View {
|
|||||||
var createWorkoutItemPickerModels = [CreateWorkoutItemPickerModel]()
|
var createWorkoutItemPickerModels = [CreateWorkoutItemPickerModel]()
|
||||||
equipment.forEach({
|
equipment.forEach({
|
||||||
let model = CreateWorkoutItemPickerModel(id: $0.id,
|
let model = CreateWorkoutItemPickerModel(id: $0.id,
|
||||||
name: $0.name?.lowercased() ?? "-")
|
name: $0.name.lowercased())
|
||||||
createWorkoutItemPickerModels.append(model)
|
createWorkoutItemPickerModels.append(model)
|
||||||
})
|
})
|
||||||
createWorkoutItemPickerModels = createWorkoutItemPickerModels.sorted(by: {
|
createWorkoutItemPickerModels = createWorkoutItemPickerModels.sorted(by: {
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ struct AllWorkoutsView: View {
|
|||||||
@State private var showWorkoutDetail = false
|
@State private var showWorkoutDetail = false
|
||||||
@State private var selectedWorkout: Workout? {
|
@State private var selectedWorkout: Workout? {
|
||||||
didSet {
|
didSet {
|
||||||
bridgeModule.currentWorkout = selectedWorkout
|
bridgeModule.currentExerciseInfo.workout = selectedWorkout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@State private var selectedPlannedWorkout: Workout? {
|
@State private var selectedPlannedWorkout: Workout? {
|
||||||
didSet {
|
didSet {
|
||||||
bridgeModule.currentWorkout = selectedPlannedWorkout
|
bridgeModule.currentExerciseInfo.workout = selectedPlannedWorkout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ struct AllWorkoutsView: View {
|
|||||||
AllWorkoutPickerView(mainViews: MainViewTypes.allCases,
|
AllWorkoutPickerView(mainViews: MainViewTypes.allCases,
|
||||||
selectedSegment: $selectedSegment,
|
selectedSegment: $selectedSegment,
|
||||||
showCurrentWorkout: {
|
showCurrentWorkout: {
|
||||||
selectedWorkout = bridgeModule.currentWorkout
|
selectedWorkout = bridgeModule.currentExerciseInfo.workout
|
||||||
})
|
})
|
||||||
|
|
||||||
switch selectedSegment {
|
switch selectedSegment {
|
||||||
@@ -87,12 +87,13 @@ struct AllWorkoutsView: View {
|
|||||||
maybeUpdateShit()
|
maybeUpdateShit()
|
||||||
}
|
}
|
||||||
.sheet(item: $selectedWorkout) { item in
|
.sheet(item: $selectedWorkout) { item in
|
||||||
let viewModel = WorkoutDetailViewModel(workout: item)
|
var isPreview = item.id == bridgeModule.currentExerciseInfo.workout?.id
|
||||||
|
let viewModel = WorkoutDetailViewModel(workout: item, isPreview: isPreview)
|
||||||
WorkoutDetailView(viewModel: viewModel)
|
WorkoutDetailView(viewModel: viewModel)
|
||||||
}
|
}
|
||||||
.sheet(item: $selectedPlannedWorkout) { item in
|
.sheet(item: $selectedPlannedWorkout) { item in
|
||||||
let viewModel = WorkoutDetailViewModel(workout: item)
|
let viewModel = WorkoutDetailViewModel(workout: item, isPreview: true)
|
||||||
WorkoutDetailView(viewModel: viewModel, showAddToCalendar: false)
|
WorkoutDetailView(viewModel: viewModel)
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $showLoginView) {
|
.sheet(isPresented: $showLoginView) {
|
||||||
LoginView(completion: {
|
LoginView(completion: {
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import SwiftUI
|
|||||||
|
|
||||||
class CreateWorkoutExercise: ObservableObject, Identifiable {
|
class CreateWorkoutExercise: ObservableObject, Identifiable {
|
||||||
let id = UUID()
|
let id = UUID()
|
||||||
var exercise: ExerciseExercise
|
var exercise: Exercise
|
||||||
@Published var reps: Int = 0
|
@Published var reps: Int = 0
|
||||||
@Published var duration: Int = 0
|
@Published var duration: Int = 0
|
||||||
@Published var weight: Int = 0
|
@Published var weight: Int = 0
|
||||||
|
|
||||||
init(exercise: ExerciseExercise, reps: Int = 0, duration: Int = 0, weight: Int = 0) {
|
init(exercise: Exercise, reps: Int = 0, duration: Int = 0, weight: Int = 0) {
|
||||||
self.exercise = exercise
|
self.exercise = exercise
|
||||||
self.reps = reps
|
self.reps = reps
|
||||||
self.duration = duration
|
self.duration = duration
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ struct ExternalWorkoutDetailView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
if let workout = bridgeModule.currentWorkout {
|
if let workout = bridgeModule.currentExerciseInfo.workout,
|
||||||
|
let exercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
GeometryReader { metrics in
|
GeometryReader { metrics in
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
@@ -26,8 +27,8 @@ struct ExternalWorkoutDetailView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VStack {
|
VStack {
|
||||||
ExtExerciseList(workout: workout,
|
ExtExerciseList(workout: workout,
|
||||||
currentExerciseIdx: bridgeModule.currentExerciseIdx)
|
currentExercise: exercise)
|
||||||
|
|
||||||
if let currentExercisePositionString = bridgeModule.currentExercisePositionString {
|
if let currentExercisePositionString = bridgeModule.currentExercisePositionString {
|
||||||
Text(currentExercisePositionString)
|
Text(currentExercisePositionString)
|
||||||
@@ -53,18 +54,20 @@ struct ExternalWorkoutDetailView: View {
|
|||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: bridgeModule.currentExercise, perform: { newValue in
|
.onChange(of: bridgeModule.currentExerciseInfo.exerciseIndex, perform: { newValue in
|
||||||
if let videoURL = VideoURLCreator.videoURL(
|
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
thotStyle: thotStyle,
|
if let videoURL = VideoURLCreator.videoURL(
|
||||||
defaultVideoURLStr: bridgeModule.currentExercise?.exercise.videoURL,
|
thotStyle: thotStyle,
|
||||||
exerciseName: bridgeModule.currentExercise?.exercise.name,
|
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||||
workout: bridgeModule.currentWorkout) {
|
exerciseName: currentExtercise.exercise.name,
|
||||||
avPlayer = AVPlayer(url: videoURL)
|
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||||
avPlayer.play()
|
avPlayer = AVPlayer(url: videoURL)
|
||||||
|
avPlayer.play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
.background(bridgeModule.currentWorkout == nil ? Color(red: 157/255, green: 138/255, blue: 255/255) : Color(uiColor: .systemBackground))
|
.background(bridgeModule.currentExerciseInfo.workout == nil ? Color(red: 157/255, green: 138/255, blue: 255/255) : Color(uiColor: .systemBackground))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +76,7 @@ struct TitleView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
if let workout = bridgeModule.currentWorkout {
|
if let workout = bridgeModule.currentExerciseInfo.workout {
|
||||||
Text(workout.name)
|
Text(workout.name)
|
||||||
.font(Font.system(size: 100))
|
.font(Font.system(size: 100))
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
@@ -91,36 +94,64 @@ struct TitleView: View {
|
|||||||
|
|
||||||
struct ExtExerciseList: View {
|
struct ExtExerciseList: View {
|
||||||
var workout: Workout
|
var workout: Workout
|
||||||
var currentExerciseIdx: Int
|
var currentExercise: SupersetExercise
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollViewReader { proxy in
|
if let supersets = workout.supersets {
|
||||||
List() {
|
ScrollViewReader { proxy in
|
||||||
ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in
|
List() {
|
||||||
let obj = workout.exercisesSortedByCreated_at[i]
|
ForEach(supersets.indices, id: \.self) { supersetIndex in
|
||||||
HStack {
|
let superset = supersets[supersetIndex]
|
||||||
if i == currentExerciseIdx {
|
|
||||||
Image(systemName: "checkmark")
|
|
||||||
.font(Font.system(size: 55))
|
|
||||||
.minimumScaleFactor(0.01)
|
|
||||||
.lineLimit(1)
|
|
||||||
.foregroundColor(.green)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(obj.exercise.name)
|
Section(content: {
|
||||||
.font(Font.system(size: 55))
|
ForEach(superset.exercises.indices, id: \.self) { exerciseIndex in
|
||||||
.minimumScaleFactor(0.01)
|
let supersetExecercise = superset.exercises[exerciseIndex]
|
||||||
.lineLimit(3)
|
|
||||||
.padding()
|
HStack {
|
||||||
.id(i)
|
if supersetExecercise.id == currentExercise.id {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
.foregroundColor(.green)
|
||||||
|
.font(Font.system(size: 55))
|
||||||
|
.minimumScaleFactor(0.01)
|
||||||
|
.lineLimit(1)
|
||||||
|
.foregroundColor(.green)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(supersetExecercise.exercise.name)
|
||||||
|
.id(exerciseIndex)
|
||||||
|
.font(Font.system(size: 55))
|
||||||
|
.minimumScaleFactor(0.01)
|
||||||
|
.lineLimit(3)
|
||||||
|
.padding()
|
||||||
|
.id(exerciseIndex)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, header: {
|
||||||
|
HStack {
|
||||||
|
Text(superset.name ?? "--")
|
||||||
|
.font(Font.system(size: 55))
|
||||||
|
.minimumScaleFactor(0.01)
|
||||||
|
.lineLimit(3)
|
||||||
|
.padding()
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
Text("\(superset.rounds) rounds")
|
||||||
|
.font(Font.system(size: 55))
|
||||||
|
.minimumScaleFactor(0.01)
|
||||||
|
.lineLimit(3)
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onChange(of: currentExercise, perform: { newValue in
|
||||||
|
withAnimation {
|
||||||
|
proxy.scrollTo(newValue, anchor: .top)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
.onChange(of: currentExerciseIdx, perform: { newValue in
|
|
||||||
withAnimation {
|
|
||||||
proxy.scrollTo(newValue, anchor: .top)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,7 +162,7 @@ struct ExtCountdownView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { metrics in
|
GeometryReader { metrics in
|
||||||
VStack {
|
VStack {
|
||||||
if let currenExercise = bridgeModule.currentExercise {
|
if let currenExercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
HStack {
|
HStack {
|
||||||
Text(currenExercise.exercise.name)
|
Text(currenExercise.exercise.name)
|
||||||
.font(.system(size: 200))
|
.font(.system(size: 200))
|
||||||
@@ -203,15 +234,15 @@ struct ExtCountdownView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExternalWorkoutDetailView_Previews: PreviewProvider {
|
//struct ExternalWorkoutDetailView_Previews: PreviewProvider {
|
||||||
static var bridge = BridgeModule.shared
|
// static var bridge = BridgeModule.shared
|
||||||
|
//
|
||||||
static var previews: some View {
|
// static var previews: some View {
|
||||||
ExternalWorkoutDetailView().environmentObject({ () -> BridgeModule in
|
// ExternalWorkoutDetailView().environmentObject({ () -> BridgeModule in
|
||||||
let envObj = BridgeModule.shared
|
// let envObj = BridgeModule.shared
|
||||||
envObj.currentWorkout = nil //PreviewData.workout()
|
// envObj.currentWorkout = nil //PreviewData.workout()
|
||||||
bridge.currentExercise = PreviewData.workout().exercisesSortedByCreated_at.first!
|
// bridge.currentExercise = PreviewData.workout().exercisesSortedByCreated_at.first!
|
||||||
return envObj
|
// return envObj
|
||||||
}() )
|
// }() )
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ struct MainView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
if let workout = workout {
|
if let workout = workout {
|
||||||
let vm = WorkoutDetailViewModel(workout: workout)
|
let vm = WorkoutDetailViewModel(workout: workout, isPreview: true)
|
||||||
WorkoutDetailView(viewModel: vm)
|
WorkoutDetailView(viewModel: vm)
|
||||||
} else {
|
} else {
|
||||||
Text("no workout selected")
|
Text("no workout selected")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ struct CountdownView: View {
|
|||||||
@StateObject var bridgeModule = BridgeModule.shared
|
@StateObject var bridgeModule = BridgeModule.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if let duration = bridgeModule.currentExercise?.duration,
|
if let duration = bridgeModule.currentExerciseInfo.currentExercise?.duration,
|
||||||
duration > 0 {
|
duration > 0 {
|
||||||
HStack {
|
HStack {
|
||||||
if bridgeModule.currentExerciseTimeLeft >= 0 && duration > bridgeModule.currentExerciseTimeLeft {
|
if bridgeModule.currentExerciseTimeLeft >= 0 && duration > bridgeModule.currentExerciseTimeLeft {
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ import AVKit
|
|||||||
struct ExerciseListView: View {
|
struct ExerciseListView: View {
|
||||||
@AppStorage("thotStyle") private var thotStyle: ThotStyle = .never
|
@AppStorage("thotStyle") private var thotStyle: ThotStyle = .never
|
||||||
@ObservedObject var bridgeModule = BridgeModule.shared
|
@ObservedObject var bridgeModule = BridgeModule.shared
|
||||||
var workout: Workout
|
|
||||||
@State var avPlayer = AVPlayer(url: URL(string: "https://dev.werkout.fitness/media/exercise_videos/2_Dumbbell_Lateral_Lunges.mp4")!)
|
@State var avPlayer = AVPlayer(url: URL(string: "https://dev.werkout.fitness/media/exercise_videos/2_Dumbbell_Lateral_Lunges.mp4")!)
|
||||||
|
var workout: Workout
|
||||||
|
|
||||||
@State var videoExercise: ExerciseExercise? {
|
@State var videoExercise: Exercise? {
|
||||||
didSet {
|
didSet {
|
||||||
if let videoURL = VideoURLCreator.videoURL(
|
if let videoURL = VideoURLCreator.videoURL(
|
||||||
thotStyle: thotStyle,
|
thotStyle: thotStyle,
|
||||||
defaultVideoURLStr: self.videoExercise?.videoURL,
|
defaultVideoURLStr: self.videoExercise?.videoURL,
|
||||||
exerciseName: self.videoExercise?.name,
|
exerciseName: self.videoExercise?.name,
|
||||||
workout: bridgeModule.currentWorkout) {
|
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||||
avPlayer = AVPlayer(url: videoURL)
|
avPlayer = AVPlayer(url: videoURL)
|
||||||
avPlayer.play()
|
avPlayer.play()
|
||||||
}
|
}
|
||||||
@@ -28,79 +28,97 @@ struct ExerciseListView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollViewReader { proxy in
|
if let supersets = workout.supersets {
|
||||||
List() {
|
ScrollViewReader { proxy in
|
||||||
ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in
|
List() {
|
||||||
let obj = workout.exercisesSortedByCreated_at[i]
|
ForEach(supersets.indices, id: \.self) { supersetIndex in
|
||||||
HStack {
|
let superset = supersets[supersetIndex]
|
||||||
if i == bridgeModule.currentExerciseIdx {
|
Section(content: {
|
||||||
Image(systemName: "checkmark")
|
ForEach(superset.exercises.indices, id: \.self) { exerciseIndex in
|
||||||
.foregroundColor(.green)
|
let supersetExecercise = superset.exercises[exerciseIndex]
|
||||||
}
|
|
||||||
|
|
||||||
Text(obj.exercise.name)
|
|
||||||
.id(i)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
if let reps = obj.reps,
|
|
||||||
reps > 0 {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "number")
|
|
||||||
.foregroundColor(.white)
|
|
||||||
.frame(width: 20, alignment: .leading)
|
|
||||||
Text("\(reps)")
|
|
||||||
.foregroundColor(.white)
|
|
||||||
.frame(width: 30, alignment: .trailing)
|
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
if supersetExecercise.id == bridgeModule.currentExerciseInfo.currentExercise?.id {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
.foregroundColor(.green)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(supersetExecercise.exercise.name)
|
||||||
|
.id(exerciseIndex)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if let reps = supersetExecercise.reps,
|
||||||
|
reps > 0 {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "number")
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.frame(width: 20, alignment: .leading)
|
||||||
|
Text("\(reps)")
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.frame(width: 30, alignment: .trailing)
|
||||||
|
|
||||||
|
}
|
||||||
|
.padding([.top, .bottom], 5)
|
||||||
|
.padding([.leading], 10)
|
||||||
|
.padding([.trailing], 15)
|
||||||
|
.background(.blue)
|
||||||
|
.cornerRadius(5, corners: [.topLeft, .bottomLeft])
|
||||||
|
.frame(alignment: .trailing)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let duration = supersetExecercise.duration,
|
||||||
|
duration > 0 {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "stopwatch")
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.frame(width: 20, alignment: .leading)
|
||||||
|
Text("\(duration)")
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.frame(width: 30, alignment: .trailing)
|
||||||
|
}
|
||||||
|
.padding([.top, .bottom], 5)
|
||||||
|
.padding([.leading], 10)
|
||||||
|
.padding([.trailing], 15)
|
||||||
|
.background(.green)
|
||||||
|
.cornerRadius(5, corners: [.topLeft, .bottomLeft])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.trailing, -20)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
if bridgeModule.isInWorkout {
|
||||||
|
bridgeModule.goToExerciseAt(section: supersetIndex, row: exerciseIndex)
|
||||||
|
} else {
|
||||||
|
// videoExercise = obj.exercise
|
||||||
|
}
|
||||||
|
// .onChange(of: bridgeModule.currentExerciseIdx, perform: { newValue in
|
||||||
|
// withAnimation {
|
||||||
|
// proxy.scrollTo(newValue, anchor: .top)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
.sheet(item: $videoExercise) { exercise in
|
||||||
|
PlayerView(player: $avPlayer)
|
||||||
|
.onAppear{
|
||||||
|
avPlayer.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding([.top, .bottom], 5)
|
}, header: {
|
||||||
.padding([.leading], 10)
|
|
||||||
.padding([.trailing], 15)
|
|
||||||
.background(.blue)
|
|
||||||
.cornerRadius(5, corners: [.topLeft, .bottomLeft])
|
|
||||||
.frame(alignment: .trailing)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let duration = obj.duration,
|
|
||||||
duration > 0 {
|
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: "stopwatch")
|
Text(superset.name ?? "--")
|
||||||
.foregroundColor(.white)
|
.foregroundColor(Color("appColor"))
|
||||||
.frame(width: 20, alignment: .leading)
|
.bold()
|
||||||
Text("\(duration)")
|
Spacer()
|
||||||
.foregroundColor(.white)
|
Text("\(superset.rounds) rounds")
|
||||||
.frame(width: 30, alignment: .trailing)
|
.foregroundColor(Color("appColor"))
|
||||||
|
.bold()
|
||||||
}
|
}
|
||||||
.padding([.top, .bottom], 5)
|
})
|
||||||
.padding([.leading], 10)
|
|
||||||
.padding([.trailing], 15)
|
|
||||||
.background(.green)
|
|
||||||
.cornerRadius(5, corners: [.topLeft, .bottomLeft])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.trailing, -20)
|
|
||||||
.contentShape(Rectangle())
|
|
||||||
.onTapGesture {
|
|
||||||
if bridgeModule.isInWorkout {
|
|
||||||
bridgeModule.goToExerciseAt(index: i)
|
|
||||||
} else {
|
|
||||||
videoExercise = obj.exercise
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: bridgeModule.currentExerciseIdx, perform: { newValue in
|
|
||||||
withAnimation {
|
|
||||||
proxy.scrollTo(newValue, anchor: .top)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
.sheet(item: $videoExercise) { exercise in
|
|
||||||
PlayerView(player: $avPlayer)
|
|
||||||
.onAppear{
|
|
||||||
avPlayer.play()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ struct WorkoutDetailView: View {
|
|||||||
|
|
||||||
@State var presentedSheet: Sheet?
|
@State var presentedSheet: Sheet?
|
||||||
@State var workoutToPlan: Workout?
|
@State var workoutToPlan: Workout?
|
||||||
var showAddToCalendar = true
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
@@ -80,7 +79,7 @@ struct WorkoutDetailView: View {
|
|||||||
bridgeModule.completeWorkout()
|
bridgeModule.completeWorkout()
|
||||||
}, planWorkout: { workout in
|
}, planWorkout: { workout in
|
||||||
workoutToPlan = workout
|
workoutToPlan = workout
|
||||||
}, workout: workout, showAddToCalendar: showAddToCalendar)
|
}, workout: workout, showAddToCalendar: viewModel.isPreview)
|
||||||
.frame(height: 44)
|
.frame(height: 44)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -101,24 +100,28 @@ struct WorkoutDetailView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: bridgeModule.currentExercise, perform: { newValue in
|
.onChange(of: bridgeModule.currentExerciseInfo.exerciseIndex, perform: { newValue in
|
||||||
if let videoURL = VideoURLCreator.videoURL(
|
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
thotStyle: thotStyle,
|
if let videoURL = VideoURLCreator.videoURL(
|
||||||
defaultVideoURLStr: newValue?.exercise.videoURL,
|
thotStyle: thotStyle,
|
||||||
exerciseName: newValue?.exercise.name,
|
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||||
workout: bridgeModule.currentWorkout) {
|
exerciseName: currentExtercise.exercise.name,
|
||||||
avPlayer = AVPlayer(url: videoURL)
|
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||||
avPlayer.play()
|
avPlayer = AVPlayer(url: videoURL)
|
||||||
|
avPlayer.play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.onAppear{
|
.onAppear{
|
||||||
if let videoURL = VideoURLCreator.videoURL(
|
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
thotStyle: thotStyle,
|
if let videoURL = VideoURLCreator.videoURL(
|
||||||
defaultVideoURLStr: bridgeModule.currentExercise?.exercise.videoURL,
|
thotStyle: thotStyle,
|
||||||
exerciseName: bridgeModule.currentExercise?.exercise.name,
|
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||||
workout: bridgeModule.currentWorkout) {
|
exerciseName: currentExtercise.exercise.name,
|
||||||
avPlayer = AVPlayer(url: videoURL)
|
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||||
avPlayer.play()
|
avPlayer = AVPlayer(url: videoURL)
|
||||||
|
avPlayer.play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bridgeModule.completedWorkout = {
|
bridgeModule.completedWorkout = {
|
||||||
@@ -132,7 +135,7 @@ struct WorkoutDetailView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createWorkoutData() -> [String:Any]? {
|
func createWorkoutData() -> [String:Any]? {
|
||||||
guard let workoutid = bridgeModule.currentWorkout?.id,
|
guard let workoutid = bridgeModule.currentExerciseInfo.workout?.id,
|
||||||
let startTime = bridgeModule.workoutStartDate?.timeFormatForUpload,
|
let startTime = bridgeModule.workoutStartDate?.timeFormatForUpload,
|
||||||
let endTime = bridgeModule.workoutEndDate?.timeFormatForUpload else {
|
let endTime = bridgeModule.workoutEndDate?.timeFormatForUpload else {
|
||||||
return nil
|
return nil
|
||||||
@@ -154,6 +157,6 @@ struct WorkoutDetailView: View {
|
|||||||
struct WorkoutDetailView_Previews: PreviewProvider {
|
struct WorkoutDetailView_Previews: PreviewProvider {
|
||||||
static let workoutDetail = PreviewData.workout()
|
static let workoutDetail = PreviewData.workout()
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
WorkoutDetailView(viewModel: WorkoutDetailViewModel(workout: WorkoutDetailView_Previews.workoutDetail, status: .showWorkout(WorkoutDetailView_Previews.workoutDetail)))
|
WorkoutDetailView(viewModel: WorkoutDetailViewModel(workout: WorkoutDetailView_Previews.workoutDetail, status: .showWorkout(WorkoutDetailView_Previews.workoutDetail), isPreview: true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,13 @@ class WorkoutDetailViewModel: ObservableObject {
|
|||||||
case loading
|
case loading
|
||||||
case showWorkout(Workout)
|
case showWorkout(Workout)
|
||||||
}
|
}
|
||||||
@Published var status: WorkoutDetailViewModelStatus
|
|
||||||
|
|
||||||
init(workout: Workout, status: WorkoutDetailViewModelStatus? = nil) {
|
@Published var status: WorkoutDetailViewModelStatus
|
||||||
|
let isPreview: Bool
|
||||||
|
|
||||||
|
init(workout: Workout, status: WorkoutDetailViewModelStatus? = nil, isPreview: Bool) {
|
||||||
self.status = .loading
|
self.status = .loading
|
||||||
|
self.isPreview = isPreview
|
||||||
|
|
||||||
if let passedStatus = status {
|
if let passedStatus = status {
|
||||||
self.status = passedStatus
|
self.status = passedStatus
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ struct WorkoutHistoryView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sheet(item: $selectedPlannedWorkout) { item in
|
.sheet(item: $selectedPlannedWorkout) { item in
|
||||||
let viewModel = WorkoutDetailViewModel(workout: item)
|
let viewModel = WorkoutDetailViewModel(workout: item, isPreview: true)
|
||||||
WorkoutDetailView(viewModel: viewModel, showAddToCalendar: true)
|
WorkoutDetailView(viewModel: viewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user