// // SPPlayerControlView.swift // ShortPlay // // 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 isCurrent: Bool = false { didSet { updatePlayIconState() } } //MARK: UI属性 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 lazy var playImageView: UIImageView = { let imageView = UIImageView() imageView.backgroundColor = .red imageView.isHidden = true return imageView }() ///右边功能区 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(hadlePlayAndOrPaused)) 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(alpha: 0.9), for: .normal) button.setTitleColor(.colorF564B6(), for: .selected) button.jx_font = .fontLight(ofSize: 11); return button } } extension SPPlayerControlView { private func sp_setupUI() { addSubview(progressView) addSubview(playImageView) addSubview(rightFeatureView) progressView.snp.makeConstraints { make in make.left.equalToSuperview().offset(10) make.centerX.equalToSuperview() make.bottom.equalToSuperview().offset(-20) make.height.equalTo(30) } playImageView.snp.makeConstraints { make in make.center.equalToSuperview() make.width.height.equalTo(100) } rightFeatureView.snp.makeConstraints { make in make.right.equalToSuperview().offset(-15) make.bottom.equalToSuperview().offset(-200) } } } extension SPPlayerControlView { private func updatePlayIconState() { let isPlaying = self.viewModel?.isPlaying ?? false if isCurrent { playImageView.isHidden = isPlaying } else { playImageView.isHidden = true } } @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 } let isCollect = !(self.shortModel?.is_collect ?? false) SPVideoAPI.requestCollectShort(isCollect: isCollect, shortPlayId: shortPlayId) { } } @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) } }