SynthReel/SynthReel/Class/Player/V/SRShortDetailControlView.swift
2025-12-02 13:27:27 +08:00

241 lines
7.7 KiB
Swift

//
// SRShortDetailControlView.swift
// SynthReel
//
// Created by on 2025/11/18.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import JXPlayer
import SnapKit
class SRShortDetailControlView: JXPlayerListControlView {
var sr_viewModel: SRShortPlayerViewModel? {
return self.viewModel as? SRShortPlayerViewModel
}
override var viewModel: JXPlayerListViewModel? {
didSet {
self.viewModel?.addObserver(self, forKeyPath: "isPlaying", context: nil)
}
}
var shortModel: SRShortModel? {
didSet {
titleLabel.text = shortModel?.name
collectButton.isSelected = shortModel?.is_collect == true
}
}
override var durationTime: TimeInterval {
didSet {
updateProgress()
let (_, m, s) = Int(durationTime).formatTimeGroup()
totalTimeLabel.text = "\(m):\(s)"
}
}
override var currentTime: TimeInterval {
didSet {
updateProgress()
let (_, m, s) = Int(currentTime).formatTimeGroup()
currentTimeLabel.text = "\(m):\(s)"
}
}
override var isLoading: Bool {
didSet {
progressView.isLoading = isLoading
}
}
lazy var progressBgView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "short_progress_bg_image"))
imageView.isUserInteractionEnabled = true
return imageView
}()
lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .font(ofSize: 14, weight: .medium)
label.textColor = .srBlue
return label
}()
lazy var progressView: SRProgressView = {
let view = SRProgressView()
view.insets = .init(top: 10, left: 5, bottom: 10, right: 5)
view.panFinish = { [weak self] progress in
guard let self = self else { return }
self.viewModel?.seekTo(Float(progress))
}
return view
}()
lazy var totalTimeLabel: UILabel = {
let label = UILabel()
label.font = .font(ofSize: 10, weight: .regular)
label.textColor = .DFDFDF
label.text = "00:00"
return label
}()
lazy var currentTimeLabel: UILabel = {
let label = UILabel()
label.font = .font(ofSize: 10, weight: .regular)
label.textColor = .DFDFDF
label.text = "00:00"
return label
}()
lazy var epButton: UIButton = {
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
guard let self = self else { return }
self.sr_viewModel?.onEpSelectorView()
}))
button.setImage(UIImage(named: "ep_icon_01"), for: .normal)
return button
}()
lazy var collectButton: UIButton = {
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
guard let self = self else { return }
guard let shortId = self.shortModel?.short_play_id else { return }
let videoId = (self.model as? SRVideoInfoModel)?.short_play_video_id
let isCollect = !(self.shortModel?.is_collect ?? false)
Task {
await SRShortApi.requestShortCollect(shortId: shortId, videoId: videoId, isCollect: isCollect)
}
}))
button.setImage(UIImage(named: "collect_icon_01"), for: .normal)
button.setImage(UIImage(named: "collect_icon_01_selected"), for: .selected)
button.setImage(UIImage(named: "collect_icon_01_selected"), for: [.selected, .highlighted])
return button
}()
lazy var playerImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "play_icon_02"))
imageView.isHidden = true
return imageView
}()
deinit {
self.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: SRShortApi.updateShortCollectStateNotification, object: nil)
let tap = UITapGestureRecognizer { [weak self] _ in
guard let self = self else { return }
self.viewModel?.userSwitchPlayAndPause()
}
self.addGestureRecognizer(tap)
sr_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func updateShortCollectStateNotification(sender: Notification) {
guard let userInfo = sender.userInfo else { return }
guard let shortId = userInfo["id"] as? String else { return }
guard let state = userInfo["state"] as? Bool else { return }
guard shortId == self.shortModel?.short_play_id else { return }
self.shortModel?.is_collect = state
collectButton.isSelected = state
}
private func updateProgress() {
guard durationTime > 0 else {
progressView.progress = 0
return
}
progressView.progress = currentTime / durationTime
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "isPlaying" {
updatePlayerViewStatus()
}
}
func updatePlayerViewStatus() {
if self.viewModel?.isPlaying == true || !isCurrent {
playerImageView.isHidden = true
} else {
playerImageView.isHidden = false
}
}
}
extension SRShortDetailControlView {
private func sr_setupUI() {
addSubview(progressBgView)
progressBgView.addSubview(titleLabel)
progressBgView.addSubview(progressView)
progressBgView.addSubview(totalTimeLabel)
progressBgView.addSubview(currentTimeLabel)
addSubview(epButton)
addSubview(collectButton)
addSubview(playerImageView)
progressBgView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 5))
make.height.equalTo(88)
}
titleLabel.snp.makeConstraints { make in
make.centerY.equalTo(progressBgView.snp.top).offset(23)
make.left.equalToSuperview().offset(9)
make.right.lessThanOrEqualToSuperview().offset(-9)
}
progressView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(4)
make.right.equalToSuperview().offset(-6)
make.bottom.equalToSuperview().offset(-30)
}
totalTimeLabel.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-11)
make.bottom.equalToSuperview().offset(-24)
}
currentTimeLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(9)
make.bottom.equalToSuperview().offset(-24)
}
epButton.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-15)
make.bottom.equalTo(progressBgView.snp.top).offset(-44)
}
collectButton.snp.makeConstraints { make in
make.centerX.equalTo(epButton)
make.bottom.equalTo(epButton.snp.top).offset(-25)
}
playerImageView.snp.makeConstraints { make in
make.center.equalToSuperview()
}
}
}