播放器开发完成
@ -160,5 +160,17 @@ extension UIColor {
|
|||||||
static func color5A5C67(alpha: CGFloat = 1) -> UIColor {
|
static func color5A5C67(alpha: CGFloat = 1) -> UIColor {
|
||||||
return color(hex: 0x5A5C67, alpha: alpha)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,17 @@ class SPVideoAPI: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///获取视频分类
|
||||||
|
static func requestShortCategoryList() {
|
||||||
|
var param = SPNetworkParameters(path: "/getCategories")
|
||||||
|
param.method = .get
|
||||||
|
|
||||||
|
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPListModel<SPShortModel>>) in
|
||||||
|
// completer?(response.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SPVideoAPI {
|
extension SPVideoAPI {
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -11,10 +11,16 @@ import UIKit
|
|||||||
class SPExplorePageController: SPViewController {
|
class SPExplorePageController: SPViewController {
|
||||||
|
|
||||||
private lazy var titles: [String] = {
|
private lazy var titles: [String] = {
|
||||||
let arr = ["Shorts".localized, "Featured".localized, "All".localized]
|
let arr = ["Shorts".localized, "All".localized]
|
||||||
return arr
|
return arr
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var viewControllers: [SPViewController] = {
|
||||||
|
let vc1 = SPExploreViewController()
|
||||||
|
let vc2 = SPAllShortViewController()
|
||||||
|
return [vc1, vc2]
|
||||||
|
}()
|
||||||
|
|
||||||
private lazy var itemWidthArr: [NSNumber] = {
|
private lazy var itemWidthArr: [NSNumber] = {
|
||||||
var arr: [NSNumber] = []
|
var arr: [NSNumber] = []
|
||||||
self.titles.forEach {
|
self.titles.forEach {
|
||||||
@ -129,7 +135,7 @@ extension SPExplorePageController: WMPageControllerDelegate, WMPageControllerDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func pageController(_ pageController: WMPageController, viewControllerAt index: Int) -> UIViewController {
|
func pageController(_ pageController: WMPageController, viewControllerAt index: Int) -> UIViewController {
|
||||||
return SPExploreViewController()
|
return viewControllers[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class SPExploreViewController: SPPlayerListViewController {
|
|||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
self.autoNextEpisode = true
|
||||||
requestDataArr(page: 1)
|
requestDataArr(page: 1)
|
||||||
|
|
||||||
self.delegate = self
|
self.delegate = self
|
||||||
@ -53,6 +53,7 @@ extension SPExploreViewController: SPPlayerListViewControllerDataSource {
|
|||||||
cell.shortModel = model
|
cell.shortModel = model
|
||||||
cell.videoInfo = model.video_info
|
cell.videoInfo = model.video_info
|
||||||
}
|
}
|
||||||
|
cell.isLoop = false
|
||||||
}
|
}
|
||||||
return oldCell
|
return oldCell
|
||||||
}
|
}
|
||||||
@ -70,8 +71,9 @@ extension SPExploreViewController {
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if let listModel = listModel, let list = listModel.list {
|
if let listModel = listModel, let list = listModel.list {
|
||||||
if page == 1 {
|
if page == 1 {
|
||||||
self.setDataArr(dataArr: list)
|
self.setDataArr(dataArr: list) { [weak self] in
|
||||||
self.play()
|
self?.play()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.addDataArr(dataArr: list)
|
self.addDataArr(dataArr: list)
|
||||||
}
|
}
|
||||||
|
@ -12,27 +12,59 @@ class SPExplorePlayerControlView: SPPlayerControlView {
|
|||||||
|
|
||||||
override var shortModel: SPShortModel? {
|
override var shortModel: SPShortModel? {
|
||||||
didSet {
|
didSet {
|
||||||
desLabel.text = shortModel?.sp_description
|
// desLabel.text = shortModel?.sp_description
|
||||||
videoInfoView.shortModel = shortModel
|
videoInfoView.shortModel = shortModel
|
||||||
|
|
||||||
|
// shortModel?.episode_total
|
||||||
|
updateEpisodeLabel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private lazy var desLabel: UILabel = {
|
override var videoInfo: SPVideoInfoModel? {
|
||||||
let label = UILabel()
|
didSet {
|
||||||
label.font = .fontRegular(ofSize: 12)
|
updateEpisodeLabel()
|
||||||
label.textColor = .colorD2D2D2()
|
}
|
||||||
label.numberOfLines = 2
|
}
|
||||||
return label
|
|
||||||
}()
|
// 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 = {
|
private lazy var videoInfoView: SPVideoPlayerInfoView = {
|
||||||
let view = SPVideoPlayerInfoView()
|
let view = SPVideoPlayerInfoView()
|
||||||
return view
|
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) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
self.progressView.isHidden = true
|
// self.progressView.isHidden = true
|
||||||
|
|
||||||
_setupUI()
|
_setupUI()
|
||||||
}
|
}
|
||||||
@ -41,23 +73,67 @@ class SPExplorePlayerControlView: SPPlayerControlView {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
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 {
|
extension SPExplorePlayerControlView {
|
||||||
|
|
||||||
private func _setupUI() {
|
private func _setupUI() {
|
||||||
addSubview(desLabel)
|
// addSubview(desLabel)
|
||||||
addSubview(videoInfoView)
|
addSubview(videoInfoView)
|
||||||
|
toolView.addSubview(episodeIconImageView)
|
||||||
|
toolView.addSubview(episodeLabel)
|
||||||
|
toolView.addSubview(allEpisodeButton)
|
||||||
|
|
||||||
desLabel.snp.makeConstraints { make in
|
// desLabel.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(15)
|
// make.left.equalToSuperview().offset(15)
|
||||||
make.right.lessThanOrEqualToSuperview().offset(-30)
|
// make.right.lessThanOrEqualToSuperview().offset(-30)
|
||||||
make.bottom.equalToSuperview().offset(-15)
|
// make.bottom.equalToSuperview().offset(-15)
|
||||||
}
|
// }
|
||||||
|
|
||||||
videoInfoView.snp.makeConstraints { make in
|
videoInfoView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(15)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,47 +13,36 @@ class SPVideoPlayerInfoView: UIView {
|
|||||||
didSet {
|
didSet {
|
||||||
coverImageView.sp_setImage(url: shortModel?.image_url)
|
coverImageView.sp_setImage(url: shortModel?.image_url)
|
||||||
titleLabel.text = shortModel?.name
|
titleLabel.text = shortModel?.name
|
||||||
|
desLabel.text = shortModel?.sp_description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: UI属性
|
override var intrinsicContentSize: CGSize {
|
||||||
private lazy var bgView: UIView = {
|
return CGSize(width: 200, height: 68)
|
||||||
let view = UIView()
|
}
|
||||||
view.layer.cornerRadius = 5
|
|
||||||
view.layer.masksToBounds = true
|
|
||||||
view.backgroundColor = .color000000(alpha: 0.27)
|
|
||||||
return view
|
|
||||||
}()
|
|
||||||
|
|
||||||
|
//MARK: UI属性
|
||||||
private lazy var coverImageView: SPImageView = {
|
private lazy var coverImageView: SPImageView = {
|
||||||
let imageView = SPImageView()
|
let imageView = SPImageView()
|
||||||
imageView.layer.cornerRadius = 5
|
imageView.layer.cornerRadius = 4
|
||||||
imageView.layer.masksToBounds = true
|
imageView.layer.masksToBounds = true
|
||||||
|
imageView.layer.borderWidth = 1
|
||||||
|
imageView.layer.borderColor = UIColor.colorFFFFFF(alpha: 0.26).cgColor
|
||||||
return imageView
|
return imageView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var titleLabel: UILabel = {
|
private lazy var titleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .fontRegular(ofSize: 13)
|
label.font = .fontMedium(ofSize: 14)
|
||||||
label.textColor = .colorFFFFFF()
|
label.textColor = .colorFFFFFF()
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var moreButton: JXButton = {
|
private lazy var desLabel: UILabel = {
|
||||||
let button = JXButton(type: .custom)
|
let label = UILabel()
|
||||||
button.colors = [UIColor.colorF56490().cgColor, UIColor.colorD568D2().cgColor]
|
label.font = .fontRegular(ofSize: 12)
|
||||||
button.startPoint = .init(x: 0, y: 0.5)
|
label.textColor = .colorA8A5AA()
|
||||||
button.endPoint = .init(x: 1, y: 0.5)
|
return label
|
||||||
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
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
@ -76,34 +65,30 @@ class SPVideoPlayerInfoView: UIView {
|
|||||||
extension SPVideoPlayerInfoView {
|
extension SPVideoPlayerInfoView {
|
||||||
|
|
||||||
private func _setupUI() {
|
private func _setupUI() {
|
||||||
addSubview(bgView)
|
|
||||||
addSubview(coverImageView)
|
addSubview(coverImageView)
|
||||||
addSubview(titleLabel)
|
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
|
coverImageView.snp.makeConstraints { make in
|
||||||
make.left.bottom.top.equalToSuperview()
|
make.left.top.bottom.equalToSuperview()
|
||||||
make.width.equalTo(49)
|
make.width.equalTo(46)
|
||||||
make.height.equalTo(66)
|
make.height.equalTo(68)
|
||||||
}
|
}
|
||||||
|
|
||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
make.left.equalTo(coverImageView.snp.right).offset(10)
|
make.left.equalTo(coverImageView.snp.right).offset(10)
|
||||||
make.top.equalTo(bgView).offset(5)
|
make.top.equalToSuperview().offset(16)
|
||||||
make.right.lessThanOrEqualToSuperview().offset(-18)
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
make.width.lessThanOrEqualTo(145)
|
||||||
}
|
}
|
||||||
|
|
||||||
moreButton.snp.makeConstraints { make in
|
desLabel.snp.makeConstraints { make in
|
||||||
make.left.equalTo(coverImageView.snp.right).offset(10)
|
make.left.equalTo(titleLabel)
|
||||||
make.bottom.equalToSuperview().offset(-5)
|
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||||
make.width.equalTo(59)
|
make.right.lessThanOrEqualToSuperview()
|
||||||
make.height.equalTo(21)
|
make.width.lessThanOrEqualTo(145)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override var contentSize: CGSize {
|
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 = {
|
private lazy var titleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .fontLight(ofSize: 15)
|
label.font = .fontBold(ofSize: 18)
|
||||||
label.textColor = .colorFFFFFF(alpha: 0.9)
|
label.textColor = .colorFFFFFF()
|
||||||
return label
|
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() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.autoNextEpisode = true
|
self.autoNextEpisode = true
|
||||||
@ -78,6 +91,8 @@ extension SPPlayerDetailViewController {
|
|||||||
private func _setupUI() {
|
private func _setupUI() {
|
||||||
view.addSubview(backButton)
|
view.addSubview(backButton)
|
||||||
view.addSubview(titleLabel)
|
view.addSubview(titleLabel)
|
||||||
|
view.addSubview(episodeLabel)
|
||||||
|
view.addSubview(bottomView)
|
||||||
|
|
||||||
backButton.snp.makeConstraints { make in
|
backButton.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(5)
|
make.left.equalToSuperview().offset(5)
|
||||||
@ -88,7 +103,18 @@ extension SPPlayerDetailViewController {
|
|||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
make.left.equalTo(backButton.snp.right)
|
make.left.equalTo(backButton.snp.right)
|
||||||
make.centerY.equalTo(backButton)
|
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
|
self.episodeView?.currentIndex = indexPath.row
|
||||||
let videoInfo = detailModel?.episodeList?[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)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +121,9 @@ class SPPlayerListViewController: SPViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func setDataArr(dataArr: [Any]) {
|
func setDataArr(dataArr: [Any], completer: (() -> Void)?) {
|
||||||
self.dataArr = dataArr
|
self.dataArr = dataArr
|
||||||
reloadData()
|
reloadData(completion: completer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addDataArr(dataArr: [Any]) {
|
func addDataArr(dataArr: [Any]) {
|
||||||
@ -260,7 +260,7 @@ extension SPPlayerListViewController {
|
|||||||
var contentOffset = self.collectionView.contentOffset
|
var contentOffset = self.collectionView.contentOffset
|
||||||
|
|
||||||
if hasNextEpisode() {
|
if hasNextEpisode() {
|
||||||
contentOffset.y = contentOffset.y + self.contentSize.height
|
contentOffset.y = floor(contentOffset.y + self.contentSize.height)
|
||||||
self.collectionView.setContentOffset(contentOffset, animated: true)
|
self.collectionView.setContentOffset(contentOffset, animated: true)
|
||||||
} else {
|
} else {
|
||||||
self.viewModel.currentPlayer?.replay()
|
self.viewModel.currentPlayer?.replay()
|
||||||
|
@ -17,6 +17,12 @@ protocol SPPlayerProtocol: NSObjectProtocol {
|
|||||||
|
|
||||||
var isCurrent: Bool { get set }
|
var isCurrent: Bool { get set }
|
||||||
|
|
||||||
|
|
||||||
|
///总进度
|
||||||
|
var duration: Int { get }
|
||||||
|
///当前进度
|
||||||
|
var currentPosition: Int { get }
|
||||||
|
|
||||||
var rate: Float { get set }
|
var rate: Float { get set }
|
||||||
|
|
||||||
///播放准备
|
///播放准备
|
||||||
@ -30,5 +36,7 @@ protocol SPPlayerProtocol: NSObjectProtocol {
|
|||||||
|
|
||||||
///从头播放
|
///从头播放
|
||||||
func replay()
|
func replay()
|
||||||
|
|
||||||
|
///设置进度
|
||||||
|
func seekToTime(toTime: Int)
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ class SPEpisodeView: HWPanModalContentView {
|
|||||||
|
|
||||||
override func backgroundConfig() -> HWBackgroundConfig {
|
override func backgroundConfig() -> HWBackgroundConfig {
|
||||||
let config = HWBackgroundConfig()
|
let config = HWBackgroundConfig()
|
||||||
config.backgroundAlpha = 0.4
|
config.backgroundAlpha = 0.6
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,11 +78,18 @@ class SPPlayerControlView: UIView {
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var playImageView: UIImageView = {
|
private(set) lazy var toolView: UIView = {
|
||||||
let imageView = UIImageView()
|
let view = UIView()
|
||||||
imageView.backgroundColor = .red
|
view.backgroundColor = .color1C1C1E()
|
||||||
imageView.isHidden = true
|
return view
|
||||||
return imageView
|
}()
|
||||||
|
|
||||||
|
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)
|
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
|
tap.delegate = self
|
||||||
self.addGestureRecognizer(tap)
|
self.addGestureRecognizer(tap)
|
||||||
|
|
||||||
@ -139,12 +146,24 @@ class SPPlayerControlView: UIView {
|
|||||||
button.setTitle(title, for: .normal);
|
button.setTitle(title, for: .normal);
|
||||||
button.setTitle(selectedTitle, for: .selected);
|
button.setTitle(selectedTitle, for: .selected);
|
||||||
button.setTitle(selectedTitle, for: [.selected, .highlighted])
|
button.setTitle(selectedTitle, for: [.selected, .highlighted])
|
||||||
button.setTitleColor(.colorFFFFFF(alpha: 0.9), for: .normal)
|
button.setTitleColor(.colorFFFFFF(), for: .normal)
|
||||||
button.setTitleColor(.colorF564B6(), for: .selected)
|
// button.setTitleColor(.colorF564B6(), for: .selected)
|
||||||
button.jx_font = .fontLight(ofSize: 11);
|
button.jx_font = .fontMedium(ofSize: 12)
|
||||||
return button
|
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() {
|
private func sp_setupUI() {
|
||||||
addSubview(bottomGradientView)
|
addSubview(bottomGradientView)
|
||||||
addSubview(progressView)
|
addSubview(progressView)
|
||||||
|
progressView.addSubview(toolView)
|
||||||
addSubview(playImageView)
|
addSubview(playImageView)
|
||||||
addSubview(rightFeatureView)
|
addSubview(rightFeatureView)
|
||||||
|
|
||||||
@ -162,15 +182,17 @@ extension SPPlayerControlView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
progressView.snp.makeConstraints { make in
|
progressView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(10)
|
make.left.right.bottom.equalToSuperview()
|
||||||
make.centerX.equalToSuperview()
|
make.height.equalTo(40)
|
||||||
make.bottom.equalToSuperview().offset(-20)
|
}
|
||||||
make.height.equalTo(30)
|
|
||||||
|
toolView.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview().offset(-2)
|
||||||
}
|
}
|
||||||
|
|
||||||
playImageView.snp.makeConstraints { make in
|
playImageView.snp.makeConstraints { make in
|
||||||
make.center.equalToSuperview()
|
make.center.equalToSuperview()
|
||||||
make.width.height.equalTo(100)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rightFeatureView.snp.makeConstraints { make in
|
rightFeatureView.snp.makeConstraints { make in
|
||||||
@ -182,15 +204,6 @@ extension SPPlayerControlView {
|
|||||||
|
|
||||||
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() {
|
@objc private func hadlePlayAndOrPaused() {
|
||||||
self.viewModel?.handlePauseOrPlay?()
|
self.viewModel?.handlePauseOrPlay?()
|
||||||
|
|
||||||
|
@ -8,6 +8,15 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class SPPlayerDetailControlView: SPPlayerControlView {
|
class SPPlayerDetailControlView: SPPlayerControlView {
|
||||||
|
///暂停按钮状态
|
||||||
|
enum PauseState {
|
||||||
|
///隐藏状态
|
||||||
|
case hidden
|
||||||
|
///显示暂停按钮
|
||||||
|
case showPause
|
||||||
|
///显示播放按钮
|
||||||
|
case showPlay
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override var durationTime: Int {
|
override var durationTime: Int {
|
||||||
@ -33,22 +42,50 @@ class SPPlayerDetailControlView: SPPlayerControlView {
|
|||||||
didSet {
|
didSet {
|
||||||
if isCurrent {
|
if isCurrent {
|
||||||
showSpeedSelectedView(isShow: false)
|
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属性
|
//MARK: UI属性
|
||||||
private lazy var episodeButton: UIButton = {
|
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)
|
button.addTarget(self, action: #selector(handleEpisodeButton), for: .touchUpInside)
|
||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var progressTimeLabel: UILabel = {
|
private lazy var progressTimeLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .fontLight(ofSize: 12)
|
label.font = .fontRegular(ofSize: 12)
|
||||||
label.textColor = .colorFFFFFF(alpha: 0.9)
|
label.textColor = .colorFFFFFF()
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -74,12 +111,32 @@ class SPPlayerDetailControlView: SPPlayerControlView {
|
|||||||
return view
|
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 {
|
deinit {
|
||||||
self.viewModel?.removeObserver(self, forKeyPath: "speedModel")
|
self.viewModel?.removeObserver(self, forKeyPath: "speedModel")
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
self.playImageView.isUserInteractionEnabled = true
|
||||||
|
self.playImageView.addTarget(self, action: #selector(handlePlayImageView), for: .touchUpInside)
|
||||||
|
|
||||||
_setupUI()
|
_setupUI()
|
||||||
}
|
}
|
||||||
@ -107,6 +164,51 @@ class SPPlayerDetailControlView: SPPlayerControlView {
|
|||||||
private func updateSpeedButton() {
|
private func updateSpeedButton() {
|
||||||
self.speedButton.setTitle(self.viewModel?.speedModel.formatString(), for: .normal)
|
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 {
|
extension SPPlayerDetailControlView {
|
||||||
@ -114,34 +216,48 @@ extension SPPlayerDetailControlView {
|
|||||||
private func _setupUI() {
|
private func _setupUI() {
|
||||||
self.rightFeatureView.addArrangedSubview(episodeButton)
|
self.rightFeatureView.addArrangedSubview(episodeButton)
|
||||||
|
|
||||||
addSubview(progressTimeLabel)
|
toolView.addSubview(progressTimeLabel)
|
||||||
addSubview(speedButton)
|
addSubview(retreatButton)
|
||||||
addSubview(speedSelectedView)
|
addSubview(advanceButton)
|
||||||
|
// addSubview(speedButton)
|
||||||
|
// addSubview(speedSelectedView)
|
||||||
|
|
||||||
self.progressView.snp.remakeConstraints { make in
|
// self.progressView.snp.remakeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(15)
|
// make.left.equalToSuperview().offset(15)
|
||||||
make.centerX.equalToSuperview()
|
// make.centerX.equalToSuperview()
|
||||||
make.height.equalTo(30)
|
// make.height.equalTo(30)
|
||||||
make.bottom.equalToSuperview().offset(-(kSPTabbarSafeBottomMargin + 10))
|
// make.bottom.equalToSuperview().offset(-(kSPTabbarSafeBottomMargin + 10))
|
||||||
}
|
// }
|
||||||
|
|
||||||
self.progressTimeLabel.snp.makeConstraints { make in
|
self.progressTimeLabel.snp.makeConstraints { make in
|
||||||
make.left.equalTo(self.progressView)
|
// make.left.equalTo(self.progressView)
|
||||||
make.bottom.equalTo(self.progressView).offset(-12)
|
// make.bottom.equalTo(self.progressView).offset(-12)
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
speedButton.snp.makeConstraints { make in
|
retreatButton.snp.makeConstraints { make in
|
||||||
make.centerY.equalTo(self.progressTimeLabel)
|
make.centerY.equalTo(playImageView)
|
||||||
make.right.equalToSuperview().offset(-15)
|
make.right.equalTo(playImageView.snp.left).offset(kSPMainW(-50))
|
||||||
make.width.equalTo(40)
|
|
||||||
make.height.equalTo(20)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
speedSelectedView.snp.makeConstraints { make in
|
advanceButton.snp.makeConstraints { make in
|
||||||
make.left.right.equalToSuperview()
|
make.centerY.equalTo(playImageView)
|
||||||
make.bottom.equalTo(self.speedButton.snp.top).offset(-30)
|
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
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import UIKit
|
|||||||
|
|
||||||
class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol {
|
class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol {
|
||||||
|
|
||||||
|
|
||||||
var PlayerControlViewClass: SPPlayerControlView.Type {
|
var PlayerControlViewClass: SPPlayerControlView.Type {
|
||||||
return SPPlayerControlView.self
|
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 {
|
var rate: Float {
|
||||||
set {
|
set {
|
||||||
return player.rate = newValue
|
player.rate = newValue
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
return player.rate
|
return player.rate
|
||||||
@ -139,6 +153,10 @@ class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol {
|
|||||||
player.replay()
|
player.replay()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func seekToTime(toTime: Int) {
|
||||||
|
player.seekToTime(toTime: toTime)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SPPlayerListCell {
|
extension SPPlayerListCell {
|
||||||
|
@ -32,10 +32,10 @@ class SPPlayerProgressView: UIView {
|
|||||||
///滑动进度
|
///滑动进度
|
||||||
private var panProgress: CGFloat = 0
|
private var panProgress: CGFloat = 0
|
||||||
|
|
||||||
var progressColor: UIColor = .colorFFFFFF(alpha: 0.12)
|
var progressColor: UIColor = .color3D4556()
|
||||||
var currentProgress: UIColor = .colorFFFFFF(alpha: 0.48)
|
var currentProgress: UIColor = .colorFFFFFF()
|
||||||
|
|
||||||
var lineWidth: CGFloat = 5
|
var lineWidth: CGFloat = 2
|
||||||
|
|
||||||
///是否在滑动中
|
///是否在滑动中
|
||||||
private var isPaning: Bool = false
|
private var isPaning: Bool = false
|
||||||
|
@ -37,6 +37,10 @@ class SPPlayerListViewModel: NSObject {
|
|||||||
currentPlayer?.rate = speedModel.getRate()
|
currentPlayer?.rate = speedModel.getRate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///设置进度
|
||||||
|
func seekToTime(toTime: Int) {
|
||||||
|
self.currentPlayer?.seekToTime(toTime: toTime)
|
||||||
|
}
|
||||||
|
|
||||||
///点暂停或播放
|
///点暂停或播放
|
||||||
var handlePauseOrPlay: (() -> Void)?
|
var handlePauseOrPlay: (() -> Void)?
|
||||||
|
@ -171,8 +171,14 @@ class SPPlayer: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func seekToTime(toTime: Int) {
|
func seekToTime(toTime: Int) {
|
||||||
// self.player.seek(toTime: Int64(toTime), seekMode: AVP_SEEKMODE_ACCURATE)
|
var time = toTime
|
||||||
self.player.seek(toTime: TimeInterval(toTime), completionHandler: nil)
|
if time < 0 {
|
||||||
|
time = 0
|
||||||
|
}
|
||||||
|
if time > self.duration {
|
||||||
|
time = self.duration
|
||||||
|
}
|
||||||
|
self.player.seek(toTime: TimeInterval(time), completionHandler: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "play@2x.png",
|
"filename" : "Frame@2x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "play@3x.png",
|
"filename" : "Frame@3x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
BIN
Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 455 B |
BIN
Thimra/Source/Assets.xcassets/icon/arrow_right_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 574 B |
22
Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Contents.json
vendored
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
BIN
Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 393 B |
BIN
Thimra/Source/Assets.xcassets/icon/episode_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
22
Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Contents.json
vendored
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
BIN
Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@2x.png
vendored
Normal file
After Width: | Height: | Size: 379 B |
BIN
Thimra/Source/Assets.xcassets/icon/pause_icon_01.imageset/Frame 1912056659@3x.png
vendored
Normal file
After Width: | Height: | Size: 605 B |
22
Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Contents.json
vendored
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
BIN
Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@2x.png
vendored
Normal file
After Width: | Height: | Size: 929 B |
BIN
Thimra/Source/Assets.xcassets/icon/play_icon_01.imageset/Frame 43@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 280 B |
Before Width: | Height: | Size: 431 B |
22
Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Contents.json
vendored
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
BIN
Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Thimra/Source/Assets.xcassets/icon/speed_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.9 KiB |
22
Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Contents.json
vendored
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
BIN
Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Thimra/Source/Assets.xcassets/icon/speed_icon_02.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
@ -20,7 +20,6 @@
|
|||||||
"Episodes" = "Episodes";
|
"Episodes" = "Episodes";
|
||||||
"Save" = "Save";
|
"Save" = "Save";
|
||||||
"Added" = "Added";
|
"Added" = "Added";
|
||||||
"Series" = "Series";
|
|
||||||
"Order Record" = "Order Record";
|
"Order Record" = "Order Record";
|
||||||
"Language" = "Language";
|
"Language" = "Language";
|
||||||
"Privacy Policy" = "Privacy Policy";
|
"Privacy Policy" = "Privacy Policy";
|
||||||
@ -40,6 +39,9 @@
|
|||||||
"More" = "More";
|
"More" = "More";
|
||||||
"Historical search" = "Historical search";
|
"Historical search" = "Historical search";
|
||||||
"Top Search" = "Top Search";
|
"Top Search" = "Top Search";
|
||||||
|
"EP%@" = "EP%@";
|
||||||
|
"Full Episodes" = "Full Episodes";
|
||||||
|
"All" = "All";
|
||||||
|
"Shorts" = "Shorts";
|
||||||
|
|
||||||
|
|
||||||
///视频详情标题
|
|
||||||
"kPlayerDetailTitleString" = "Episode %@ / %@";
|
|
||||||
|
@ -428,7 +428,7 @@ static NSInteger const kWMControllerCountUndefined = -1;
|
|||||||
WMScrollView *scrollView = [[WMScrollView alloc] init];
|
WMScrollView *scrollView = [[WMScrollView alloc] init];
|
||||||
scrollView.scrollsToTop = NO;
|
scrollView.scrollsToTop = NO;
|
||||||
scrollView.pagingEnabled = YES;
|
scrollView.pagingEnabled = YES;
|
||||||
scrollView.backgroundColor = [UIColor whiteColor];
|
scrollView.backgroundColor = [UIColor clearColor];
|
||||||
scrollView.delegate = self;
|
scrollView.delegate = self;
|
||||||
scrollView.showsVerticalScrollIndicator = NO;
|
scrollView.showsVerticalScrollIndicator = NO;
|
||||||
scrollView.showsHorizontalScrollIndicator = NO;
|
scrollView.showsHorizontalScrollIndicator = NO;
|
||||||
@ -681,7 +681,7 @@ static NSInteger const kWMControllerCountUndefined = -1;
|
|||||||
#pragma mark - Life Cycle
|
#pragma mark - Life Cycle
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
self.view.backgroundColor = [UIColor whiteColor];
|
self.view.backgroundColor = [UIColor clearColor];
|
||||||
if (!self.childControllersCount) return;
|
if (!self.childControllersCount) return;
|
||||||
[self wm_calculateSize];
|
[self wm_calculateSize];
|
||||||
[self wm_addScrollView];
|
[self wm_addScrollView];
|
||||||
|