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
|
|
||||||
} else {
|
|
||||||
self.exercises = [ExerciseElement]()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.name = try container.decode(String.self, forKey: .name)
|
self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "NA"
|
||||||
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,14 +56,17 @@ 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
|
||||||
@@ -75,17 +75,14 @@ class BridgeModule: NSObject, ObservableObject {
|
|||||||
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,10 +95,7 @@ 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
|
||||||
@@ -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 {
|
|
||||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
|
||||||
updateCurrent(exercise: nextExercise)
|
|
||||||
} else {
|
} else {
|
||||||
completeWorkout()
|
completeWorkout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func previousExercise() {
|
func previousExercise() {
|
||||||
currentExerciseIdx -= 1
|
if let nextSupersetExercise = currentExerciseInfo.previousExercise {
|
||||||
if currentExerciseIdx < 0 {
|
updateCurrent(exercise: nextSupersetExercise)
|
||||||
currentExerciseIdx = 0
|
|
||||||
}
|
|
||||||
if let currentWorkout = currentWorkout {
|
|
||||||
if currentExerciseIdx < currentWorkout.exercises.count {
|
|
||||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
|
||||||
updateCurrent(exercise: nextExercise)
|
|
||||||
} else {
|
} else {
|
||||||
completeWorkout()
|
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,27 +258,27 @@ 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 not a timer we need to set the watch display with number of reps
|
||||||
// if timer it will set when timer updates
|
// if timer it will set when timer updates
|
||||||
let watchModel = WatchPackageModel(currentExerciseName: self.currentExercise?.exercise.name ?? "-", currentTimeLeft: intWatchDispaly, workoutStartDate: self.workoutStartDate ?? Date())
|
let watchModel = WatchPackageModel(currentExerciseName: currentExercise.exercise.name, currentTimeLeft: reps, workoutStartDate: self.workoutStartDate ?? Date())
|
||||||
let model = PhoneToWatchActions.inExercise(watchModel)
|
let model = PhoneToWatchActions.inExercise(watchModel)
|
||||||
let data = try! JSONEncoder().encode(model)
|
let data = try! JSONEncoder().encode(model)
|
||||||
self.send(data)
|
self.send(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
|
func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
|
||||||
if let model = try? JSONDecoder().decode(WatchActions.self, from: messageData) {
|
if let model = try? JSONDecoder().decode(WatchActions.self, from: messageData) {
|
||||||
|
|||||||
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,14 +2,18 @@
|
|||||||
"id": 21,
|
"id": 21,
|
||||||
"name": "Ipad",
|
"name": "Ipad",
|
||||||
"description": "description",
|
"description": "description",
|
||||||
|
"supersets": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
"exercises": [
|
"exercises": [
|
||||||
{
|
{
|
||||||
"workout": 21,
|
"id": 1,
|
||||||
"exercise": {
|
"exercise": {
|
||||||
"id": 520,
|
"id": 520,
|
||||||
"muscles": [
|
"muscles": [
|
||||||
{
|
{
|
||||||
"id": 7264,
|
"id": 7264,
|
||||||
|
"name": "hip flexor",
|
||||||
"created_at": "2023-06-14T17:05:39.760515Z",
|
"created_at": "2023-06-14T17:05:39.760515Z",
|
||||||
"updated_at": "2023-06-14T17:05:39.761372Z",
|
"updated_at": "2023-06-14T17:05:39.761372Z",
|
||||||
"exercise": 520,
|
"exercise": 520,
|
||||||
@@ -17,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 7265,
|
"id": 7265,
|
||||||
|
"name": "glutes",
|
||||||
"created_at": "2023-06-14T17:05:39.762342Z",
|
"created_at": "2023-06-14T17:05:39.762342Z",
|
||||||
"updated_at": "2023-06-14T17:05:39.762814Z",
|
"updated_at": "2023-06-14T17:05:39.762814Z",
|
||||||
"exercise": 520,
|
"exercise": 520,
|
||||||
@@ -26,6 +31,7 @@
|
|||||||
"equipment": [
|
"equipment": [
|
||||||
{
|
{
|
||||||
"id": 941,
|
"id": 941,
|
||||||
|
"name": "Wall",
|
||||||
"created_at": "2023-06-13T02:28:04.289213Z",
|
"created_at": "2023-06-13T02:28:04.289213Z",
|
||||||
"updated_at": "2023-06-13T02:28:04.290354Z",
|
"updated_at": "2023-06-13T02:28:04.290354Z",
|
||||||
"exercise": 520,
|
"exercise": 520,
|
||||||
@@ -52,101 +58,152 @@
|
|||||||
"muscle_groups": "hip flexor,glutes",
|
"muscle_groups": "hip flexor,glutes",
|
||||||
"synonyms": ""
|
"synonyms": ""
|
||||||
},
|
},
|
||||||
"weight": 0,
|
"created_at": "2023-07-17T18:56:36.984049Z",
|
||||||
"reps": 0,
|
"updated_at": "2023-07-17T19:06:00.534838Z",
|
||||||
"duration": null,
|
"weight": null,
|
||||||
"duration_audio": null,
|
"reps": null,
|
||||||
"weight_audio": "/media/quantities_audio/for_0_pounds.m4a",
|
"duration": 30,
|
||||||
"created_at": "2023-06-20T21:03:00.127620Z"
|
"order": 1,
|
||||||
|
"superset": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"workout": 21,
|
"id": 2,
|
||||||
"exercise": {
|
"exercise": {
|
||||||
"id": 37,
|
"id": 992,
|
||||||
"muscles": [
|
"muscles": [
|
||||||
{
|
{
|
||||||
"id": 7272,
|
"id": 7270,
|
||||||
"created_at": "2023-06-14T17:05:39.772195Z",
|
"name": "hamstrings",
|
||||||
"updated_at": "2023-06-14T17:05:39.772765Z",
|
"created_at": "2023-06-14T17:05:39.769351Z",
|
||||||
"exercise": 37,
|
"updated_at": "2023-06-14T17:05:39.769758Z",
|
||||||
"muscle": 4
|
"exercise": 992,
|
||||||
|
"muscle": 6
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 7273,
|
"id": 7271,
|
||||||
"created_at": "2023-06-14T17:05:39.773621Z",
|
"name": "glutes",
|
||||||
"updated_at": "2023-06-14T17:05:39.774079Z",
|
"created_at": "2023-06-14T17:05:39.770480Z",
|
||||||
"exercise": 37,
|
"updated_at": "2023-06-14T17:05:39.771111Z",
|
||||||
"muscle": 6
|
"exercise": 992,
|
||||||
|
"muscle": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"equipment": [
|
"equipment": [
|
||||||
{
|
{
|
||||||
"id": 945,
|
"id": 944,
|
||||||
"created_at": "2023-06-13T02:28:04.295672Z",
|
"name": "Dumbbell",
|
||||||
"updated_at": "2023-06-13T02:28:04.296237Z",
|
"created_at": "2023-06-13T02:28:04.294180Z",
|
||||||
"exercise": 37,
|
"updated_at": "2023-06-13T02:28:04.294658Z",
|
||||||
"equipment": 1088
|
"exercise": 992,
|
||||||
|
"equipment": 1091
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"audio_url": "exercise_audio/2_Kettlebell_Clean.m4a",
|
"audio_url": "exercise_audio/2_Dumbbell_Single-Leg_Deadlift.m4a",
|
||||||
"video_url": "exercise_videos/2_Kettlebell_Clean.mp4",
|
"video_url": "exercise_videos/2_Dumbbell_Single-Leg_Deadlift.mp4",
|
||||||
"created_at": "2023-06-11T22:50:18.813591Z",
|
"created_at": "2023-06-11T22:50:19.197099Z",
|
||||||
"updated_at": "2023-06-11T22:50:18.813600Z",
|
"updated_at": "2023-06-11T22:50:19.197105Z",
|
||||||
"name": "2 Kettlebell Clean",
|
"name": "2 Dumbbell Single-Leg Deadlift",
|
||||||
"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.",
|
"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": "",
|
"side": "right_leg",
|
||||||
"is_two_dumbbells": false,
|
"is_two_dumbbells": true,
|
||||||
"is_trackable_distance": false,
|
"is_trackable_distance": false,
|
||||||
"is_alternating": false,
|
"is_alternating": false,
|
||||||
"is_weight": true,
|
"is_weight": true,
|
||||||
"is_distance": false,
|
"is_distance": false,
|
||||||
"is_duration": true,
|
"is_duration": true,
|
||||||
"is_reps": true,
|
"is_reps": true,
|
||||||
"joints_used": "shoulder,ankle,knee,hip,elbow",
|
"joints_used": "ankle,lumbar spine,hip,knee,wrist",
|
||||||
"movement_patterns": "lower pull - hip hinge,upper pull",
|
"movement_patterns": "lower pull,lower pull - hip hinge",
|
||||||
"equipment_required": "Kettlebell",
|
"equipment_required": "Dumbbell",
|
||||||
"muscle_groups": "glutes,hamstrings",
|
"muscle_groups": "hamstrings,glutes",
|
||||||
"synonyms": ""
|
"synonyms": "2 Dumbbell Single Leg Deadlift"
|
||||||
},
|
},
|
||||||
"weight": 0,
|
"created_at": "2023-07-17T18:56:36.984523Z",
|
||||||
"reps": 0,
|
"updated_at": "2023-07-17T19:06:00.535334Z",
|
||||||
|
"weight": 30,
|
||||||
|
"reps": null,
|
||||||
"duration": null,
|
"duration": null,
|
||||||
"duration_audio": null,
|
"order": 2,
|
||||||
"weight_audio": "/media/quantities_audio/for_0_pounds.m4a",
|
"superset": 1
|
||||||
"created_at": "2023-06-20T21:03:00.131018Z"
|
}
|
||||||
|
],
|
||||||
|
"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,
|
||||||
|
"exercises": [
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
"exercise": {
|
"exercise": {
|
||||||
"id": 798,
|
"id": 992,
|
||||||
"muscles": [],
|
"muscles": [
|
||||||
"equipment": [],
|
{
|
||||||
"audio_url": "exercise_audio/Recover.m4a",
|
"id": 7270,
|
||||||
"video_url": "exercise_videos/Recover.mp4",
|
"name": "hamstrings",
|
||||||
"created_at": "2023-06-11T22:50:19.127914Z",
|
"created_at": "2023-06-14T17:05:39.769351Z",
|
||||||
"updated_at": "2023-06-11T22:50:19.127921Z",
|
"updated_at": "2023-06-14T17:05:39.769758Z",
|
||||||
"name": "Recover",
|
"exercise": 992,
|
||||||
"description": "Use this time to catch your breath. It will help you get more out of what's next",
|
"muscle": 6
|
||||||
"side": "",
|
},
|
||||||
"is_two_dumbbells": false,
|
{
|
||||||
|
"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_trackable_distance": false,
|
||||||
"is_alternating": false,
|
"is_alternating": false,
|
||||||
"is_weight": false,
|
"is_weight": true,
|
||||||
"is_distance": false,
|
"is_distance": false,
|
||||||
"is_duration": true,
|
"is_duration": true,
|
||||||
"is_reps": false,
|
"is_reps": true,
|
||||||
"joints_used": "",
|
"joints_used": "ankle,lumbar spine,hip,knee,wrist",
|
||||||
"movement_patterns": "",
|
"movement_patterns": "lower pull,lower pull - hip hinge",
|
||||||
"equipment_required": "",
|
"equipment_required": "Dumbbell",
|
||||||
"muscle_groups": "",
|
"muscle_groups": "hamstrings,glutes",
|
||||||
"synonyms": null
|
"synonyms": "2 Dumbbell Single Leg Deadlift"
|
||||||
},
|
},
|
||||||
"weight": 0,
|
"created_at": "2023-07-17T18:58:35.585418Z",
|
||||||
"reps": 0,
|
"updated_at": "2023-07-17T18:58:35.585435Z",
|
||||||
|
"weight": 11,
|
||||||
|
"reps": null,
|
||||||
"duration": null,
|
"duration": null,
|
||||||
"duration_audio": null,
|
"order": 1,
|
||||||
"weight_audio": "/media/quantities_audio/for_0_pounds.m4a",
|
"superset": 2
|
||||||
"created_at": "2023-06-20T21:03:00.134981Z"
|
}
|
||||||
|
],
|
||||||
|
"created_at": "2023-07-17T18:58:35.584036Z",
|
||||||
|
"updated_at": "2023-07-17T19:03:57.175639Z",
|
||||||
|
"name": "two",
|
||||||
|
"rounds": 3,
|
||||||
|
"order": 2,
|
||||||
|
"workout": 21
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"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 {
|
||||||
@@ -27,7 +28,7 @@ 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 currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
if let videoURL = VideoURLCreator.videoURL(
|
if let videoURL = VideoURLCreator.videoURL(
|
||||||
thotStyle: thotStyle,
|
thotStyle: thotStyle,
|
||||||
defaultVideoURLStr: bridgeModule.currentExercise?.exercise.videoURL,
|
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||||
exerciseName: bridgeModule.currentExercise?.exercise.name,
|
exerciseName: currentExtercise.exercise.name,
|
||||||
workout: bridgeModule.currentWorkout) {
|
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||||
avPlayer = AVPlayer(url: videoURL)
|
avPlayer = AVPlayer(url: videoURL)
|
||||||
avPlayer.play()
|
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,32 +94,59 @@ 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 {
|
||||||
|
if let supersets = workout.supersets {
|
||||||
ScrollViewReader { proxy in
|
ScrollViewReader { proxy in
|
||||||
List() {
|
List() {
|
||||||
ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in
|
ForEach(supersets.indices, id: \.self) { supersetIndex in
|
||||||
let obj = workout.exercisesSortedByCreated_at[i]
|
let superset = supersets[supersetIndex]
|
||||||
|
|
||||||
|
Section(content: {
|
||||||
|
ForEach(superset.exercises.indices, id: \.self) { exerciseIndex in
|
||||||
|
let supersetExecercise = superset.exercises[exerciseIndex]
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
if i == currentExerciseIdx {
|
if supersetExecercise.id == currentExercise.id {
|
||||||
Image(systemName: "checkmark")
|
Image(systemName: "checkmark")
|
||||||
|
.foregroundColor(.green)
|
||||||
.font(Font.system(size: 55))
|
.font(Font.system(size: 55))
|
||||||
.minimumScaleFactor(0.01)
|
.minimumScaleFactor(0.01)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.foregroundColor(.green)
|
.foregroundColor(.green)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(obj.exercise.name)
|
Text(supersetExecercise.exercise.name)
|
||||||
|
.id(exerciseIndex)
|
||||||
.font(Font.system(size: 55))
|
.font(Font.system(size: 55))
|
||||||
.minimumScaleFactor(0.01)
|
.minimumScaleFactor(0.01)
|
||||||
.lineLimit(3)
|
.lineLimit(3)
|
||||||
.padding()
|
.padding()
|
||||||
.id(i)
|
.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: currentExerciseIdx, perform: { newValue in
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onChange(of: currentExercise, perform: { newValue in
|
||||||
withAnimation {
|
withAnimation {
|
||||||
proxy.scrollTo(newValue, anchor: .top)
|
proxy.scrollTo(newValue, anchor: .top)
|
||||||
}
|
}
|
||||||
@@ -124,6 +154,7 @@ struct ExtExerciseList: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ExtCountdownView: View {
|
struct ExtCountdownView: View {
|
||||||
@StateObject var bridgeModule = BridgeModule.shared
|
@StateObject var bridgeModule = BridgeModule.shared
|
||||||
@@ -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,22 +28,27 @@ struct ExerciseListView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
if let supersets = workout.supersets {
|
||||||
ScrollViewReader { proxy in
|
ScrollViewReader { proxy in
|
||||||
List() {
|
List() {
|
||||||
ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in
|
ForEach(supersets.indices, id: \.self) { supersetIndex in
|
||||||
let obj = workout.exercisesSortedByCreated_at[i]
|
let superset = supersets[supersetIndex]
|
||||||
|
Section(content: {
|
||||||
|
ForEach(superset.exercises.indices, id: \.self) { exerciseIndex in
|
||||||
|
let supersetExecercise = superset.exercises[exerciseIndex]
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
if i == bridgeModule.currentExerciseIdx {
|
if supersetExecercise.id == bridgeModule.currentExerciseInfo.currentExercise?.id {
|
||||||
Image(systemName: "checkmark")
|
Image(systemName: "checkmark")
|
||||||
.foregroundColor(.green)
|
.foregroundColor(.green)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(obj.exercise.name)
|
Text(supersetExecercise.exercise.name)
|
||||||
.id(i)
|
.id(exerciseIndex)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if let reps = obj.reps,
|
if let reps = supersetExecercise.reps,
|
||||||
reps > 0 {
|
reps > 0 {
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: "number")
|
Image(systemName: "number")
|
||||||
@@ -62,7 +67,7 @@ struct ExerciseListView: View {
|
|||||||
.frame(alignment: .trailing)
|
.frame(alignment: .trailing)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let duration = obj.duration,
|
if let duration = supersetExecercise.duration,
|
||||||
duration > 0 {
|
duration > 0 {
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: "stopwatch")
|
Image(systemName: "stopwatch")
|
||||||
@@ -83,18 +88,15 @@ struct ExerciseListView: View {
|
|||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if bridgeModule.isInWorkout {
|
if bridgeModule.isInWorkout {
|
||||||
bridgeModule.goToExerciseAt(index: i)
|
bridgeModule.goToExerciseAt(section: supersetIndex, row: exerciseIndex)
|
||||||
} else {
|
} else {
|
||||||
videoExercise = obj.exercise
|
// videoExercise = obj.exercise
|
||||||
}
|
}
|
||||||
}
|
// .onChange(of: bridgeModule.currentExerciseIdx, perform: { newValue in
|
||||||
}
|
// withAnimation {
|
||||||
}
|
// proxy.scrollTo(newValue, anchor: .top)
|
||||||
.onChange(of: bridgeModule.currentExerciseIdx, perform: { newValue in
|
// }
|
||||||
withAnimation {
|
// })
|
||||||
proxy.scrollTo(newValue, anchor: .top)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
.sheet(item: $videoExercise) { exercise in
|
.sheet(item: $videoExercise) { exercise in
|
||||||
PlayerView(player: $avPlayer)
|
PlayerView(player: $avPlayer)
|
||||||
@@ -103,6 +105,22 @@ struct ExerciseListView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, header: {
|
||||||
|
HStack {
|
||||||
|
Text(superset.name ?? "--")
|
||||||
|
.foregroundColor(Color("appColor"))
|
||||||
|
.bold()
|
||||||
|
Spacer()
|
||||||
|
Text("\(superset.rounds) rounds")
|
||||||
|
.foregroundColor(Color("appColor"))
|
||||||
|
.bold()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExerciseListView_Previews: PreviewProvider {
|
struct ExerciseListView_Previews: PreviewProvider {
|
||||||
|
|||||||
@@ -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,25 +100,29 @@ struct WorkoutDetailView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: bridgeModule.currentExercise, perform: { newValue in
|
.onChange(of: bridgeModule.currentExerciseInfo.exerciseIndex, perform: { newValue in
|
||||||
|
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
if let videoURL = VideoURLCreator.videoURL(
|
if let videoURL = VideoURLCreator.videoURL(
|
||||||
thotStyle: thotStyle,
|
thotStyle: thotStyle,
|
||||||
defaultVideoURLStr: newValue?.exercise.videoURL,
|
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||||
exerciseName: newValue?.exercise.name,
|
exerciseName: currentExtercise.exercise.name,
|
||||||
workout: bridgeModule.currentWorkout) {
|
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||||
avPlayer = AVPlayer(url: videoURL)
|
avPlayer = AVPlayer(url: videoURL)
|
||||||
avPlayer.play()
|
avPlayer.play()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.onAppear{
|
.onAppear{
|
||||||
|
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||||
if let videoURL = VideoURLCreator.videoURL(
|
if let videoURL = VideoURLCreator.videoURL(
|
||||||
thotStyle: thotStyle,
|
thotStyle: thotStyle,
|
||||||
defaultVideoURLStr: bridgeModule.currentExercise?.exercise.videoURL,
|
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||||
exerciseName: bridgeModule.currentExercise?.exercise.name,
|
exerciseName: currentExtercise.exercise.name,
|
||||||
workout: bridgeModule.currentWorkout) {
|
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||||
avPlayer = AVPlayer(url: videoURL)
|
avPlayer = AVPlayer(url: videoURL)
|
||||||
avPlayer.play()
|
avPlayer.play()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bridgeModule.completedWorkout = {
|
bridgeModule.completedWorkout = {
|
||||||
if let workoutData = createWorkoutData() {
|
if let workoutData = createWorkoutData() {
|
||||||
@@ -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