From 0e687036b6df5364ce4456b28f4f435fab94592c Mon Sep 17 00:00:00 2001 From: Trey t Date: Wed, 5 Jul 2023 09:20:25 -0500 Subject: [PATCH] WIP --- Werkout_ios.xcodeproj/project.pbxproj | 8 +- .../Views/AddExercise/AddExerciseView.swift | 5 +- .../Views/ExternalWorkoutDetailView.swift | 14 +++- Werkout_ios/Views/PlayerUIView.swift | 82 +++++++++++++++++++ Werkout_ios/Views/VideoPlayerView.swift | 61 -------------- .../WorkoutDetail/WorkoutDetailView.swift | 28 ++++--- 6 files changed, 116 insertions(+), 82 deletions(-) create mode 100644 Werkout_ios/Views/PlayerUIView.swift delete mode 100644 Werkout_ios/Views/VideoPlayerView.swift diff --git a/Werkout_ios.xcodeproj/project.pbxproj b/Werkout_ios.xcodeproj/project.pbxproj index 3c45949..42a3b27 100644 --- a/Werkout_ios.xcodeproj/project.pbxproj +++ b/Werkout_ios.xcodeproj/project.pbxproj @@ -9,12 +9,12 @@ /* Begin PBXBuildFile section */ 1C31C8842A53AE3E00350540 /* short_beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 1C31C8822A53AE3E00350540 /* short_beep.m4a */; }; 1C31C8852A53AE3E00350540 /* long_beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 1C31C8832A53AE3E00350540 /* long_beep.m4a */; }; + 1C31C8872A55B2CC00350540 /* PlayerUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C31C8862A55B2CC00350540 /* PlayerUIView.swift */; }; 1C485C832A489B9C00A6F896 /* CompletedWorkouts.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C485C822A489B9C00A6F896 /* CompletedWorkouts.json */; }; 1C485C872A4915C400A6F896 /* CreateWorkoutItemPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.swift */; }; 1C485C8A2A492BB400A6F896 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C892A492BB400A6F896 /* LoginView.swift */; }; 1C485C8C2A49D65600A6F896 /* WorkoutHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C8B2A49D65600A6F896 /* WorkoutHistoryView.swift */; }; 1C485C8D2A49D95700A6F896 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A822A42347D0042FFBD /* Extensions.swift */; }; - 1C6D0A372A4BE9A500D98B06 /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6D0A362A4BE9A500D98B06 /* VideoPlayerView.swift */; }; 1CAF4D8A2A5132F900B00E50 /* PlannedWorkout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CAF4D892A5132F900B00E50 /* PlannedWorkout.swift */; }; 1CAF4D8C2A51339200B00E50 /* PlannedWorkouts.json in Resources */ = {isa = PBXBuildFile; fileRef = 1CAF4D8B2A51339200B00E50 /* PlannedWorkouts.json */; }; 1CAF4D952A52180600B00E50 /* PlanWorkoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CAF4D942A52180600B00E50 /* PlanWorkoutView.swift */; }; @@ -106,11 +106,11 @@ /* Begin PBXFileReference section */ 1C31C8822A53AE3E00350540 /* short_beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = short_beep.m4a; sourceTree = ""; }; 1C31C8832A53AE3E00350540 /* long_beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = long_beep.m4a; sourceTree = ""; }; + 1C31C8862A55B2CC00350540 /* PlayerUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerUIView.swift; sourceTree = ""; }; 1C485C822A489B9C00A6F896 /* CompletedWorkouts.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = CompletedWorkouts.json; sourceTree = ""; }; 1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateWorkoutItemPickerView.swift; sourceTree = ""; }; 1C485C892A492BB400A6F896 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; 1C485C8B2A49D65600A6F896 /* WorkoutHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutHistoryView.swift; sourceTree = ""; }; - 1C6D0A362A4BE9A500D98B06 /* VideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerView.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; }; 1C6D0A402A4BECA400D98B06 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.4.sdk/System/Library/Frameworks/AVKit.framework; sourceTree = DEVELOPER_DIR; }; @@ -289,7 +289,7 @@ 1CF65A3B2A3972CE0042FFBD /* ExternalWorkoutDetailView.swift */, 1CF65A2C2A3972840042FFBD /* MainView.swift */, 1CAF4D942A52180600B00E50 /* PlanWorkoutView.swift */, - 1C6D0A362A4BE9A500D98B06 /* VideoPlayerView.swift */, + 1C31C8862A55B2CC00350540 /* PlayerUIView.swift */, 1C485C8B2A49D65600A6F896 /* WorkoutHistoryView.swift */, 1CF65A8B2A44B7590042FFBD /* AccountView */, 1CF65A8A2A44B74D0042FFBD /* AddExercise */, @@ -529,7 +529,6 @@ 1CF65A522A3A90A00042FFBD /* PreviewData.swift in Sources */, 1CF65A852A43E8060042FFBD /* CompletedWorkout.swift in Sources */, 1CF65A6E2A3F60480042FFBD /* CreateViewModels.swift in Sources */, - 1C6D0A372A4BE9A500D98B06 /* VideoPlayerView.swift in Sources */, 1CF65A4C2A39FDA20042FFBD /* WorkoutDetailView.swift in Sources */, 1CF65A8E2A44B78B0042FFBD /* CompletedWorkoutView.swift in Sources */, 1CF65A432A39FB410042FFBD /* Workout.swift in Sources */, @@ -537,6 +536,7 @@ 1CF65A592A3BF4B60042FFBD /* Muscle.swift in Sources */, 1CAF4D8A2A5132F900B00E50 /* PlannedWorkout.swift in Sources */, 1CF65A2B2A3972840042FFBD /* Werkout_ios.xcdatamodeld in Sources */, + 1C31C8872A55B2CC00350540 /* PlayerUIView.swift in Sources */, 1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */, 1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */, 1C485C8A2A492BB400A6F896 /* LoginView.swift in Sources */, diff --git a/Werkout_ios/Views/AddExercise/AddExerciseView.swift b/Werkout_ios/Views/AddExercise/AddExerciseView.swift index b03be9d..fe00d4d 100644 --- a/Werkout_ios/Views/AddExercise/AddExerciseView.swift +++ b/Werkout_ios/Views/AddExercise/AddExerciseView.swift @@ -72,7 +72,10 @@ struct AddExerciseView: View { filteredExercises = exercises } .sheet(item: $videoExercise) { exercise in - VideoPlayerView(avPlayer: $avPlayer) + PlayerView(player: $avPlayer) + .onAppear{ + avPlayer.play() + } } .sheet(item: $createWorkoutItemPickerViewModel) { item in CreateWorkoutItemPickerView(viewModel: item, completed: { selectedids in diff --git a/Werkout_ios/Views/ExternalWorkoutDetailView.swift b/Werkout_ios/Views/ExternalWorkoutDetailView.swift index 78147e3..37aa9ee 100644 --- a/Werkout_ios/Views/ExternalWorkoutDetailView.swift +++ b/Werkout_ios/Views/ExternalWorkoutDetailView.swift @@ -19,8 +19,11 @@ struct ExternalWorkoutDetailView: View { GeometryReader { metrics in VStack { HStack { - VideoPlayerView(avPlayer: $avPlayer, showDoneButton: false) + PlayerView(player: $avPlayer) .frame(width: metrics.size.width * 0.6, height: metrics.size.height * 0.8) + .onAppear{ + avPlayer.play() + } ExtExerciseList(workout: workout, currentExerciseIdx: bridgeModule.currentExerciseIdx) @@ -39,17 +42,22 @@ struct ExternalWorkoutDetailView: View { } } .onChange(of: bridgeModule.currentExercise, perform: { newValue in + var _url: URL? if showNSFWVideos { if let viddd = newValue?.exercise.nsfwVideoURL, let url = URL(string: BaseURLs.currentBaseURL + viddd) { - avPlayer = AVPlayer(url: url) + _url = url } } else { if let viddd = newValue?.exercise.videoURL, let url = URL(string: BaseURLs.currentBaseURL + viddd) { - avPlayer = AVPlayer(url: url) + _url = url } } + if let __url = _url { + avPlayer = AVPlayer(url: __url) + avPlayer.play() + } }) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.background) diff --git a/Werkout_ios/Views/PlayerUIView.swift b/Werkout_ios/Views/PlayerUIView.swift new file mode 100644 index 0000000..5bcdb1c --- /dev/null +++ b/Werkout_ios/Views/PlayerUIView.swift @@ -0,0 +1,82 @@ +// +// PlayerUIView.swift +// Werkout_ios +// +// Created by Trey Tartt on 7/5/23. +// + +import SwiftUI +import AVKit + +class PlayerUIView: UIView { + + // MARK: Class Property + + let playerLayer = AVPlayerLayer() + + // MARK: Init + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + init(player: AVPlayer) { + super.init(frame: .zero) + self.playerSetup(player: player) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + // MARK: Life-Cycle + + override func layoutSubviews() { + super.layoutSubviews() + playerLayer.frame = bounds + } + + // MARK: Class Methods + + private func playerSetup(player: AVPlayer) { + playerLayer.player = player + player.actionAtItemEnd = .none + layer.addSublayer(playerLayer) + + self.setObserver() + } + + func setObserver() { + NotificationCenter.default.removeObserver(self) + NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(notification:)), + name: .AVPlayerItemDidPlayToEndTime, + object: playerLayer.player?.currentItem) + } + + @objc func playerItemDidReachEnd(notification: Notification) { + if let playerItem = notification.object as? AVPlayerItem { + playerItem.seek(to: .zero, completionHandler: nil) + self.playerLayer.player?.play() + } + } +} + +struct PlayerView: UIViewRepresentable { + + @Binding var player: AVPlayer + + func makeUIView(context: Context) -> PlayerUIView { + return PlayerUIView(player: player) + } + + func updateUIView(_ uiView: PlayerUIView, context: UIViewRepresentableContext) { + uiView.playerLayer.player = player + + //Add player observer. + uiView.setObserver() + } +} diff --git a/Werkout_ios/Views/VideoPlayerView.swift b/Werkout_ios/Views/VideoPlayerView.swift deleted file mode 100644 index 8e4bf2d..0000000 --- a/Werkout_ios/Views/VideoPlayerView.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// VideoPlayerView.swift -// Werkout_ios -// -// Created by Trey Tartt on 6/27/23. -// - -import SwiftUI -import AVKit -import Combine - -struct VideoPlayerView: View { - @Environment(\.dismiss) var dismiss - @Binding var avPlayer: AVPlayer - var showDoneButton = true - - var pub = NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime) - - var body: some View { - VStack { - if self.showDoneButton { - Button(action: { - dismiss() - }, label: { - Text("Done") - }) - .padding() - .frame(maxWidth: .infinity) - .background(Color(uiColor: UIColor(red: 0.11, green: 0.11, blue: 0.12, alpha: 1))) - } - - VideoPlayer(player: avPlayer) - .onAppear{ - _ = try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: .mixWithOthers) - - avPlayer.play() - } - } - .background(.black) - .onReceive(pub) { (output) in - avPlayer.pause() - avPlayer.seek(to: .zero) - _ = try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: .mixWithOthers) - - avPlayer.play() - } - .onChange(of: avPlayer, perform: { newValue in - avPlayer.play() - }) - } -} - - -//struct VideoPlayerView_Previews: PreviewProvider { -// static let exercise = PreviewData.parseExercises().first! -// -// static var previews: some View { -// VideoPlayerView(url: Bundle.main.url(forResource: "Straight_Leg_Sit_Up", withExtension: "mp4")!) -// } -//} - diff --git a/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift b/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift index a154a3e..f16e18d 100644 --- a/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift +++ b/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift @@ -40,8 +40,11 @@ struct WorkoutDetailView: View { .padding() GeometryReader { metrics in - WorkoutDetailVideoPlayerView(avPlayer: $avPlayer) + PlayerView(player: $avPlayer) .frame(width: metrics.size.width * 1, height: metrics.size.height * 1) + .onAppear{ + avPlayer.play() + } } } InfoView(workout: workout) @@ -75,17 +78,22 @@ struct WorkoutDetailView: View { } } .onChange(of: bridgeModule.currentExercise, perform: { newValue in + var _url: URL? if showNSFWVideos { if let viddd = newValue?.exercise.nsfwVideoURL, let url = URL(string: BaseURLs.currentBaseURL + viddd) { - avPlayer = AVPlayer(url: url) + _url = url } } else { if let viddd = newValue?.exercise.videoURL, let url = URL(string: BaseURLs.currentBaseURL + viddd) { - avPlayer = AVPlayer(url: url) + _url = url } } + if let __url = _url { + avPlayer = AVPlayer(url: __url) + avPlayer.play() + } }) .onAppear{ bridgeModule.completedWorkout = { @@ -118,15 +126,6 @@ struct WorkoutDetailView: View { } } -struct WorkoutDetailVideoPlayerView: View { - @ObservedObject var bridgeModule = BridgeModule.shared - @Binding var avPlayer: AVPlayer - - var body: some View { - VideoPlayerView(avPlayer: $avPlayer, showDoneButton: false) - } -} - struct InfoView: View { @ObservedObject var bridgeModule = BridgeModule.shared var workout: Workout @@ -306,7 +305,10 @@ struct ExerciseListView: View { } } .sheet(item: $videoExercise) { exercise in - VideoPlayerView(avPlayer: $avPlayer) + PlayerView(player: $avPlayer) + .onAppear{ + avPlayer.play() + } } } }