- Handled inline play play pause.
- Created a enum to handle the play pause resume functionality - Added tap handler with animation for cells. - Made logic if one audio is playing and then other audio plays , it ill deinit the first audio and play second. - Added deinit to the view controller, if the view dismiss the play will stop and denitialize
This commit is contained in:
@@ -73,6 +73,7 @@
|
||||
527AC6FA2C17387300434FB7 /* SongBlogDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527AC6F92C17387300434FB7 /* SongBlogDM.swift */; };
|
||||
527AC6FD2C173A5100434FB7 /* SongListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527AC6FB2C173A5100434FB7 /* SongListCell.swift */; };
|
||||
527AC6FE2C173A5100434FB7 /* SongListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 527AC6FC2C173A5100434FB7 /* SongListCell.xib */; };
|
||||
527AC7012C182DCE00434FB7 /* TimeStringToSeconds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527AC7002C182DCE00434FB7 /* TimeStringToSeconds.swift */; };
|
||||
529B0DD42C06156B00CFC54B /* LoginNavVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 529B0DD32C06156B00CFC54B /* LoginNavVC.swift */; };
|
||||
529B0DD62C070C0F00CFC54B /* GuestDataDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 529B0DD52C070C0F00CFC54B /* GuestDataDM.swift */; };
|
||||
52A3F6A52BECBA8D0000BB0B /* LinkedChildDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A3F6A42BECBA8D0000BB0B /* LinkedChildDM.swift */; };
|
||||
@@ -274,6 +275,7 @@
|
||||
527AC6F92C17387300434FB7 /* SongBlogDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongBlogDM.swift; sourceTree = "<group>"; };
|
||||
527AC6FB2C173A5100434FB7 /* SongListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongListCell.swift; sourceTree = "<group>"; };
|
||||
527AC6FC2C173A5100434FB7 /* SongListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SongListCell.xib; sourceTree = "<group>"; };
|
||||
527AC7002C182DCE00434FB7 /* TimeStringToSeconds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeStringToSeconds.swift; sourceTree = "<group>"; };
|
||||
529B0DD32C06156B00CFC54B /* LoginNavVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginNavVC.swift; sourceTree = "<group>"; };
|
||||
529B0DD52C070C0F00CFC54B /* GuestDataDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestDataDM.swift; sourceTree = "<group>"; };
|
||||
52A3F6A42BECBA8D0000BB0B /* LinkedChildDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkedChildDM.swift; sourceTree = "<group>"; };
|
||||
@@ -770,6 +772,14 @@
|
||||
path = Alerts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
527AC6FF2C182D1700434FB7 /* Timer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
527AC7002C182DCE00434FB7 /* TimeStringToSeconds.swift */,
|
||||
);
|
||||
path = Timer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
52C1A4DF2C05B670007BAA50 /* Delegate */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -792,6 +802,7 @@
|
||||
52C8B0512BDA4B51003B51D0 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
527AC6FF2C182D1700434FB7 /* Timer */,
|
||||
9CBE1B3E2C0F37B200CA6E61 /* DropDown */,
|
||||
9C535DB62C0089A700DA6DCD /* Animation */,
|
||||
525953D22BE8B2CD00191286 /* UIApplication */,
|
||||
@@ -1422,6 +1433,7 @@
|
||||
9C535DB52C005A6D00DA6DCD /* KeyWindowFix.swift in Sources */,
|
||||
9C9BEEC72BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift in Sources */,
|
||||
5222426A2BFC7AFC0085C632 /* SideMenuVC.swift in Sources */,
|
||||
527AC7012C182DCE00434FB7 /* TimeStringToSeconds.swift in Sources */,
|
||||
9CBCB29D2BE4D6BB007D7934 /* LoginVM.swift in Sources */,
|
||||
524C42312C0499560016A11C /* NotificationCenterReloads.swift in Sources */,
|
||||
9C8C4FAE2C1315410017DD3B /* WebViewVC.swift in Sources */,
|
||||
|
||||
48
WOKA/Helpers/Timer/TimeStringToSeconds.swift
Normal file
48
WOKA/Helpers/Timer/TimeStringToSeconds.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// TimeStringToSeconds.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 11/06/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension String {
|
||||
|
||||
func timeStringToSeconds() -> Int? {
|
||||
let components = self.split(separator: ":")
|
||||
|
||||
switch components.count {
|
||||
case 2:
|
||||
// MM:SS format
|
||||
let minutes = Int(components[0]) ?? 0
|
||||
let seconds = Int(components[1]) ?? 0
|
||||
return (minutes * 60) + seconds
|
||||
case 3:
|
||||
// HH:MM:SS format
|
||||
let hours = Int(components[0]) ?? 0
|
||||
let minutes = Int(components[1]) ?? 0
|
||||
let seconds = Int(components[2]) ?? 0
|
||||
return (hours * 3600) + (minutes * 60) + seconds
|
||||
default:
|
||||
// Invalid format
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func checkHourZero() -> String{
|
||||
// Function to format the time
|
||||
// Split the time string by ":"
|
||||
let components = self.split(separator: ":")
|
||||
|
||||
// Check if the time string starts with "00"
|
||||
if components.count == 3 && components[0] == "00" {
|
||||
// Remove the initial "00:"
|
||||
return "\(components[1]):\(components[2])"
|
||||
} else {
|
||||
// Return the original time string
|
||||
return self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -757,7 +757,7 @@
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemGreenColor">
|
||||
<color red="0.20392156862745098" green="0.7803921568627451" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.20392156859999999" green="0.78039215689999997" blue="0.34901960780000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -16,14 +16,16 @@ class MoreVC: UIViewController {
|
||||
@IBOutlet weak var songTableView: UITableView!
|
||||
|
||||
var vm = MoreVM()
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
vm.vc = self
|
||||
vm.initView()
|
||||
|
||||
}
|
||||
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
vm.player.pause()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - TableView DataSource , Delegates
|
||||
@@ -36,17 +38,104 @@ 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)
|
||||
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)
|
||||
// }
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let data = vm.songData[indexPath.row]
|
||||
if let url = data.contentMoreDetails?.first?.url{
|
||||
vm.player = AVPlayer()
|
||||
vm.playSong(urlString: url)
|
||||
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}
|
||||
/*
|
||||
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:
|
||||
print("Player is playing")
|
||||
vm.player.pause()
|
||||
case .pause:
|
||||
print("Player is pause")
|
||||
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
|
||||
*/
|
||||
|
||||
print("Other cell playing")
|
||||
}
|
||||
}else{
|
||||
// if there is no playing audio before
|
||||
vm.playerStatus = .play
|
||||
vm.currentIndexPlayingSong = indexPath.row
|
||||
tableView.reloadRows(at: [indexPath], with: .none)
|
||||
let data = vm.songData[indexPath.row]
|
||||
playSong(url: data.contentMoreDetails?.first?.url)
|
||||
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 playSong(url : String?){
|
||||
if let url {
|
||||
vm.player = AVPlayer(url: URL(string: url)!)
|
||||
vm.observePlayer()
|
||||
vm.player.play()
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
@@ -95,8 +184,48 @@ extension MoreVC : UICollectionViewDelegateFlowLayout{
|
||||
let widthPerItem = availableWidth / itemsPerRow
|
||||
return CGSize(width: widthPerItem, height: widthPerItem - 20)
|
||||
}
|
||||
|
||||
// func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
|
||||
// return UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SongListCell.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 10/06/24.
|
||||
// Created by Bilal Khan on 10/06/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -12,22 +12,129 @@ class SongListCell: UITableViewCell {
|
||||
@IBOutlet weak var ongoingTimeLabel: UILabel!
|
||||
@IBOutlet weak var totalTimeLabel: UILabel!
|
||||
@IBOutlet weak var songTitle: UILabel!
|
||||
@IBOutlet weak var outerStack: UIStackView!
|
||||
@IBOutlet weak var playPauseImage: UIImageView!
|
||||
@IBOutlet weak var indicatorView: UIView!
|
||||
|
||||
// typealias btnTappedBlock = (String?) -> Void
|
||||
// var btnTapped : btnTappedBlock!
|
||||
|
||||
var timer: Timer?
|
||||
private var currentTime: Int = 0
|
||||
var totalTime: Int = 0
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
|
||||
// self.addTapGesture { [weak self] in
|
||||
// guard let self else{return}
|
||||
// UIView.animate(withDuration: 0.1, animations: {
|
||||
// self.outerStack.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
|
||||
// }) { _ in
|
||||
// UIView.animate(withDuration: 0.1) {
|
||||
// self.outerStack.transform = .identity
|
||||
// self.btnTapped(self.ongoingTimeLabel.text)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
func setData(data : SongBlogDM.PaintDatum){
|
||||
self.totalTimeLabel.text = "/" + (data.songDuration ?? "0:00")
|
||||
self.ongoingTimeLabel.text = "0:00"
|
||||
self.songTitle.text = data.title!
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
// Invalidate the timer when the cell is reused
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
ongoingTimeLabel.text = "0:00"
|
||||
}
|
||||
|
||||
func setData(data: SongBlogDM.PaintDatum, playerStatus: PlayerStatus) {
|
||||
ongoingTimeLabel.text = "00:00"
|
||||
totalTime = 0
|
||||
currentTime = 0
|
||||
|
||||
|
||||
switch playerStatus{
|
||||
case .stopped:
|
||||
playPauseImage.image = UIImage(systemName: "play.fill")
|
||||
case .pause:
|
||||
playPauseImage.image = UIImage(systemName: "play.fill")
|
||||
case .play:
|
||||
playPauseImage.image = UIImage(systemName: "pause.fill")
|
||||
totalTime = data.songDuration?.timeStringToSeconds() ?? 0
|
||||
|
||||
// if let onGoingTime{
|
||||
// currentTime = onGoingTime.timeStringToSeconds() ?? 0
|
||||
// ongoingTimeLabel.text = onGoingTime
|
||||
// }else{
|
||||
// currentTime = 0
|
||||
// }
|
||||
startCountdown()
|
||||
|
||||
case .resume:
|
||||
playPauseImage.image = UIImage(systemName: "pause.fill")
|
||||
totalTime = data.songDuration?.timeStringToSeconds() ?? 0
|
||||
// if let onGoingTime{
|
||||
// currentTime = onGoingTime.timeStringToSeconds() ?? 0
|
||||
// ongoingTimeLabel.text = onGoingTime
|
||||
// }else{
|
||||
// currentTime = 0
|
||||
// }
|
||||
startCountdown()
|
||||
case .loading:
|
||||
break
|
||||
}
|
||||
|
||||
// Set total time label and song title
|
||||
if let totalDuration = data.songDuration{
|
||||
//Check of the hour is zero removing it
|
||||
let totalTimeFiltered = totalDuration.checkHourZero()
|
||||
totalTimeLabel.text = "/" + totalTimeFiltered
|
||||
}else{
|
||||
totalTimeLabel.text = "/" + (data.songDuration ?? "00:00")
|
||||
}
|
||||
|
||||
songTitle.text = data.title ?? "Unknown Title"
|
||||
}
|
||||
|
||||
private func startCountdown() {
|
||||
// Invalidate any existing timer
|
||||
timer?.invalidate()
|
||||
|
||||
// Schedule a new timer
|
||||
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCountdown), userInfo: nil, repeats: true)
|
||||
}
|
||||
|
||||
@objc private func updateCountdown() {
|
||||
// Update the timer label
|
||||
if currentTime < totalTime {
|
||||
currentTime += 1
|
||||
ongoingTimeLabel.text = formatTime(currentTime)
|
||||
} else {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
}
|
||||
}
|
||||
// @objc private func updateCountdown() {
|
||||
// // Update countdown label
|
||||
// if totalTime > 0 {
|
||||
// totalTime -= 1
|
||||
// ongoingTimeLabel.text = formatTime(totalTime)
|
||||
// } else {
|
||||
// timer?.invalidate()
|
||||
// timer = nil
|
||||
// ongoingTimeLabel.text = "0:00"
|
||||
// }
|
||||
// }
|
||||
|
||||
private func formatTime(_ seconds: Int) -> String {
|
||||
// Format time as MM:SS
|
||||
let minutes = seconds / 60
|
||||
let seconds = seconds % 60
|
||||
return String(format: "%02d:%02d", minutes, seconds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,25 @@
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="ngc-D8-N88">
|
||||
<rect key="frame" x="0.0" y="0.0" width="96.666666666666671" height="59"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="play.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="MdW-yq-Mld">
|
||||
<rect key="frame" x="0.0" y="2" width="59" height="55"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="MdW-yq-Mld" secondAttribute="height" multiplier="1:1" id="XHF-ha-GMe"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rtY-dp-opx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="59" height="59"/>
|
||||
<subviews>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kPE-0t-owy">
|
||||
<rect key="frame" x="-59" y="0.0" width="59" height="59"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="kPE-0t-owy" secondAttribute="height" multiplier="1:1" id="z5t-lK-vIu"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="play.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="MdW-yq-Mld">
|
||||
<rect key="frame" x="0.0" y="2" width="59" height="55"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="MdW-yq-Mld" secondAttribute="height" multiplier="1:1" id="XHF-ha-GMe"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Text" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QJ2-HR-46k">
|
||||
<rect key="frame" x="64" y="0.0" width="32.666666666666657" height="59"/>
|
||||
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="16"/>
|
||||
@@ -43,8 +55,8 @@
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="eI6-es-65E">
|
||||
<rect key="frame" x="287.33333333333331" y="0.0" width="48.666666666666686" height="59"/>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eI6-es-65E">
|
||||
<rect key="frame" x="258" y="0.0" width="78" height="59"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0:00" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mcL-xd-aWa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="34.666666666666664" height="59"/>
|
||||
@@ -52,8 +64,8 @@
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="/" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5XU-52-i0j">
|
||||
<rect key="frame" x="39.666666666666686" y="0.0" width="9" height="59"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="/0:00" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5XU-52-i0j">
|
||||
<rect key="frame" x="34.666666666666686" y="0.0" width="43.333333333333343" height="59"/>
|
||||
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="16"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -81,7 +93,10 @@
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outlet property="indicatorView" destination="kPE-0t-owy" id="zk4-72-spv"/>
|
||||
<outlet property="ongoingTimeLabel" destination="mcL-xd-aWa" id="RAG-Kd-oGz"/>
|
||||
<outlet property="outerStack" destination="era-Az-5kr" id="doP-ZG-AnD"/>
|
||||
<outlet property="playPauseImage" destination="MdW-yq-Mld" id="QWN-o8-gMJ"/>
|
||||
<outlet property="songTitle" destination="QJ2-HR-46k" id="de9-lx-Wmg"/>
|
||||
<outlet property="totalTimeLabel" destination="5XU-52-i0j" id="2BY-NO-kXO"/>
|
||||
</connections>
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
import UIKit
|
||||
import AVFoundation
|
||||
|
||||
enum PlayerStatus{
|
||||
case play
|
||||
case loading
|
||||
case pause
|
||||
case resume
|
||||
case stopped
|
||||
}
|
||||
class MoreVM{
|
||||
|
||||
weak var vc : MoreVC!
|
||||
@@ -15,27 +22,54 @@ class MoreVM{
|
||||
var blogData = [BlogDM.Blog]()
|
||||
|
||||
var songData = [SongBlogDM.PaintDatum]()
|
||||
var player: AVPlayer?
|
||||
|
||||
var player = AVPlayer()
|
||||
var playerObserver: NSKeyValueObservation?
|
||||
var playerStatus = PlayerStatus.loading
|
||||
|
||||
var currentIndexPlayingSong : Int?
|
||||
|
||||
func initView(){
|
||||
getBLogs()
|
||||
getSong()
|
||||
setupCell()
|
||||
vc.songTableView.showsVerticalScrollIndicator = false
|
||||
vc.songTableView.showsHorizontalScrollIndicator = false
|
||||
vc.homeBtn.addTapGesture {
|
||||
self.vc.dismiss(animated: true)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
func playSong(urlString: String) {
|
||||
guard let url = URL(string: urlString) else {
|
||||
print("Invalid URL string.")
|
||||
return
|
||||
}
|
||||
|
||||
player = AVPlayer(url: url)
|
||||
player?.play()
|
||||
func observePlayer() {
|
||||
playerObserver = self.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.playerStatus = .play
|
||||
case .paused:
|
||||
print("Player is paused")
|
||||
self.playerStatus = .pause
|
||||
case .waitingToPlayAtSpecifiedRate:
|
||||
print("Player is waiting to play at specified rate")
|
||||
self.playerStatus = .loading
|
||||
@unknown default:
|
||||
print("Unknown player status")
|
||||
}
|
||||
})
|
||||
}
|
||||
//
|
||||
// func playSong(urlString: String) {
|
||||
// guard let url = URL(string: urlString) else {
|
||||
// print("Invalid URL string.")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// player = AVPlayer(url: url)
|
||||
// player?.play()
|
||||
// }
|
||||
|
||||
func setupCell(){
|
||||
vc.blogsCollectionView.register(UINib(nibName: K.CellIdentifier.Home.blogsCell, bundle: nil), forCellWithReuseIdentifier: K.CellIdentifier.Home.blogsCell)
|
||||
|
||||
Reference in New Issue
Block a user