304 lines
9.3 KiB
Swift
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()
|
|
}
|
|
}
|