Files
Woka_Native_iOS/WOKA/Karaoke/Controller/AVPlayerVC.swift
2024-07-11 20:31:25 +05:30

266 lines
9.3 KiB
Swift

//
// AVPlayerVC.swift
// WOKA
//
// Created by Bilal on 05/07/2024.
//
import UIKit
import AVFoundation
class AVPlayerVC: UIViewController {
@IBOutlet weak var viewControll: UIView!
@IBOutlet weak var stackCtrView: UIStackView!
@IBOutlet weak var loadingIndicator: UIActivityIndicatorView!
@IBOutlet weak var sliderStack: UIStackView!
@IBOutlet weak var tintView: UIView!
@IBOutlet weak var videoTitle: UILabel!
@IBOutlet weak var karaokeStack: UIStackView!
@IBOutlet weak var playPauseRecordStack: UIStackView!
@IBOutlet weak var karaokeLoading: UIActivityIndicatorView!
@IBOutlet weak var reloadBtn: UIButton!
@IBOutlet weak var img10SecBack: UIImageView! {
didSet {
self.img10SecBack.isUserInteractionEnabled = true
self.img10SecBack.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap10SecBack)))
}
}
@IBOutlet weak var imgPlay: UIImageView! {
didSet {
self.imgPlay.isUserInteractionEnabled = true
self.imgPlay.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTapPlayPause)))
}
}
@IBOutlet weak var img10SecFor: UIImageView! {
didSet {
self.img10SecFor.isUserInteractionEnabled = true
self.img10SecFor.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap10SecNext)))
}
}
@IBOutlet weak var lbCurrentTime: UILabel!
@IBOutlet weak var lbTotalTime: UILabel!
@IBOutlet weak var seekSlider: UISlider! {
didSet {
self.seekSlider.addTarget(self, action: #selector(onTapToSlide), for: .valueChanged)
}
}
var videoURL : String?
var titleVideo : String?
var vm = AVPlayerVM()
// MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
vm.vc = self
vm.initView()
hideShowIndicator(isLoading: true)
viewControll.addTapGesture {
self.vm.timer?.invalidate()
self.vm.showHideControls()
}
}
override func viewDidAppear(_ animated: Bool) {
self.vm.setVideoPlayer()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.vm.player?.pause()
self.vm.player = nil
}
deinit {
NotificationCenter.default.removeObserver(self)
self.vm.player?.currentItem?.removeObserver(self, forKeyPath: "status")
vm.player?.removeObserver(self, forKeyPath: "rate")
if let playerItem = vm.player?.currentItem {
playerItem.removeObserver(self, forKeyPath: "isPlaybackBufferEmpty")
playerItem.removeObserver(self, forKeyPath: "isPlaybackLikelyToKeepUp")
}
}
// MARK: - Button Clicks & Tap Handler
@IBAction func reloadBtnTapped(_ sender: UIButton) {
vm.isFinished = false
vm.reloadVideo()
}
@IBAction func closeBtnTapped(_ sender: UIButton) {
self.dismiss(animated: true)
}
@IBAction func startStopRecording(_ sender: LocalisedElementsButton) {
}
@IBAction func playPauseBtn(_ sender: LocalisedElementsButton) {
}
@objc func onTap10SecNext() {
guard let currentTime = self.vm.player?.currentTime() else { return }
let seekTime10Sec = CMTimeGetSeconds(currentTime).advanced(by: 10)
let seekTime = CMTime(value: CMTimeValue(seekTime10Sec), timescale: 1)
vm.timer?.invalidate()
vm.timer = nil
hideShowIndicator(isLoading: true)
self.vm.player?.seek(to: seekTime, completionHandler: { [weak self] completed in
if completed{
guard let self else{return}
hideShowIndicator(isLoading: false)
vm.startTimer()
}
})
}
@objc func onTap10SecBack() {
guard let currentTime = self.vm.player?.currentTime() else { return }
vm.timer?.invalidate()
vm.timer = nil
hideShowIndicator(isLoading: true)
let seekTime10Sec = CMTimeGetSeconds(currentTime).advanced(by: -10)
let seekTime = CMTime(value: CMTimeValue(seekTime10Sec), timescale: 1)
self.vm.player?.seek(to: seekTime, completionHandler: { [weak self] completed in
if completed{
guard let self else{return}
hideShowIndicator(isLoading: false)
vm.startTimer()
}
})
}
func hideShowIndicator(isLoading : Bool){
if isLoading{
self.imgPlay.isHidden = true
self.loadingIndicator.startAnimating()
}else{
self.imgPlay.isHidden = false
self.loadingIndicator.stopAnimating()
self.loadingIndicator.hidesWhenStopped = true
}
}
@objc func onTapPlayPause() {
if self.vm.player?.timeControlStatus == .playing {
self.imgPlay.image = UIImage(systemName: "play.circle")
self.vm.player?.pause()
} else {
self.imgPlay.image = UIImage(systemName: "pause.circle")
self.vm.player?.play()
}
}
@objc func onTapToSlide() {
if vm.timer != nil{
vm.timer?.invalidate()
vm.timer = nil
}
self.vm.isThumbSeek = true
guard let duration = self.vm.player?.currentItem?.duration else { return }
let value = Float64(self.seekSlider.value) * CMTimeGetSeconds(duration)
if value.isNaN == false {
let seekTime = CMTime(value: CMTimeValue(value), timescale: 1)
self.vm.player?.seek(to: seekTime, completionHandler: { completed in
if completed {
self.vm.isThumbSeek = false
self.vm.startTimer()
}
})
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "rate" {
if let player = object as? AVPlayer {
if player.rate == 0 {
print("Player is paused")
} else {
print("Player is playing")
hideShowIndicator(isLoading: false)
imgPlay.image = UIImage(systemName: "pause.circle")
}
}
} else if let playerItem = object as? AVPlayerItem {
if keyPath == "isPlaybackBufferEmpty" {
if playerItem.isPlaybackBufferEmpty {
print("Loading")
hideShowIndicator(isLoading: true)
}
} else if keyPath == "isPlaybackLikelyToKeepUp" {
if playerItem.isPlaybackLikelyToKeepUp {
print("finished")
hideShowIndicator(isLoading: false)
}
}
}
}
// // Observe for player item status changes
// override func observeValue(forKeyPath keyPath: String?,
// of object: Any?,
// change: [NSKeyValueChangeKey : Any]?,
// context: UnsafeMutableRawPointer?) {
// if keyPath == "status" {
// if let playerItem = object as? AVPlayerItem {
// switch playerItem.status {
// case .readyToPlay:
// // Ready to play
// print("Player item is ready to play.")
// vm.player?.play()
// hideShowIndicator(isLoading: false)
// imgPlay.image = UIImage(systemName: "pause.circle")
// case .failed:
// // Failed
// if let error = playerItem.error {
// print("Player item error: \(error.localizedDescription)")
// vm.handlePlayerError(error)
// }
// case .unknown:
// // Unknown status
// print("Player item status is unknown.")
// @unknown default:
// // Handle unexpected cases
// print("Player item status is unknown.")
// }
// }
// }
// }
// @objc private func onTapToggleScreen() {
// if #available(iOS 16.0, *) {
// guard let windowSceen = self.view.window?.windowScene else { return }
// if windowSceen.interfaceOrientation == .portrait {
// windowSceen.requestGeometryUpdate(.iOS(interfaceOrientations: .landscape)) { error in
// print(error.localizedDescription)
// }
// } else {
// windowSceen.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait)) { error in
// print(error.localizedDescription)
// }
// }
// } else {
// if UIDevice.current.orientation == .portrait {
// let orientation = UIInterfaceOrientation.landscapeRight.rawValue
// UIDevice.current.setValue(orientation, forKey: "orientation")
// } else {
// let orientation = UIInterfaceOrientation.portrait.rawValue
// UIDevice.current.setValue(orientation, forKey: "orientation")
// }
// }
// }
}