I have a json file that has a list of media stations. I've presented them in four different sections based off of their "category" and "medium" properties. The issue I have is accessing these items in the didSelectRowAt method and passing them to a media player VC so they can be played in an interface that allows switching between stations with a forward and back button. I am able to easily pass the stations array to the media player VC but I can't get a meaningful indexPath or Int of some sort to be able to index into my stations array and add or subtract 1 to the position to change the station. I'm not sure how to proceed. One thing to note is that there is only 1 tv station in the stations array and its the first item,, if that makes a difference. I've included my code below and left out some of the UI code for readability.
import AVKit
import BlackLabsColor
import SDWebImage
import UIKit
private let reuseIdentifier = "Cell"
class MediaCollectionVC2: UICollectionViewController {
var stations = [Station]()
var myVC = MediaPlayerVC()
override func viewDidLoad() {
super.viewDidLoad()
fetchRadioStation()
collectionView.register(MediaCollectionViewCell.self, forCellWithReuseIdentifier: MediaCollectionViewCell.identifier)
collectionView.register(MediaCollectionSectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: MediaCollectionSectionReusableView.identifier)
collectionView.backgroundColor = .gray
self.title = "Live Media"
}
override func numberOfSections(in collectionView: UICollectionView) -> Int { return 4 }
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
var numOfItems = 0
for station in stations {
if station.medium == "TV" {
numOfItems += 1
}
}
return numOfItems
case 1:
var numOfItems = 0
for station in stations {
if station.category == "News" && station.medium == "Radio" {
numOfItems += 1
}
}
return numOfItems
case 2:
var numOfItems = 0
for station in stations {
if station.category == "Entertainment" && station.medium == "Radio" {
numOfItems += 1
}
}
return numOfItems
case 3:
var numOfItems = 0
for station in stations {
if station.category == "Religious" && station.medium == "Radio" {
numOfItems += 1
}
}
return numOfItems
default:
print("number of items in section problem")
}
return 10
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: MediaCollectionSectionReusableView.identifier, for: indexPath) as! MediaCollectionSectionReusableView
switch indexPath.section {
case 0:
sectionHeader.label.text = "TV"
return sectionHeader
case 1:
sectionHeader.label.text = "News Radio"
return sectionHeader
case 2:
sectionHeader.label.text = "Entertainment Radio"
return sectionHeader
case 3:
sectionHeader.label.text = "Religious Radio"
return sectionHeader
default:
sectionHeader.label.text = "Section Header Issue"
return sectionHeader
}
} else {
print("section header issue")
return UICollectionReusableView()
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MediaCollectionViewCell.identifier, for: indexPath) as! MediaCollectionViewCell
switch indexPath.section {
case 0:
let tvStations = stations.filter { $0.medium == "TV" }
let tvStation = tvStations[indexPath.row]
cell.imageView.image = UIImage(named: tvStation.name)
cell.titleLabel.text = tvStation.name
return cell
case 1:
let newsRadioStations = stations.filter { $0.category == "News" && $0.medium == "Radio" }
let newsRadioStation = newsRadioStations[indexPath.row]
cell.imageView.image = UIImage(named: "\(newsRadioStation.name).jpg")
cell.titleLabel.text = newsRadioStation.name
return cell
case 2:
let entertainmentRadioStations = stations.filter { $0.category == "Entertainment" && $0.medium == "Radio" }
let entertainmentRadioStation = entertainmentRadioStations[indexPath.row]
cell.imageView.image = UIImage(named: "\(entertainmentRadioStations.name).jpg")
cell.titleLabel.text = entertainmentRadioStation.name
return cell
case 3:
let religiousRadioStations = stations.filter { $0.category == "Religious" && $0.medium == "Radio" }
let religiousRadioStation = religiousRadioStations[indexPath.row]
cell.titleLabel.text = religiousRadioStation.name
return cell
default:
cell.imageView.image = UIImage(named: "tv")
cell.titleLabel.text = "PROBLEMO"
return cell
}
}
// ISSUES HERE
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
switch indexPath.section {
case 0:
let tvStations = stations.filter { $0.medium == "TV" }
let tvStation = tvStations[indexPath.row]
playVideo(streamURL: tvStation.streamURL)
// Works perfectly fine since I'm not presenting a view controller
case 1:
// Issues arise as I need to pass only radio stations to the player view controller.
let radioStations = stations.filter { $0.medium == "Radio" }
let position = indexPath.item
myVC.stations = radioStations
myVC.position = position
present(myVC, animated: true)
default:
print("nada")
}
}
func playVideo(streamURL: String) {
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
guard let url = URL(string: streamURL) else {
print("url issue")
return
}
let player = AVPlayer(url: url)
let playerController = AVPlayerViewController()
playerController.player = player
present(playerController, animated: true)
player.play()
} catch {
print("error: \(error)")
}
}
func fetchRadioStation() {
let baseURL = "https://jsonkeeper.com/b/"
guard let url = URL(string: baseURL) else {
print("station list URL invalid")
return
}
let session = URLSession(configuration: .default)
session.dataTask(with: url) { data, response, error in
if error != nil {
print(error ?? "error fetching stations")
return
}
if let safeData = data {
self.parseJSON(data: safeData)
}
}.resume()
}
func parseJSON(data: Data) {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(StationData.self, from: data)
let newsData = decodedData.stations
for item in newsData {
let name = item.name
let streamURL = item.streamURL
let desc = item.desc
let category = item.category
let medium = item.medium
let station = Station(name: name, streamURL: streamURL, desc: desc, category: category, medium: medium)
DispatchQueue.main.async {
self.stations.append(station)
self.collectionView.reloadData()
}
}
print("all stations loaded successfully")
} catch {
print("Error decoding: \(error)")
}
}
}
// Media Player VC
import AVFoundation
import BlackLabsColor
import SDWebImage
import UIKit
class MediaPlayerVC: UIViewController {
var backButton: UIButton!
var nextButton: UIButton!
public var station: Int = 0
public var stations = [Station]()
var player: AVPlayer?
var isPlaying: Bool = true
let playPauseButton = UIButton()
override func loadView() {
super.loadView()
configure()
}
override func viewDidLoad() {
super.viewDidLoad()
configure()
}
func configure() {
let station = stations[position]
let urlString = station.streamURL
do {
try AVAudioSession.sharedInstance().setCategory(.playback)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
guard let url = URL(string: urlString) else {
print("url issue")
return
}
player = AVPlayer(url: url)
guard let player = player else {
print("player issue")
return
}
player.volume = 0.5
player.play()
} catch {
print("error: \(error)")
}
}
@objc func playPauseButtonTapped(_ button: UIButton) {
player?.play()
isPlaying.toggle()
if isPlaying == true {
playPauseButton.setBackgroundImage(UIImage(systemName: "pause"), for: .normal)
} else {
player?.pause()
playPauseButton.setBackgroundImage(UIImage(systemName: "play"), for: .normal)
}
}
@objc func nextButtonTapped(_ button: UIButton) {
if position < stations.count - 1 {
position = position + 1
player?.pause()
for subview in view.subviews {
subview.removeFromSuperview()
}
loadView()
}
}
@objc func backButtonTapped(_ button: UIButton) {
if position > 0 {
position = position - 1
player?.pause()
for subview in view.subviews {
subview.removeFromSuperview()
}
loadView()
}
}
}