diff --git a/Thimra/Base/Extension/UIColor+SPAdd.swift b/Thimra/Base/Extension/UIColor+SPAdd.swift index 6a06d27..17ec061 100644 --- a/Thimra/Base/Extension/UIColor+SPAdd.swift +++ b/Thimra/Base/Extension/UIColor+SPAdd.swift @@ -160,5 +160,17 @@ extension UIColor { static func color5A5C67(alpha: CGFloat = 1) -> UIColor { return color(hex: 0x5A5C67, alpha: alpha) } + + static func color3D4556(alpha: CGFloat = 1) -> UIColor { + return color(hex: 0x3D4556, alpha: alpha) + } + + static func color1C1C1E(alpha: CGFloat = 1) -> UIColor { + return color(hex: 0x1C1C1E, alpha: alpha) + } + + static func colorEC3324(alpha: CGFloat = 1) -> UIColor { + return color(hex: 0xEC3324, alpha: alpha) + } } diff --git a/Thimra/Base/Networking/API/SPVideoAPI.swift b/Thimra/Base/Networking/API/SPVideoAPI.swift index b7869a7..05143dc 100644 --- a/Thimra/Base/Networking/API/SPVideoAPI.swift +++ b/Thimra/Base/Networking/API/SPVideoAPI.swift @@ -104,6 +104,17 @@ class SPVideoAPI: NSObject { } } + ///获取视频分类 + static func requestShortCategoryList() { + var param = SPNetworkParameters(path: "/getCategories") + param.method = .get + + SPNetwork.request(parameters: param) { (response: SPNetworkResponse>) in +// completer?(response.data) + } + + } + } extension SPVideoAPI { diff --git a/Thimra/Class/Explore/Controller/SPAllShortViewController.swift b/Thimra/Class/Explore/Controller/SPAllShortViewController.swift new file mode 100644 index 0000000..29d0653 --- /dev/null +++ b/Thimra/Class/Explore/Controller/SPAllShortViewController.swift @@ -0,0 +1,27 @@ +// +// SPAllShortViewController.swift +// Thimra +// +// Created by Overseas on 2025/4/23. +// + +import UIKit + +class SPAllShortViewController: SPViewController { + + override func viewDidLoad() { + super.viewDidLoad() + self.view.backgroundColor = .clear + SPVideoAPI.requestShortCategoryList() + + } + + override func setBgImageView() { + + } +} + +extension SPAllShortViewController { + + +} diff --git a/Thimra/Class/Explore/Controller/SPExplorePageController.swift b/Thimra/Class/Explore/Controller/SPExplorePageController.swift index 44fa9c6..b76949a 100644 --- a/Thimra/Class/Explore/Controller/SPExplorePageController.swift +++ b/Thimra/Class/Explore/Controller/SPExplorePageController.swift @@ -11,10 +11,16 @@ import UIKit class SPExplorePageController: SPViewController { private lazy var titles: [String] = { - let arr = ["Shorts".localized, "Featured".localized, "All".localized] + let arr = ["Shorts".localized, "All".localized] return arr }() + private lazy var viewControllers: [SPViewController] = { + let vc1 = SPExploreViewController() + let vc2 = SPAllShortViewController() + return [vc1, vc2] + }() + private lazy var itemWidthArr: [NSNumber] = { var arr: [NSNumber] = [] self.titles.forEach { @@ -129,7 +135,7 @@ extension SPExplorePageController: WMPageControllerDelegate, WMPageControllerDat } func pageController(_ pageController: WMPageController, viewControllerAt index: Int) -> UIViewController { - return SPExploreViewController() + return viewControllers[index] } diff --git a/Thimra/Class/Explore/Controller/SPExploreViewController.swift b/Thimra/Class/Explore/Controller/SPExploreViewController.swift index 67f26e2..bf800e8 100644 --- a/Thimra/Class/Explore/Controller/SPExploreViewController.swift +++ b/Thimra/Class/Explore/Controller/SPExploreViewController.swift @@ -15,7 +15,7 @@ class SPExploreViewController: SPPlayerListViewController { override func viewDidLoad() { super.viewDidLoad() - + self.autoNextEpisode = true requestDataArr(page: 1) self.delegate = self @@ -53,6 +53,7 @@ extension SPExploreViewController: SPPlayerListViewControllerDataSource { cell.shortModel = model cell.videoInfo = model.video_info } + cell.isLoop = false } return oldCell } @@ -70,8 +71,9 @@ extension SPExploreViewController { guard let self = self else { return } if let listModel = listModel, let list = listModel.list { if page == 1 { - self.setDataArr(dataArr: list) - self.play() + self.setDataArr(dataArr: list) { [weak self] in + self?.play() + } } else { self.addDataArr(dataArr: list) } diff --git a/Thimra/Class/Explore/View/SPExplorePlayerControlView.swift b/Thimra/Class/Explore/View/SPExplorePlayerControlView.swift index 97b02fc..f748e91 100644 --- a/Thimra/Class/Explore/View/SPExplorePlayerControlView.swift +++ b/Thimra/Class/Explore/View/SPExplorePlayerControlView.swift @@ -12,27 +12,59 @@ class SPExplorePlayerControlView: SPPlayerControlView { override var shortModel: SPShortModel? { didSet { - desLabel.text = shortModel?.sp_description +// desLabel.text = shortModel?.sp_description videoInfoView.shortModel = shortModel + +// shortModel?.episode_total + updateEpisodeLabel() } } - private lazy var desLabel: UILabel = { - let label = UILabel() - label.font = .fontRegular(ofSize: 12) - label.textColor = .colorD2D2D2() - label.numberOfLines = 2 - return label - }() + override var videoInfo: SPVideoInfoModel? { + didSet { + updateEpisodeLabel() + } + } + +// private lazy var desLabel: UILabel = { +// let label = UILabel() +// label.font = .fontRegular(ofSize: 12) +// label.textColor = .colorD2D2D2() +// label.numberOfLines = 2 +// return label +// }() private lazy var videoInfoView: SPVideoPlayerInfoView = { let view = SPVideoPlayerInfoView() return view }() + private lazy var episodeIconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "episode_icon_01")) + return imageView + }() + + private lazy var episodeLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 12) + return label + }() + + private lazy var allEpisodeButton: UIButton = { + let button = JXButton(type: .custom) + button.setTitle("Full Episodes".localized, for: .normal) + button.setTitleColor(.colorEC3324(), for: .normal) + button.setImage(UIImage(named: "arrow_right_icon_01"), for: .normal) + button.jx_font = .fontMedium(ofSize: 12) + button.titleDirection = .left + button.space = 4 + button.addTarget(self, action: #selector(handleAllEpisodeButton), for: .touchUpInside) + return button + }() + override init(frame: CGRect) { super.init(frame: frame) - self.progressView.isHidden = true +// self.progressView.isHidden = true _setupUI() } @@ -41,23 +73,67 @@ class SPExplorePlayerControlView: SPPlayerControlView { fatalError("init(coder:) has not been implemented") } + private func updateEpisodeLabel() { + let totalEpisode = String(format: "EP%@".localized, "\(self.shortModel?.episode_total ?? 0)") + let currentEpisode = String(format: "EP%@".localized, self.videoInfo?.episode ?? "0") + let episodeStr = "\(currentEpisode)/\(totalEpisode)" + let range = NSRange(location: episodeStr.length() - totalEpisode.length(), length: totalEpisode.length()) + + let string = NSMutableAttributedString(string: episodeStr) + string.color = .colorEC3324() + string.setColor(.colorFFFFFF(), range: range) + + episodeLabel.attributedText = string + + } + +} + +extension SPExplorePlayerControlView { + + @objc private func handleAllEpisodeButton() { + let vc = SPPlayerDetailViewController() + vc.shortPlayId = self.shortModel?.short_play_id + self.viewController?.navigationController?.pushViewController(vc, animated: true) + } + + } extension SPExplorePlayerControlView { private func _setupUI() { - addSubview(desLabel) +// addSubview(desLabel) addSubview(videoInfoView) + toolView.addSubview(episodeIconImageView) + toolView.addSubview(episodeLabel) + toolView.addSubview(allEpisodeButton) - desLabel.snp.makeConstraints { make in - make.left.equalToSuperview().offset(15) - make.right.lessThanOrEqualToSuperview().offset(-30) - make.bottom.equalToSuperview().offset(-15) - } +// desLabel.snp.makeConstraints { make in +// make.left.equalToSuperview().offset(15) +// make.right.lessThanOrEqualToSuperview().offset(-30) +// make.bottom.equalToSuperview().offset(-15) +// } videoInfoView.snp.makeConstraints { make in make.left.equalToSuperview().offset(15) - make.bottom.equalTo(desLabel.snp.top).offset(-10) +// make.bottom.equalTo(desLabel.snp.top).offset(-10) + make.bottom.equalToSuperview().offset(-54) + } + + episodeIconImageView.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(14) + } + + episodeLabel.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalTo(episodeIconImageView.snp.right).offset(4) + } + + allEpisodeButton.snp.makeConstraints { make in + make.top.bottom.equalToSuperview() + make.right.equalToSuperview().offset(-14) } } } diff --git a/Thimra/Class/Explore/View/SPVideoPlayerInfoView.swift b/Thimra/Class/Explore/View/SPVideoPlayerInfoView.swift index a3eb08d..dc1307a 100644 --- a/Thimra/Class/Explore/View/SPVideoPlayerInfoView.swift +++ b/Thimra/Class/Explore/View/SPVideoPlayerInfoView.swift @@ -13,47 +13,36 @@ class SPVideoPlayerInfoView: UIView { didSet { coverImageView.sp_setImage(url: shortModel?.image_url) titleLabel.text = shortModel?.name + desLabel.text = shortModel?.sp_description } } - //MARK: UI属性 - private lazy var bgView: UIView = { - let view = UIView() - view.layer.cornerRadius = 5 - view.layer.masksToBounds = true - view.backgroundColor = .color000000(alpha: 0.27) - return view - }() + override var intrinsicContentSize: CGSize { + return CGSize(width: 200, height: 68) + } + //MARK: UI属性 private lazy var coverImageView: SPImageView = { let imageView = SPImageView() - imageView.layer.cornerRadius = 5 + imageView.layer.cornerRadius = 4 imageView.layer.masksToBounds = true + imageView.layer.borderWidth = 1 + imageView.layer.borderColor = UIColor.colorFFFFFF(alpha: 0.26).cgColor return imageView }() private lazy var titleLabel: UILabel = { let label = UILabel() - label.font = .fontRegular(ofSize: 13) + label.font = .fontMedium(ofSize: 14) label.textColor = .colorFFFFFF() return label }() - private lazy var moreButton: JXButton = { - let button = JXButton(type: .custom) - button.colors = [UIColor.colorF56490().cgColor, UIColor.colorD568D2().cgColor] - button.startPoint = .init(x: 0, y: 0.5) - button.endPoint = .init(x: 1, y: 0.5) - button.locations = [0, 1] - button.setImage(UIImage(named: "play_icon_02"), for: .normal) - button.setTitle("Series".localized, for: .normal) - button.setTitleColor(.colorFFFFFF(), for: .normal) - button.jx_font = .fontRegular(ofSize: 11) - button.layer.cornerRadius = 10.5 - button.layer.masksToBounds = true - button.space = 2 - button.addTarget(self, action: #selector(handleMoreButton), for: .touchUpInside) - return button + private lazy var desLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 12) + label.textColor = .colorA8A5AA() + return label }() override init(frame: CGRect) { @@ -76,34 +65,30 @@ class SPVideoPlayerInfoView: UIView { extension SPVideoPlayerInfoView { private func _setupUI() { - addSubview(bgView) + addSubview(coverImageView) addSubview(titleLabel) - addSubview(moreButton) + addSubview(desLabel) - bgView.snp.makeConstraints { make in - make.left.right.bottom.equalToSuperview() - make.width.equalTo(240) - make.height.equalTo(54) - } coverImageView.snp.makeConstraints { make in - make.left.bottom.top.equalToSuperview() - make.width.equalTo(49) - make.height.equalTo(66) + make.left.top.bottom.equalToSuperview() + make.width.equalTo(46) + make.height.equalTo(68) } titleLabel.snp.makeConstraints { make in make.left.equalTo(coverImageView.snp.right).offset(10) - make.top.equalTo(bgView).offset(5) - make.right.lessThanOrEqualToSuperview().offset(-18) + make.top.equalToSuperview().offset(16) + make.right.lessThanOrEqualToSuperview() + make.width.lessThanOrEqualTo(145) } - moreButton.snp.makeConstraints { make in - make.left.equalTo(coverImageView.snp.right).offset(10) - make.bottom.equalToSuperview().offset(-5) - make.width.equalTo(59) - make.height.equalTo(21) + desLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.top.equalTo(titleLabel.snp.bottom).offset(8) + make.right.lessThanOrEqualToSuperview() + make.width.lessThanOrEqualTo(145) } diff --git a/Thimra/Class/Player/Controller/SPPlayerDetailViewController.swift b/Thimra/Class/Player/Controller/SPPlayerDetailViewController.swift index 2d1ecd8..eac9f8f 100644 --- a/Thimra/Class/Player/Controller/SPPlayerDetailViewController.swift +++ b/Thimra/Class/Player/Controller/SPPlayerDetailViewController.swift @@ -14,7 +14,7 @@ class SPPlayerDetailViewController: SPPlayerListViewController { } override var contentSize: CGSize { - return CGSize(width: kSPScreenWidth, height: kSPScreenHeight) + return CGSize(width: kSPScreenWidth, height: kSPScreenHeight - kSPTabbarSafeBottomMargin - 35) } @@ -37,11 +37,24 @@ class SPPlayerDetailViewController: SPPlayerListViewController { private lazy var titleLabel: UILabel = { let label = UILabel() - label.font = .fontLight(ofSize: 15) - label.textColor = .colorFFFFFF(alpha: 0.9) + label.font = .fontBold(ofSize: 18) + label.textColor = .colorFFFFFF() return label }() + private lazy var episodeLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 18) + label.textColor = .colorFFFFFF(alpha: 0.4) + return label + }() + + private lazy var bottomView: UIView = { + let view = UIView() + view.backgroundColor = .color1C1C1E() + return view + }() + override func viewDidLoad() { super.viewDidLoad() self.autoNextEpisode = true @@ -78,6 +91,8 @@ extension SPPlayerDetailViewController { private func _setupUI() { view.addSubview(backButton) view.addSubview(titleLabel) + view.addSubview(episodeLabel) + view.addSubview(bottomView) backButton.snp.makeConstraints { make in make.left.equalToSuperview().offset(5) @@ -88,7 +103,18 @@ extension SPPlayerDetailViewController { titleLabel.snp.makeConstraints { make in make.left.equalTo(backButton.snp.right) make.centerY.equalTo(backButton) - make.right.equalToSuperview().offset(-15) +// make.right.equalToSuperview().offset(-15) + make.width.lessThanOrEqualTo(kSPScreenWidth - 130) + } + + episodeLabel.snp.makeConstraints { make in + make.centerY.equalTo(titleLabel) + make.left.equalTo(titleLabel.snp.right).offset(16) + } + + bottomView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalTo(self.collectionView.snp.bottom) } } @@ -136,7 +162,9 @@ extension SPPlayerDetailViewController: SPPlayerListViewControllerDataSource, SP self.episodeView?.currentIndex = indexPath.row let videoInfo = detailModel?.episodeList?[indexPath.row] - titleLabel.text = String(format: "kPlayerDetailTitleString".localized, "\(videoInfo?.episode ?? "0")", self.detailModel?.shortPlayInfo?.name ?? "") +// titleLabel.text = String(format: "kPlayerDetailTitleString".localized, "\(videoInfo?.episode ?? "0")", self.detailModel?.shortPlayInfo?.name ?? "") + titleLabel.text = detailModel?.shortPlayInfo?.name + episodeLabel.text = "\(videoInfo?.episode ?? "0")/\(detailModel?.shortPlayInfo?.episode_total ?? 0)" } } diff --git a/Thimra/Class/Player/Controller/SPPlayerListViewController.swift b/Thimra/Class/Player/Controller/SPPlayerListViewController.swift index a18a0bb..aa51419 100644 --- a/Thimra/Class/Player/Controller/SPPlayerListViewController.swift +++ b/Thimra/Class/Player/Controller/SPPlayerListViewController.swift @@ -121,9 +121,9 @@ class SPPlayerListViewController: SPViewController { } - func setDataArr(dataArr: [Any]) { + func setDataArr(dataArr: [Any], completer: (() -> Void)?) { self.dataArr = dataArr - reloadData() + reloadData(completion: completer) } func addDataArr(dataArr: [Any]) { @@ -260,7 +260,7 @@ extension SPPlayerListViewController { var contentOffset = self.collectionView.contentOffset if hasNextEpisode() { - contentOffset.y = contentOffset.y + self.contentSize.height + contentOffset.y = floor(contentOffset.y + self.contentSize.height) self.collectionView.setContentOffset(contentOffset, animated: true) } else { self.viewModel.currentPlayer?.replay() diff --git a/Thimra/Class/Player/Model/SPPlayerProtocol.swift b/Thimra/Class/Player/Model/SPPlayerProtocol.swift index 2e29d07..d46276f 100644 --- a/Thimra/Class/Player/Model/SPPlayerProtocol.swift +++ b/Thimra/Class/Player/Model/SPPlayerProtocol.swift @@ -17,6 +17,12 @@ protocol SPPlayerProtocol: NSObjectProtocol { var isCurrent: Bool { get set } + + ///总进度 + var duration: Int { get } + ///当前进度 + var currentPosition: Int { get } + var rate: Float { get set } ///播放准备 @@ -30,5 +36,7 @@ protocol SPPlayerProtocol: NSObjectProtocol { ///从头播放 func replay() - + + ///设置进度 + func seekToTime(toTime: Int) } diff --git a/Thimra/Class/Player/View/SPEpisodeView.swift b/Thimra/Class/Player/View/SPEpisodeView.swift index fbaee3a..d6cf318 100644 --- a/Thimra/Class/Player/View/SPEpisodeView.swift +++ b/Thimra/Class/Player/View/SPEpisodeView.swift @@ -169,7 +169,7 @@ class SPEpisodeView: HWPanModalContentView { override func backgroundConfig() -> HWBackgroundConfig { let config = HWBackgroundConfig() - config.backgroundAlpha = 0.4 + config.backgroundAlpha = 0.6 return config } diff --git a/Thimra/Class/Player/View/SPPlayerControlView.swift b/Thimra/Class/Player/View/SPPlayerControlView.swift index 997ca24..e50eb75 100644 --- a/Thimra/Class/Player/View/SPPlayerControlView.swift +++ b/Thimra/Class/Player/View/SPPlayerControlView.swift @@ -78,11 +78,18 @@ class SPPlayerControlView: UIView { return view }() - private lazy var playImageView: UIImageView = { - let imageView = UIImageView() - imageView.backgroundColor = .red - imageView.isHidden = true - return imageView + private(set) lazy var toolView: UIView = { + let view = UIView() + view.backgroundColor = .color1C1C1E() + return view + }() + + private(set) lazy var playImageView: UIButton = { + let button = UIButton(type: .custom) + button.isHidden = true + button.setImage(UIImage(named: "play_icon_01"), for: .normal) + button.isUserInteractionEnabled = false + return button }() ///右边功能区 @@ -110,7 +117,7 @@ class SPPlayerControlView: UIView { NotificationCenter.default.addObserver(self, selector: #selector(updateShortCollectStateNotification), name: SPVideoAPI.updateShortCollectStateNotification, object: nil) - let tap = UITapGestureRecognizer(target: self, action: #selector(hadlePlayAndOrPaused)) + let tap = UITapGestureRecognizer(target: self, action: #selector(handleScreen)) tap.delegate = self self.addGestureRecognizer(tap) @@ -139,12 +146,24 @@ class SPPlayerControlView: UIView { button.setTitle(title, for: .normal); button.setTitle(selectedTitle, for: .selected); button.setTitle(selectedTitle, for: [.selected, .highlighted]) - button.setTitleColor(.colorFFFFFF(alpha: 0.9), for: .normal) - button.setTitleColor(.colorF564B6(), for: .selected) - button.jx_font = .fontLight(ofSize: 11); + button.setTitleColor(.colorFFFFFF(), for: .normal) +// button.setTitleColor(.colorF564B6(), for: .selected) + button.jx_font = .fontMedium(ofSize: 12) return button } + @objc func handleScreen() { + self.hadlePlayAndOrPaused() + } + + func updatePlayIconState() { + let isPlaying = self.viewModel?.isPlaying ?? false + if isCurrent { + playImageView.isHidden = isPlaying + } else { + playImageView.isHidden = true + } + } } @@ -153,6 +172,7 @@ extension SPPlayerControlView { private func sp_setupUI() { addSubview(bottomGradientView) addSubview(progressView) + progressView.addSubview(toolView) addSubview(playImageView) addSubview(rightFeatureView) @@ -162,15 +182,17 @@ extension SPPlayerControlView { } progressView.snp.makeConstraints { make in - make.left.equalToSuperview().offset(10) - make.centerX.equalToSuperview() - make.bottom.equalToSuperview().offset(-20) - make.height.equalTo(30) + make.left.right.bottom.equalToSuperview() + make.height.equalTo(40) + } + + toolView.snp.makeConstraints { make in + make.left.right.top.equalToSuperview() + make.bottom.equalToSuperview().offset(-2) } playImageView.snp.makeConstraints { make in make.center.equalToSuperview() - make.width.height.equalTo(100) } rightFeatureView.snp.makeConstraints { make in @@ -182,15 +204,6 @@ extension SPPlayerControlView { extension SPPlayerControlView { - private func updatePlayIconState() { - let isPlaying = self.viewModel?.isPlaying ?? false - if isCurrent { - playImageView.isHidden = isPlaying - } else { - playImageView.isHidden = true - } - } - @objc private func hadlePlayAndOrPaused() { self.viewModel?.handlePauseOrPlay?() diff --git a/Thimra/Class/Player/View/SPPlayerDetailControlView.swift b/Thimra/Class/Player/View/SPPlayerDetailControlView.swift index 0e4c119..891a7ce 100644 --- a/Thimra/Class/Player/View/SPPlayerDetailControlView.swift +++ b/Thimra/Class/Player/View/SPPlayerDetailControlView.swift @@ -8,6 +8,15 @@ import UIKit class SPPlayerDetailControlView: SPPlayerControlView { + ///暂停按钮状态 + enum PauseState { + ///隐藏状态 + case hidden + ///显示暂停按钮 + case showPause + ///显示播放按钮 + case showPlay + } override var durationTime: Int { @@ -33,22 +42,50 @@ class SPPlayerDetailControlView: SPPlayerControlView { 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: "episodes_icon_01")) + 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 = .fontLight(ofSize: 12) - label.textColor = .colorFFFFFF(alpha: 0.9) + label.font = .fontRegular(ofSize: 12) + label.textColor = .colorFFFFFF() return label }() @@ -74,12 +111,32 @@ class SPPlayerDetailControlView: SPPlayerControlView { 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() } @@ -107,6 +164,51 @@ class SPPlayerDetailControlView: SPPlayerControlView { 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 { @@ -114,34 +216,48 @@ extension SPPlayerDetailControlView { private func _setupUI() { self.rightFeatureView.addArrangedSubview(episodeButton) - addSubview(progressTimeLabel) - addSubview(speedButton) - addSubview(speedSelectedView) + 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.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.left.equalTo(self.progressView) +// make.bottom.equalTo(self.progressView).offset(-12) + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(16) } - speedButton.snp.makeConstraints { make in - make.centerY.equalTo(self.progressTimeLabel) - make.right.equalToSuperview().offset(-15) - make.width.equalTo(40) - make.height.equalTo(20) + retreatButton.snp.makeConstraints { make in + make.centerY.equalTo(playImageView) + make.right.equalTo(playImageView.snp.left).offset(kSPMainW(-50)) } - speedSelectedView.snp.makeConstraints { make in - make.left.right.equalToSuperview() - make.bottom.equalTo(self.speedButton.snp.top).offset(-30) + 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) +// } + } } @@ -164,4 +280,24 @@ extension SPPlayerDetailControlView { 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() + } } diff --git a/Thimra/Class/Player/View/SPPlayerListCell.swift b/Thimra/Class/Player/View/SPPlayerListCell.swift index 8656c9f..a6e6940 100644 --- a/Thimra/Class/Player/View/SPPlayerListCell.swift +++ b/Thimra/Class/Player/View/SPPlayerListCell.swift @@ -9,6 +9,7 @@ import UIKit class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol { + var PlayerControlViewClass: SPPlayerControlView.Type { return SPPlayerControlView.self } @@ -111,9 +112,22 @@ class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol { } } + ///总进度 + var duration: Int { + get { + return player.duration + } + } + ///当前进度 + var currentPosition: Int { + get { + return player.currentPosition + } + } + var rate: Float { set { - return player.rate = newValue + player.rate = newValue } get { return player.rate @@ -139,6 +153,10 @@ class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol { player.replay() } + func seekToTime(toTime: Int) { + player.seekToTime(toTime: toTime) + } + } extension SPPlayerListCell { diff --git a/Thimra/Class/Player/View/SPPlayerProgressView.swift b/Thimra/Class/Player/View/SPPlayerProgressView.swift index b8f5db0..c8ab7de 100644 --- a/Thimra/Class/Player/View/SPPlayerProgressView.swift +++ b/Thimra/Class/Player/View/SPPlayerProgressView.swift @@ -32,10 +32,10 @@ class SPPlayerProgressView: UIView { ///滑动进度 private var panProgress: CGFloat = 0 - var progressColor: UIColor = .colorFFFFFF(alpha: 0.12) - var currentProgress: UIColor = .colorFFFFFF(alpha: 0.48) + var progressColor: UIColor = .color3D4556() + var currentProgress: UIColor = .colorFFFFFF() - var lineWidth: CGFloat = 5 + var lineWidth: CGFloat = 2 ///是否在滑动中 private var isPaning: Bool = false diff --git a/Thimra/Class/Player/ViewModel/SPPlayerListViewModel.swift b/Thimra/Class/Player/ViewModel/SPPlayerListViewModel.swift index 342871f..135e2d8 100644 --- a/Thimra/Class/Player/ViewModel/SPPlayerListViewModel.swift +++ b/Thimra/Class/Player/ViewModel/SPPlayerListViewModel.swift @@ -37,6 +37,10 @@ class SPPlayerListViewModel: NSObject { currentPlayer?.rate = speedModel.getRate() } + ///设置进度 + func seekToTime(toTime: Int) { + self.currentPlayer?.seekToTime(toTime: toTime) + } ///点暂停或播放 var handlePauseOrPlay: (() -> Void)? diff --git a/Thimra/Libs/Player/SPPlayer.swift b/Thimra/Libs/Player/SPPlayer.swift index 360945e..8f71aaf 100644 --- a/Thimra/Libs/Player/SPPlayer.swift +++ b/Thimra/Libs/Player/SPPlayer.swift @@ -171,8 +171,14 @@ class SPPlayer: NSObject { } func seekToTime(toTime: Int) { -// self.player.seek(toTime: Int64(toTime), seekMode: AVP_SEEKMODE_ACCURATE) - self.player.seek(toTime: TimeInterval(toTime), completionHandler: nil) + var time = toTime + if time < 0 { + time = 0 + } + if time > self.duration { + time = self.duration + } + self.player.seek(toTime: TimeInterval(time), completionHandler: nil) } diff --git a/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/Contents.json b/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Contents.json similarity index 79% rename from Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/Contents.json rename to Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Contents.json index c9f3912..5c4d3b1 100644 --- a/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/Contents.json +++ b/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Contents.json @@ -5,12 +5,12 @@ "scale" : "1x" }, { - "filename" : "play@2x.png", + "filename" : "Frame@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "play@3x.png", + "filename" : "Frame@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@2x.png b/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..b6ef0c6 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@2x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@3x.png b/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..d4e4cba Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@3x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Contents.json b/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@2x.png b/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..145dcc9 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@2x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@3x.png b/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..d71d29d Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@3x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/episodes_icon_01.imageset/Contents.json b/Thimra/Source/Assets.xcassets/icon/episode_icon_02.imageset/Contents.json similarity index 100% rename from Thimra/Source/Assets.xcassets/icon/episodes_icon_01.imageset/Contents.json rename to Thimra/Source/Assets.xcassets/icon/episode_icon_02.imageset/Contents.json diff --git a/Thimra/Source/Assets.xcassets/icon/episodes_icon_01.imageset/Episodes@2x.png b/Thimra/Source/Assets.xcassets/icon/episode_icon_02.imageset/Episodes@2x.png similarity index 100% rename from Thimra/Source/Assets.xcassets/icon/episodes_icon_01.imageset/Episodes@2x.png rename to Thimra/Source/Assets.xcassets/icon/episode_icon_02.imageset/Episodes@2x.png diff --git a/Thimra/Source/Assets.xcassets/icon/episodes_icon_01.imageset/Episodes@3x.png b/Thimra/Source/Assets.xcassets/icon/episode_icon_02.imageset/Episodes@3x.png similarity index 100% rename from Thimra/Source/Assets.xcassets/icon/episodes_icon_01.imageset/Episodes@3x.png rename to Thimra/Source/Assets.xcassets/icon/episode_icon_02.imageset/Episodes@3x.png diff --git a/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Contents.json b/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Contents.json new file mode 100644 index 0000000..10b3cfd --- /dev/null +++ b/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 1912056659@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 1912056659@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@2x.png b/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@2x.png new file mode 100644 index 0000000..3f0f6e3 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@2x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@3x.png b/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@3x.png new file mode 100644 index 0000000..7b8d0a8 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@3x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Contents.json b/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Contents.json new file mode 100644 index 0000000..69ce867 --- /dev/null +++ b/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 43@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 43@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@2x.png b/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@2x.png new file mode 100644 index 0000000..3a16fd6 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@2x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@3x.png b/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@3x.png new file mode 100644 index 0000000..4a910ec Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@3x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@2x.png b/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@2x.png deleted file mode 100644 index 14317dd..0000000 Binary files a/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@2x.png and /dev/null differ diff --git a/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@3x.png b/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@3x.png deleted file mode 100644 index a99f806..0000000 Binary files a/Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@3x.png and /dev/null differ diff --git a/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Contents.json b/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@2x.png b/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..a50f03b Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@2x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@3x.png b/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..7a841d9 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@3x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Contents.json b/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@2x.png b/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@2x.png new file mode 100644 index 0000000..6563856 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@2x.png differ diff --git a/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@3x.png b/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@3x.png new file mode 100644 index 0000000..94675c0 Binary files /dev/null and b/Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@3x.png differ diff --git a/Thimra/Source/en.lproj/Localizable.strings b/Thimra/Source/en.lproj/Localizable.strings index 4453b65..cecbc0d 100644 --- a/Thimra/Source/en.lproj/Localizable.strings +++ b/Thimra/Source/en.lproj/Localizable.strings @@ -20,7 +20,6 @@ "Episodes" = "Episodes"; "Save" = "Save"; "Added" = "Added"; -"Series" = "Series"; "Order Record" = "Order Record"; "Language" = "Language"; "Privacy Policy" = "Privacy Policy"; @@ -40,6 +39,9 @@ "More" = "More"; "Historical search" = "Historical search"; "Top Search" = "Top Search"; +"EP%@" = "EP%@"; +"Full Episodes" = "Full Episodes"; +"All" = "All"; +"Shorts" = "Shorts"; + -///视频详情标题 -"kPlayerDetailTitleString" = "Episode %@ / %@"; diff --git a/Thimra/Thirdparty/WMPageController/WMPageController.m b/Thimra/Thirdparty/WMPageController/WMPageController.m index 296cda0..1e00464 100755 --- a/Thimra/Thirdparty/WMPageController/WMPageController.m +++ b/Thimra/Thirdparty/WMPageController/WMPageController.m @@ -428,7 +428,7 @@ static NSInteger const kWMControllerCountUndefined = -1; WMScrollView *scrollView = [[WMScrollView alloc] init]; scrollView.scrollsToTop = NO; scrollView.pagingEnabled = YES; - scrollView.backgroundColor = [UIColor whiteColor]; + scrollView.backgroundColor = [UIColor clearColor]; scrollView.delegate = self; scrollView.showsVerticalScrollIndicator = NO; scrollView.showsHorizontalScrollIndicator = NO; @@ -681,7 +681,7 @@ static NSInteger const kWMControllerCountUndefined = -1; #pragma mark - Life Cycle - (void)viewDidLoad { [super viewDidLoad]; - self.view.backgroundColor = [UIColor whiteColor]; + self.view.backgroundColor = [UIColor clearColor]; if (!self.childControllersCount) return; [self wm_calculateSize]; [self wm_addScrollView];