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

304 lines
9.3 KiB
Swift

//
// SPPlayerDetailControlView.swift
// Thimra
//
// Created by on 2025/4/16.
//
import UIKit
class SPPlayerDetailControlView: SPPlayerControlView {
///
enum PauseState {
///
case hidden
///
case showPause
///
case showPlay
}
override var durationTime: Int {
didSet {
updateProgressTimeLabel()
}
}
override var currentTime: Int {
didSet {
updateProgressTimeLabel()
}
}
override var viewModel: SPPlayerListViewModel? {
didSet {
self.viewModel?.addObserver(self, forKeyPath: "speedModel", context: nil)
updateSpeedButton()
}
}
override var isCurrent: Bool {
didSet {
if isCurrent {
showSpeedSelectedView(isShow: false)
} else {
self.timer?.invalidate()
self.timer = nil
self.pauseState = .hidden
}
}
}
///
private lazy var pauseState = PauseState.hidden {
didSet {
switch pauseState {
case .hidden:
self.playImageView.isHidden = true
self.retreatButton.isHidden = true
self.advanceButton.isHidden = true
case .showPause:
self.playImageView.isHidden = false
self.retreatButton.isHidden = false
self.advanceButton.isHidden = false
self.playImageView.setImage(UIImage(named: "pause_icon_01"), for: .normal)
case .showPlay:
self.playImageView.isHidden = false
self.retreatButton.isHidden = false
self.advanceButton.isHidden = false
self.playImageView.setImage(UIImage(named: "play_icon_01"), for: .normal)
}
}
}
///
private var timer: Timer?
//MARK: UI
private lazy var episodeButton: UIButton = {
let button = createFeatureButton(title: "Episodes".localized, image: UIImage(named: "episode_icon_02"))
button.addTarget(self, action: #selector(handleEpisodeButton), for: .touchUpInside)
return button
}()
private lazy var progressTimeLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorFFFFFF()
return label
}()
private lazy var speedButton: UIButton = {
let button = UIButton(type: .custom)
button.setBackgroundImage(UIImage(color: .colorFFFFFF(alpha: 0.2)), for: .normal)
button.setTitleColor(.colorFFFFFF(alpha: 0.9), for: .normal)
button.titleLabel?.font = .fontLight(ofSize: 11)
button.layer.cornerRadius = 10
button.layer.masksToBounds = true
button.addTarget(self, action: #selector(handleSpeedButton), for: .touchUpInside)
return button
}()
private lazy var speedSelectedView: SPSpeedSelectedView = {
let view = SPSpeedSelectedView()
view.isHidden = true
view.didSelectedSpeed = { [weak self] speedModel in
guard let self = self else { return }
self.viewModel?.setSpeedPlay(speedModel: speedModel)
self.showSpeedSelectedView(isShow: false)
}
return view
}()
///退
private lazy var retreatButton: UIButton = {
let button = UIButton(type: .custom)
button.isHidden = true
button.setImage(UIImage(named: "speed_icon_01"), for: .normal)
button.addTarget(self, action: #selector(handleRetreatButton), for: .touchUpInside)
return button
}()
///
private lazy var advanceButton: UIButton = {
let button = UIButton(type: .custom)
button.isHidden = true
button.setImage(UIImage(named: "speed_icon_02"), for: .normal)
button.addTarget(self, action: #selector(handleAdvanceButton), for: .touchUpInside)
return button
}()
deinit {
self.viewModel?.removeObserver(self, forKeyPath: "speedModel")
}
override init(frame: CGRect) {
super.init(frame: frame)
self.playImageView.isUserInteractionEnabled = true
self.playImageView.addTarget(self, action: #selector(handlePlayImageView), for: .touchUpInside)
_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
if keyPath == "speedModel" {
updateSpeedButton()
}
}
private func updateProgressTimeLabel() {
let currentTime = self.currentTime.formatTimeGroup()
let durationTime = self.durationTime.formatTimeGroup()
progressTimeLabel.text = "\(currentTime.1):\(currentTime.2)/\(durationTime.1):\(durationTime.2)"
}
///
private func updateSpeedButton() {
self.speedButton.setTitle(self.viewModel?.speedModel.formatString(), for: .normal)
}
///
override func handleScreen() {
if self.pauseState == .hidden {
self.pauseState = .showPause
resetTimer()
} else if self.pauseState == .showPause {
self.pauseState = .hidden
self.cleanTimer()
}
}
override func updatePlayIconState() {
guard isCurrent else { return }
guard self.pauseState != .hidden else { return }
if self.viewModel?.isPlaying == true {
self.pauseState = .showPause
self.resetTimer()
} else {
self.pauseState = .showPlay
self.cleanTimer()
}
}
@objc private func handleHiddenTimer() {
self.pauseState = .hidden
}
///
private func cleanTimer() {
self.timer?.invalidate()
self.timer = nil
}
///
private func resetTimer() {
cleanTimer()
self.timer = Timer.scheduledTimer(timeInterval: 5, target: YYWeakProxy(target: self), selector: #selector(handleHiddenTimer), userInfo: nil, repeats: false)
}
}
extension SPPlayerDetailControlView {
private func _setupUI() {
self.rightFeatureView.addArrangedSubview(episodeButton)
toolView.addSubview(progressTimeLabel)
addSubview(retreatButton)
addSubview(advanceButton)
// addSubview(speedButton)
// addSubview(speedSelectedView)
// self.progressView.snp.remakeConstraints { make in
// make.left.equalToSuperview().offset(15)
// make.centerX.equalToSuperview()
// make.height.equalTo(30)
// make.bottom.equalToSuperview().offset(-(kSPTabbarSafeBottomMargin + 10))
// }
self.progressTimeLabel.snp.makeConstraints { make in
// make.left.equalTo(self.progressView)
// make.bottom.equalTo(self.progressView).offset(-12)
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(16)
}
retreatButton.snp.makeConstraints { make in
make.centerY.equalTo(playImageView)
make.right.equalTo(playImageView.snp.left).offset(kSPMainW(-50))
}
advanceButton.snp.makeConstraints { make in
make.centerY.equalTo(playImageView)
make.left.equalTo(playImageView.snp.right).offset(kSPMainW(50))
}
// speedButton.snp.makeConstraints { make in
// make.centerY.equalTo(self.progressTimeLabel)
// make.right.equalToSuperview().offset(-15)
// make.width.equalTo(40)
// make.height.equalTo(20)
// }
// speedSelectedView.snp.makeConstraints { make in
// make.left.right.equalToSuperview()
// make.bottom.equalTo(self.speedButton.snp.top).offset(-30)
// }
}
}
extension SPPlayerDetailControlView {
@objc private func handleEpisodeButton() {
self.viewModel?.handleEpisode?()
}
@objc private func handleSpeedButton() {
showSpeedSelectedView(isShow: speedSelectedView.isHidden)
}
///
private func showSpeedSelectedView(isShow: Bool) {
speedSelectedView.isHidden = !isShow
rightFeatureView.isHidden = isShow
if isShow {
self.speedSelectedView.currentSpeed = self.viewModel?.speedModel.speed ?? .x1
}
}
@objc private func handlePlayImageView() {
self.viewModel?.handlePauseOrPlay?()
}
///退
@objc private func handleRetreatButton() {
self.viewModel?.seekToTime(toTime: self.currentTime - 5)
resetTimer()
}
///
@objc private func handleAdvanceButton() {
self.viewModel?.seekToTime(toTime: self.currentTime + 5)
resetTimer()
}
}