MoviaBox/ShortPlay/Class/Player/Controller/SPPlayerListViewController.swift

330 lines
10 KiB
Swift

//
// SPPlayerListViewController.swift
// ShortPlay
//
// Created by on 2025/4/8.
//
import UIKit
@objc protocol SPPlayerListViewControllerDelegate {
///
@objc optional func sp_playerViewControllerLoadNewDataV2(playerViewController: SPPlayerListViewController)
///
@objc optional func sp_playerViewControllerShouldLoadMoreData(playerViewController: SPPlayerListViewController) -> Bool
///
@objc optional func sp_playerViewControllerLoadMoreData(playerViewController: SPPlayerListViewController)
///
@objc optional func sp_playerViewControllerLoadUpMoreData(playerViewController: SPPlayerListViewController)
///
// @objc optional func yd_playerViewController(playerListViewController: BCListPlayerViewController, didShowPlayerPage playerViewController: YDBasePlayerViewController)
}
@objc protocol SPPlayerListViewControllerDataSource {
func sp_playerListViewController(_ viewController: SPPlayerListViewController, _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath, oldCell: UICollectionViewCell) -> UICollectionViewCell
func sp_playerListViewController(_ viewController: SPPlayerListViewController, _ collectionView: UICollectionView, numberOfItemsInSection section: Int, oldNumber: Int) -> Int
}
class SPPlayerListViewController: SPViewController {
var contentSize: CGSize {
return CGSize(width: kSPScreenWidth, height: kSPScreenHeight - kSPTabBarHeight)
}
var PlayerCellClass: SPPlayerListCell.Type {
return SPPlayerListCell.self
}
weak var delegate: SPPlayerListViewControllerDelegate?
weak var dataSource: SPPlayerListViewControllerDataSource?
private(set) var dataArr: [Any] = []
var pagination: SPListPaginationModel?
///
var autoNextEpisode = false
private(set) var viewModel = SPPlayerListViewModel()
private(set) var currentIndexPath = IndexPath(row: 0, section: 0)
private lazy var collectionViewLayout: UICollectionViewLayout = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = contentSize
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
return layout
}()
private(set) lazy var collectionView: SPCollectionView = {
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isPagingEnabled = true
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.bounces = false
collectionView.scrollsToTop = false
PlayerCellClass.registerCell(collectionView: collectionView)
return collectionView
}()
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
//
do {
try? KTVHTTPCache.proxyStart()
}
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActiveNotification), name: UIApplication.didBecomeActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willResignActiveNotification), name: UIApplication.willResignActiveNotification, object: nil)
sp_setupUI()
sp_addActio()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if getDataCount() > 0 && self.viewModel.isPlaying {
self.viewModel.currentPlayer?.start()
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.viewModel.currentPlayer?.pause()
}
func setDataArr(dataArr: [Any]) {
self.dataArr = dataArr
reloadData()
}
func clearDataArr() {
self.dataArr.removeAll()
self.viewModel.currentPlayer = nil
self.collectionView.reloadData()
}
func play() {
if self.isDidAppear {
self.viewModel.currentPlayer?.start()
}
self.viewModel.isPlaying = true
if getDataCount() - currentIndexPath.row <= 2 {
self.loadMoreData()
}
if currentIndexPath.row <= 2 {
// self.loadUpMoreData()
}
}
func reloadData() {
CATransaction.begin()
self.collectionView.reloadData()
CATransaction.commit()
}
func getDataCount() -> Int {
return self.collectionView(self.collectionView, numberOfItemsInSection: 0)
}
}
extension SPPlayerListViewController {
private func sp_setupUI() {
view.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
private func sp_addActio() {
self.viewModel.handlePauseOrPlay = { [weak self] in
self?.clickPauseOrPlay()
}
self.viewModel.handlePlayFinish = { [weak self] in
self?.currentPlayFinish()
}
}
}
extension SPPlayerListViewController {
///
private func clickPauseOrPlay() {
// let model = self.dataArr[currentIndexPath.section]
///
// if self.onVideoPay() {
// return
// }
if self.viewModel.isPlaying {
self.viewModel.isPlaying = false
self.viewModel.currentPlayer?.pause()
} else {
self.viewModel.isPlaying = true
self.viewModel.currentPlayer?.start()
}
}
///
private func currentPlayFinish() {
guard self.autoNextEpisode else { return }
scrollToNextEpisode()
}
///
private func scrollToNextEpisode() {
var contentOffset = self.collectionView.contentOffset
if hasNextEpisode() {
contentOffset.y = contentOffset.y + self.contentSize.height
self.collectionView.setContentOffset(contentOffset, animated: true)
} else {
self.viewModel.currentPlayer?.replay()
}
}
///
private func hasNextEpisode() -> Bool {
let contentOffset = self.collectionView.contentOffset
let contentSize = self.collectionView.contentSize
if contentOffset.y >= contentSize.height - self.contentSize.height {
return false
}
return true
}
}
//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource --------------
extension SPPlayerListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell: UICollectionViewCell = PlayerCellClass.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
if let newCell = self.dataSource?.sp_playerListViewController(self, collectionView, cellForItemAt: indexPath, oldCell: cell) {
cell = newCell
}
if let cell = cell as? SPPlayerListCell {
if cell.viewModel == nil {
cell.viewModel = viewModel
}
// let model = dataArr[indexPath.row]
// cell.model = model
}
if self.viewModel.currentPlayer == nil, indexPath == currentIndexPath, let playerProtocol = cell as? SPPlayerProtocol {
self.currentIndexPath = indexPath
self.viewModel.currentPlayer = playerProtocol
}
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let count = dataArr.count
if let newCount = self.dataSource?.sp_playerListViewController(self, collectionView, numberOfItemsInSection: section, oldNumber: count) {
return newCount
} else {
return count
}
}
//
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
scrollDidEnd(scrollView)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
scrollDidEnd(scrollView)
}
private func scrollDidEnd(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let indexPaths = self.collectionView.indexPathsForVisibleItems
for indexPath in indexPaths {
guard let cell = self.collectionView.cellForItem(at: indexPath) else { continue }
if offsetY == cell.frame.origin.y {
if self.currentIndexPath != indexPath {
self.skip(indexPath: indexPath)
}
}
}
}
private func skip(indexPath: IndexPath) {
currentIndexPath = indexPath
guard let currentPlayer = self.collectionView.cellForItem(at: indexPath) as? SPPlayerProtocol else { return }
self.viewModel.currentPlayer = currentPlayer
// currentCell = self.collectionView.cellForItem(at: indexPath) as? BCListPlayerCell
self.play()
}
}
//MARK: -------------- APP --------------
extension SPPlayerListViewController {
@objc func didBecomeActiveNotification() {
if getDataCount() > 0 && self.viewModel.isPlaying && isDidAppear {
self.viewModel.currentPlayer?.start()
}
}
@objc func willResignActiveNotification() {
self.viewModel.currentPlayer?.pause()
}
}
extension SPPlayerListViewController {
private func loadMoreData() {
let isLoad = self.delegate?.sp_playerViewControllerShouldLoadMoreData?(playerViewController: self)
if isLoad != false {
self.delegate?.sp_playerViewControllerLoadMoreData?(playerViewController: self)
}
}
private func loadUpMoreData() {
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
// guard let self = self else { return }
// }
self.delegate?.sp_playerViewControllerLoadUpMoreData?(playerViewController: self)
}
}