266 lines
9.3 KiB
Swift
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")
|
|
// }
|
|
// }
|
|
// }
|
|
}
|