MoviaBox/Thimra/Class/Player/View/SPPlayerControlView.swift
2025-04-23 11:33:46 +08:00

286 lines
8.8 KiB
Swift

//
// SPPlayerControlView.swift
// Thimra
//
// Created by on 2025/4/9.
//
import UIKit
class SPPlayerControlView: UIView {
weak var viewModel: SPPlayerListViewModel? {
didSet {
viewModel?.addObserver(self, forKeyPath: "isPlaying", context: nil)
}
}
var shortModel: SPShortModel? {
didSet {
updateCollectButtonState()
}
}
var videoInfo: SPVideoInfoModel? {
didSet {
}
}
///
var panProgressFinishBlock: ((_ progress: CGFloat) -> Void)?
///0-1
var progress: CGFloat = 0 {
didSet {
progressView.progress = progress
}
}
var durationTime: Int = 0
var currentTime: Int = 0
var isCurrent: Bool = false {
didSet {
updatePlayIconState()
}
}
//MARK: UI
///
private lazy var bottomGradientView: SPGradientView = {
let view = SPGradientView()
view.colors = [UIColor.color000000(alpha: 0).cgColor, UIColor.color000000(alpha: 0.5).cgColor]
view.startPoint = .init(x: 0.5, y: 0)
view.endPoint = .init(x: 0.5, y: 1)
view.locations = [0, 1]
view.isUserInteractionEnabled = false
return view
}()
private(set) lazy var progressView: SPPlayerProgressView = {
let view = SPPlayerProgressView()
view.panStart = { [weak self] in
guard let self = self else { return }
self.panProgressStart()
}
view.panChange = { [weak self] progress in
guard let self = self else { return }
self.panProgressChange(progress: progress)
}
view.panFinish = { [weak self] progress in
guard let self = self else { return }
self.panProgressFinish(progress: progress)
}
return view
}()
private(set) lazy var toolView: UIView = {
let view = UIView()
view.backgroundColor = .color1C1C1E()
return view
}()
private(set) lazy var playImageView: UIButton = {
let button = UIButton(type: .custom)
button.isHidden = true
button.setImage(UIImage(named: "play_icon_01"), for: .normal)
button.isUserInteractionEnabled = false
return button
}()
///
private(set) lazy var rightFeatureView: UIStackView = {
let view = UIStackView(arrangedSubviews: [collectButton])
view.axis = .vertical
view.spacing = 25
return view
}()
///
private lazy var collectButton: UIButton = {
let button = createFeatureButton(title: "Save".localized, selectedTitle: "Added".localized, image: UIImage(named: "collect_icon_01"), selectedImage: UIImage(named: "collect_icon_01_selected"))
button.addTarget(self, action: #selector(handleCollectButton), for: .touchUpInside)
return button
}()
deinit {
viewModel?.removeObserver(self, forKeyPath: "isPlaying")
NotificationCenter.default.removeObserver(self)
}
override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(updateShortCollectStateNotification), name: SPVideoAPI.updateShortCollectStateNotification, object: nil)
let tap = UITapGestureRecognizer(target: self, action: #selector(handleScreen))
tap.delegate = self
self.addGestureRecognizer(tap)
sp_setupUI()
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "isPlaying" {
updatePlayIconState()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createFeatureButton(title: String?, selectedTitle: String? = nil, image: UIImage?, selectedImage: UIImage? = nil) -> UIButton {
let button = JXButton(type: .custom)
button.titleDirection = .down
button.setImage(image, for: .normal)
button.setImage(selectedImage, for: .selected)
button.setImage(selectedImage, for: [.selected, .highlighted])
button.setTitle(title, for: .normal);
button.setTitle(selectedTitle, for: .selected);
button.setTitle(selectedTitle, for: [.selected, .highlighted])
button.setTitleColor(.colorFFFFFF(), for: .normal)
// button.setTitleColor(.colorF564B6(), for: .selected)
button.jx_font = .fontMedium(ofSize: 12)
return button
}
@objc func handleScreen() {
self.hadlePlayAndOrPaused()
}
func updatePlayIconState() {
let isPlaying = self.viewModel?.isPlaying ?? false
if isCurrent {
playImageView.isHidden = isPlaying
} else {
playImageView.isHidden = true
}
}
}
extension SPPlayerControlView {
private func sp_setupUI() {
addSubview(bottomGradientView)
addSubview(progressView)
progressView.addSubview(toolView)
addSubview(playImageView)
addSubview(rightFeatureView)
bottomGradientView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(kSPTabbarSafeBottomMargin + 200)
}
progressView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(40)
}
toolView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.bottom.equalToSuperview().offset(-2)
}
playImageView.snp.makeConstraints { make in
make.center.equalToSuperview()
}
rightFeatureView.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-15)
make.bottom.equalToSuperview().offset(-200)
}
}
}
extension SPPlayerControlView {
@objc private func hadlePlayAndOrPaused() {
self.viewModel?.handlePauseOrPlay?()
// guard let model = model as? SPShortModel else { return }
// let vc = SPTVPlayerListViewController()
// vc.shortPlayId = model.short_play_id
// vc.videoId = model.video_info?.short_play_video_id
// SPAPPTool.topViewController()?.navigationController?.pushViewController(vc, animated: true)
}
@objc private func handleCollectButton() {
guard let shortPlayId = self.videoInfo?.short_play_id else { return }
guard let videoId = self.videoInfo?.short_play_video_id else { return }
let isCollect = !(self.shortModel?.is_collect ?? false)
SPVideoAPI.requestCollectShort(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId) {
}
}
@objc private func updateShortCollectStateNotification(sender: Notification) {
guard let userInfo = sender.userInfo else { return }
guard let shortPlayId = userInfo["id"] as? String else { return }
guard let isCollect = userInfo["state"] as? Bool else { return }
guard shortPlayId == self.videoInfo?.short_play_id else { return }
self.shortModel?.is_collect = isCollect;
updateCollectButtonState()
}
private func updateCollectButtonState() {
self.collectButton.isSelected = self.shortModel?.is_collect ?? false
}
}
extension SPPlayerControlView {
///
private func panProgressStart() {
// self.isHidden = true
// screenProgressView.duration = self.player?.duration ?? 0
// screenProgressView.frame = self.window?.bounds ?? .zero
//
// self.window?.addSubview(screenProgressView)
//
// var point = self.progressView.convert(CGPoint(x: 0, y: 0), to: self.window)
// point.y = point.y + self.progressView.size.height - self.progressView.lineWidth / 2
//
// screenProgressView.point = point
}
///
private func panProgressChange(progress: CGFloat) {
// screenProgressView.progress = progress
}
///
private func panProgressFinish(progress: CGFloat) {
// self.isHidden = false
// screenProgressView.removeFromSuperview()
self.panProgressFinishBlock?(progress)
}
}
//MARK: -------------- UIGestureRecognizerDelegate --------------
extension SPPlayerControlView: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view != self {
return false
} else {
return true
}
}
}