首页新页面开发,闹钟电话异常暂停处理
@ -480,5 +480,13 @@ extension UIColor {
|
||||
static func colorAD7433(alpha: CGFloat = 1) -> UIColor {
|
||||
return color(hex: 0xAD7433, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorFFC234(alpha: CGFloat = 1) -> UIColor {
|
||||
return color(hex: 0xFFC234, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorFFDD00(alpha: CGFloat = 1) -> UIColor {
|
||||
return color(hex: 0xFFDD00, alpha: alpha)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class SPHomeAPI: NSObject {
|
||||
///首页模块接口
|
||||
static func requestHomeModuleData(completer: ((_ model: SPHomeModuleModel?) -> Void)?) {
|
||||
var param = SPNetworkParameters(path: "/homeModuleData")
|
||||
// let param = SPNetworkParameters(path: "/homeBannerAndNineSquare")
|
||||
// var param = SPNetworkParameters(path: "/home/all-modules")
|
||||
param.method = .get
|
||||
|
||||
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPHomeModuleModel>) in
|
||||
|
@ -151,7 +151,7 @@ class SPVideoAPI: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
///获取分类短剧
|
||||
///获取分类短剧
|
||||
static func requestCategoryShortList(page: Int, id: String, completer: ((_ listModel: SPListModel<SPShortModel>?) -> Void)?) {
|
||||
var param = SPNetworkParameters(path: "/videoList")
|
||||
param.method = .get
|
||||
|
@ -78,6 +78,8 @@ class SPHomeViewController: SPHomeChildController {
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
private var headerView: SPHomeHeaderView?
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
@ -105,6 +107,13 @@ class SPHomeViewController: SPHomeChildController {
|
||||
requestPlayHistory()
|
||||
}
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
self.headerView?.isDidAppear = self.isDidAppear
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
self.headerView?.isDidAppear = self.isDidAppear
|
||||
}
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
@ -228,6 +237,7 @@ extension SPHomeViewController: UICollectionViewDelegate, UICollectionViewDataSo
|
||||
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
||||
if let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerView", for: indexPath) as? SPHomeHeaderView {
|
||||
headerView.viewModel = self.viewModel
|
||||
self.headerView = headerView
|
||||
return headerView
|
||||
}
|
||||
return UICollectionReusableView()
|
||||
@ -259,12 +269,22 @@ extension SPHomeViewController {
|
||||
requestListDataArr(page: 1) { [weak self] in
|
||||
self?.requestGroup.leave()
|
||||
}
|
||||
self.requestGroup.enter()
|
||||
requestCategoryShortList(id: "3") { [weak self] in
|
||||
self?.requestGroup.leave()
|
||||
}
|
||||
// self.requestGroup.enter()
|
||||
// requestCategoryShortList(id: "1") { [weak self] in
|
||||
// self?.requestGroup.leave()
|
||||
// }
|
||||
|
||||
|
||||
self.requestGroup.notify(queue: DispatchQueue.main) {
|
||||
completer?()
|
||||
}
|
||||
}
|
||||
|
||||
///获取模版数据 包括banner 九宫格等
|
||||
private func requestModuleData(completer: (() -> Void)? = nil) {
|
||||
SPHomeAPI.requestHomeModuleData { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
@ -279,6 +299,28 @@ extension SPHomeViewController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///甜宠ID= 3
|
||||
///虐恋ID=1
|
||||
private func requestCategoryShortList(id: String, completer: (() -> Void)?) {
|
||||
|
||||
SPVideoAPI.requestCategoryShortList(page: 1, id: id) { [weak self] listModel in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let list = listModel?.list {
|
||||
if id == "3" {
|
||||
self.viewModel.categoryDataArr1 = list
|
||||
} else {
|
||||
self.viewModel.categoryDataArr2 = list
|
||||
}
|
||||
self.layout.headerReferenceSize = CGSize(width: kSPScreenWidth, height: SPHomeHeaderView.contentHeight(viewModel: self.viewModel))
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
self.updateEmptyState()
|
||||
completer?()
|
||||
}
|
||||
}
|
||||
|
||||
///获取播放记录
|
||||
private func requestPlayHistory(completer: (() -> Void)? = nil) {
|
||||
SPVideoAPI.requestPlayHistoryList(page: 1) { [weak self] listModel in
|
||||
|
40
MoviaBox/Class/Home/View/SPHomeCategoryVideoCell.swift
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// SPHomeCategoryVideoCell.swift
|
||||
// MoviaBox
|
||||
//
|
||||
// Created by 佳尔 on 2025/5/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SPHomeCategoryVideoCell: SPCollectionViewCell {
|
||||
|
||||
var model: SPShortModel? {
|
||||
didSet {
|
||||
coverImageView.sp_setImage(url: model?.image_url)
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var coverImageView: SPImageView = {
|
||||
let imageView = SPImageView()
|
||||
imageView.layer.cornerRadius = 8
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
contentView.addSubview(coverImageView)
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
257
MoviaBox/Class/Home/View/SPHomeCategoryVideoView.swift
Normal file
@ -0,0 +1,257 @@
|
||||
//
|
||||
// SPHomeCategoryVideoView.swift
|
||||
// MoviaBox
|
||||
//
|
||||
// Created by 佳尔 on 2025/5/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SPHomeCategoryVideoView: UIView {
|
||||
|
||||
static func contentHeight() -> CGFloat {
|
||||
return 372
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
let width = kSPScreenWidth
|
||||
return CGSize(width: width, height: Self.contentHeight())
|
||||
}
|
||||
|
||||
|
||||
var image: UIImage? {
|
||||
didSet {
|
||||
bgImageView.image = image
|
||||
}
|
||||
}
|
||||
|
||||
var dataArr: [SPShortModel] = [] {
|
||||
didSet {
|
||||
if dataArr.count > 10 {
|
||||
topDataArr = Array(dataArr.prefix(10))
|
||||
bottomDataArr = Array(dataArr.suffix(from: dataArr.count - 10))
|
||||
} else {
|
||||
topDataArr = dataArr
|
||||
bottomDataArr.removeAll()
|
||||
}
|
||||
self.topCollectionView.reloadData()
|
||||
|
||||
updateTimerState()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var isDidAppear: Bool = false {
|
||||
didSet {
|
||||
updateTimerState()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var topDataArr: [SPShortModel] = []
|
||||
private lazy var bottomDataArr: [SPShortModel] = []
|
||||
|
||||
private var timer: Timer?
|
||||
|
||||
private var displayLink: CADisplayLink?
|
||||
|
||||
///被拖拽的View
|
||||
private var draggingView: UIScrollView?
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.isUserInteractionEnabled = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = CGSize(width: 101, height: 135)
|
||||
layout.footerReferenceSize = CGSize(width: 8, height: 135)
|
||||
layout.scrollDirection = .horizontal
|
||||
layout.minimumLineSpacing = 8
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var topCollectionView: SPCollectionView = {
|
||||
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
SPHomeCategoryVideoCell.registerCell(collectionView: collectionView)
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
private lazy var bottomCollectionView: SPCollectionView = {
|
||||
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
SPHomeCategoryVideoCell.registerCell(collectionView: collectionView)
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
deinit {
|
||||
self.displayLink?.invalidate()
|
||||
self.timer?.invalidate()
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func updateTimerState() {
|
||||
|
||||
if dataArr.count > 0, isDidAppear {
|
||||
startTimer()
|
||||
} else {
|
||||
stopTimer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension SPHomeCategoryVideoView {
|
||||
private func startTimer() {
|
||||
// if timer == nil {
|
||||
// self.timer = Timer.scheduledTimer(timeInterval: 1, target: YYWeakProxy(target: self), selector: #selector(handleTimer), userInfo: nil, repeats: true)
|
||||
// RunLoop.main.add(self.timer!, forMode: .common)
|
||||
// }
|
||||
|
||||
if displayLink == nil {
|
||||
displayLink = CADisplayLink(target: YYWeakProxy(target: self), selector: #selector(handleTimer))
|
||||
displayLink?.add(to: .main, forMode: .common)
|
||||
}
|
||||
}
|
||||
|
||||
private func stopTimer() {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
|
||||
displayLink?.invalidate()
|
||||
displayLink = nil
|
||||
}
|
||||
|
||||
@objc private func handleTimer() {
|
||||
// 向左滑动 Top
|
||||
if draggingView != topCollectionView {
|
||||
let topOffset = CGPoint(x: topCollectionView.contentOffset.x + 0.5, y: 0)
|
||||
if topOffset.x < topCollectionView.contentSize.width - topCollectionView.bounds.width {
|
||||
topCollectionView.contentOffset = topOffset
|
||||
} else {
|
||||
topCollectionView.contentOffset = .zero
|
||||
}
|
||||
}
|
||||
|
||||
// 向右滑动 Bottom
|
||||
if draggingView != bottomCollectionView {
|
||||
let bottomOffset = CGPoint(x: bottomCollectionView.contentOffset.x - 0.5, y: 0)
|
||||
if bottomOffset.x > 0 {
|
||||
bottomCollectionView.contentOffset = bottomOffset
|
||||
} else {
|
||||
bottomCollectionView.contentOffset = CGPoint(x: bottomCollectionView.contentSize.width - bottomCollectionView.bounds.width, y: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SPHomeCategoryVideoView {
|
||||
|
||||
private func _setupUI() {
|
||||
addSubview(bgImageView)
|
||||
bgImageView.addSubview(topCollectionView)
|
||||
bgImageView.addSubview(bottomCollectionView)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.right.equalToSuperview().offset(-16)
|
||||
make.top.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
topCollectionView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(70)
|
||||
make.height.equalTo(self.collectionViewLayout.itemSize.height)
|
||||
}
|
||||
|
||||
bottomCollectionView.snp.makeConstraints { make in
|
||||
make.left.right.height.equalTo(topCollectionView)
|
||||
make.top.equalTo(topCollectionView.snp.bottom).offset(8)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource --------------
|
||||
extension SPHomeCategoryVideoView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let model: SPShortModel
|
||||
if collectionView == topCollectionView {
|
||||
model = topDataArr[indexPath.row]
|
||||
} else {
|
||||
model = bottomDataArr[indexPath.row]
|
||||
}
|
||||
|
||||
let cell = SPHomeCategoryVideoCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
|
||||
cell.model = model
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
if collectionView == topCollectionView {
|
||||
return topDataArr.count
|
||||
} else {
|
||||
return bottomDataArr.count
|
||||
}
|
||||
}
|
||||
|
||||
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
return 3
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model: SPShortModel
|
||||
if collectionView == topCollectionView {
|
||||
model = topDataArr[indexPath.row]
|
||||
} else {
|
||||
model = bottomDataArr[indexPath.row]
|
||||
}
|
||||
|
||||
let vc = SPPlayerDetailViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||
draggingView = scrollView
|
||||
}
|
||||
|
||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
draggingView = nil
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
|
||||
let offsetX = scrollView.contentOffset.x
|
||||
let contentWidth = scrollView.contentSize.width
|
||||
let sectionWidth = contentWidth / 3
|
||||
|
||||
if contentWidth <= scrollView.size.width { return }
|
||||
|
||||
if offsetX < sectionWidth {
|
||||
scrollView.contentOffset = CGPoint(x: sectionWidth * 2, y: 0)
|
||||
} else if offsetX > sectionWidth * 2 {
|
||||
scrollView.contentOffset = CGPoint(x: sectionWidth, y: 0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -30,7 +30,7 @@ class SPHomeDataItemView: UIView {
|
||||
|
||||
private(set) lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontWeight(ofSize: 18, weight: 400)
|
||||
label.font = .fontMedium(ofSize: 18)
|
||||
label.textColor = .colorFFFFFF()
|
||||
return label
|
||||
}()
|
||||
|
@ -34,9 +34,23 @@ class SPHomeHeaderView: UICollectionReusableView {
|
||||
exploreView.titleLabel.text = moduleModel?.nineSquare?.title
|
||||
exploreView.dataArr = list
|
||||
}
|
||||
|
||||
// stackView.addArrangedSubview(trendingView)
|
||||
// trendingView.dataArr = moduleModel?.bannerData
|
||||
|
||||
if let list = viewModel?.categoryDataArr1, list.count > 0 {
|
||||
stackView.addArrangedSubview(categoryVideoView1)
|
||||
categoryVideoView1.dataArr = list
|
||||
}
|
||||
|
||||
if let list = moduleModel?.hotData, list.count > 0 {
|
||||
stackView.addArrangedSubview(trendingView)
|
||||
trendingView.dataArr = list
|
||||
}
|
||||
|
||||
if let list = viewModel?.categoryDataArr2, list.count > 0 {
|
||||
stackView.addArrangedSubview(categoryVideoView2)
|
||||
categoryVideoView2.dataArr = list
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// stackView.addArrangedSubview(hotView)
|
||||
// hotView.dataArr = moduleModel?.bannerData
|
||||
@ -50,6 +64,13 @@ class SPHomeHeaderView: UICollectionReusableView {
|
||||
}
|
||||
}
|
||||
|
||||
var isDidAppear: Bool = false {
|
||||
didSet {
|
||||
self.categoryVideoView1.isDidAppear = isDidAppear
|
||||
self.categoryVideoView2.isDidAppear = isDidAppear
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
@ -93,6 +114,20 @@ class SPHomeHeaderView: UICollectionReusableView {
|
||||
return view
|
||||
}()
|
||||
|
||||
///甜宠
|
||||
private lazy var categoryVideoView1: SPHomeCategoryVideoView = {
|
||||
let view = SPHomeCategoryVideoView()
|
||||
view.image = UIImage(named: "category_bg_image_01")
|
||||
return view
|
||||
}()
|
||||
|
||||
///虐恋
|
||||
private lazy var categoryVideoView2: SPHomeCategoryVideoView = {
|
||||
let view = SPHomeCategoryVideoView()
|
||||
view.image = UIImage(named: "category_bg_image_02")
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var trendingView: SPHomeTrendingView = {
|
||||
let view = SPHomeTrendingView()
|
||||
return view
|
||||
@ -111,6 +146,7 @@ class SPHomeHeaderView: UICollectionReusableView {
|
||||
private lazy var titleView: SPHomeDataItemView = {
|
||||
let view = SPHomeDataItemView()
|
||||
view.titleLabel.text = "movia_more_for_you".localized
|
||||
view.iconImageView.image = UIImage(named: "mark_icon_02")
|
||||
return view
|
||||
}()
|
||||
|
||||
@ -228,7 +264,29 @@ extension SPHomeHeaderView {
|
||||
height = height + SPHomeExploreView.contentHeight(dataArr: list)
|
||||
}
|
||||
|
||||
// height = height + SPHomeTrendingView.contentHeight(dataArr: moduleModel?.bannerData ?? []) + 25
|
||||
///甜宠数据
|
||||
if viewModel.categoryDataArr1.count > 0 {
|
||||
if height > 0 {
|
||||
height = height + 25
|
||||
}
|
||||
height = height + SPHomeCategoryVideoView.contentHeight()
|
||||
}
|
||||
|
||||
///虐恋
|
||||
if viewModel.categoryDataArr2.count > 0 {
|
||||
if height > 0 {
|
||||
height = height + 25
|
||||
}
|
||||
height = height + SPHomeCategoryVideoView.contentHeight()
|
||||
}
|
||||
|
||||
if let list = moduleModel?.hotData, list.count > 0 {
|
||||
if height > 0 {
|
||||
height = height + 25
|
||||
}
|
||||
height = height + SPHomeTrendingView.contentHeight(dataArr: list)
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// height = height + SPHomeHotView.contentHeight(dataArr: moduleModel?.bannerData ?? []) + 25
|
||||
|
@ -13,37 +13,82 @@ class SPHomeTrendingCell: SPCollectionViewCell {
|
||||
didSet {
|
||||
coverImageView.sp_setImage(url: model?.image_url)
|
||||
titleLabel.text = model?.name
|
||||
hotView.setTitle("\(model?.watch_total ?? 0)", for: .normal)
|
||||
|
||||
if let tag = model?.tag_type, !tag.isEmpty {
|
||||
tagView.setTitle(tag, for: .normal)
|
||||
tagView.isHidden = false
|
||||
} else {
|
||||
tagView.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var row: Int = 0 {
|
||||
didSet {
|
||||
let num = row + 1
|
||||
if num < 4 {
|
||||
numBgView.image = UIImage(named: "num_bg_icon_\(num)")
|
||||
} else {
|
||||
numBgView.image = UIImage(named: "num_bg_icon_4")
|
||||
}
|
||||
|
||||
numLabel.text = "\(num)"
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var coverImageView: SPImageView = {
|
||||
let imageView = SPImageView()
|
||||
imageView.layer.cornerRadius = 10
|
||||
imageView.layer.cornerRadius = 6
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var numBgView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var numLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 20)
|
||||
label.textColor = .colorFFFFFF()
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontLight(ofSize: 13)
|
||||
label.textColor = .colorFFFFFF(alpha: 0.9)
|
||||
label.font = .fontMedium(ofSize: 12)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var hotBgView: SPGradientView = {
|
||||
let view = SPGradientView()
|
||||
view.colors = [UIColor.colorF56490().cgColor, UIColor.colorBF6BFF().cgColor]
|
||||
view.startPoint = .init(x: 0.5, y: 0)
|
||||
view.endPoint = .init(x: 0.5, y: 1)
|
||||
view.locations = [0, 1]
|
||||
view.addRadius(topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 6)
|
||||
return view
|
||||
private lazy var hotView: JXButton = {
|
||||
let button = JXButton(type: .custom)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.titleDirection = .right
|
||||
button.jx_font = .fontRegular(ofSize: 10)
|
||||
button.leftAndRightMargin = 6
|
||||
button.setImage(UIImage(named: "hot_icon_01"), for: .normal)
|
||||
button.setTitleColor(.colorFFDD00(), for: .normal)
|
||||
button.backgroundColor = .colorD9D9D9(alpha: 0.16)
|
||||
button.layer.cornerRadius = 2
|
||||
button.layer.masksToBounds = true
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var hotIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "hot_icon_01"))
|
||||
return imageView
|
||||
private lazy var tagView: JXButton = {
|
||||
let button = JXButton(type: .custom)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.backgroundColor = .colorD9D9D9(alpha: 0.16)
|
||||
button.layer.cornerRadius = 2
|
||||
button.layer.masksToBounds = true
|
||||
button.jx_font = .fontRegular(ofSize: 10)
|
||||
button.setTitleColor(.colorFFFFFF(), for: .normal)
|
||||
button.leftAndRightMargin = 6
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
@ -62,30 +107,45 @@ extension SPHomeTrendingCell {
|
||||
|
||||
private func _setupUI() {
|
||||
contentView.addSubview(coverImageView)
|
||||
coverImageView.addSubview(numBgView)
|
||||
numBgView.addSubview(numLabel)
|
||||
contentView.addSubview(titleLabel)
|
||||
coverImageView.addSubview(hotBgView)
|
||||
hotBgView.addSubview(hotIconImageView)
|
||||
contentView.addSubview(hotView)
|
||||
contentView.addSubview(tagView)
|
||||
// coverImageView.addSubview(hotBgView)
|
||||
// hotBgView.addSubview(hotIconImageView)
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-38)
|
||||
make.left.top.bottom.equalToSuperview()
|
||||
make.width.equalTo(82)
|
||||
}
|
||||
|
||||
numBgView.snp.makeConstraints { make in
|
||||
make.left.top.equalToSuperview()
|
||||
}
|
||||
|
||||
numLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.top.equalTo(coverImageView.snp.bottom).offset(5)
|
||||
make.left.equalTo(coverImageView.snp.right).offset(8)
|
||||
make.top.equalToSuperview().offset(12)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-5)
|
||||
}
|
||||
|
||||
hotBgView.snp.makeConstraints { make in
|
||||
make.left.top.equalToSuperview()
|
||||
make.width.equalTo(22)
|
||||
make.height.equalTo(16)
|
||||
hotView.snp.makeConstraints { make in
|
||||
make.left.equalTo(titleLabel)
|
||||
make.top.equalToSuperview().offset(56)
|
||||
make.height.equalTo(18)
|
||||
}
|
||||
|
||||
hotIconImageView.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
tagView.snp.makeConstraints { make in
|
||||
make.left.equalTo(hotView)
|
||||
make.top.equalTo(hotView.snp.bottom).offset(8)
|
||||
make.height.equalTo(18)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,47 +7,44 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class SPHomeTrendingView: SPHomeDataItemView {
|
||||
class SPHomeTrendingView: UIView {
|
||||
|
||||
private static func itemSize() -> CGSize {
|
||||
let width = floor((kSPScreenWidth - 15 * 2 - 12 * 2) / 3)
|
||||
let imageScale: CGFloat = 153 / 107
|
||||
let height = width * imageScale + 38
|
||||
|
||||
return CGSize(width: width, height: height)
|
||||
return CGSize(width: 224, height: 106)
|
||||
}
|
||||
|
||||
override class func contentHeight(dataArr: [SPShortModel]) -> CGFloat {
|
||||
|
||||
var height = self.contentToTop
|
||||
|
||||
var lineCount = dataArr.count / 3
|
||||
if dataArr.count % 3 > 0 {
|
||||
lineCount += 1
|
||||
}
|
||||
|
||||
let contentHeight = itemSize().height * CGFloat(lineCount) + 12 * CGFloat(lineCount - 1)
|
||||
if contentHeight > 0 {
|
||||
height += contentHeight
|
||||
} else {
|
||||
height += 1
|
||||
}
|
||||
|
||||
return height
|
||||
class func contentHeight(dataArr: [SPShortModel]) -> CGFloat {
|
||||
return 388
|
||||
}
|
||||
|
||||
override var dataArr: [SPShortModel]? {
|
||||
var dataArr: [SPShortModel]? {
|
||||
didSet {
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var bgView: UIImageView = {
|
||||
let view = UIImageView(image: UIImage(named: "category_bg_image_03"))
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 18)
|
||||
label.textColor = .colorFFC234()
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.minimumLineSpacing = 12
|
||||
layout.minimumInteritemSpacing = 12
|
||||
layout.itemSize = Self.itemSize()
|
||||
layout.sectionInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
|
||||
layout.sectionInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
|
||||
layout.scrollDirection = .horizontal
|
||||
return layout
|
||||
}()
|
||||
|
||||
@ -55,7 +52,9 @@ class SPHomeTrendingView: SPHomeDataItemView {
|
||||
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.isScrollEnabled = false
|
||||
// collectionView.isScrollEnabled = false
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
SPHomeTrendingCell.registerCell(collectionView: collectionView)
|
||||
return collectionView
|
||||
}()
|
||||
@ -63,7 +62,6 @@ class SPHomeTrendingView: SPHomeDataItemView {
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.titleLabel.text = "movia_trending_now".localized
|
||||
|
||||
_setupUI()
|
||||
@ -77,10 +75,23 @@ class SPHomeTrendingView: SPHomeDataItemView {
|
||||
extension SPHomeTrendingView {
|
||||
|
||||
private func _setupUI() {
|
||||
contentView.addSubview(collectionView)
|
||||
addSubview(bgView)
|
||||
addSubview(titleLabel)
|
||||
addSubview(collectionView)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.equalToSuperview().offset(14)
|
||||
}
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(46)
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +101,7 @@ extension SPHomeTrendingView {
|
||||
extension SPHomeTrendingView: UICollectionViewDataSource, UICollectionViewDelegate {
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = SPHomeTrendingCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
|
||||
cell.row = indexPath.row
|
||||
cell.model = dataArr?[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
@ -12,8 +12,15 @@ class SPHomeViewModel: NSObject {
|
||||
lazy var page = 1
|
||||
lazy var dataArr: [SPShortModel] = []
|
||||
|
||||
///模版数据
|
||||
var moduleModel: SPHomeModuleModel?
|
||||
|
||||
///分类数据
|
||||
///甜宠
|
||||
var categoryDataArr1: [SPShortModel] = []
|
||||
///虐恋
|
||||
var categoryDataArr2: [SPShortModel] = []
|
||||
|
||||
///历史记录
|
||||
var playHistoryArr: [SPShortModel]?
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AVKit
|
||||
|
||||
@objc protocol SPPlayerListViewControllerDelegate {
|
||||
|
||||
@ -274,21 +275,10 @@ extension SPPlayerListViewController {
|
||||
extension SPPlayerListViewController {
|
||||
///点击播放或暂停
|
||||
private func clickPauseOrPlay() {
|
||||
// let model = self.dataArr[currentIndexPath.section]
|
||||
///打开支付页面
|
||||
// if self.onVideoPay() {
|
||||
// return
|
||||
// }
|
||||
|
||||
if self.viewModel.isPlaying {
|
||||
self.pause()
|
||||
// self.viewModel.isPlaying = false
|
||||
// self.viewModel.currentPlayer?.pause()
|
||||
} else {
|
||||
self.play()
|
||||
|
||||
// self.viewModel.isPlaying = true
|
||||
// self.viewModel.currentPlayer?.start()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ class SPShortModel: SPModel, SmartCodable {
|
||||
var short_play_video_id: String?
|
||||
var tag_type: String?
|
||||
var video_info: SPVideoInfoModel?
|
||||
///观看数
|
||||
var watch_total: Int?
|
||||
var current_episode: String?
|
||||
var video_url: String?
|
||||
|
@ -66,6 +66,9 @@ class SPPlayer: NSObject {
|
||||
*/
|
||||
private var isAddIdleTimerDisabledObserver = false
|
||||
|
||||
///音频占用情况
|
||||
private var interruptionType: AVAudioSession.InterruptionType?
|
||||
|
||||
///总进度
|
||||
var duration: Int {
|
||||
return Int(self.player.totalTime)
|
||||
@ -103,11 +106,17 @@ class SPPlayer: NSObject {
|
||||
var isLoop = true
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
self.stop()
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
//声音被打断的通知(电话打来)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(interruptionNotification(sender:)), name: AVAudioSession.interruptionNotification, object: nil)
|
||||
//耳机插入和拔出的通知
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(routeChangeNotification(sender:)), name: AVAudioSession.routeChangeNotification, object: nil)
|
||||
|
||||
player.scalingMode = .aspectFill
|
||||
sp_addAction()
|
||||
}
|
||||
@ -160,7 +169,9 @@ class SPPlayer: NSObject {
|
||||
|
||||
func start() {
|
||||
self.isPlaying = true
|
||||
player.play()
|
||||
if self.interruptionType != .began {
|
||||
player.play()
|
||||
}
|
||||
|
||||
UIApplication.shared.isIdleTimerDisabled = true
|
||||
self.addIdleTimerDisabledObserver()
|
||||
@ -211,9 +222,9 @@ extension SPPlayer {
|
||||
//播放状态
|
||||
player.playerPlayStateChanged = { [weak self] (asset, playState) in
|
||||
guard let self = self else { return }
|
||||
if playState == .playStatePlaying, !isPlaying {
|
||||
if playState == .playStatePlaying && !isPlaying {
|
||||
self.pause()
|
||||
} else if playState == .playStatePaused, isPlaying {
|
||||
} else if playState == .playStatePaused, isPlaying, self.interruptionType != .began {
|
||||
self.start()
|
||||
}
|
||||
switch playState {
|
||||
@ -238,9 +249,9 @@ extension SPPlayer {
|
||||
//加载状态
|
||||
player.playerLoadStateChanged = { [weak self] (asset, loadState) in
|
||||
guard let self = self else { return }
|
||||
if loadState == .playable, !isPlaying {
|
||||
if loadState == .playable && !isPlaying {
|
||||
self.pause()
|
||||
} else if loadState == .playable, isPlaying, self.player.playState != .playStatePlaying {
|
||||
} else if loadState == .playable, isPlaying, self.player.playState != .playStatePlaying, self.interruptionType != .began {
|
||||
self.start()
|
||||
}
|
||||
|
||||
@ -294,3 +305,26 @@ extension SPPlayer {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- 监听视频中断 --------------
|
||||
extension SPPlayer {
|
||||
|
||||
@objc private func interruptionNotification(sender: Notification) {
|
||||
guard let userInfo = sender.userInfo else { return }
|
||||
guard let interruptionType = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt else { return }
|
||||
|
||||
self.interruptionType = AVAudioSession.InterruptionType(rawValue: interruptionType)
|
||||
if self.interruptionType == .began {
|
||||
self.player.pause()
|
||||
} else {
|
||||
if self.isPlaying {
|
||||
self.player.play()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@objc private func routeChangeNotification(sender: Notification) {
|
||||
// self.pause()
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "hot@2x.png",
|
||||
"filename" : "🔥@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "hot@3x.png",
|
||||
"filename" : "🔥@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 533 B |
Before Width: | Height: | Size: 931 B |
BIN
MoviaBox/Source/Assets.xcassets/icon/hot_icon_01.imageset/🔥@2x.png
vendored
Normal file
After Width: | Height: | Size: 970 B |
BIN
MoviaBox/Source/Assets.xcassets/icon/hot_icon_01.imageset/🔥@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.2 KiB |
22
MoviaBox/Source/Assets.xcassets/icon/mark_icon_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 47@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 47@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/icon/mark_icon_02.imageset/Group 47@2x.png
vendored
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
MoviaBox/Source/Assets.xcassets/icon/mark_icon_02.imageset/Group 47@3x.png
vendored
Normal file
After Width: | Height: | Size: 6.2 KiB |
22
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_1.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 145@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 145@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_1.imageset/Frame 145@2x.png
vendored
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_1.imageset/Frame 145@3x.png
vendored
Normal file
After Width: | Height: | Size: 5.1 KiB |
22
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_2.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 146@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 146@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_2.imageset/Frame 146@2x.png
vendored
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_2.imageset/Frame 146@3x.png
vendored
Normal file
After Width: | Height: | Size: 5.6 KiB |
22
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_3.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 1912056663@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 1912056663@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_3.imageset/Frame 1912056663@2x.png
vendored
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_3.imageset/Frame 1912056663@3x.png
vendored
Normal file
After Width: | Height: | Size: 5.6 KiB |
22
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_4.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 58@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 58@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_4.imageset/Frame 58@2x.png
vendored
Normal file
After Width: | Height: | Size: 305 B |
BIN
MoviaBox/Source/Assets.xcassets/icon/num_bg_icon_4.imageset/Frame 58@3x.png
vendored
Normal file
After Width: | Height: | Size: 465 B |
22
MoviaBox/Source/Assets.xcassets/image/category_bg_image_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "甜宠类-卡片@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "甜宠类-卡片@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/image/category_bg_image_01.imageset/甜宠类-卡片@2x.png
vendored
Normal file
After Width: | Height: | Size: 430 KiB |
BIN
MoviaBox/Source/Assets.xcassets/image/category_bg_image_01.imageset/甜宠类-卡片@3x.png
vendored
Normal file
After Width: | Height: | Size: 931 KiB |
22
MoviaBox/Source/Assets.xcassets/image/category_bg_image_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "虐恋类-卡片@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "虐恋类-卡片@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/image/category_bg_image_02.imageset/虐恋类-卡片@2x.png
vendored
Normal file
After Width: | Height: | Size: 386 KiB |
BIN
MoviaBox/Source/Assets.xcassets/image/category_bg_image_02.imageset/虐恋类-卡片@3x.png
vendored
Normal file
After Width: | Height: | Size: 645 KiB |
22
MoviaBox/Source/Assets.xcassets/image/category_bg_image_03.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 131@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 131@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
MoviaBox/Source/Assets.xcassets/image/category_bg_image_03.imageset/Frame 131@2x.png
vendored
Normal file
After Width: | Height: | Size: 331 KiB |
BIN
MoviaBox/Source/Assets.xcassets/image/category_bg_image_03.imageset/Frame 131@3x.png
vendored
Normal file
After Width: | Height: | Size: 710 KiB |