241 lines
7.7 KiB
Swift
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()
|
|
}
|
|
}
|
|
|
|
}
|