Fableon/Fableon/Object/Class/Player/V/FAPlayerDetailControlView.swift
湖北秦九 008d5b55b8 1
2025-11-21 09:12:46 +08:00

254 lines
8.0 KiB
Swift

//
// FAPlayerDetailControlView.swift
// Fableon
//
// Created by on 2025/9/16.
//
import UIKit
import JXPlayer
import SwiftUI
class FAPlayerDetailControlView: JXPlayerListControlView {
override var viewModel: JXPlayerListViewModel? {
didSet {
self.viewModel?.addObserver(self, forKeyPath: "isPlaying", context: nil)
}
}
var fa_viewModel: FAShortDetailViewModel? {
return self.viewModel as? FAShortDetailViewModel
}
override var model: Any? {
didSet {
let model = self.model as? FAVideoInfoModel
updateEp()
}
}
var shortModel: FAShortPlayModel? {
didSet {
updateEp()
shortNameLabel.text = shortModel?.name
textLabel.text = shortModel?.fa_description
collectButton.isSelected = shortModel?.is_collect == true
}
}
override var durationTime: TimeInterval {
didSet {
updateProgress()
}
}
override var currentTime: TimeInterval {
didSet {
updateProgress()
}
}
override var isCurrent: Bool {
didSet {
playButton.setNeedsUpdateConfiguration()
}
}
override var isLoading: Bool {
didSet {
progressView.isLoading = isLoading
}
}
private lazy var epButton: UIHostingController<FAPlayerEpUIButton> = {
let view = FAPlayerEpUIButton()
let hc = UIHostingController(rootView: view)
hc.view.backgroundColor = .clear
return hc
}()
private lazy var progressView: FAPlayerProgressView = {
let view = FAPlayerProgressView()
view.insets = .init(top: 10, left: 16, bottom: 10, right: 16)
view.panFinish = { [weak self] progress in
guard let self = self else { return }
self.viewModel?.seekTo(Float(progress))
}
return view
}()
private lazy var textLabel: UILabel = {
let label = UILabel()
label.font = .font(ofSize: 12, weight: .regular);
label.textColor = UIColor(named: .color_FFFFFF)!.withAlphaComponent(0.8)
label.numberOfLines = 2
return label
}()
private lazy var shortNameLabel: UILabel = {
let label = UILabel()
label.font = .font(ofSize: 16, weight: .medium)
label.textColor = UIColor(named: .color_FFFFFF)
return label
}()
private lazy var playButton: UIButton = {
let config = UIButton.Configuration.plain()
let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
self?.fa_viewModel?.userSwitchPlayAndPause()
}))
button.configurationUpdateHandler = { [weak self] button in
guard let self = self else { return }
if self.viewModel?.isPlaying == true || !isCurrent {
button.configuration?.image = UIImage(named: "pause_icon")
} else {
button.configuration?.image = UIImage(named: "play_icon_01")
}
}
return button
}()
private lazy var collectButton: UIButton = {
var config = UIButton.Configuration.plain()
config.background.backgroundColor = .clear
let button = UIButton(configuration: config)
button.configurationUpdateHandler = { [weak self] button in
guard let self = self else { return }
if button.isSelected {
button.configuration?.image = UIImage(named: "collect_star_icon_selected")
} else {
button.configuration?.image = UIImage(named: "collect_star_icon")
}
}
button.addAction(UIAction(handler: { [weak self] _ in
guard let self = self else { return }
guard let shortPlayId = self.shortModel?.short_play_id else { return }
let videoId = (self.model as? FAVideoInfoModel)?.short_play_video_id
let isCollect = !(self.shortModel?.is_collect ?? false)
if isCollect {
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
} else {
let alert = FARemoveCollectAlert()
alert.clickHighlightButton = {
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
}
alert.show()
}
}), for: .touchUpInside)
return button
}()
deinit {
NotificationCenter.default.removeObserver(self)
}
override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(updateShortCollectStateNotification), name: FAAPI.updateShortCollectStateNotification, object: nil)
fa_setupLayout()
}
@MainActor required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "isPlaying" {
playButton.setNeedsUpdateConfiguration()
}
}
private func updateEp() {
let model = self.model as? FAVideoInfoModel
let text = "fableon_episode_set".localizedReplace(text: model?.episode ?? "") + "/" + "fableon_episode_set".localizedReplace(text: "\(shortModel?.episode_total ?? 0)")
var view = FAPlayerEpUIButton(text: text)
view.clickHandle = { [weak self] in
self?.fa_viewModel?.onEpSelectorView()
}
epButton.rootView = view
}
private func updateProgress() {
guard durationTime > 0 else {
progressView.progress = 0
return
}
progressView.progress = currentTime / durationTime
}
@objc private func updateShortCollectStateNotification(sender: Notification) {
guard let userInfo = sender.userInfo else { return }
guard let shortPlayId = userInfo["id"] as? String else { return }
guard let state = userInfo["state"] as? Bool else { return }
guard shortPlayId == self.shortModel?.short_play_id else { return }
self.shortModel?.is_collect = state
collectButton.isSelected = state
}
}
extension FAPlayerDetailControlView {
private func fa_setupLayout() {
addSubview(epButton.view)
addSubview(progressView)
addSubview(textLabel)
addSubview(shortNameLabel)
addSubview(playButton)
addSubview(collectButton)
epButton.view.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
}
progressView.snp.makeConstraints { make in
make.left.equalToSuperview()
make.centerX.equalToSuperview()
make.bottom.equalTo(epButton.view.snp.top).offset(-8)
}
textLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.right.lessThanOrEqualToSuperview().offset(-84)
make.bottom.equalTo(progressView.snp.top).offset(1)
}
shortNameLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.bottom.equalTo(textLabel.snp.top).offset(-5)
make.right.lessThanOrEqualToSuperview().offset(-84)
}
playButton.snp.makeConstraints { make in
make.center.equalToSuperview()
}
collectButton.snp.makeConstraints { make in
make.top.equalToSuperview().offset(UIScreen.safeTop)
make.right.equalToSuperview().offset(-16)
make.height.equalTo(44)
}
}
}