diff --git a/Werkout_ios.xcodeproj/project.pbxproj b/Werkout_ios.xcodeproj/project.pbxproj index 924e2e1..d6d673b 100644 --- a/Werkout_ios.xcodeproj/project.pbxproj +++ b/Werkout_ios.xcodeproj/project.pbxproj @@ -16,6 +16,13 @@ 1C485C8C2A49D65600A6F896 /* WorkoutHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C8B2A49D65600A6F896 /* WorkoutHistoryView.swift */; }; 1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A822A42347D0042FFBD /* Extensions.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 */; }; + 1C5190C82A589CDA00885849 /* CurrentWorkoutElapsedTimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C72A589CDA00885849 /* CurrentWorkoutElapsedTimeView.swift */; }; + 1C5190CA2A589CEC00885849 /* ExerciseListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190C92A589CEC00885849 /* ExerciseListView.swift */; }; + 1C5190CC2A589D0000885849 /* CountdownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190CB2A589D0000885849 /* CountdownView.swift */; }; + 1C5190CE2A589D4100885849 /* AllWorkoutPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190CD2A589D4100885849 /* AllWorkoutPickerView.swift */; }; + 1C5190D02A589D5F00885849 /* AllWorkoutsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5190CF2A589D5F00885849 /* AllWorkoutsListView.swift */; }; 1C6BF28F2A56602B00450FD7 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6BF28E2A56602B00450FD7 /* Keychain.swift */; }; 1CAF4D8A2A5132F900B00E50 /* PlannedWorkout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CAF4D892A5132F900B00E50 /* PlannedWorkout.swift */; }; 1CAF4D8C2A51339200B00E50 /* PlannedWorkouts.json in Resources */ = {isa = PBXBuildFile; fileRef = 1CAF4D8B2A51339200B00E50 /* PlannedWorkouts.json */; }; @@ -114,6 +121,13 @@ 1C485C892A492BB400A6F896 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; 1C485C8B2A49D65600A6F896 /* WorkoutHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutHistoryView.swift; sourceTree = ""; }; 1C5190C12A57CA5F00885849 /* OvalTextFieldStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OvalTextFieldStyle.swift; sourceTree = ""; }; + 1C5190C32A589CAC00885849 /* InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = ""; }; + 1C5190C52A589CC100885849 /* ActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionsView.swift; sourceTree = ""; }; + 1C5190C72A589CDA00885849 /* CurrentWorkoutElapsedTimeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentWorkoutElapsedTimeView.swift; sourceTree = ""; }; + 1C5190C92A589CEC00885849 /* ExerciseListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseListView.swift; sourceTree = ""; }; + 1C5190CB2A589D0000885849 /* CountdownView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountdownView.swift; sourceTree = ""; }; + 1C5190CD2A589D4100885849 /* AllWorkoutPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllWorkoutPickerView.swift; sourceTree = ""; }; + 1C5190CF2A589D5F00885849 /* AllWorkoutsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllWorkoutsListView.swift; sourceTree = ""; }; 1C6BF28E2A56602B00450FD7 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; 1C6D0A3C2A4BEC9700D98B06 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS9.4.sdk/System/Library/Frameworks/AVKit.framework; sourceTree = DEVELOPER_DIR; }; 1C6D0A3D2A4BEC9700D98B06 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS9.4.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; @@ -340,6 +354,11 @@ children = ( 1CF65A4B2A39FDA20042FFBD /* WorkoutDetailView.swift */, 1CF65A4D2A39FF200042FFBD /* WorkoutDetailViewModel.swift */, + 1C5190C32A589CAC00885849 /* InfoView.swift */, + 1C5190C52A589CC100885849 /* ActionsView.swift */, + 1C5190C72A589CDA00885849 /* CurrentWorkoutElapsedTimeView.swift */, + 1C5190C92A589CEC00885849 /* ExerciseListView.swift */, + 1C5190CB2A589D0000885849 /* CountdownView.swift */, ); path = WorkoutDetail; sourceTree = ""; @@ -348,6 +367,8 @@ isa = PBXGroup; children = ( 1CF65A622A3BF6A30042FFBD /* AllWorkoutsView.swift */, + 1C5190CD2A589D4100885849 /* AllWorkoutPickerView.swift */, + 1C5190CF2A589D5F00885849 /* AllWorkoutsListView.swift */, ); path = AllWorkouts; sourceTree = ""; @@ -527,6 +548,7 @@ 1CF65A7B2A3F83440042FFBD /* CreateWorkoutSupersetActionsView.swift in Sources */, 1CF65A262A3972840042FFBD /* Werkout_iosApp.swift in Sources */, 1C6BF28F2A56602B00450FD7 /* Keychain.swift in Sources */, + 1C5190C42A589CAC00885849 /* InfoView.swift in Sources */, 1CF65A3C2A3972CE0042FFBD /* ExternalWorkoutDetailView.swift in Sources */, 1CF65A632A3BF6A30042FFBD /* AllWorkoutsView.swift in Sources */, 1CF65A692A3C018F0042FFBD /* AccountView.swift in Sources */, @@ -534,6 +556,7 @@ 1CF65A472A39FB6C0042FFBD /* RegisteredUser.swift in Sources */, 1CF65AB32A452F360042FFBD /* WatchPackageModel.swift in Sources */, 1CF65A522A3A90A00042FFBD /* PreviewData.swift in Sources */, + 1C5190CE2A589D4100885849 /* AllWorkoutPickerView.swift in Sources */, 1CF65A852A43E8060042FFBD /* CompletedWorkout.swift in Sources */, 1CF65A6E2A3F60480042FFBD /* CreateViewModels.swift in Sources */, 1CF65A4C2A39FDA20042FFBD /* WorkoutDetailView.swift in Sources */, @@ -541,8 +564,11 @@ 1CF65A432A39FB410042FFBD /* Workout.swift in Sources */, 1CF65A502A3A1EA90042FFBD /* BridgeModule.swift in Sources */, 1CF65A592A3BF4B60042FFBD /* Muscle.swift in Sources */, + 1C5190D02A589D5F00885849 /* AllWorkoutsListView.swift in Sources */, + 1C5190CA2A589CEC00885849 /* ExerciseListView.swift in Sources */, 1CAF4D8A2A5132F900B00E50 /* PlannedWorkout.swift in Sources */, 1C5190C22A57CA5F00885849 /* OvalTextFieldStyle.swift in Sources */, + 1C5190CC2A589D0000885849 /* CountdownView.swift in Sources */, 1CF65A2B2A3972840042FFBD /* Werkout_ios.xcdatamodeld in Sources */, 1C31C8872A55B2CC00350540 /* PlayerUIView.swift in Sources */, 1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */, @@ -554,7 +580,9 @@ 1CF65ABA2A4894430042FFBD /* UserStore.swift in Sources */, 1C485C8C2A49D65600A6F896 /* WorkoutHistoryView.swift in Sources */, 1CAF4D952A52180600B00E50 /* PlanWorkoutView.swift in Sources */, + 1C5190C62A589CC100885849 /* ActionsView.swift in Sources */, 1CF65A5B2A3BF4BE0042FFBD /* Equipment.swift in Sources */, + 1C5190C82A589CDA00885849 /* CurrentWorkoutElapsedTimeView.swift in Sources */, 1CF65A452A39FB550042FFBD /* Exercise.swift in Sources */, 1CF65A612A3BF6020042FFBD /* AddExerciseView.swift in Sources */, 1C485C872A4915C400A6F896 /* CreateWorkoutItemPickerView.swift in Sources */, diff --git a/Werkout_ios/Views/AllWorkouts/AllWorkoutPickerView.swift b/Werkout_ios/Views/AllWorkouts/AllWorkoutPickerView.swift new file mode 100644 index 0000000..6f5afc6 --- /dev/null +++ b/Werkout_ios/Views/AllWorkouts/AllWorkoutPickerView.swift @@ -0,0 +1,37 @@ +// +// AllWorkoutPickerView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/7/23. +// + +import SwiftUI + +struct AllWorkoutPickerView: View { + var mainViews: [MainViewTypes] + @Binding var selectedSegment: MainViewTypes + @StateObject var bridgeModule = BridgeModule.shared + var showCurrentWorkout: (() -> Void) + + var body: some View { + HStack { + Picker("", selection: $selectedSegment) { + ForEach(mainViews, id: \.self) { viewType in + Text(viewType.title) + } + } + .pickerStyle(.segmented) + .padding([.top, .leading, .trailing]) + + if bridgeModule.isInWorkout { + Button(action: { + showCurrentWorkout() + }, label: { + Image(systemName: "figure.strengthtraining.traditional") + .padding(.trailing) + }) + .tint(.blue) + } + } + } +} diff --git a/Werkout_ios/Views/AllWorkouts/AllWorkoutsListView.swift b/Werkout_ios/Views/AllWorkouts/AllWorkoutsListView.swift new file mode 100644 index 0000000..363a896 --- /dev/null +++ b/Werkout_ios/Views/AllWorkouts/AllWorkoutsListView.swift @@ -0,0 +1,88 @@ +// +// AllWorkoutsListView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/7/23. +// + +import SwiftUI + +struct AllWorkoutsListView: View { + @State var searchString: String = "" + let workouts: [Workout] + + let selectedWorkout: ((Workout) -> Void) + + var filteredWorkouts: [Workout] { + if !searchString.isEmpty, searchString.count > 0 { + return workouts.filter({ + if $0.name.lowercased().contains(searchString.lowercased()) { + return true + } + if let equipment = $0.equipment?.joined(separator: "").lowercased(), + equipment.contains(searchString.lowercased()) { + return true + } + if let muscles = $0.muscles?.joined(separator: "").lowercased(), + muscles.contains(searchString.lowercased()) { + return true + } + + return false + }) + } else { + return workouts + } + } + var refresh: (() -> Void) + + var body: some View { + VStack { + List { + ForEach(filteredWorkouts, id:\.name) { workout in + Section { + VStack { + Text(workout.name) + .font(.title2) + .frame(maxWidth: .infinity, alignment: .leading) + Text(workout.description ?? "") + .frame(maxWidth: .infinity, alignment: .leading) + + if let muscles = workout.muscles, + muscles.joined(separator: ", ").count > 0{ + Divider() + Text(muscles.joined(separator: ", ")) + .font(.footnote) + .frame(maxWidth: .infinity, alignment: .leading) + } + + if let equipment = workout.equipment, + equipment.joined(separator: ", ").count > 0 { + Divider() + Text(equipment.joined(separator: ", ")) + .font(.footnote) + .frame(maxWidth: .infinity, alignment: .leading) + } + } + .contentShape(Rectangle()) + .onTapGesture { + selectedWorkout(workout) + } + } + } + } + .refreshable { + refresh() + } + + TextField("Filter" ,text: $searchString) + .padding() + .textFieldStyle(OvalTextFieldStyle()) + // TextField("Filter", text: $searchString) + // .padding() + // .overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color(uiColor: .darkGray), style: StrokeStyle(lineWidth: 1.0))) + // .padding() + // .background(Color(uiColor: .systemGroupedBackground)) + } + } +} diff --git a/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift b/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift index 039ceec..9f261e1 100644 --- a/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift +++ b/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift @@ -178,115 +178,6 @@ struct AllWorkoutsView: View { } } -struct AllWorkoutPickerView: View { - var mainViews: [MainViewTypes] - @Binding var selectedSegment: MainViewTypes - @StateObject var bridgeModule = BridgeModule.shared - var showCurrentWorkout: (() -> Void) - - var body: some View { - HStack { - Picker("", selection: $selectedSegment) { - ForEach(mainViews, id: \.self) { viewType in - Text(viewType.title) - } - } - .pickerStyle(.segmented) - .padding([.top, .leading, .trailing]) - - if bridgeModule.isInWorkout { - Button(action: { - showCurrentWorkout() - }, label: { - Image(systemName: "figure.strengthtraining.traditional") - .padding(.trailing) - }) - .tint(.blue) - } - } - } -} - -struct AllWorkoutsListView: View { - @State var searchString: String = "" - let workouts: [Workout] - - let selectedWorkout: ((Workout) -> Void) - - var filteredWorkouts: [Workout] { - if !searchString.isEmpty, searchString.count > 0 { - return workouts.filter({ - if $0.name.lowercased().contains(searchString.lowercased()) { - return true - } - if let equipment = $0.equipment?.joined(separator: "").lowercased(), - equipment.contains(searchString.lowercased()) { - return true - } - if let muscles = $0.muscles?.joined(separator: "").lowercased(), - muscles.contains(searchString.lowercased()) { - return true - } - - return false - }) - } else { - return workouts - } - } - var refresh: (() -> Void) - - var body: some View { - VStack { - List { - ForEach(filteredWorkouts, id:\.name) { workout in - Section { - VStack { - Text(workout.name) - .font(.title2) - .frame(maxWidth: .infinity, alignment: .leading) - Text(workout.description ?? "") - .frame(maxWidth: .infinity, alignment: .leading) - - if let muscles = workout.muscles, - muscles.joined(separator: ", ").count > 0{ - Divider() - Text(muscles.joined(separator: ", ")) - .font(.footnote) - .frame(maxWidth: .infinity, alignment: .leading) - } - - if let equipment = workout.equipment, - equipment.joined(separator: ", ").count > 0 { - Divider() - Text(equipment.joined(separator: ", ")) - .font(.footnote) - .frame(maxWidth: .infinity, alignment: .leading) - } - } - .contentShape(Rectangle()) - .onTapGesture { - selectedWorkout(workout) - } - } - } - } - .refreshable { - refresh() - } - - TextField("Filter" ,text: $searchString) - .padding() - .textFieldStyle(OvalTextFieldStyle()) -// TextField("Filter", text: $searchString) -// .padding() -// .overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color(uiColor: .darkGray), style: StrokeStyle(lineWidth: 1.0))) -// .padding() -// .background(Color(uiColor: .systemGroupedBackground)) - } - } -} - struct AllWorkoutsView_Previews: PreviewProvider { static var previews: some View { AllWorkoutsView(workouts: PreviewData.allWorkouts()) diff --git a/Werkout_ios/Views/WorkoutDetail/ActionsView.swift b/Werkout_ios/Views/WorkoutDetail/ActionsView.swift new file mode 100644 index 0000000..ee22537 --- /dev/null +++ b/Werkout_ios/Views/WorkoutDetail/ActionsView.swift @@ -0,0 +1,101 @@ +// +// ActionsView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/7/23. +// + +import SwiftUI + +struct ActionsView: View { + @ObservedObject var bridgeModule = BridgeModule.shared + var completedWorkout: (() -> Void)? + var planWorkout: ((Workout) -> Void)? + + var workout: Workout + @Environment(\.dismiss) var dismiss + var showAddToCalendar: Bool + + var body: some View { + HStack { + if bridgeModule.isInWorkout == false { + Button(action: { + bridgeModule.resetCurrentWorkout() + dismiss() + }, label: { + Image(systemName: "xmark.octagon.fill") + .font(.title) + .frame(maxWidth: .infinity, maxHeight: .infinity) + }) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.red) + .foregroundColor(.white) + + if showAddToCalendar { + Button(action: { + planWorkout?(workout) + }, label: { + Image(systemName: "calendar.badge.plus") + .font(.title) + .frame(maxWidth: .infinity, maxHeight: .infinity) + }) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.blue) + .foregroundColor(.white) + } + + Button(action: { + startWorkout() + }, label: { + Image(systemName: "arrowtriangle.forward.fill") + .font(.title) + .frame(maxWidth: .infinity, maxHeight: .infinity) + }) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.green) + .foregroundColor(.white) + } else { + Button(action: { + nextExercise() + }, label: { + Image(systemName: "arrow.forward") + .font(.title) + .frame(maxWidth: .infinity, maxHeight: .infinity) + }) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.green) + .foregroundColor(.white) + + Button(action: { + bridgeModule.pauseWorkout() + }, label: { + Image(systemName: "pause.circle.fill") + .font(.title) + .frame(maxWidth: .infinity, maxHeight: .infinity) + }) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.yellow) + .foregroundColor(.white) + + Button(action: { + completedWorkout?() + }, label: { + Image(systemName: "checkmark") + .font(.title) + .frame(maxWidth: .infinity, maxHeight: .infinity) + }) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.blue) + .foregroundColor(.white) + } + } + } + + func nextExercise() { + bridgeModule.nextExercise() + } + + func startWorkout() { + bridgeModule.start(workout: workout) + } +} diff --git a/Werkout_ios/Views/WorkoutDetail/CountdownView.swift b/Werkout_ios/Views/WorkoutDetail/CountdownView.swift new file mode 100644 index 0000000..74866f5 --- /dev/null +++ b/Werkout_ios/Views/WorkoutDetail/CountdownView.swift @@ -0,0 +1,25 @@ +// +// CountdownView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/7/23. +// + +import SwiftUI + +struct CountdownView: View { + @StateObject var bridgeModule = BridgeModule.shared + + var body: some View { + if let duration = bridgeModule.currentExercise?.duration, + duration > 0 { + HStack { + if bridgeModule.currentExerciseTimeLeft >= 0 && duration > bridgeModule.currentExerciseTimeLeft { + ProgressView(value: Float(bridgeModule.currentExerciseTimeLeft), total: Float(duration)) + Text("\(bridgeModule.currentExerciseTimeLeft)") + .font(.body) + } + } + } + } +} diff --git a/Werkout_ios/Views/WorkoutDetail/CurrentWorkoutElapsedTimeView.swift b/Werkout_ios/Views/WorkoutDetail/CurrentWorkoutElapsedTimeView.swift new file mode 100644 index 0000000..c6cc2cf --- /dev/null +++ b/Werkout_ios/Views/WorkoutDetail/CurrentWorkoutElapsedTimeView.swift @@ -0,0 +1,19 @@ +// +// CurrentWorkoutElapsedTimeView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/7/23. +// + +import SwiftUI + +struct CurrentWorkoutElapsedTimeView: View { + @ObservedObject var bridgeModule = BridgeModule.shared + + var body: some View { + if bridgeModule.currentWorkoutRunTimeInSeconds > -1 { + Text("\(Double(bridgeModule.currentWorkoutRunTimeInSeconds).asString(style: .positional))") + .font(.title2) + } + } +} diff --git a/Werkout_ios/Views/WorkoutDetail/ExerciseListView.swift b/Werkout_ios/Views/WorkoutDetail/ExerciseListView.swift new file mode 100644 index 0000000..294c539 --- /dev/null +++ b/Werkout_ios/Views/WorkoutDetail/ExerciseListView.swift @@ -0,0 +1,104 @@ +// +// ExerciseListView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/7/23. +// + +import SwiftUI +import AVKit + +struct ExerciseListView: View { + @AppStorage("showNSFWVideos") private var showNSFWVideos = false + @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 videoExercise: ExerciseExercise? { + didSet { + if showNSFWVideos { + if let viddd = self.videoExercise?.nsfwVideoURL, + let url = URL(string: BaseURLs.currentBaseURL + viddd) { + avPlayer = AVPlayer(url: url) + } + } else { + if let viddd = self.videoExercise?.videoURL, + let url = URL(string: BaseURLs.currentBaseURL + viddd) { + avPlayer = AVPlayer(url: url) + } + } + } + } + + 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) + + } + .padding(5) + .background(.blue) + .cornerRadius(5, corners: [.topLeft, .bottomLeft]) + .frame(alignment: .trailing) + } + + if let duration = obj.duration, + duration > 0 { + HStack { + Image(systemName: "stopwatch") + .foregroundColor(.white) + .frame(width: 20, alignment: .leading) + Text("\(duration)") + .foregroundColor(.white) + .frame(width: 30, alignment: .trailing) + } + .padding(5) + .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() + } + } + } +} diff --git a/Werkout_ios/Views/WorkoutDetail/InfoView.swift b/Werkout_ios/Views/WorkoutDetail/InfoView.swift new file mode 100644 index 0000000..3adf4d7 --- /dev/null +++ b/Werkout_ios/Views/WorkoutDetail/InfoView.swift @@ -0,0 +1,30 @@ +// +// InfoView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/7/23. +// + +import SwiftUI + +struct InfoView: View { + @ObservedObject var bridgeModule = BridgeModule.shared + var workout: Workout + + var body: some View { + VStack { + if bridgeModule.isInWorkout == false { + Text(workout.name) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.title3) + .padding() + if let desc = workout.description { + Text(desc) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.body) + .padding([.leading, .trailing]) + } + } + } + } +} diff --git a/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift b/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift index 097c169..a7173c6 100644 --- a/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift +++ b/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift @@ -150,244 +150,6 @@ struct WorkoutDetailView: View { } } -struct InfoView: View { - @ObservedObject var bridgeModule = BridgeModule.shared - var workout: Workout - - var body: some View { - VStack { - if bridgeModule.isInWorkout == false { - Text(workout.name) - .frame(maxWidth: .infinity, alignment: .leading) - .font(.title3) - .padding() - if let desc = workout.description { - Text(desc) - .frame(maxWidth: .infinity, alignment: .leading) - .font(.body) - .padding([.leading, .trailing]) - } - } - } - } -} - -struct ActionsView: View { - @ObservedObject var bridgeModule = BridgeModule.shared - var completedWorkout: (() -> Void)? - var planWorkout: ((Workout) -> Void)? - - var workout: Workout - @Environment(\.dismiss) var dismiss - var showAddToCalendar: Bool - - var body: some View { - HStack { - if bridgeModule.isInWorkout == false { - Button(action: { - bridgeModule.resetCurrentWorkout() - dismiss() - }, label: { - Image(systemName: "xmark.octagon.fill") - .font(.title) - .frame(maxWidth: .infinity, maxHeight: .infinity) - }) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.red) - .foregroundColor(.white) - - if showAddToCalendar { - Button(action: { - planWorkout?(workout) - }, label: { - Image(systemName: "calendar.badge.plus") - .font(.title) - .frame(maxWidth: .infinity, maxHeight: .infinity) - }) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.blue) - .foregroundColor(.white) - } - - Button(action: { - startWorkout() - }, label: { - Image(systemName: "arrowtriangle.forward.fill") - .font(.title) - .frame(maxWidth: .infinity, maxHeight: .infinity) - }) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.green) - .foregroundColor(.white) - } else { - Button(action: { - nextExercise() - }, label: { - Image(systemName: "arrow.forward") - .font(.title) - .frame(maxWidth: .infinity, maxHeight: .infinity) - }) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.green) - .foregroundColor(.white) - - Button(action: { - bridgeModule.pauseWorkout() - }, label: { - Image(systemName: "pause.circle.fill") - .font(.title) - .frame(maxWidth: .infinity, maxHeight: .infinity) - }) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.yellow) - .foregroundColor(.white) - - Button(action: { - completedWorkout?() - }, label: { - Image(systemName: "checkmark") - .font(.title) - .frame(maxWidth: .infinity, maxHeight: .infinity) - }) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.blue) - .foregroundColor(.white) - } - } - } - - func nextExercise() { - bridgeModule.nextExercise() - } - - func startWorkout() { - bridgeModule.start(workout: workout) - } -} - -struct CurrentWorkoutElapsedTimeView: View { - @ObservedObject var bridgeModule = BridgeModule.shared - - var body: some View { - if bridgeModule.currentWorkoutRunTimeInSeconds > -1 { - Text("\(Double(bridgeModule.currentWorkoutRunTimeInSeconds).asString(style: .positional))") - .font(.title2) - } - } -} - -struct ExerciseListView: View { - @AppStorage("showNSFWVideos") private var showNSFWVideos = false - @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 videoExercise: ExerciseExercise? { - didSet { - if showNSFWVideos { - if let viddd = self.videoExercise?.nsfwVideoURL, - let url = URL(string: BaseURLs.currentBaseURL + viddd) { - avPlayer = AVPlayer(url: url) - } - } else { - if let viddd = self.videoExercise?.videoURL, - let url = URL(string: BaseURLs.currentBaseURL + viddd) { - avPlayer = AVPlayer(url: url) - } - } - } - } - - 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) - - } - .padding(5) - .background(.blue) - .cornerRadius(5, corners: [.topLeft, .bottomLeft]) - .frame(alignment: .trailing) - } - - if let duration = obj.duration, - duration > 0 { - HStack { - Image(systemName: "stopwatch") - .foregroundColor(.white) - .frame(width: 20, alignment: .leading) - Text("\(duration)") - .foregroundColor(.white) - .frame(width: 30, alignment: .trailing) - } - .padding(5) - .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() - } - } - } -} - -struct CountdownView: View { - @StateObject var bridgeModule = BridgeModule.shared - - var body: some View { - if let duration = bridgeModule.currentExercise?.duration, - duration > 0 { - HStack { - if bridgeModule.currentExerciseTimeLeft >= 0 && duration > bridgeModule.currentExerciseTimeLeft { - ProgressView(value: Float(bridgeModule.currentExerciseTimeLeft), total: Float(duration)) - Text("\(bridgeModule.currentExerciseTimeLeft)") - .font(.body) - } - } - } - } -} - struct WorkoutDetailView_Previews: PreviewProvider { static let workoutDetail = PreviewData.workout() static var previews: some View {