Files
Woka_Native_iOS/WOKA/Theme/Controller/MoreVC.swift
Bilal 945ae7f45c - Fixed TC 16, TC 17
- added activity indicators for more vm with retry handling
- fixed a issue where karaoke user view was not reflecting when the player closed
2024-08-23 20:34:08 +05:30

310 lines
12 KiB
Swift

//
// MoreVC.swift
// WOKA
//
// Created by MacBook Pro on 10/06/24.
//
import UIKit
import AVFoundation
class MoreVC: UIViewController {
@IBOutlet weak var blogsCollectionView: UICollectionView!
@IBOutlet weak var homeBtn: UIView!
@IBOutlet weak var songTableView: UITableView!
@IBOutlet weak var blogRetryStack: UIStackView!
@IBOutlet weak var blogActivityIndicator: UIActivityIndicatorView!
@IBOutlet weak var blogRetryBtn: LocalisedElementsButton!
@IBOutlet weak var songRetryStack: UIStackView!
@IBOutlet weak var songActivityIndicator: UIActivityIndicatorView!
@IBOutlet weak var songRetry: LocalisedElementsButton!
var vm = MoreVM()
var timeObserverToken: Any?
override func viewDidLoad() {
super.viewDidLoad()
vm.vc = self
vm.initView()
}
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.post(name: .enableDisableSideBar, object: nil, userInfo: ["type": false])
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.post(name: .enableDisableSideBar, object: nil, userInfo: ["type": true])
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch {
print("Failed to deactivate audio session: \(error.localizedDescription)")
}
vm.player?.pause()
}
@IBAction func playTrailerBtnTapped(_ sender: LocalisedElementsButton) {
PersistentStorage.shared.addTrailerCount()
let item = JwPlayerItemCreate(url: APIEndPoints.StaticURLs.masilaUrl, poster: nil, titles: "Masila")
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer, videoIDs: [0])
}
@IBAction func retryBtnTapped(_ sender: LocalisedElementsButton) {
}
}
// MARK: - TableView DataSource , Delegates
extension MoreVC : TableViewSRC{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return vm.songData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SongListCell", for: indexPath) as! SongListCell
let songData = vm.songData[indexPath.row]
// let isActive = (indexPath.row == vm.currentIndexPlayingSong)
if let index = vm.currentIndexPlayingSong , index == indexPath.row{
cell.setData(data: songData,playerStatus: vm.playerStatus, active: true, currentTime: currentTimePlayer)
}else{
cell.setData(data: songData,playerStatus: .stopped , active: false, currentTime: 0)
}
return cell
}
func getFormattedTime(from player: AVPlayer) -> String {
let currentTime = player.currentTime()
let seconds = CMTimeGetSeconds(currentTime)
if !seconds.isFinite {
return "00:00:00"
}
let hours = Int(seconds) / 3600
let minutes = (Int(seconds) % 3600) / 60
let secs = Int(seconds) % 60
return String(format: "%02d:%02d:%02d", hours, minutes, secs)
}
func handleTap(indexPath : IndexPath){
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) else { return }
addAnimation(cell: cell) { [weak self] in
guard let self else{return}
PersistentStorage.shared.addOthersCount()
/*
this will declare if the song is playing or not
*/
if let playingIndex = vm.currentIndexPlayingSong {
if indexPath.row == playingIndex{ // if same row is selected pause the row
print(vm.playerStatus)
switch vm.playerStatus{
case .play: // if player is playing pause it.
print("Player is playing")
vm.player?.pause()
vm.playerStatus = .pause
tableView.reloadRows(at: [IndexPath(row: vm.currentIndexPlayingSong!, section: 0)], with: .none)
case .pause:
vm.player?.play()
vm.playerStatus = .resume
tableView.reloadRows(at: [IndexPath(row: vm.currentIndexPlayingSong!, section: 0)], with: .none)
case .loading:
print("Player is loading")
case .resume:
print("Player is resume")
default:
break
}
}else{
/*
this means other cell was playing now stop it and play this new cell
first reload the playing cell and pause the audio
*/
//Reset Old Cell
vm.playerStatus = .stopped
tableView.reloadRows(at: [IndexPath(row: vm.currentIndexPlayingSong!, section: 0)], with: .none)
//Update new cell
vm.currentIndexPlayingSong = indexPath.row
vm.playerStatus = .loading
currentTimePlayer = 0
tableView.reloadRows(at: [indexPath], with: .none)
let data = vm.songData[indexPath.row]
startPlaying(song: data, at: indexPath)
print("Other cell playing")
}
}else{
// if there is no playing audio before
vm.playerStatus = .loading
vm.currentIndexPlayingSong = indexPath.row
currentTimePlayer = 0
tableView.reloadRows(at: [indexPath], with: .none)
let data = vm.songData[indexPath.row]
startPlaying(song: data, at: indexPath)
print("First Play")
}
}
}
func addAnimation(cell : UITableViewCell, completion : @escaping () -> Void){
UIView.animate(withDuration: 0.1,animations: {
cell.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
},
completion: { _ in
UIView.animate(withDuration: 0.1) {
cell.transform = CGAffineTransform.identity
completion()
}
})
}
func startPlaying(song: SongBlogDM.PaintDatum, at indexPath: IndexPath) {
// Set up and start the player
stopPlaying()
if let urlString = song.contentMoreDetails?.first?.url , let url = URL(string: urlString){
vm.player = AVPlayer(url: url)
vm.player?.play()
vm.playerStatus = .play
vm.currentIndexPlayingSong = indexPath.row
addPeriodicTimeObserver()
vm.observePlayer()
}
}
func stopPlaying() {
// Remove the periodic time observer
removePeriodicTimeObserver()
// Stop the player
vm.player?.pause()
// vm.player = nil
vm.playerStatus = .stopped
vm.currentIndexPlayingSong = nil
}
func removePeriodicTimeObserver() {
if let token = timeObserverToken {
vm.player?.removeTimeObserver(token)
timeObserverToken = nil
}
}
func addPeriodicTimeObserver() {
let interval = CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
timeObserverToken = vm.player?.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in
guard let self = self else { return }
currentTimePlayer = Int(CMTimeGetSeconds(time))
if let currentPlayingIndex = self.vm.currentIndexPlayingSong,
let cell = self.songTableView.cellForRow(at: IndexPath(row: currentPlayingIndex, section: 0)) as? SongListCell {
cell.updateCurrentTime()
}
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
// MARK: - CollectionView DataSource Delegate
extension MoreVC : CollectionViewSRC{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return vm.blogData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.CellIdentifier.Home.blogsCell, for: indexPath) as! BlogsCell
cell.setData(data : vm.blogData[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
PersistentStorage.shared.addOthersCount()
let data = vm.blogData[indexPath.row]
let sb = UIStoryboard(name: K.StoryBoard.theme, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Theme.blogDetailsVC) as! BlogDetailsVC
vcPush.blogData = data
vcPush.modalPresentationStyle = .overCurrentContext
vcPush.modalTransitionStyle = .crossDissolve
self.present(vcPush, animated: true)
}
}
// MARK: - Collection Flow Layout
extension MoreVC : UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemsPerRow: CGFloat = 2.2
let paddingSpace = 5 * (itemsPerRow + 1)
let availableWidth = collectionView.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
}
}
//class VideoAVPlayer {
//
// var player: AVPlayer?
// var playerObserver: NSKeyValueObservation?
// var status = PlayerStatus.loading
//
// init(url: URL) {
// self.player = AVPlayer(url: url)
// observePlayer()
// }
//
// private func observePlayer() {
// playerObserver = player?.observe(\.timeControlStatus, options: [.new, .old], changeHandler: { [weak self] player, change in
// guard let self = self else { return }
// switch player.timeControlStatus {
// case .playing:
// print("Player is playing")
// self.status = .play
// case .paused:
// print("Player is paused")
// self.status = .pause
// case .waitingToPlayAtSpecifiedRate:
// print("Player is waiting to play at specified rate")
// self.status = .loading
// @unknown default:
// print("Unknown player status")
// }
// })
// }
//
// deinit {
// playerObserver?.invalidate()
// }
//
// func play() {
// player?.play()
// }
//
// func pause() {
// player?.pause()
// }
//}