Veloria/Veloria/Class/Player/View/VPVideoPlayerCell.swift
2025-06-13 18:21:03 +08:00

225 lines
5.4 KiB
Swift

//
// VPVideoPlayerCell.swift
// Veloria
//
// Created by on 2025/5/22.
//
import UIKit
class VPVideoPlayerCell: VPCollectionViewCell, VPPlayerProtocol {
var ControlViewClass: VPVideoPlayerControlView.Type {
return VPVideoPlayerControlView.self
}
weak var viewModel: VPVideoPlayViewModel? {
didSet {
self.controlView.viewModel = self.viewModel
}
}
var shortModel: VPShortModel? {
didSet {
self.controlView.shortModel = shortModel
coverImageView.vp_setImage(url: shortModel?.image_url)
}
}
var videoInfo: VPVideoInfoModel? {
didSet {
self.controlView.progress = 0
self.controlView.currentTime = 0
self.controlView.durationTime = 0
self.controlView.videoInfo = videoInfo
player.setPlayUrl(url: videoInfo?.video_url ?? "")
}
}
var isLoop = true {
didSet {
player.isLoop = isLoop
}
}
private lazy var player: VPPlayer = {
let player = VPPlayer()
player.playerView = playerView
player.delegate = self
return player
}()
//MARK: UI
private lazy var playerView: UIView = {
let view = UIView()
return view
}()
private lazy var coverImageView: VPImageView = {
let imageView = VPImageView()
return imageView
}()
private(set) lazy var controlView: VPVideoPlayerControlView = {
let view = ControlViewClass.init()
view.panProgressFinishBlock = { [weak self] progress in
guard let self = self else { return }
let duration = CGFloat(self.player.duration)
let toTime = progress * duration
self.player.seekToTime(toTime: Int(toTime))
}
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
vp_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: VPPlayerProtocol
var playerFinishHadle: (() -> Void)?
var isCurrent: Bool = false {
didSet {
controlView.isCurrent = isCurrent
if !isCurrent {
self.coverImageView.isHidden = false
}
}
}
var hasLastEpisodeUnlocked: Bool = false
var duration: Int {
get {
return player.duration
}
}
var currentPosition: Int {
get {
player.currentPosition
}
}
var rate: Float {
set {
player.rate = newValue
}
get {
player.rate
}
}
func prepare() {
player.setPlayUrl(url: videoInfo?.video_url ?? "")
// self.player.stop()
// self.player.prepare()
}
func start() {
player.start()
}
func pause() {
player.pause()
}
func replay() {
player.replay()
}
func seekToTime(toTime: Int) {
player.seekToTime(toTime: toTime)
}
}
extension VPVideoPlayerCell {
private func vp_setupUI() {
contentView.addSubview(playerView)
contentView.addSubview(coverImageView)
contentView.addSubview(controlView)
coverImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
playerView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
controlView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}
//MARK: -------------- SPPlayerDelegate --------------
extension VPVideoPlayerCell: VPPlayerDelegate {
func vp_playCompletion(_ player: VPPlayer) {
// self.playerFinishHadle?()
self.viewModel?.handlePlayFinish?()
}
func vp_playLoadingEnd(_ player: VPPlayer) {
}
func vp_playTimeChanged(_ player: VPPlayer, currentTime: Int, duration: Int) {
controlView.progress = CGFloat(currentTime) / CGFloat(duration)
controlView.currentTime = currentTime
controlView.durationTime = duration
self.viewModel?.handlePlayTimeDidChange?(currentTime)
}
func vp_firstRenderedStart(_ player: VPPlayer) {
}
func vp_player(_ player: VPPlayer, playStateDidChanged state: VPPlayer.PlayState) {
updateCoverShowState()
}
func vp_player(_ player: VPPlayer, loadStateDidChange state: VPPlayer.LoadState) {
if state == .prepare || state == .stalled {
self.controlView.isLoading = true
} else {
self.controlView.isLoading = false
}
updateCoverShowState()
}
func vp_playerReadyToPlay(_ player: VPPlayer) {
self.seekToTime(toTime: (videoInfo?.play_seconds ?? 0) / 1000)
player.rate = self.viewModel?.rateModel.rate.getRate() ?? 1
}
private func updateCoverShowState() {
let loadState = self.player.loadState
let playState = self.player.playState
if isCurrent && (loadState == .playable || loadState == .playthroughOK) && (playState == .playing) {
self.coverImageView.isHidden = true
}
}
}