Swift - CollectionView's didSelectItemAt: Unable to switch on indexPath.section to access correct item

254 Views Asked by At

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()
    }

}

}

0

There are 0 best solutions below