From 5bfc5c725a2bae7c92b5c9f1a11708277aafa06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=BE?= Date: Wed, 23 Apr 2025 11:33:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=92=AD=E6=94=BE=E5=99=A8=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Thimra/Base/Extension/UIColor+SPAdd.swift | 12 ++ Thimra/Base/Networking/API/SPVideoAPI.swift | 11 ++ .../Controller/SPAllShortViewController.swift | 27 +++ .../Controller/SPExplorePageController.swift | 10 +- .../Controller/SPExploreViewController.swift | 8 +- .../View/SPExplorePlayerControlView.swift | 108 +++++++++-- .../Explore/View/SPVideoPlayerInfoView.swift | 69 +++---- .../SPPlayerDetailViewController.swift | 38 +++- .../SPPlayerListViewController.swift | 6 +- .../Class/Player/Model/SPPlayerProtocol.swift | 10 +- Thimra/Class/Player/View/SPEpisodeView.swift | 2 +- .../Player/View/SPPlayerControlView.swift | 59 +++--- .../View/SPPlayerDetailControlView.swift | 180 +++++++++++++++--- .../Class/Player/View/SPPlayerListCell.swift | 20 +- .../Player/View/SPPlayerProgressView.swift | 6 +- .../ViewModel/SPPlayerListViewModel.swift | 4 + Thimra/Libs/Player/SPPlayer.swift | 10 +- .../Contents.json | 4 +- .../arrow_right_icon_01.imageset/Frame@2x.png | Bin 0 -> 455 bytes .../arrow_right_icon_01.imageset/Frame@3x.png | Bin 0 -> 574 bytes .../episode_icon_01.imageset/Contents.json | 22 +++ .../episode_icon_01.imageset/Frame@2x.png | Bin 0 -> 393 bytes .../episode_icon_01.imageset/Frame@3x.png | Bin 0 -> 551 bytes .../Contents.json | 0 .../Episodes@2x.png | Bin .../Episodes@3x.png | Bin .../icon/pause_icon_01.imageset/Contents.json | 22 +++ .../Frame 1912056659@2x.png | Bin 0 -> 379 bytes .../Frame 1912056659@3x.png | Bin 0 -> 605 bytes .../icon/play_icon_01.imageset/Contents.json | 22 +++ .../play_icon_01.imageset/Frame 43@2x.png | Bin 0 -> 929 bytes .../play_icon_01.imageset/Frame 43@3x.png | Bin 0 -> 1326 bytes .../icon/play_icon_02.imageset/play@2x.png | Bin 280 -> 0 bytes .../icon/play_icon_02.imageset/play@3x.png | Bin 431 -> 0 bytes .../icon/speed_icon_01.imageset/Contents.json | 22 +++ .../icon/speed_icon_01.imageset/Frame@2x.png | Bin 0 -> 1291 bytes .../icon/speed_icon_01.imageset/Frame@3x.png | Bin 0 -> 1933 bytes .../icon/speed_icon_02.imageset/Contents.json | 22 +++ .../icon/speed_icon_02.imageset/Frame@2x.png | Bin 0 -> 1294 bytes .../icon/speed_icon_02.imageset/Frame@3x.png | Bin 0 -> 1885 bytes Thimra/Source/en.lproj/Localizable.strings | 8 +- .../WMPageController/WMPageController.m | 4 +- 42 files changed, 575 insertions(+), 131 deletions(-) create mode 100644 Thimra/Class/Explore/Controller/SPAllShortViewController.swift rename Thimra/Source/Assets.xcassets/icon/{play_icon_02.imageset => arrow_right_icon_01.imageset}/Contents.json (79%) create mode 100644 Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@2x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@3x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Contents.json create mode 100644 Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@2x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@3x.png rename Thimra/Source/Assets.xcassets/icon/{episodes_icon_01.imageset => episode_icon_02.imageset}/Contents.json (100%) rename Thimra/Source/Assets.xcassets/icon/{episodes_icon_01.imageset => episode_icon_02.imageset}/Episodes@2x.png (100%) rename Thimra/Source/Assets.xcassets/icon/{episodes_icon_01.imageset => episode_icon_02.imageset}/Episodes@3x.png (100%) create mode 100644 Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Contents.json create mode 100644 Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@2x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@3x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Contents.json create mode 100644 Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@2x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@3x.png delete mode 100644 Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@2x.png delete mode 100644 Thimra/Source/Assets.xcassets/icon/play_icon_02.imageset/play@3x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Contents.json create mode 100644 Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@2x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@3x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Contents.json create mode 100644 Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@2x.png create mode 100644 Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@3x.png 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 0000000000000000000000000000000000000000..b6ef0c672ae24247e3959a399461705b0e0e78b8 GIT binary patch literal 455 zcmV;&0XY7NP) z!$1s`?4%DjFgM5r5|dOZQ_`_FAid+*!%S+9U{cb-3F0^nWsZ;|P*TJe(l9nIu)Vtm zUa_kgN$-t5I}7l~z$Ql+hAVd7JFYv6#;4 zmqfIj&F8x`O+Vnb1O$gHODmD0Sg^>msfgPZP!qYe5$P1DiClq2B?t!C1i=#^-m!Ud z1_Rly_pTfV4DhhsD&DLen`6rJN1Yt47S(Y$9$);)s&(~On&ck0d#aUGl z1wm3HS8cII@1P_nM5RM6FltdrE*pfrNjf>&0-Nwv+Yk-NR;#;7qtD!qrT+-f=|h{r%UD4qZa@G002ovPDHLkV1l|(y59f* literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d4e4cba2c7e0eedbf951ed71fc8f780cb7c18e6a GIT binary patch literal 574 zcmV-E0>S->P)ZTlI7c=*1O*htH2Q?J@UiIf7FK$Qk@qqG|1!HZO@1Nvv{P#D!u7?NL#*qE=9c0w|Um`UBbuDr!N+o&MCI zRh#S1FVq+hMKws(D5=1^bf}8^s?}_M2FvC9p}FiUlnrLamXunzjJ<|b)Xp-FA`j9! zqTBcKG@bTz=9;LX-xw-ts;Nia`RtE9HAN57$3DTF>apj*r1Q=Pqry@{xZBP480tTS z=@r2w^PyxWwmnB7`g_bNw;$XXl?oKh*l{M*`1+ifMECBqle=G$t45 z7#MAk<2YSvSc?>+_B+=mFe+M&QN(dAgK3+>t<8 M07*qoM6N<$f-U;>aR2}S literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..145dcc93e5314fddef9a07d70da3650da4af54a8 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9E$svykh8Km+7D9BhG z|JnHOX*GWhK;I+Cf!&lb9mXr$&AWB|^r-hFQkg=(UGWd;RR~3!`7?E^gU* z(o6Dh&YXnbxk4M?Sx*%^XEC*lBme$1Cap)p50!SiF@HRqJ^Qtt!1{>QpIjewtT?c2 zUawl5x4xT|>%6d)M>oA+8=!9Vfb&1!4BL|@|0MnVl_la=)as$QQN}LziY=q^_7lep lW%)VXd)&-2j)s0K~#7F-I#%O zgCG!w&rXmL9HAp*1V>ukH(%Rxdw;VmDW$!6kS`Ne@ULPDam6r7h zhsN#FMZg?Li{C!U(e3`?&I)0l+^QZa{zAG>a=@NLAT`G;)|ZClFaC3n`$=Cpo<>YZ zjuWk~3&-2!U8e1@jG29%-B=r%69zvWu#DnCRsho|R3LM~49AvA%Ym6yK)7S$5~#?w zeJ%)w-N4qqopf_t6zyP5WWwI-ry~0KyMd7!Nj|Zi>WBdv2e(NCfqM{jsFUOqjf~X+ zd0R3_@fT#DB!OW#zPx0C2uXdPe4U#^V35yIHix28LZpEqAN)H?m3z+?X zCp^jE7U7=c4im=@lkiIBD)&ADq#aG{C^c%3SW`SOn>@UPY4Vjep#eH?wzFU{g1k7g zjvqZDs<)6!Du#O$JboC&Rc{F-s&6cqpIl4HQKBj*fcZZ72E!6nITLIwdr#5YLe9#W pQ1%Ba2ezf*gVj5Ku)5GA=@TEj6T54a)^q>>002ovPDHLkV1jdT?E?S+ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3f0f6e3a7dc73e2f83e3ef4e95abb6d0e839661c GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^86eET1|(%=wk`xxoCO|{#S9E$svykh8Km+7D9BhG z>|6ZHCk-dbi& zM&?8PmG3uAKj~*w&jZxS@b8F;-v*u2#kF#eBi3imdZybP{{H^sH4g7TGQVzo7yWGA zz5T~?C#VI?aVTUu$|<5gG#KfuvyOk<_w)0szaT$;V2rU5xo+9pe+I``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBxlf)hjv*C{Z?7KoJ?tRhaM6@?2~!69MMhJl zK!(39T$dVdiX2cqXm3{KFZH%`$%{u>k&gG2QXEnN~i{#2J ze*KHSnOg8ULjUv6IiGFh9#^foUb*G;j)ND!-@kPE#`5hScO=KgHdo4TxBm5S_RZ{q zulX5&KJvNWuQ#sd?W^}HSi<5yO5h2Dtn~+Dk3GJ-`7kg*&%`zVp7GgM?zzqL>^tvX z{LW94wBEYz_34^>&*r$j{+0S8V%pPn`bRE)XNN@^L)~}g$ASjm3Jv~(W75;r&t;uc GLK6T5ljn~B literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3a16fd68f6743001fb6fbb2e0ef03e09af96530e GIT binary patch literal 929 zcmV;S177@zP)kyg^~ z-PPUm&1n3PqtX=mWr7MYT~@p>(PKe!=1F&P}fo+>p*Av z@?6G2q+_X!Ss;yrFlRCi?xJ-~^V2=Cb12i@%wHP&Lo-~uXBp_J#PdY2Pa5gOdnn5x z?wh26Vei80{Ny1}%jNv!DNt*x*UHPX++(1Yi~pZ27YWv|YP@K+lxEBG9rP#MMQ`+O zdM`6mOQ6>5hP~PXwbt@$$GrGZwFZJ&EX!*S)GGQ|!}BUG6t;@CrEVKB&@C*-vA_3P z3c?|7zhdSm2I_XD*Q=bXJq~f*vL9>k4hom$Sc8FvGo7CpXgrf`BLhf17k$6LKza3k+K_?r>OBNxpu#awURQm; zz(9F1P~p~nzraBGY(n`~*GF%24 zFWNlQg@J}ckY&tyrV9gwyID4Cn4m41SQscw(s`x}19cm=aSpeoQBxq1yY=^F3V8GhOEJpj%f@)EX++qoPA16@3g~ zg%4XVT(&^1=9`~zS7C1XUfUc)L_|bHL_|bHL}mC1QAt5=^T>Qr00000NkvXXu0mjf D(Q>83 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4a910ecedc9b04508ec027343ba5d4ccd5db6d8c GIT binary patch literal 1326 zcmY*ZeK^wz93N&aOgJxDGf7I)dX%*4aAxv4#p#r{LZNVe=4CoB)tseWSxLj$rHezQ z*}TjS(T}pUnMc%C785(}nU~1CE!=kh^?jbt_w#(d-_P@Wzu$kpH%|I{B6N^C5C{a} z?S&6iF+&YFOqHqJPJ)Uy172rRAP_688X6vShjXf;MoOS34#E_o{#6NRtQ)}%0%6m1 zzeZ}SWS2MIEhs}{`eQ#Kh+zDDuAw{D&R`o0lB*r3MS%@!-qw7e@c_b7p`Qej;(ln< zK%VZq7H+eRD=9rjnkg;a*k773pEsVl5*xE9tPO^$W_%M@Ll5o|XSrOduuMv88)S2q z`wkyvrZW0s8Z0$~se1nIL+@y`dDnVgm|QIST%e6HHepaWOv~z{5nfw6Qy!K`9XY{7 zv!NdwLd+D8@xrku!tt}d7a9d(Qu!x4EsWw^U)*m zYYsY~Y-tu*O}IJS%R!NwdHx%wjPORcwF; z-&W-FY@xxHBGH3odWf3f%m_@K8@rMN_O2I5KO9&&WJ@39_~js|=FITBVYxf7=Rb}Z zqUiOgyN0NrZXwZUk*rID@h1hqWZ_q&G59C#Jm22eZj~i_I~+de4cmcTxR5mQ-r^T0 zUjVMS{K}7q)_0it!z3wsF;xKMNAl&@@Y}I3KIC7P?*Jq7rO#06y!74(MS}3pGKbs*J`^;G*$?j&EtaxQpiubS5&$oB-C*0xsPxNIohikxz%4`D^ zy>NP<#QsM&th8ynsE1VJ^K>sv9KBR9CgHyJ2QCTS44B)Kx*4APO{(ydnK#A%F;Ehwr3ez@cOwzuUTA4 zTU!{$W!7!fExmAZ5glZl5fDdg)*=eVYBqDX2;)-g7RG|!?0bsxBvj^0{T@z=s|mFw z(woPdF{J)HOdZPeNI($aiyW@XN#GBR66WW1zh}OZ(jD6nYZ(Px#(n&-?R5(wy)IAOXK^VsI|D)tADtF)_KJK8BprBT{2_=a}q7aGN9c&@U*hyw( z!?1RDOfkt6^P8E>`#vJ@P+*TY&=^wznm{CJo%cW=I0rfoS^zysr(aUkhBW{-reWel6sD!Hw^YEwrobgBt+R1E^OOswUDis4u>VsEgKFtzFIE6R#{Px$X-PyuR7gwBmpv~9K^TRf6QzcVMEnsNrJtcu2@#2iC}@O4r_i8K(-4VJ(9jZ{ zitD2j4|#LEpeVumJ2zazzSA13yIy2bz4`)Ncc8K<&Q; zq=B;(T>%@h`g*(Si-3*w0UQIG*H(&xd0_u5|zbvp7U`K5qSeJB>rM^tC zvFyA*16#nVr1w?@lnqWeR=_DRDe0yeyee?Qx&%fg*(&@QRf7#SCTS-GcwCbGbFYeT zfe}fMzQE>sXTXf4Yag2{$Z;|QIfxD9+?RovWljNyzAQ6Hlc=mMTALdT5d@ZjxrXRt z#mobHd0JoE21~Qd{%GP-6!L}|!roohj?MEtHCM;+wl{8fFJ9tpo~nzy)0sDkB8sx+ Z{sM(ss2}K)_uv2k002ovPDHLkV1fqgwwC|^ 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 0000000000000000000000000000000000000000..a50f03b9dd7fe8978a1b81df0cdc0e278ece0cda GIT binary patch literal 1291 zcmV+m1@!ufP)X9PgIxqNAvV1W0ioEL-do=RE z@>j0>+#SsgE3a_Oh6cj-ykq&sQnTza9=Z31Wi545Zp1q*N~r<&mn;?HjNqe!_TW5> zHHa}pjeJzdVHgZF2z1x@f%&MA*f4KtB&K?@u%bF4cJ=3V3 zXUmL~ZZ`56#2Dk=ql|dOH=39L!`!Df%85Y&jFGlw`gN3s+h#F}!yvWi;gfrXN7s!< zuNz7M!jUdg(#)_9mv9GyKPVQ2Aqrg3LV%u)Tt+D=286K~V;nG^;%dC{<4J%qW*am5 zfL>7A2<|$z-8lm?j%Hp-TCwy(?Z^$yY{chnqRru81BLoe@)V;fXu7Ksge z8iY)-$m-Yrlo*kloSE%p}lu-T~S7iyY9_@f6{4^s7ut; zZMv*2adl0X9BBKJbLt)7wA+Y%+;5YR7e=qS?b@r z%I2PSB?c&4AMIG~NVlT2+Sk_i4e1qXLy_2KHLf@7yIaBW6nN<!N+Dq2e)Uq9|4r-fSPvOUgev};`d`QlSj9Wzu&8!>h_&6P30#$4O!%X^9h`lLXYVfEt0T@NG)j#~ALQMT}N zjWqFxvefO}XtU*1ZF$IXn>-$j=dDRE#pQVo=_6O$6xl53B#^B!KMtDZU_bhh)Jt-Z z>^{&>t`^65 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7a841d9d5c788050304f15f591254dc0822b73ce GIT binary patch literal 1933 zcmV;82Xgp{P)#CK~#7F?VatB z+cpq}SDE~eQ-RSzoC?AYa;YG41$GCLE4WJqI#+OZ1-w*nP6ebZ@VSCF*Z|DvC<<6m z1PD-kW-z2i`~a}{SOAM9(aOro%F4>h%F6s~Tz>+n^kJui(xKJi<7TtDr$p%YztV>{ z_Wi%;@XDUQvf-H49-r;`R~^1^&~bjIrJyrqi(%eVBv=sqd>sxtG?%6Xl28tC>?5@j(dIlpjGac5;9gW%Jru$X$QJ2gLn+`w>>_FW(IhXXbf9^hJM~#9fwDn6Zrd>t>fMu##6(nv6DA>HceYxrU~w7PB20+FdA2la9APO zBZ4qI>Em}c2I z$%O-uLoc>>Ct(M4Fn z<20se2|N*zmZp1T+;sVX(KH`~X?>s+;Bxk~5MUGo3Gv4{xQsn5i~!+O6cdbRPYXq- z?M{&X1~Hp&jN^_L4rJZqYyj^@}r^{AdCj38#x33qe_1h4oXwIgaN#`e*(6pGingeT)x98DllH&yGu2wH9lg(JV2i1gFzI zJWG(H)_AYOpN{`4GI3u9INg1a zu>ji@?;z)pdfWrInNveczz*7ukyxl;;GUElqnyTpl4q3A`K#XVu8HVY4}aZQ^f^xw z{z0d+xO`6<+u~~h!_FYQ#_BM8Is0rW0aMhN?16D@a?By%-o9{>7$shdVA!~BdlXdQ z{dF&2DvAuQq4U3#fm-vPA_KR5vq&&S&MpV?*!!(0KCaPyO9HMzF#S<@3OfduV)C5? zT!Ucdz_sooTEWbIN(L{jV|X6SXT#M;^?rY)hzOL6WeA2|I_P=U3I8i_1+!mzW3RdU zRw7BcU4w{#_7cpk3Lo?;^`AVbe1rXDFV!&v`}=~-U;(SQA!~53CV4% zc&}k8aDju2Jhm&8Q3jg9zzf^50b6_;DknhOk*_Q?ihsm<`zzhfKfON3% zwv;n4&06TkM-Mp&2&UOOAdGT`1TYFggK!RWBod~ENIyYxOoIYHo*mL@_Tl@2Hzozf zulp>0jd9c{c_tn5PkOk7#HuQn>d|ZYRuGkaR*lP;##m2COjm>zUH8oY`8aikb*{45Wz~JI4o^F>^;8Zs z8=%Mt>9sxQ;1gKqVUGiEgk=@`F$3pvK@{Uc{urFmm`cn1m6es1m6es1mE8FkM}au; TCXU|E00000NkvXXu0mjf{&0s+ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6563856d469995b25403a80aec375711d0e7c113 GIT binary patch literal 1294 zcmV+p1@ZccP)1!Gb#S4Ag9?%k?x?_Ya8Q9w1ql`WtdK&SL@!%@h?#sd zJHGK*kE~W&tscOYD_5@cXMq_Yxs=CBI(=`9 zA}UTt74yU7o7$2#m@Y*Ts%t!QJ~qA|$OwhJ#z08MD|u|72gnd=uzVKz2|c(q=3Sc` z90%O@B1?qxE=81eewM*MqHitAg>Qe^9B>2n?|>Fbb%BthLpHi3%O zA|(cf+SAm5vXw`=X{D)0Q;1QETmBJMFV5sG;^C}lK-L@1+Tt7XPU{V3|LV8@~ z^1VZ57)u#dAsa`YYh(&_K-ozlQQ<$eYqCX#TbU7l#Kf5TD65R|WFO#};Y$6xFM-e= zsMVYzQoO8-uj_UOU7@=#mY4zhU2C#JUPaX5gXLW_WAL=cTu_^5Hr8S4WSw#LWOtr_ zDEwbp-X&XyRHW+g`N_Jc{Jod-x2A3d(&%Pwv=63hB;c_+7X>E7X(80X*~;>-Ez&5= zQ?<_5i0|hcGuqJZU6NO+C6BwI@)`r5m$Ahr-;qvXo((d@r;zuScR!KNVRrc&8RAoj zZCd;T=@jPKAVYj^x3Iixkj`84+?#>Bgto>4dH`)izKMH%Mow^y)g_$lo~iwt+T(63 z&JZg(BR!h}dPRnp`KsAryE`gN_-6iA??2&aovMr8s>vAU#@1vQfVK;#W0j4k0o)on zFh-Z*aUVy?D)4P(irpaxIQ7QxW%>7Wl?F&Rnd$+t?HCKPDS?k&;qV4X#U_eaSl_^t|Rdh-3TH)@p{1>X2i&2hJ zSjxQkEsH<~1?(GCx2b1FP5vwBfmQ{4sw+0o-fcVdbe(!ud_D&5rJOhDf}Fw z--_-2JLul1TH!x|`ZR!z5`Cb1D|5=3Yj0=|L;AaOkCi+kbLc+cQz8Yry+U?pLk@Tv zGJUc~?J8}ja@4y5nL+<4fdWH7_W_hTC#3|GvBr?leFCx0K`8-cJYi_)-+fozXSOkg z{u7AxXbr~jDV_&RjFkDwQ=gh+TW^F?#;*jT?&eHVk3(f*&Uvc5BKi8FyQ&;+!*Sb~_ALneSCAFFkoG3sft2T`w@scHaI3rX88wnY0J# zL&c1anE!)umwSe!W=>0uE+$Y+MctkLi>Uh_>~>c!gz8#fIMRB|PZFlK)+{e2ckAg)}wa-}1G017>gp&<3|uK)l507*qoM6N<$ Eg5a8EivR!s literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..94675c09a3c41e15caf56abcaa3a6e9328ea6b94 GIT binary patch literal 1885 zcmV-j2cr0iP)`w3&2%saHBJn}t zlj3vEJ(Mkp0{Ifa#RYgtw6L(Su&}VOu#lb=6$pR}zPaSaxV`6gp(Z+2t9t#+ z?T4_{YV}Hy;AO7(=9XkRTWMqNolkUPp#kUosU2s9|nuM`Me?0;?eE~6AcdR$w$BRsSX0*Ik0 zs}M~X;<0y)#B|hEepunwpYjAKZ(h388z;3YMR2Xo(@WkhCkby9d zuw&4JDFw(2@D3iJ(7=A2az`@((pkw@7?>lddp0yPP8Ekj0sA(0Lo?+RaVQk98`VG3 z%z>Lb9ab2aT|q&Ef;)N_;2z}&CQJjfD2&bo$Y$MX7Iti3lf(XyGmp&hv0(ERp@5v4 z5XUyPmcLS}P(SQC{4Es*#+MldgM0$>n598sO&Hvw7Ty>u&(t~pwc-8ZnlL)7?92jZ zVIUVGFwI9=F3JOyN3`X#9on%srqq~g!~379Oj=4K>la%pHX8!8xH{wu^~^nAIx z%SmgCIB|UQ7oEmv|0hOB%06Lzx}?7%(h|qX^(_9O{Z@jElRhTS~g4ICN{wysrEn zR>G+MMHiS0-i!@67K<=s4psc1@UY(BEzKBPVN5IHV+ix6#>TwkI0Zgx%xk2R#5%8A znmM-avTpnkqqYdN9lz>>_BSYrizQaMf?z9*uH*lY;=nque+mP+mOzAwLYLorbn@b$(~TgZT;?fiO!!Y1y#^f45liknyxWjnXdxYfw{p86iiZzp$v z4ZIc?#XYw_xxM2}mdK6sPW}CL;QK|dnLfhMOl&9uQ<^6XFB&Osk;o{ig@Ifs;Ur4u zyF-(E+1DD|rmWSx7waHDcI>_b2eyGzXyf%Cc`7RFl@_8)c4<8uN}aN7b&b z_xPSN$5xnU&3oA&q@t+UnyoOpgJLCgrlnyUk}<`d7zK=(K`t`<(D~P=34zo8v~s@aD`Sch#z*Hb2;I-@dVjkn`RsrGJIw{?7h?oZx{2d}Wo7xj z{;d^7uNFN5=KIN~wZIo!0vMcp>ouZ7IvR|t* ziTgCS@HGtq8L!gKf5d3cE-*de+XE$n|Mr)G@-#lhF|8f0C<1W1uRduaA?RBgKjAEx zo3olCfww6WUk1bw{|}O`(XpJm{5t*|5tyfQD@p`1n?A;I@U+j<*mtMQVBQ$QDt17PQ$x&-1M5Xps<1~V-Ra;SHAgjB$ z6`axOh&l6DwH1jV+L6yOk~uEL)>nSzmfOeGYPF*|0S`|rN{E;wobNmn+#h3@ni}Uc zD~tREs&URMe~_0zVob8dvJ~q8{5&yyDm5}#S{vOfa|LpIP?5|~?#rX*Q+y)b=nNX#v^@6~HzrYroF4zBgH+U|0FoJw)R=)lP6yTE7JEG#T6EG#T6EM&p| X=v(7=e0s>200000NkvXXu0mjfz~PA2 literal 0 HcmV?d00001 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];