WIP
This commit is contained in:
@@ -17,6 +17,10 @@
|
||||
1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A822A42347D0042FFBD /* Extensions.swift */; };
|
||||
1C4AFF152A60F25F0027710B /* 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 */; };
|
||||
1C5190C42A589CAC00885849 /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C32A589CAC00885849 /* InfoView.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -269,6 +275,7 @@
|
||||
1CF65A822A42347D0042FFBD /* Extensions.swift */,
|
||||
1CF65A272A3972840042FFBD /* Persistence.swift */,
|
||||
1CD0C6662A5CA19600970E52 /* BaseURLs.swift */,
|
||||
1C4AFF1A2A65FB190027710B /* CurrentWorkoutInfo.swift */,
|
||||
1CF65A4F2A3A1EA90042FFBD /* BridgeModule.swift */,
|
||||
1CF65A802A412AA30042FFBD /* DataStore.swift */,
|
||||
1CF65AB92A4894430042FFBD /* UserStore.swift */,
|
||||
@@ -314,6 +321,7 @@
|
||||
1CAF4D892A5132F900B00E50 /* PlannedWorkout.swift */,
|
||||
1CF65A462A39FB6C0042FFBD /* RegisteredUser.swift */,
|
||||
1CF65A422A39FB410042FFBD /* Workout.swift */,
|
||||
1C4AFF172A65CD290027710B /* Superset.swift */,
|
||||
);
|
||||
path = APIModels;
|
||||
sourceTree = "<group>";
|
||||
@@ -583,6 +591,7 @@
|
||||
1CF65A852A43E8060042FFBD /* CompletedWorkout.swift in Sources */,
|
||||
1CF65A6E2A3F60480042FFBD /* CreateViewModels.swift in Sources */,
|
||||
1CF65A4C2A39FDA20042FFBD /* WorkoutDetailView.swift in Sources */,
|
||||
1C4AFF182A65CD290027710B /* Superset.swift in Sources */,
|
||||
1CF65A8E2A44B78B0042FFBD /* CompletedWorkoutView.swift in Sources */,
|
||||
1CF65A432A39FB410042FFBD /* Workout.swift in Sources */,
|
||||
1CF65A502A3A1EA90042FFBD /* BridgeModule.swift in Sources */,
|
||||
@@ -597,6 +606,7 @@
|
||||
1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */,
|
||||
1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */,
|
||||
1C485C8A2A492BB400A6F896 /* LoginView.swift in Sources */,
|
||||
1C4AFF1B2A65FB190027710B /* CurrentWorkoutInfo.swift in Sources */,
|
||||
1CF65A732A3F60D20042FFBD /* CreateExerciseActionsView.swift in Sources */,
|
||||
1CF65A832A42347D0042FFBD /* Extensions.swift in Sources */,
|
||||
1CF65A282A3972840042FFBD /* Persistence.swift in Sources */,
|
||||
@@ -619,6 +629,7 @@
|
||||
files = (
|
||||
1CF65A982A452D270042FFBD /* ContentView.swift in Sources */,
|
||||
1CF65A962A452D270042FFBD /* Werkout_watchApp.swift in Sources */,
|
||||
1C4AFF192A65CD6F0027710B /* Superset.swift in Sources */,
|
||||
1CF65AA92A452D9C0042FFBD /* Workout.swift in Sources */,
|
||||
1CF65AA62A452D9C0042FFBD /* Equipment.swift in Sources */,
|
||||
1C4AFF162A60F27E0027710B /* ThotStyle.swift in Sources */,
|
||||
@@ -627,6 +638,7 @@
|
||||
1CF65AB62A4532940042FFBD /* WatchMainViewModel.swift in Sources */,
|
||||
1CD0C6682A5CA1A200970E52 /* BaseURLs.swift in Sources */,
|
||||
1CF65AA72A452D9C0042FFBD /* Muscle.swift in Sources */,
|
||||
1C4AFF1C2A65FB2B0027710B /* CurrentWorkoutInfo.swift in Sources */,
|
||||
1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */,
|
||||
1CF65AAB2A452DAC0042FFBD /* PreviewData.swift in Sources */,
|
||||
1CF65AA52A452D9C0042FFBD /* CompletedWorkout.swift in Sources */,
|
||||
|
||||
@@ -6,28 +6,18 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Equipment: Codable {
|
||||
let id: Int
|
||||
let createdAt, updatedAt: String
|
||||
let category, name: String?
|
||||
let name, createdAt, updatedAt: String
|
||||
let is_weight: Bool?
|
||||
let category: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case id, name
|
||||
case createdAt = "created_at"
|
||||
case updatedAt = "updated_at"
|
||||
case category, name
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
case is_weight
|
||||
case category
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,32 +7,39 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct ExerciseElement: Codable, Equatable {
|
||||
let workout: Int
|
||||
let exercise: ExerciseExercise
|
||||
struct SupersetExercise: Identifiable, Codable, Equatable, Hashable {
|
||||
var id = UUID()
|
||||
|
||||
let workout: Int?
|
||||
let exercise: Exercise
|
||||
let weight: Int?
|
||||
let reps: Int?
|
||||
let duration: Int?
|
||||
let durationAudio: String?
|
||||
let weightAudio: String?
|
||||
let createdAt: String
|
||||
let order, superset: Int
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case workout, exercise, weight, reps, duration
|
||||
case workout, exercise, weight, reps, duration, order, superset
|
||||
case durationAudio = "duration_audio"
|
||||
case weightAudio = "weight_audio"
|
||||
case createdAt = "created_at"
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
return hasher.combine(id)
|
||||
}
|
||||
}
|
||||
|
||||
struct ExerciseExercise: Codable, Hashable, Identifiable {
|
||||
static func == (lhs: ExerciseExercise, rhs: ExerciseExercise) -> Bool {
|
||||
struct Exercise: Identifiable, Codable, Equatable {
|
||||
static func == (lhs: Exercise, rhs: Exercise) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
|
||||
let id: Int
|
||||
let muscles: [ExerciseMuscle]
|
||||
let equipment: [ExerciseEquipment]
|
||||
let equipment: [Equipment]
|
||||
let muscles: [Muscle]
|
||||
let audioURL, videoURL, createdAt, updatedAt: String
|
||||
let name, description, side: String
|
||||
let isTwoDumbbells, isTrackableDistance, isAlternating, isWeight: Bool
|
||||
|
||||
@@ -9,18 +9,11 @@ import Foundation
|
||||
|
||||
struct Muscle: Codable {
|
||||
let id: Int
|
||||
let name: String
|
||||
}
|
||||
|
||||
struct ExerciseMuscle: Codable, Hashable {
|
||||
let id: Int
|
||||
let createdAt, updatedAt: String
|
||||
let exercise, muscle: Int
|
||||
let name, createdAt, updatedAt: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case id, name
|
||||
case createdAt = "created_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 name: String
|
||||
let description: String?
|
||||
let exercises: [ExerciseElement]
|
||||
let supersets: [Superset]?
|
||||
let registeredUser: RegisteredUser?
|
||||
let femaleVideos, maleVideos, bothVideos: [String]?
|
||||
let muscles: [String]?
|
||||
let equipment: [String]?
|
||||
let exercise_count: Int?
|
||||
let maleVideos: [String]?
|
||||
let femaleVideos: [String]?
|
||||
let bothVideos: [String]?
|
||||
|
||||
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 maleVideos = "male_videos"
|
||||
case femaleVideos = "female_videos"
|
||||
@@ -34,31 +32,18 @@ struct Workout: Codable, Identifiable, Equatable {
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
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.registeredUser = try container.decodeIfPresent(RegisteredUser.self, forKey: .registeredUser)
|
||||
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.maleVideos = try container.decodeIfPresent([String].self, forKey: .maleVideos)
|
||||
self.bothVideos = try container.decodeIfPresent([String].self, forKey: .bothVideos)
|
||||
}
|
||||
|
||||
var exercisesSortedByCreated_at: [ExerciseElement] {
|
||||
return self.exercises.sorted(by: {
|
||||
if let lhsDate = $0.createdAt.dateFromServerDate,
|
||||
let rhsDate = $1.createdAt.dateFromServerDate {
|
||||
return lhsDate < rhsDate
|
||||
}
|
||||
return false
|
||||
})
|
||||
self.supersets = try container.decodeIfPresent([Superset].self, forKey: .supersets)
|
||||
|
||||
self.equipment = try container.decodeIfPresent([String].self, forKey: .equipment)
|
||||
self.muscles = try container.decodeIfPresent([String].self, forKey: .muscles)
|
||||
self.exercise_count = try container.decodeIfPresent(Int.self, forKey: .exercise_count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ enum BaseURLs: String {
|
||||
case dev = "https://dev.werkout.fitness"
|
||||
|
||||
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
|
||||
private var currentWorkoutRunTimer: Timer?
|
||||
|
||||
var currentWorkout: Workout?
|
||||
public private(set) var workoutStartDate: Date?
|
||||
|
||||
private var currentExerciseTimer: Timer?
|
||||
public private(set) var currentExerciseIdx: Int = -1 {
|
||||
didSet {
|
||||
self.currentExercisePositionString = "\(self.currentExerciseIdx+1)/\(self.currentWorkout?.exercises.count ?? 0)"
|
||||
}
|
||||
}
|
||||
|
||||
@Published public private(set) var currentExerciseInfo = CurrentWorkoutInfo()
|
||||
@Published var previewWorkout: Workout?
|
||||
|
||||
@Published var currentExerciseTimeLeft: Int = 0
|
||||
@Published var currentExercise: ExerciseElement?
|
||||
var currentExercisePositionString: String?
|
||||
|
||||
private var isWatchConnected = false
|
||||
@@ -59,33 +56,33 @@ class BridgeModule: NSObject, ObservableObject {
|
||||
var audioPlayer: AVAudioPlayer?
|
||||
|
||||
func start(workout: Workout) {
|
||||
self.currentWorkout = workout
|
||||
currentExerciseInfo.complete = {
|
||||
self.completeWorkout()
|
||||
}
|
||||
|
||||
currentExerciseInfo.start(workout: workout)
|
||||
currentWorkoutRunTimeInSeconds = 0
|
||||
currentWorkoutRunTimer?.invalidate()
|
||||
currentWorkoutRunTimer = nil
|
||||
|
||||
currentExerciseIdx = 0
|
||||
let exercise = workout.exercises[currentExerciseIdx]
|
||||
updateCurrent(exercise: exercise)
|
||||
startWorkoutTimer()
|
||||
workoutStartDate = Date()
|
||||
isInWorkout = true
|
||||
|
||||
if WCSession.isSupported() {
|
||||
WCSession.default.delegate = self
|
||||
WCSession.default.activate()
|
||||
if let superetExercise = currentExerciseInfo.currentExercise {
|
||||
updateCurrent(exercise: superetExercise)
|
||||
startWorkoutTimer()
|
||||
workoutStartDate = Date()
|
||||
isInWorkout = true
|
||||
|
||||
if WCSession.isSupported() {
|
||||
WCSession.default.delegate = self
|
||||
WCSession.default.activate()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func goToExerciseAt(index: Int) {
|
||||
guard let currentWorkout = currentWorkout else {
|
||||
return
|
||||
func goToExerciseAt(section: Int, row: Int) {
|
||||
if let superetExercise = currentExerciseInfo.goToWorkoutAt(supersetIndex: section,
|
||||
exerciseIndex: row) {
|
||||
updateCurrent(exercise: superetExercise)
|
||||
}
|
||||
|
||||
currentExerciseIdx = index
|
||||
let exercise = currentWorkout.exercises[index]
|
||||
updateCurrent(exercise: exercise)
|
||||
}
|
||||
|
||||
func resetCurrentWorkout() {
|
||||
@@ -98,11 +95,8 @@ class BridgeModule: NSObject, ObservableObject {
|
||||
self.currentExerciseTimer = nil
|
||||
|
||||
self.currentWorkoutRunTimeInSeconds = -1
|
||||
self.currentExerciseIdx = -1
|
||||
|
||||
self.currentExercise = nil
|
||||
self.currentWorkout = nil
|
||||
|
||||
self.currentExerciseInfo.reset()
|
||||
|
||||
self.isInWorkout = false
|
||||
self.workoutStartDate = nil
|
||||
self.workoutEndDate = nil
|
||||
@@ -162,38 +156,24 @@ class BridgeModule: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
func nextExercise() {
|
||||
currentExerciseIdx += 1
|
||||
if let currentWorkout = currentWorkout {
|
||||
if currentExerciseIdx < currentWorkout.exercises.count {
|
||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
||||
updateCurrent(exercise: nextExercise)
|
||||
} else {
|
||||
completeWorkout()
|
||||
}
|
||||
if let nextSupersetExercise = currentExerciseInfo.nextExercise {
|
||||
updateCurrent(exercise: nextSupersetExercise)
|
||||
} else {
|
||||
completeWorkout()
|
||||
}
|
||||
}
|
||||
|
||||
func previousExercise() {
|
||||
currentExerciseIdx -= 1
|
||||
if currentExerciseIdx < 0 {
|
||||
currentExerciseIdx = 0
|
||||
}
|
||||
if let currentWorkout = currentWorkout {
|
||||
if currentExerciseIdx < currentWorkout.exercises.count {
|
||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
||||
updateCurrent(exercise: nextExercise)
|
||||
} else {
|
||||
completeWorkout()
|
||||
}
|
||||
if let nextSupersetExercise = currentExerciseInfo.previousExercise {
|
||||
updateCurrent(exercise: nextSupersetExercise)
|
||||
} else {
|
||||
completeWorkout()
|
||||
}
|
||||
}
|
||||
|
||||
func restartExercise() {
|
||||
if let currentWorkout = currentWorkout {
|
||||
if currentExerciseIdx < currentWorkout.exercises.count {
|
||||
let nextExercise = currentWorkout.exercises[currentExerciseIdx]
|
||||
updateCurrent(exercise: nextExercise)
|
||||
}
|
||||
if let currentExercise = currentExerciseInfo.currentExercise {
|
||||
updateCurrent(exercise: currentExercise)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,15 +181,12 @@ class BridgeModule: NSObject, ObservableObject {
|
||||
currentWorkoutRunTimeInSeconds += 1
|
||||
}
|
||||
|
||||
func updateCurrent(exercise: ExerciseElement) {
|
||||
func updateCurrent(exercise: SupersetExercise) {
|
||||
DispatchQueue.main.async {
|
||||
self.currentExerciseTimer?.invalidate()
|
||||
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.sendCurrentExerciseToWatch()
|
||||
@@ -281,25 +258,25 @@ extension BridgeModule: WCSessionDelegate {
|
||||
}
|
||||
|
||||
func sendCurrentExerciseToWatch() {
|
||||
if let duration = currentExercise?.duration,
|
||||
if let currentExercise = currentExerciseInfo.currentExercise,
|
||||
let duration = currentExercise.duration ,
|
||||
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 data = try! JSONEncoder().encode(model)
|
||||
send(data)
|
||||
} else {
|
||||
var intWatchDispaly = -1
|
||||
if let reps = self.currentExercise?.reps,
|
||||
if let currentExercise = currentExerciseInfo.currentExercise,
|
||||
let reps = currentExercise.reps,
|
||||
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 allMuscles: [Muscle]?
|
||||
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
|
||||
|
||||
|
||||
@@ -2,151 +2,208 @@
|
||||
"id": 21,
|
||||
"name": "Ipad",
|
||||
"description": "description",
|
||||
"exercises": [
|
||||
"supersets": [
|
||||
{
|
||||
"workout": 21,
|
||||
"exercise": {
|
||||
"id": 520,
|
||||
"muscles": [
|
||||
{
|
||||
"id": 7264,
|
||||
"created_at": "2023-06-14T17:05:39.760515Z",
|
||||
"updated_at": "2023-06-14T17:05:39.761372Z",
|
||||
"exercise": 520,
|
||||
"muscle": 16
|
||||
"id": 1,
|
||||
"exercises": [
|
||||
{
|
||||
"id": 1,
|
||||
"exercise": {
|
||||
"id": 520,
|
||||
"muscles": [
|
||||
{
|
||||
"id": 7264,
|
||||
"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": ""
|
||||
},
|
||||
{
|
||||
"id": 7265,
|
||||
"created_at": "2023-06-14T17:05:39.762342Z",
|
||||
"updated_at": "2023-06-14T17:05:39.762814Z",
|
||||
"exercise": 520,
|
||||
"muscle": 4
|
||||
}
|
||||
],
|
||||
"equipment": [
|
||||
{
|
||||
"id": 941,
|
||||
"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": ""
|
||||
},
|
||||
"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.127620Z"
|
||||
"created_at": "2023-07-17T18:56:36.984049Z",
|
||||
"updated_at": "2023-07-17T19:06:00.534838Z",
|
||||
"weight": null,
|
||||
"reps": null,
|
||||
"duration": 30,
|
||||
"order": 1,
|
||||
"superset": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"exercise": {
|
||||
"id": 992,
|
||||
"muscles": [
|
||||
{
|
||||
"id": 7270,
|
||||
"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: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,
|
||||
"exercise": {
|
||||
"id": 37,
|
||||
"muscles": [
|
||||
{
|
||||
"id": 7272,
|
||||
"created_at": "2023-06-14T17:05:39.772195Z",
|
||||
"updated_at": "2023-06-14T17:05:39.772765Z",
|
||||
"exercise": 37,
|
||||
"muscle": 4
|
||||
"id": 2,
|
||||
"exercises": [
|
||||
{
|
||||
"id": 3,
|
||||
"exercise": {
|
||||
"id": 992,
|
||||
"muscles": [
|
||||
{
|
||||
"id": 7270,
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"id": 7273,
|
||||
"created_at": "2023-06-14T17:05:39.773621Z",
|
||||
"updated_at": "2023-06-14T17:05:39.774079Z",
|
||||
"exercise": 37,
|
||||
"muscle": 6
|
||||
}
|
||||
],
|
||||
"equipment": [
|
||||
{
|
||||
"id": 945,
|
||||
"created_at": "2023-06-13T02:28:04.295672Z",
|
||||
"updated_at": "2023-06-13T02:28:04.296237Z",
|
||||
"exercise": 37,
|
||||
"equipment": 1088
|
||||
}
|
||||
],
|
||||
"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"
|
||||
"created_at": "2023-07-17T18:58:35.585418Z",
|
||||
"updated_at": "2023-07-17T18:58:35.585435Z",
|
||||
"weight": 11,
|
||||
"reps": null,
|
||||
"duration": null,
|
||||
"order": 1,
|
||||
"superset": 2
|
||||
}
|
||||
],
|
||||
"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": {
|
||||
|
||||
@@ -32,7 +32,7 @@ class AllEquipmentFetchable: Fetchable {
|
||||
}
|
||||
|
||||
class AllExerciseFetchable: Fetchable {
|
||||
typealias Response = [ExerciseExercise]
|
||||
typealias Response = [Exercise]
|
||||
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") {
|
||||
do {
|
||||
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
|
||||
} catch {
|
||||
print(error)
|
||||
|
||||
@@ -18,15 +18,15 @@ struct AddExerciseView: View {
|
||||
|
||||
@State var selectedMuscles = [Muscle]()
|
||||
@State var selectedEquipment = [Equipment]()
|
||||
@State var filteredExercises = [ExerciseExercise]()
|
||||
@State var filteredExercises = [Exercise]()
|
||||
|
||||
@StateObject var bridgeModule = BridgeModule.shared
|
||||
@Environment(\.dismiss) var dismiss
|
||||
var selectedExercise: ((ExerciseExercise) -> Void)
|
||||
var selectedExercise: ((Exercise) -> Void)
|
||||
@State var createWorkoutItemPickerViewModel: CreateWorkoutItemPickerViewModel?
|
||||
@State var createWorkoutItemPickerViewType: CreateWorkoutItemPickerViewType?
|
||||
@State var searchString: String = ""
|
||||
@State var videoExercise: ExerciseExercise? {
|
||||
@State var videoExercise: Exercise? {
|
||||
didSet {
|
||||
if let viddd = self.videoExercise?.videoURL,
|
||||
let url = URL(string: BaseURLs.currentBaseURL + viddd) {
|
||||
@@ -111,19 +111,19 @@ struct AddExerciseView: View {
|
||||
|
||||
func filterExercises() {
|
||||
if selectedMuscles.count == 0 {
|
||||
filteredExercises = [ExerciseExercise]()
|
||||
filteredExercises = [Exercise]()
|
||||
return
|
||||
}
|
||||
|
||||
if selectedEquipment.count == 0 {
|
||||
filteredExercises = [ExerciseExercise]()
|
||||
filteredExercises = [Exercise]()
|
||||
return
|
||||
}
|
||||
|
||||
guard let exercises = DataStore.shared.allExercise,
|
||||
let muscles = DataStore.shared.allMuscles,
|
||||
let equipment = DataStore.shared.allEquipment else {
|
||||
filteredExercises = [ExerciseExercise]()
|
||||
filteredExercises = [Exercise]()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ struct AddExerciseView: View {
|
||||
if selectedMuscles.count == muscles.count {
|
||||
hasCorrectMuscles = true
|
||||
} else {
|
||||
let exerciseMuscleIds = exercise.muscles.map({ $0.muscle })
|
||||
let exerciseMuscleIds = exercise.muscles.map({ $0.id })
|
||||
let selctedMuscleIds = selectedMuscles.map({ $0.id })
|
||||
// if one items match
|
||||
if exerciseMuscleIds.contains(where: selctedMuscleIds.contains) {
|
||||
@@ -146,7 +146,7 @@ struct AddExerciseView: View {
|
||||
if selectedEquipment.count == equipment.count {
|
||||
hasCorrectEquipment = true
|
||||
} else {
|
||||
let exerciseEquipmentIds = exercise.equipment.map({ $0.equipment })
|
||||
let exerciseEquipmentIds = exercise.equipment.map({ $0.id })
|
||||
let selctedEquipmentIds = selectedEquipment.map({ $0.id })
|
||||
// if one items match
|
||||
if exerciseEquipmentIds.contains(where: selctedEquipmentIds.contains) {
|
||||
@@ -198,7 +198,7 @@ struct AddExerciseView: View {
|
||||
var createWorkoutItemPickerModels = [CreateWorkoutItemPickerModel]()
|
||||
equipment.forEach({
|
||||
let model = CreateWorkoutItemPickerModel(id: $0.id,
|
||||
name: $0.name?.lowercased() ?? "-")
|
||||
name: $0.name.lowercased())
|
||||
createWorkoutItemPickerModels.append(model)
|
||||
})
|
||||
createWorkoutItemPickerModels = createWorkoutItemPickerModels.sorted(by: {
|
||||
|
||||
@@ -35,13 +35,13 @@ struct AllWorkoutsView: View {
|
||||
@State private var showWorkoutDetail = false
|
||||
@State private var selectedWorkout: Workout? {
|
||||
didSet {
|
||||
bridgeModule.currentWorkout = selectedWorkout
|
||||
bridgeModule.currentExerciseInfo.workout = selectedWorkout
|
||||
}
|
||||
}
|
||||
|
||||
@State private var selectedPlannedWorkout: Workout? {
|
||||
didSet {
|
||||
bridgeModule.currentWorkout = selectedPlannedWorkout
|
||||
bridgeModule.currentExerciseInfo.workout = selectedPlannedWorkout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ struct AllWorkoutsView: View {
|
||||
AllWorkoutPickerView(mainViews: MainViewTypes.allCases,
|
||||
selectedSegment: $selectedSegment,
|
||||
showCurrentWorkout: {
|
||||
selectedWorkout = bridgeModule.currentWorkout
|
||||
selectedWorkout = bridgeModule.currentExerciseInfo.workout
|
||||
})
|
||||
|
||||
switch selectedSegment {
|
||||
@@ -87,12 +87,13 @@ struct AllWorkoutsView: View {
|
||||
maybeUpdateShit()
|
||||
}
|
||||
.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)
|
||||
}
|
||||
.sheet(item: $selectedPlannedWorkout) { item in
|
||||
let viewModel = WorkoutDetailViewModel(workout: item)
|
||||
WorkoutDetailView(viewModel: viewModel, showAddToCalendar: false)
|
||||
let viewModel = WorkoutDetailViewModel(workout: item, isPreview: true)
|
||||
WorkoutDetailView(viewModel: viewModel)
|
||||
}
|
||||
.sheet(isPresented: $showLoginView) {
|
||||
LoginView(completion: {
|
||||
|
||||
@@ -9,12 +9,12 @@ import SwiftUI
|
||||
|
||||
class CreateWorkoutExercise: ObservableObject, Identifiable {
|
||||
let id = UUID()
|
||||
var exercise: ExerciseExercise
|
||||
var exercise: Exercise
|
||||
@Published var reps: Int = 0
|
||||
@Published var duration: 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.reps = reps
|
||||
self.duration = duration
|
||||
|
||||
@@ -15,7 +15,8 @@ struct ExternalWorkoutDetailView: View {
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if let workout = bridgeModule.currentWorkout {
|
||||
if let workout = bridgeModule.currentExerciseInfo.workout,
|
||||
let exercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||
GeometryReader { metrics in
|
||||
VStack {
|
||||
HStack {
|
||||
@@ -26,8 +27,8 @@ struct ExternalWorkoutDetailView: View {
|
||||
}
|
||||
|
||||
VStack {
|
||||
ExtExerciseList(workout: workout,
|
||||
currentExerciseIdx: bridgeModule.currentExerciseIdx)
|
||||
ExtExerciseList(workout: workout,
|
||||
currentExercise: exercise)
|
||||
|
||||
if let currentExercisePositionString = bridgeModule.currentExercisePositionString {
|
||||
Text(currentExercisePositionString)
|
||||
@@ -53,18 +54,20 @@ struct ExternalWorkoutDetailView: View {
|
||||
.scaledToFill()
|
||||
}
|
||||
}
|
||||
.onChange(of: bridgeModule.currentExercise, perform: { newValue in
|
||||
if let videoURL = VideoURLCreator.videoURL(
|
||||
thotStyle: thotStyle,
|
||||
defaultVideoURLStr: bridgeModule.currentExercise?.exercise.videoURL,
|
||||
exerciseName: bridgeModule.currentExercise?.exercise.name,
|
||||
workout: bridgeModule.currentWorkout) {
|
||||
avPlayer = AVPlayer(url: videoURL)
|
||||
avPlayer.play()
|
||||
.onChange(of: bridgeModule.currentExerciseInfo.exerciseIndex, perform: { newValue in
|
||||
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||
if let videoURL = VideoURLCreator.videoURL(
|
||||
thotStyle: thotStyle,
|
||||
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||
exerciseName: currentExtercise.exercise.name,
|
||||
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||
avPlayer = AVPlayer(url: videoURL)
|
||||
avPlayer.play()
|
||||
}
|
||||
}
|
||||
})
|
||||
.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 {
|
||||
HStack {
|
||||
if let workout = bridgeModule.currentWorkout {
|
||||
if let workout = bridgeModule.currentExerciseInfo.workout {
|
||||
Text(workout.name)
|
||||
.font(Font.system(size: 100))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@@ -91,36 +94,64 @@ struct TitleView: View {
|
||||
|
||||
struct ExtExerciseList: View {
|
||||
var workout: Workout
|
||||
var currentExerciseIdx: Int
|
||||
var currentExercise: SupersetExercise
|
||||
|
||||
var body: some View {
|
||||
ScrollViewReader { proxy in
|
||||
List() {
|
||||
ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in
|
||||
let obj = workout.exercisesSortedByCreated_at[i]
|
||||
HStack {
|
||||
if i == currentExerciseIdx {
|
||||
Image(systemName: "checkmark")
|
||||
.font(Font.system(size: 55))
|
||||
.minimumScaleFactor(0.01)
|
||||
.lineLimit(1)
|
||||
.foregroundColor(.green)
|
||||
}
|
||||
if let supersets = workout.supersets {
|
||||
ScrollViewReader { proxy in
|
||||
List() {
|
||||
ForEach(supersets.indices, id: \.self) { supersetIndex in
|
||||
let superset = supersets[supersetIndex]
|
||||
|
||||
Text(obj.exercise.name)
|
||||
.font(Font.system(size: 55))
|
||||
.minimumScaleFactor(0.01)
|
||||
.lineLimit(3)
|
||||
.padding()
|
||||
.id(i)
|
||||
Section(content: {
|
||||
ForEach(superset.exercises.indices, id: \.self) { exerciseIndex in
|
||||
let supersetExecercise = superset.exercises[exerciseIndex]
|
||||
|
||||
HStack {
|
||||
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 {
|
||||
GeometryReader { metrics in
|
||||
VStack {
|
||||
if let currenExercise = bridgeModule.currentExercise {
|
||||
if let currenExercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||
HStack {
|
||||
Text(currenExercise.exercise.name)
|
||||
.font(.system(size: 200))
|
||||
@@ -203,15 +234,15 @@ struct ExtCountdownView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct ExternalWorkoutDetailView_Previews: PreviewProvider {
|
||||
static var bridge = BridgeModule.shared
|
||||
|
||||
static var previews: some View {
|
||||
ExternalWorkoutDetailView().environmentObject({ () -> BridgeModule in
|
||||
let envObj = BridgeModule.shared
|
||||
envObj.currentWorkout = nil //PreviewData.workout()
|
||||
bridge.currentExercise = PreviewData.workout().exercisesSortedByCreated_at.first!
|
||||
return envObj
|
||||
}() )
|
||||
}
|
||||
}
|
||||
//struct ExternalWorkoutDetailView_Previews: PreviewProvider {
|
||||
// static var bridge = BridgeModule.shared
|
||||
//
|
||||
// static var previews: some View {
|
||||
// ExternalWorkoutDetailView().environmentObject({ () -> BridgeModule in
|
||||
// let envObj = BridgeModule.shared
|
||||
// envObj.currentWorkout = nil //PreviewData.workout()
|
||||
// bridge.currentExercise = PreviewData.workout().exercisesSortedByCreated_at.first!
|
||||
// return envObj
|
||||
// }() )
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -15,7 +15,7 @@ struct MainView: View {
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if let workout = workout {
|
||||
let vm = WorkoutDetailViewModel(workout: workout)
|
||||
let vm = WorkoutDetailViewModel(workout: workout, isPreview: true)
|
||||
WorkoutDetailView(viewModel: vm)
|
||||
} else {
|
||||
Text("no workout selected")
|
||||
|
||||
@@ -11,7 +11,7 @@ struct CountdownView: View {
|
||||
@StateObject var bridgeModule = BridgeModule.shared
|
||||
|
||||
var body: some View {
|
||||
if let duration = bridgeModule.currentExercise?.duration,
|
||||
if let duration = bridgeModule.currentExerciseInfo.currentExercise?.duration,
|
||||
duration > 0 {
|
||||
HStack {
|
||||
if bridgeModule.currentExerciseTimeLeft >= 0 && duration > bridgeModule.currentExerciseTimeLeft {
|
||||
|
||||
@@ -11,16 +11,16 @@ import AVKit
|
||||
struct ExerciseListView: View {
|
||||
@AppStorage("thotStyle") private var thotStyle: ThotStyle = .never
|
||||
@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")!)
|
||||
var workout: Workout
|
||||
|
||||
@State var videoExercise: ExerciseExercise? {
|
||||
@State var videoExercise: Exercise? {
|
||||
didSet {
|
||||
if let videoURL = VideoURLCreator.videoURL(
|
||||
thotStyle: thotStyle,
|
||||
defaultVideoURLStr: self.videoExercise?.videoURL,
|
||||
exerciseName: self.videoExercise?.name,
|
||||
workout: bridgeModule.currentWorkout) {
|
||||
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||
avPlayer = AVPlayer(url: videoURL)
|
||||
avPlayer.play()
|
||||
}
|
||||
@@ -28,79 +28,97 @@ struct ExerciseListView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ScrollViewReader { proxy in
|
||||
List() {
|
||||
ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in
|
||||
let obj = workout.exercisesSortedByCreated_at[i]
|
||||
HStack {
|
||||
if i == bridgeModule.currentExerciseIdx {
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.green)
|
||||
}
|
||||
|
||||
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)
|
||||
if let supersets = workout.supersets {
|
||||
ScrollViewReader { proxy in
|
||||
List() {
|
||||
ForEach(supersets.indices, id: \.self) { supersetIndex in
|
||||
let superset = supersets[supersetIndex]
|
||||
Section(content: {
|
||||
ForEach(superset.exercises.indices, id: \.self) { exerciseIndex in
|
||||
let supersetExecercise = superset.exercises[exerciseIndex]
|
||||
|
||||
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)
|
||||
.padding([.leading], 10)
|
||||
.padding([.trailing], 15)
|
||||
.background(.blue)
|
||||
.cornerRadius(5, corners: [.topLeft, .bottomLeft])
|
||||
.frame(alignment: .trailing)
|
||||
}
|
||||
|
||||
if let duration = obj.duration,
|
||||
duration > 0 {
|
||||
}, header: {
|
||||
HStack {
|
||||
Image(systemName: "stopwatch")
|
||||
.foregroundColor(.white)
|
||||
.frame(width: 20, alignment: .leading)
|
||||
Text("\(duration)")
|
||||
.foregroundColor(.white)
|
||||
.frame(width: 30, alignment: .trailing)
|
||||
Text(superset.name ?? "--")
|
||||
.foregroundColor(Color("appColor"))
|
||||
.bold()
|
||||
Spacer()
|
||||
Text("\(superset.rounds) rounds")
|
||||
.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 workoutToPlan: Workout?
|
||||
var showAddToCalendar = true
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
@@ -80,7 +79,7 @@ struct WorkoutDetailView: View {
|
||||
bridgeModule.completeWorkout()
|
||||
}, planWorkout: { workout in
|
||||
workoutToPlan = workout
|
||||
}, workout: workout, showAddToCalendar: showAddToCalendar)
|
||||
}, workout: workout, showAddToCalendar: viewModel.isPreview)
|
||||
.frame(height: 44)
|
||||
|
||||
}
|
||||
@@ -101,24 +100,28 @@ struct WorkoutDetailView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: bridgeModule.currentExercise, perform: { newValue in
|
||||
if let videoURL = VideoURLCreator.videoURL(
|
||||
thotStyle: thotStyle,
|
||||
defaultVideoURLStr: newValue?.exercise.videoURL,
|
||||
exerciseName: newValue?.exercise.name,
|
||||
workout: bridgeModule.currentWorkout) {
|
||||
avPlayer = AVPlayer(url: videoURL)
|
||||
avPlayer.play()
|
||||
.onChange(of: bridgeModule.currentExerciseInfo.exerciseIndex, perform: { newValue in
|
||||
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||
if let videoURL = VideoURLCreator.videoURL(
|
||||
thotStyle: thotStyle,
|
||||
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||
exerciseName: currentExtercise.exercise.name,
|
||||
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||
avPlayer = AVPlayer(url: videoURL)
|
||||
avPlayer.play()
|
||||
}
|
||||
}
|
||||
})
|
||||
.onAppear{
|
||||
if let videoURL = VideoURLCreator.videoURL(
|
||||
thotStyle: thotStyle,
|
||||
defaultVideoURLStr: bridgeModule.currentExercise?.exercise.videoURL,
|
||||
exerciseName: bridgeModule.currentExercise?.exercise.name,
|
||||
workout: bridgeModule.currentWorkout) {
|
||||
avPlayer = AVPlayer(url: videoURL)
|
||||
avPlayer.play()
|
||||
if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise {
|
||||
if let videoURL = VideoURLCreator.videoURL(
|
||||
thotStyle: thotStyle,
|
||||
defaultVideoURLStr: currentExtercise.exercise.videoURL,
|
||||
exerciseName: currentExtercise.exercise.name,
|
||||
workout: bridgeModule.currentExerciseInfo.workout) {
|
||||
avPlayer = AVPlayer(url: videoURL)
|
||||
avPlayer.play()
|
||||
}
|
||||
}
|
||||
|
||||
bridgeModule.completedWorkout = {
|
||||
@@ -132,7 +135,7 @@ struct WorkoutDetailView: View {
|
||||
}
|
||||
|
||||
func createWorkoutData() -> [String:Any]? {
|
||||
guard let workoutid = bridgeModule.currentWorkout?.id,
|
||||
guard let workoutid = bridgeModule.currentExerciseInfo.workout?.id,
|
||||
let startTime = bridgeModule.workoutStartDate?.timeFormatForUpload,
|
||||
let endTime = bridgeModule.workoutEndDate?.timeFormatForUpload else {
|
||||
return nil
|
||||
@@ -154,6 +157,6 @@ struct WorkoutDetailView: View {
|
||||
struct WorkoutDetailView_Previews: PreviewProvider {
|
||||
static let workoutDetail = PreviewData.workout()
|
||||
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 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.isPreview = isPreview
|
||||
|
||||
if let passedStatus = status {
|
||||
self.status = passedStatus
|
||||
|
||||
@@ -79,8 +79,8 @@ struct WorkoutHistoryView: View {
|
||||
}
|
||||
}
|
||||
.sheet(item: $selectedPlannedWorkout) { item in
|
||||
let viewModel = WorkoutDetailViewModel(workout: item)
|
||||
WorkoutDetailView(viewModel: viewModel, showAddToCalendar: true)
|
||||
let viewModel = WorkoutDetailViewModel(workout: item, isPreview: true)
|
||||
WorkoutDetailView(viewModel: viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user