From 4887db2d4a37ceba8bcdb1673653dc81b68cf031 Mon Sep 17 00:00:00 2001 From: BilalKhanWDI Date: Wed, 12 Jun 2024 19:47:40 +0530 Subject: [PATCH] - Working on Song listing, Reworked - Added a global handling of timer and cell reuse. - Fixed the issue of song timer. Made the AvPlayer Optional to handle multiple instances - Made a logic to handle the player stop. matched the current time with the total time. --- WOKA/Info.plist | 1 + WOKA/Main/Delegate/AppDelegate.swift | 14 ++- WOKA/SideBarNav/SideBarNav.storyboard | 64 ++++++------- WOKA/Theme/Base.lproj/Theme.storyboard | 14 +-- WOKA/Theme/Controller/MoreVC.swift | 99 ++++++++++++++------ WOKA/Theme/View/BlogsCell.xib | 6 +- WOKA/Theme/View/SongListCell.swift | 120 ++++++++----------------- WOKA/Theme/ViewModel/MoreVM.swift | 111 +++++++++++++++++++++-- 8 files changed, 266 insertions(+), 163 deletions(-) diff --git a/WOKA/Info.plist b/WOKA/Info.plist index 1b62a00..d08457d 100644 --- a/WOKA/Info.plist +++ b/WOKA/Info.plist @@ -38,6 +38,7 @@ UIBackgroundModes + audio remote-notification diff --git a/WOKA/Main/Delegate/AppDelegate.swift b/WOKA/Main/Delegate/AppDelegate.swift index 954da9c..7baa4ca 100644 --- a/WOKA/Main/Delegate/AppDelegate.swift +++ b/WOKA/Main/Delegate/AppDelegate.swift @@ -9,6 +9,7 @@ import UIKit import Lottie import IQKeyboardManagerSwift import JWPlayerKit +import AVFAudio @main class AppDelegate: UIResponder, UIApplicationDelegate { @@ -40,10 +41,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate { configureSideBar() JWPlayerKitLicense.setLicenseKey("Lgok1t7H4PKY+M8FZqmCx54ibUF+NeCTn+xgd+/LVTaRdc+L") - + setupAudioSession() return true } + + func setupAudioSession() { + let session = AVAudioSession.sharedInstance() + do { + try session.setCategory(.playback, mode: .default) + try session.setActive(true) + } catch { + print("Failed to set up audio session") + } + } + // var myOrientation: UIInterfaceOrientationMask = .portrait // // func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { diff --git a/WOKA/SideBarNav/SideBarNav.storyboard b/WOKA/SideBarNav/SideBarNav.storyboard index b3e8f0f..ebd1c3c 100644 --- a/WOKA/SideBarNav/SideBarNav.storyboard +++ b/WOKA/SideBarNav/SideBarNav.storyboard @@ -131,7 +131,7 @@ - + @@ -225,16 +225,16 @@ - + - + - + - + @@ -378,10 +378,10 @@ - + - + @@ -403,7 +403,7 @@ - + - + @@ -439,7 +439,7 @@ - + - + @@ -475,7 +475,7 @@ - + - + - + - + - + @@ -500,7 +500,7 @@ - + - + - + @@ -757,7 +757,7 @@ - + diff --git a/WOKA/Theme/Controller/MoreVC.swift b/WOKA/Theme/Controller/MoreVC.swift index 1f4c121..2a70a17 100644 --- a/WOKA/Theme/Controller/MoreVC.swift +++ b/WOKA/Theme/Controller/MoreVC.swift @@ -16,7 +16,8 @@ class MoreVC: UIViewController { @IBOutlet weak var songTableView: UITableView! var vm = MoreVM() - + var timeObserverToken: Any? + override func viewDidLoad() { super.viewDidLoad() vm.vc = self @@ -24,7 +25,7 @@ class MoreVC: UIViewController { } override func viewWillDisappear(_ animated: Bool) { - vm.player.pause() + vm.player?.pause() } } @@ -36,22 +37,16 @@ extension MoreVC : TableViewSRC{ } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: K.CellIdentifier.Home.songListCell) as! SongListCell - let data = vm.songData[indexPath.row] - cell.setData(data: data,playerStatus: vm.playerStatus) -// if let playingIndex = vm.currentIndexPlayingSong { -// if indexPath.row == playingIndex{ -// if vm.onGoingTime != nil{ // if index is nil that means its just paused -// cell.setData(data: data,playerStatus: vm.playerStatus,onGoingTime: vm.onGoingTime) -// }else{ // if index is there it means song is playing and needs to be paused -// cell.setData(data: data,playerStatus: .resume,onGoingTime: vm.onGoingTime) -// } -// }else{ -// cell.setData(data: data,playerStatus: vm.playerStatus,onGoingTime: nil) -// } -// }else{ -// cell.setData(data: data,playerStatus: .stopped ,onGoingTime: nil) -// } + + 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 } @@ -85,11 +80,15 @@ extension MoreVC : TableViewSRC{ if indexPath.row == playingIndex{ // if same row is selected pause the row print(vm.playerStatus) switch vm.playerStatus{ - case .play: + case .play: // if player is playing pause it. print("Player is playing") - vm.player.pause() + vm.player?.pause() + vm.playerStatus = .pause + tableView.reloadRows(at: [IndexPath(row: vm.currentIndexPlayingSong!, section: 0)], with: .none) case .pause: - print("Player is 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: @@ -102,16 +101,27 @@ extension MoreVC : TableViewSRC{ 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 = .play + vm.playerStatus = .loading vm.currentIndexPlayingSong = indexPath.row + currentTimePlayer = 0 tableView.reloadRows(at: [indexPath], with: .none) let data = vm.songData[indexPath.row] - playSong(url: data.contentMoreDetails?.first?.url) + startPlaying(song: data, at: indexPath) print("First Play") } } @@ -130,11 +140,46 @@ extension MoreVC : TableViewSRC{ }) } - func playSong(url : String?){ - if let url { - vm.player = AVPlayer(url: URL(string: url)!) + 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() - vm.player.play() + } + } + + 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: vm.currentIndexPlayingSong ?? 0, section: 0)) as? SongListCell { + cell.updateCurrentTime() + } } } diff --git a/WOKA/Theme/View/BlogsCell.xib b/WOKA/Theme/View/BlogsCell.xib index 30dcd79..7288a4a 100644 --- a/WOKA/Theme/View/BlogsCell.xib +++ b/WOKA/Theme/View/BlogsCell.xib @@ -29,14 +29,14 @@ - + - + - +