// // MainView.swift // Werkout_ios // // Created by Trey Tartt on 6/14/23. // import SwiftUI import AVKit struct WorkoutDetailView: View { @StateObject var viewModel: WorkoutDetailViewModel @State var avPlayer = AVPlayer(url: URL(string: "https://dev.werkout.fitness/media/exercise_videos/2_Dumbbell_Lateral_Lunges.mp4")!) @StateObject var bridgeModule = BridgeModule.shared @Environment(\.dismiss) var dismiss @AppStorage(Constants.phoneThotStyle) private var phoneThotStyle: ThotStyle = .never @AppStorage(Constants.thotGenderOption) private var thotGenderOption: String = "female" enum Sheet: Identifiable { case completedWorkout([String: Any]) var id: String { return UUID().uuidString } } @State var presentedSheet: Sheet? @State var workoutToPlan: Workout? @State var showExecersizeInfo: Bool = false var body: some View { ZStack { switch viewModel.status { case .loading: Text("Loading") case .showWorkout(let workout): VStack(spacing: 0) { if bridgeModule.isInWorkout { HStack { CurrentWorkoutElapsedTimeView() CountdownView() } .padding() .frame(maxWidth: .infinity) if phoneThotStyle != .off { GeometryReader { metrics in ZStack { PlayerView(player: $avPlayer) .frame(width: metrics.size.width * 1, height: metrics.size.height * 1) .onAppear{ avPlayer.play() } } Button(action: { if let assetURL = ((avPlayer.currentItem?.asset) as? AVURLAsset)?.url, let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise, let otherVideoURL = VideoURLCreator.videoURL( thotStyle: VideoURLCreator.otherVideoType(forVideoURL: assetURL), gender: thotGenderOption, defaultVideoURLStr: currentExtercise.exercise.videoURL, exerciseName: currentExtercise.exercise.name, workout: bridgeModule.currentExerciseInfo.workout) { avPlayer = AVPlayer(url: otherVideoURL) avPlayer.play() } }, label: { Image(systemName: "arrow.triangle.2.circlepath.camera.fill") .frame(width: 44, height: 44) }) .foregroundColor(.blue) .cornerRadius(4) .frame(width: 160, height: 120) .position(x: metrics.size.width - 22, y: metrics.size.height - 30) Button(action: { showExecersizeInfo.toggle() }, label: { Image(systemName: "info.circle.fill") .frame(width: 44, height: 44) }) .foregroundColor(.blue) .cornerRadius(4) .frame(width: 120, height: 120) .position(x: 22, y: metrics.size.height - 30) } } } InfoView(workout: workout) .padding(.bottom) if bridgeModule.isInWorkout { Divider() HStack { Text("Round \(bridgeModule.currentExerciseInfo.currentRound) of \(bridgeModule.currentExerciseInfo.numberOfRoundsInCurrentSuperSet)") .font(.title3) .lineLimit(1) .padding() .bold() Text("Current: \(bridgeModule.currentExerciseInfo.allSupersetExecerciseIndex+1) of \(bridgeModule.currentExerciseInfo.workout?.allSupersetExecercise?.count ?? -99)") .font(.title3) .lineLimit(1) .padding() .bold() } } ExerciseListView(workout: workout, showExecersizeInfo: $showExecersizeInfo) ActionsView(completedWorkout: { bridgeModule.completeWorkout() }, planWorkout: { workout in workoutToPlan = workout }, workout: workout, showAddToCalendar: viewModel.isPreview, startWorkoutAction: { startWorkout(workout: workout) }) .frame(height: 44) } .sheet(item: $presentedSheet) { item in switch item { case .completedWorkout(let data): CompletedWorkoutView(postData: data, workout: workout, completedWorkoutDismissed: { uploaded in if uploaded { dismiss() } }) } } .sheet(item: $workoutToPlan) { workout in PlanWorkoutView(workout: workout, addedPlannedWorkout: { dismiss() }) } } } .onChange(of: bridgeModule.currentExerciseInfo.allSupersetExecerciseIndex, perform: { _ in playVideos() }) .onChange(of: bridgeModule.isInWorkout, perform: { _ in playVideos() }) .onAppear{ if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise { if let videoURL = VideoURLCreator.videoURL( thotStyle: phoneThotStyle, gender: thotGenderOption, defaultVideoURLStr: currentExtercise.exercise.videoURL, exerciseName: currentExtercise.exercise.name, workout: bridgeModule.currentExerciseInfo.workout) { avPlayer = AVPlayer(url: videoURL) avPlayer.play() } } } .onReceive(NotificationCenter.default.publisher( for: UIScene.willEnterForegroundNotification)) { _ in avPlayer.play() } } func playVideos() { if let currentExtercise = bridgeModule.currentExerciseInfo.currentExercise { if let videoURL = VideoURLCreator.videoURL( thotStyle: phoneThotStyle, gender: thotGenderOption, defaultVideoURLStr: currentExtercise.exercise.videoURL, exerciseName: currentExtercise.exercise.name, workout: bridgeModule.currentExerciseInfo.workout) { avPlayer = AVPlayer(url: videoURL) avPlayer.play() } } } func startWorkout(workout: Workout) { bridgeModule.completedWorkout = { if let workoutData = createWorkoutData() { presentedSheet = .completedWorkout(workoutData) bridgeModule.resetCurrentWorkout() } } bridgeModule.start(workout: workout) } func createWorkoutData() -> [String:Any]? { guard let workoutid = bridgeModule.currentExerciseInfo.workout?.id, let startTime = bridgeModule.workoutStartDate?.timeFormatForUpload, let endTime = bridgeModule.workoutEndDate?.timeFormatForUpload else { return nil } let postBody = [ "difficulty": 1, "workout_start_time": startTime, "workout_end_time": endTime, "workout": workoutid, "total_time": bridgeModule.currentWorkoutRunTimeInSeconds ] as [String : Any] return postBody } } 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), isPreview: true)) } }