收藏列表,播放记录列表
@ -15,10 +15,12 @@ class SPTabBarController: UITabBarController {
|
|||||||
let nav1 = createNavigationController(viewController: SPHomePageController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_01"), selectedImage: UIImage(named: "tabbar_icon_01_selected"))
|
let nav1 = createNavigationController(viewController: SPHomePageController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_01"), selectedImage: UIImage(named: "tabbar_icon_01_selected"))
|
||||||
|
|
||||||
let nav2 = createNavigationController(viewController: SPExploreViewController(), title: "For You".localized, image: UIImage(named: "tabbar_icon_02"), selectedImage: UIImage(named: "tabbar_icon_02_selected"))
|
let nav2 = createNavigationController(viewController: SPExploreViewController(), title: "For You".localized, image: UIImage(named: "tabbar_icon_02"), selectedImage: UIImage(named: "tabbar_icon_02_selected"))
|
||||||
|
|
||||||
|
let nav4 = createNavigationController(viewController: SPMyListViewController(), title: "My list".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
|
||||||
|
|
||||||
let nav5 = createNavigationController(viewController: SPMineViewController(), title: "Profile".localized, image: UIImage(named: "tabbar_icon_05"), selectedImage: UIImage(named: "tabbar_icon_05_selected"))
|
let nav5 = createNavigationController(viewController: SPMineViewController(), title: "Profile".localized, image: UIImage(named: "tabbar_icon_05"), selectedImage: UIImage(named: "tabbar_icon_05_selected"))
|
||||||
|
|
||||||
self.viewControllers = [nav1, nav2, nav5]
|
self.viewControllers = [nav1, nav2, nav4, nav5]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +90,10 @@ class SPViewController: UIViewController, JYPageChildContollerProtocol {
|
|||||||
func fetchChildControllerScrollView() -> UIScrollView? {
|
func fetchChildControllerScrollView() -> UIScrollView? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleHeaderRefresh(_ completer: (() -> Void)?) {}
|
||||||
|
|
||||||
|
func handleFooterRefresh(_ completer: (() -> Void)?) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,5 +76,13 @@ extension UIColor {
|
|||||||
static func colorD568D2(alpha: CGFloat = 1) -> UIColor {
|
static func colorD568D2(alpha: CGFloat = 1) -> UIColor {
|
||||||
return color(hex: 0xD568D2, alpha: alpha)
|
return color(hex: 0xD568D2, alpha: alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func color8A899F(alpha: CGFloat = 1) -> UIColor {
|
||||||
|
return color(hex: 0x8A899F, alpha: alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func color888888(alpha: CGFloat = 1) -> UIColor {
|
||||||
|
return color(hex: 0x888888, alpha: alpha)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
64
ShortPlay/Base/Extension/UIScrollView+SPRefresh.swift
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// UIScrollView+SPRefresh.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension UIScrollView {
|
||||||
|
func sp_addRefreshHeader(insetTop: CGFloat = 0, block: (() -> Void)?) {
|
||||||
|
|
||||||
|
|
||||||
|
self.mj_header = MJRefreshNormalHeader(refreshingBlock: {
|
||||||
|
block?()
|
||||||
|
})
|
||||||
|
self.mj_header?.ignoredScrollViewContentInsetTop = insetTop
|
||||||
|
}
|
||||||
|
|
||||||
|
func sp_addRefreshFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) {
|
||||||
|
let footer = MJRefreshAutoNormalFooter(refreshingBlock: {
|
||||||
|
block?()
|
||||||
|
})
|
||||||
|
footer.ignoredScrollViewContentInsetBottom = insetBottom
|
||||||
|
// footer.stateLabel?.font = .text_sm
|
||||||
|
// footer.stateLabel?.textColor = .system_text_secondary_300
|
||||||
|
|
||||||
|
self.mj_footer = footer
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// func sp_setRefreshFooterTitle(title: String = NSLocalizedString("已经到底了~", comment: ""), state: MJRefreshState) {
|
||||||
|
// (self.mj_footer as? MJRefreshAutoStateFooter)?.setTitle(title, for: state)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func sp_addRefreshBackFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) {
|
||||||
|
self.mj_footer = MJRefreshBackNormalFooter(refreshingBlock: {
|
||||||
|
block?()
|
||||||
|
})
|
||||||
|
|
||||||
|
self.mj_footer?.ignoredScrollViewContentInsetBottom = insetBottom
|
||||||
|
}
|
||||||
|
|
||||||
|
func sp_endHeaderRefreshing() {
|
||||||
|
self.mj_header?.endRefreshing()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sp_endFooterRefreshing() {
|
||||||
|
if self.mj_footer?.state == .noMoreData { return }
|
||||||
|
self.mj_footer?.endRefreshing()
|
||||||
|
}
|
||||||
|
|
||||||
|
///重置没有更多
|
||||||
|
func sp_resetNoMoreData() {
|
||||||
|
self.mj_footer?.resetNoMoreData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sp_endRefreshingWithNoMoreData() {
|
||||||
|
// self.mj_footer?.state = .noMoreData
|
||||||
|
self.mj_footer?.endRefreshingWithNoMoreData()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -46,5 +46,19 @@ class SPHomeAPI: NSObject {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///搜索
|
||||||
|
static func requestSearch(text: String, completer: ((_ list: [SPShortModel]?) -> Void)?) {
|
||||||
|
var param = SPNetworkParameters(path: "/search")
|
||||||
|
param.method = .get
|
||||||
|
param.parameters = [
|
||||||
|
"search" : text
|
||||||
|
]
|
||||||
|
|
||||||
|
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPListModel<SPShortModel>>) in
|
||||||
|
completer?(response.data?.list)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
23
ShortPlay/Base/Networking/API/SPUserAPI.swift
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// SPUserAPI.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPUserAPI: NSObject {
|
||||||
|
|
||||||
|
|
||||||
|
static func requestUserInfo(completer: ((_ userInfo: SPUserInfo?) -> Void)?) {
|
||||||
|
|
||||||
|
var param = SPNetworkParameters(path: "/customer/info")
|
||||||
|
param.method = .get
|
||||||
|
|
||||||
|
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPUserInfo>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -69,6 +69,20 @@ class SPVideoAPI: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///收藏列表
|
||||||
|
static func requestCollectList(page: Int, completer: ((_ listModel: SPListModel<SPShortModel>?) -> Void)?) {
|
||||||
|
var param = SPNetworkParameters(path: "/myCollections")
|
||||||
|
param.method = .get
|
||||||
|
param.parameters = [
|
||||||
|
"current_page" : page,
|
||||||
|
"page_size" : 20
|
||||||
|
]
|
||||||
|
|
||||||
|
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPListModel<SPShortModel>>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SPVideoAPI {
|
extension SPVideoAPI {
|
||||||
|
@ -51,7 +51,7 @@ extension SPApi: TargetType {
|
|||||||
var path: String {
|
var path: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .request(let parameters):
|
case .request(let parameters):
|
||||||
return parameters.path
|
return SPURLPathPrefix + parameters.path
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -72,44 +72,36 @@ class SPNetwork: NSObject {
|
|||||||
let code = response.statusCode
|
let code = response.statusCode
|
||||||
if code == 401 || code == 402 || code == 403 {
|
if code == 401 || code == 402 || code == 403 {
|
||||||
|
|
||||||
///重新获取token
|
if parameters.path == "/customer/register" {
|
||||||
self.requestToken(completer: nil)
|
var res = SPNetworkResponse<T>()
|
||||||
|
res.code = -1
|
||||||
///将请求失败数据重新请求
|
if parameters.isToast {
|
||||||
if let tokenOperation = self.tokenOperation, parameters.path != "/customer/register" {
|
SPToast.show(text: "Error".localized)
|
||||||
|
|
||||||
let requestOperation = BlockOperation {
|
|
||||||
let semaphore = DispatchSemaphore(value: 0)
|
|
||||||
_request(parameters: parameters) { (response: SPNetworkResponse<T>) in
|
|
||||||
semaphore.signal()
|
|
||||||
completion?(response)
|
|
||||||
}
|
|
||||||
semaphore.wait()
|
|
||||||
}
|
}
|
||||||
///设置依赖关系
|
completion?(res)
|
||||||
requestOperation.addDependency(tokenOperation)
|
} else {
|
||||||
|
///重新获取token
|
||||||
|
self.requestToken(completer: nil)
|
||||||
|
|
||||||
operationQueue.addOperation(requestOperation)
|
///将请求失败数据重新请求
|
||||||
|
if let tokenOperation = self.tokenOperation, parameters.path != "/customer/register" {
|
||||||
|
|
||||||
|
let requestOperation = BlockOperation {
|
||||||
|
let semaphore = DispatchSemaphore(value: 0)
|
||||||
|
_request(parameters: parameters) { (response: SPNetworkResponse<T>) in
|
||||||
|
semaphore.signal()
|
||||||
|
completion?(response)
|
||||||
|
}
|
||||||
|
semaphore.wait()
|
||||||
|
}
|
||||||
|
///设置依赖关系
|
||||||
|
requestOperation.addDependency(tokenOperation)
|
||||||
|
|
||||||
|
operationQueue.addOperation(requestOperation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// if !SPLoginManager.manager.isRefreshingToken {
|
|
||||||
// SPLoginManager.manager.requestVisitorLogin {
|
|
||||||
// if let _ = SPLoginManager.manager.token {
|
|
||||||
// self.request(parameters: parameters, completion: completion)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// if parameters.path != "/customer/register" {
|
|
||||||
//// while SPLoginManager.manager.isRefreshingToken {
|
|
||||||
//// RunLoop.current.run(mode: .default, before: Date.distantFuture)
|
|
||||||
//// }
|
|
||||||
//// if let _ = SPLoginManager.manager.token {
|
|
||||||
//// self.request(parameters: parameters, completion: completion)
|
|
||||||
//// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,14 @@ import UIKit
|
|||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
let SPBaseURL = "https://test1-api.guyantv.com"
|
let SPBaseURL = "https://test1-api.guyantv.com"
|
||||||
|
let SPURLPathPrefix = ""
|
||||||
|
//let SPBaseURL = "https://api-mireotv.mireotv.com"
|
||||||
|
//let SPURLPathPrefix = "/4da6fd4c"
|
||||||
|
|
||||||
let SPWebBaseURL = "https://www.guyantv.com"
|
let SPWebBaseURL = "https://www.guyantv.com"
|
||||||
#else
|
#else
|
||||||
let SPBaseURL = "https://test1-api.guyantv.com"
|
let SPBaseURL = "https://test1-api.guyantv.com"
|
||||||
|
let SPURLPathPrefix = "/4da6fd4c"
|
||||||
let SPWebBaseURL = "https://www.guyantv.com"
|
let SPWebBaseURL = "https://www.guyantv.com"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -19,6 +19,29 @@ class SPSearchViewController: SPViewController {
|
|||||||
private lazy var searchInputView: SPSearchInputView = {
|
private lazy var searchInputView: SPSearchInputView = {
|
||||||
let view = SPSearchInputView()
|
let view = SPSearchInputView()
|
||||||
view.textField.delegate = self
|
view.textField.delegate = self
|
||||||
|
view.textDidChange = { [weak self] text in
|
||||||
|
self?.textDidChange(text: text)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
///搜索首页
|
||||||
|
private lazy var homeView: SPSearchHomeView = {
|
||||||
|
let view = SPSearchHomeView()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
///联想页面
|
||||||
|
private lazy var associativeView: SPSearchAssociativeView = {
|
||||||
|
let view = SPSearchAssociativeView()
|
||||||
|
view.isHidden = true
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
///搜索结果
|
||||||
|
private lazy var resultView: SPSearchResultView = {
|
||||||
|
let view = SPSearchResultView()
|
||||||
|
view.isHidden = true
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -41,6 +64,9 @@ extension SPSearchViewController {
|
|||||||
private func _setupUI() {
|
private func _setupUI() {
|
||||||
view.addSubview(backButton)
|
view.addSubview(backButton)
|
||||||
view.addSubview(searchInputView)
|
view.addSubview(searchInputView)
|
||||||
|
view.addSubview(homeView)
|
||||||
|
view.addSubview(resultView)
|
||||||
|
view.addSubview(associativeView)
|
||||||
|
|
||||||
backButton.snp.makeConstraints { make in
|
backButton.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(5)
|
make.left.equalToSuperview().offset(5)
|
||||||
@ -54,6 +80,19 @@ extension SPSearchViewController {
|
|||||||
make.left.equalTo(backButton.snp.right).offset(5)
|
make.left.equalTo(backButton.snp.right).offset(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
homeView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalTo(searchInputView.snp.bottom).offset(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalTo(homeView)
|
||||||
|
}
|
||||||
|
|
||||||
|
associativeView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalTo(homeView)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -69,4 +108,31 @@ extension SPSearchViewController: UITextFieldDelegate {
|
|||||||
spLog(message: "结束编辑")
|
spLog(message: "结束编辑")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
spLog(message: "点击搜索")
|
||||||
|
if let text = textField.text, text.count > 0 {
|
||||||
|
// self.requestSearch(text: text)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
///文本发生变化
|
||||||
|
func textDidChange(text: String) {
|
||||||
|
if text.count > 0 {
|
||||||
|
self.associativeView.isHidden = false
|
||||||
|
self.homeView.isHidden = true
|
||||||
|
} else {
|
||||||
|
self.associativeView.isHidden = true
|
||||||
|
self.homeView.isHidden = false
|
||||||
|
}
|
||||||
|
self.associativeView.search(text: text)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPSearchViewController {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
75
ShortPlay/Class/Home/View/SPSearchAssociativeCell.swift
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//
|
||||||
|
// SPSearchAssociativeCell.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPSearchAssociativeCell: SPTableViewCell {
|
||||||
|
|
||||||
|
|
||||||
|
var searchText: String?
|
||||||
|
|
||||||
|
var model: SPShortModel? {
|
||||||
|
didSet {
|
||||||
|
|
||||||
|
if let string = model?.titleAttributedString {
|
||||||
|
titleLabel.attributedText = string
|
||||||
|
} else {
|
||||||
|
let string = NSMutableAttributedString(string: model?.name ?? "")
|
||||||
|
string.color = .color8A899F()
|
||||||
|
|
||||||
|
if let range = model?.name?.ocString().range(of: searchText ?? "") {
|
||||||
|
string.setColor(.colorFFFFFF(), range: range)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.attributedText = string
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var iconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "play_icon_03"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontRegular(ofSize: 14)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPSearchAssociativeCell {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
contentView.addSubview(iconImageView)
|
||||||
|
contentView.addSubview(titleLabel)
|
||||||
|
|
||||||
|
iconImageView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(15)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(40)
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
96
ShortPlay/Class/Home/View/SPSearchAssociativeView.swift
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
//
|
||||||
|
// SPSearchAssociativeView.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPSearchAssociativeView: UIView {
|
||||||
|
|
||||||
|
|
||||||
|
private(set) lazy var searchText: String = ""
|
||||||
|
|
||||||
|
private lazy var dataArr: [SPShortModel] = []
|
||||||
|
|
||||||
|
private lazy var tableView: SPTableView = {
|
||||||
|
let tableView = SPTableView(frame: .zero, style: .plain)
|
||||||
|
tableView.delegate = self
|
||||||
|
tableView.dataSource = self
|
||||||
|
tableView.rowHeight = 50
|
||||||
|
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSPTabbarSafeBottomMargin, right: 0)
|
||||||
|
SPSearchAssociativeCell.registerCell(tableView: tableView)
|
||||||
|
return tableView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func search(text: String) {
|
||||||
|
self.searchText = text
|
||||||
|
|
||||||
|
self.requestSearch(text: text)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPSearchAssociativeView {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
addSubview(tableView)
|
||||||
|
|
||||||
|
tableView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- UITableViewDelegate & UITableViewDataSource --------------
|
||||||
|
extension SPSearchAssociativeView: UITableViewDelegate, UITableViewDataSource {
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let cell = SPSearchAssociativeCell.dequeueReusableCell(tableView: tableView, indexPath: indexPath)
|
||||||
|
cell.searchText = self.searchText
|
||||||
|
cell.model = dataArr[indexPath.row]
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
let model = self.dataArr[indexPath.row]
|
||||||
|
|
||||||
|
let vc = SPPlayerDetailViewController()
|
||||||
|
vc.shortPlayId = model.short_play_id
|
||||||
|
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPSearchAssociativeView {
|
||||||
|
|
||||||
|
private func requestSearch(text: String) {
|
||||||
|
|
||||||
|
SPHomeAPI.requestSearch(text: text) { [weak self] list in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if self.searchText != text { return; }
|
||||||
|
|
||||||
|
if let list = list {
|
||||||
|
self.dataArr = list
|
||||||
|
self.tableView.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,8 @@ class SPSearchInputView: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var textDidChange: ((_ text: String) -> Void)?
|
||||||
|
|
||||||
//MARK: UI属性
|
//MARK: UI属性
|
||||||
private lazy var iconImageView: UIImageView = {
|
private lazy var iconImageView: UIImageView = {
|
||||||
let imageView = UIImageView(image: UIImage(named: "search_icon_02"))
|
let imageView = UIImageView(image: UIImage(named: "search_icon_02"))
|
||||||
@ -30,6 +32,10 @@ class SPSearchInputView: UIView {
|
|||||||
private(set) lazy var textField: SPTextField = {
|
private(set) lazy var textField: SPTextField = {
|
||||||
let textField = SPTextField()
|
let textField = SPTextField()
|
||||||
textField.font = .fontRegular(ofSize: 12)
|
textField.font = .fontRegular(ofSize: 12)
|
||||||
|
textField.returnKeyType = .search
|
||||||
|
textField.textDidChange = { [weak self] text in
|
||||||
|
self?.textDidChange?(text)
|
||||||
|
}
|
||||||
return textField
|
return textField
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
20
ShortPlay/Class/Home/View/SPSearchResultCell.swift
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// SPSearchResultCell.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPSearchResultCell: SPTableViewCell {
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Only override draw() if you perform custom drawing.
|
||||||
|
// An empty implementation adversely affects performance during animation.
|
||||||
|
override func draw(_ rect: CGRect) {
|
||||||
|
// Drawing code
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
71
ShortPlay/Class/Home/View/SPSearchResultView.swift
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// SPSearchResultView.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPSearchResultView: UIView {
|
||||||
|
|
||||||
|
|
||||||
|
private lazy var tableView: SPTableView = {
|
||||||
|
let tableView = SPTableView(frame: .zero, style: .plain)
|
||||||
|
tableView.delegate = self
|
||||||
|
tableView.dataSource = self
|
||||||
|
SPSearchResultCell.registerCell(tableView: tableView)
|
||||||
|
return tableView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
// _setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPSearchResultView {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
addSubview(tableView)
|
||||||
|
|
||||||
|
tableView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- UITableViewDelegate & UITableViewDataSource --------------
|
||||||
|
extension SPSearchResultView: UITableViewDelegate, UITableViewDataSource {
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return 10
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let cell = SPSearchResultCell.dequeueReusableCell(tableView: tableView, indexPath: indexPath)
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPSearchResultView {
|
||||||
|
|
||||||
|
private func requestSearch(text: String) {
|
||||||
|
|
||||||
|
// SPHomeAPI.requestSearch(text: text)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
14
ShortPlay/Class/Home/ViewModel/SPSearchViewModel.swift
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// SPSearchViewModel.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPSearchViewModel: NSObject {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -33,6 +33,8 @@ class SPMineViewController: SPViewController {
|
|||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
requestUserInfo()
|
||||||
|
|
||||||
_setupUI()
|
_setupUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +92,12 @@ extension SPMineViewController: UITableViewDelegate, UITableViewDataSource {
|
|||||||
|
|
||||||
extension SPMineViewController {
|
extension SPMineViewController {
|
||||||
|
|
||||||
// func
|
private func requestUserInfo() {
|
||||||
|
|
||||||
|
SPUserAPI.requestUserInfo { userInfo in
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
//
|
||||||
|
// SPCollectListViewController.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPCollectListViewController: SPViewController {
|
||||||
|
|
||||||
|
|
||||||
|
private lazy var dataArr: [SPShortModel] = []
|
||||||
|
private var page: Int?
|
||||||
|
|
||||||
|
//MARK: UI属性
|
||||||
|
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||||
|
let itemWidth = floor((kSPScreenWidth - 30 - 9 * 2) / 3)
|
||||||
|
let itemHeight = 146 / 109 * itemWidth + 36
|
||||||
|
|
||||||
|
let layout = UICollectionViewFlowLayout()
|
||||||
|
layout.itemSize = .init(width: itemWidth, height: itemHeight)
|
||||||
|
layout.minimumLineSpacing = 10
|
||||||
|
layout.minimumInteritemSpacing = 9
|
||||||
|
layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15)
|
||||||
|
|
||||||
|
return layout
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionView: SPCollectionView = {
|
||||||
|
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
|
collectionView.delegate = self
|
||||||
|
collectionView.dataSource = self
|
||||||
|
collectionView.contentInset = .init(top: 10, left: 0, bottom: 0, right: 0)
|
||||||
|
collectionView.sp_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
||||||
|
self?.handleHeaderRefresh(nil)
|
||||||
|
}
|
||||||
|
collectionView.sp_addRefreshFooter { [weak self] in
|
||||||
|
self?.handleFooterRefresh(nil)
|
||||||
|
}
|
||||||
|
SPCollectListCell.registerCell(collectionView: collectionView)
|
||||||
|
return collectionView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
|
||||||
|
requestDataList(page: 1, completer: nil)
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setBgImageView() { }
|
||||||
|
|
||||||
|
|
||||||
|
override func handleHeaderRefresh() {
|
||||||
|
requestDataList(page: 1) { [weak self] in
|
||||||
|
self?.collectionView.sp_endHeaderRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPCollectListViewController {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
|
collectionView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource --------------
|
||||||
|
extension SPCollectListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
let cell = SPCollectListCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
|
||||||
|
cell.model = dataArr[indexPath.row]
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return self.dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPCollectListViewController {
|
||||||
|
|
||||||
|
private func requestDataList(page: Int, completer: (() -> Void)?) {
|
||||||
|
|
||||||
|
SPVideoAPI.requestCollectList(page: page) { [weak self] listModel in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
if let listModel = listModel, let list = listModel.list {
|
||||||
|
if page == 1 {
|
||||||
|
self.dataArr.removeAll()
|
||||||
|
}
|
||||||
|
self.dataArr += list
|
||||||
|
|
||||||
|
self.page = page
|
||||||
|
|
||||||
|
self.collectionView.reloadData()
|
||||||
|
|
||||||
|
}
|
||||||
|
completer?()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// SPMyListViewController.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPMyListViewController: SPViewController {
|
||||||
|
|
||||||
|
|
||||||
|
private lazy var titles = ["Follow List".localized, "Play List".localized]
|
||||||
|
|
||||||
|
private lazy var viewControllers: [SPViewController] = {
|
||||||
|
let vc1 = SPCollectListViewController()
|
||||||
|
let vc2 = SPPlayHistoryViewController()
|
||||||
|
return [vc1, vc2]
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var pageView: JYPageController = {
|
||||||
|
let pageView = JYPageController()
|
||||||
|
pageView.delegate = self
|
||||||
|
pageView.dataSource = self
|
||||||
|
pageView.config.indicatorWidth = 20
|
||||||
|
pageView.config.indicatorHeight = 4
|
||||||
|
pageView.config.indicatorCornerRadius = 2
|
||||||
|
pageView.config.indicatorColor = .colorFFFFFF(alpha: 0.9)
|
||||||
|
pageView.config.selectedTitleColor = .colorFFFFFF(alpha: 0.9)
|
||||||
|
pageView.config.selectedTitleFont = 16
|
||||||
|
pageView.config.selectedTitleFontWeight = .medium
|
||||||
|
pageView.config.normalTitleColor = .color888888()
|
||||||
|
pageView.config.normalTitleFont = 15
|
||||||
|
pageView.config.normalTitleFontWeight = .regular
|
||||||
|
pageView.config.leftPadding = 15
|
||||||
|
pageView.config.itemsMargin = 40
|
||||||
|
return pageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPMyListViewController {
|
||||||
|
private func _setupUI() {
|
||||||
|
addChild(pageView)
|
||||||
|
view.addSubview(pageView.view)
|
||||||
|
|
||||||
|
pageView.view.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//MARK: -------------- JYPageControllerDelegate & JYPageControllerDataSource --------------
|
||||||
|
extension SPMyListViewController: JYPageControllerDelegate, JYPageControllerDataSource {
|
||||||
|
func pageController(_ pageController: JYPageController, frameForSegmentedView segmentedView: JYSegmentedView) -> CGRect {
|
||||||
|
return .init(x: 0, y: kSPStatusbarHeight + 10, width: kSPScreenWidth, height: 35)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pageController(_ pageController: JYPageController, frameForContainerView container: UIScrollView) -> CGRect {
|
||||||
|
let y = kSPStatusbarHeight + 10 + 35
|
||||||
|
return .init(x: 0, y: kSPStatusbarHeight + 10 + 35, width: kSPScreenWidth, height: kSPScreenHeight - y - kSPTabBarHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pageController(_ pageController: JYPageController, titleAt index: Int) -> String {
|
||||||
|
return titles[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberOfChildControllers() -> Int {
|
||||||
|
return titles.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func childController(atIndex index: Int) -> any JYPageChildContollerProtocol {
|
||||||
|
return self.viewControllers[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
//
|
||||||
|
// SPPlayHistoryViewController.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPPlayHistoryViewController: SPViewController {
|
||||||
|
|
||||||
|
private lazy var dataArr: [SPShortModel] = []
|
||||||
|
private var page: Int?
|
||||||
|
|
||||||
|
//MARK: UI属性
|
||||||
|
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||||
|
let itemWidth = floor((kSPScreenWidth - 30 - 9 * 2) / 3)
|
||||||
|
let itemHeight = 146 / 109 * itemWidth + 36
|
||||||
|
|
||||||
|
let layout = UICollectionViewFlowLayout()
|
||||||
|
layout.itemSize = .init(width: itemWidth, height: itemHeight)
|
||||||
|
layout.minimumLineSpacing = 10
|
||||||
|
layout.minimumInteritemSpacing = 9
|
||||||
|
layout.sectionInset = .init(top: 10, left: 15, bottom: 0, right: 15)
|
||||||
|
|
||||||
|
return layout
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionView: SPCollectionView = {
|
||||||
|
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
|
collectionView.delegate = self
|
||||||
|
collectionView.dataSource = self
|
||||||
|
SPCollectListCell.registerCell(collectionView: collectionView)
|
||||||
|
return collectionView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
|
||||||
|
requestDataList(page: 1, completer: nil)
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setBgImageView() { }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPPlayHistoryViewController {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
|
collectionView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource --------------
|
||||||
|
extension SPPlayHistoryViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
let cell = SPCollectListCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
|
||||||
|
cell.model = dataArr[indexPath.row]
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return self.dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPPlayHistoryViewController {
|
||||||
|
|
||||||
|
private func requestDataList(page: Int, completer: (() -> Void)?) {
|
||||||
|
|
||||||
|
SPVideoAPI.requestCollectList(page: page) { [weak self] listModel in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
if let listModel = listModel, let list = listModel.list {
|
||||||
|
if page == 1 {
|
||||||
|
self.dataArr.removeAll()
|
||||||
|
}
|
||||||
|
self.dataArr += list
|
||||||
|
|
||||||
|
self.page = page
|
||||||
|
|
||||||
|
self.collectionView.reloadData()
|
||||||
|
|
||||||
|
}
|
||||||
|
completer?()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
66
ShortPlay/Class/MyList/View/SPCollectListCell.swift
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// SPCollectListCell.swift
|
||||||
|
// ShortPlay
|
||||||
|
//
|
||||||
|
// Created by 曾觉新 on 2025/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPCollectListCell: SPCollectionViewCell {
|
||||||
|
|
||||||
|
var model: SPShortModel? {
|
||||||
|
didSet {
|
||||||
|
coverImageView.sp_setImage(url: model?.image_url)
|
||||||
|
titleLabel.text = model?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var coverImageView: SPImageView = {
|
||||||
|
let imageView = SPImageView()
|
||||||
|
imageView.layer.cornerRadius = 7
|
||||||
|
imageView.layer.masksToBounds = true
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontRegular(ofSize: 13)
|
||||||
|
label.textColor = .colorFFFFFF(alpha: 0.9)
|
||||||
|
label.numberOfLines = 2
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPCollectListCell {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
contentView.addSubview(coverImageView)
|
||||||
|
contentView.addSubview(titleLabel)
|
||||||
|
|
||||||
|
coverImageView.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview().offset(-36)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.top.equalTo(coverImageView.snp.bottom).offset(5)
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -28,6 +28,9 @@ class SPShortModel: SPModel, SmartCodable {
|
|||||||
var video_info: SPVideoInfoModel?
|
var video_info: SPVideoInfoModel?
|
||||||
var watch_total: Int?
|
var watch_total: Int?
|
||||||
|
|
||||||
|
@IgnoredKey
|
||||||
|
var titleAttributedString: NSAttributedString?
|
||||||
|
|
||||||
|
|
||||||
static func mappingForKey() -> [SmartKeyTransformer]? {
|
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||||
return [
|
return [
|
||||||
|
@ -11,6 +11,29 @@ import SmartCodable
|
|||||||
class SPUserInfo: SPModel, SmartCodable, NSSecureCoding {
|
class SPUserInfo: SPModel, SmartCodable, NSSecureCoding {
|
||||||
|
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
var customer_id: String?
|
||||||
|
var is_guide_vip: String?
|
||||||
|
var is_tourist: String?
|
||||||
|
var family_name: String?
|
||||||
|
var giving_name: String?
|
||||||
|
var vip_end_time: String?
|
||||||
|
var third_access_id: String?
|
||||||
|
var is_vip: Bool?
|
||||||
|
var coin_left_total: Int?
|
||||||
|
var vip_type: String?
|
||||||
|
var email: String?
|
||||||
|
var third_access_platform: String?
|
||||||
|
var ip_address: String?
|
||||||
|
var country_code: String?
|
||||||
|
var user_level: String?
|
||||||
|
var send_coin_left_total: String?
|
||||||
|
var avator: String?
|
||||||
|
var sign_in_status: String?
|
||||||
|
var registered_days: String?
|
||||||
|
var ln: String?
|
||||||
|
var country: String?
|
||||||
|
|
||||||
|
|
||||||
required init() { }
|
required init() { }
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "Frame@2x.png",
|
"filename" : "My list@2x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "Frame@3x.png",
|
"filename" : "My list@3x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 984 B |
Before Width: | Height: | Size: 2.0 KiB |
BIN
ShortPlay/Source/Assets.xcassets/TabBar/tabbar_icon_04.imageset/My list@2x.png
vendored
Normal file
After Width: | Height: | Size: 872 B |
BIN
ShortPlay/Source/Assets.xcassets/TabBar/tabbar_icon_04.imageset/My list@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
@ -5,10 +5,12 @@
|
|||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "My list@2x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "My list@3x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
|
BIN
ShortPlay/Source/Assets.xcassets/TabBar/tabbar_icon_04_selected.imageset/My list@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
ShortPlay/Source/Assets.xcassets/TabBar/tabbar_icon_04_selected.imageset/My list@3x.png
vendored
Normal file
After Width: | Height: | Size: 3.2 KiB |
22
ShortPlay/Source/Assets.xcassets/icon/play_icon_03.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "play@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "play@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
ShortPlay/Source/Assets.xcassets/icon/play_icon_03.imageset/play@2x.png
vendored
Normal file
After Width: | Height: | Size: 895 B |
BIN
ShortPlay/Source/Assets.xcassets/icon/play_icon_03.imageset/play@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
@ -12,3 +12,4 @@
|
|||||||
#import "NSUserDefaults+JXAdd.h"
|
#import "NSUserDefaults+JXAdd.h"
|
||||||
#import <KTVHTTPCache.h>
|
#import <KTVHTTPCache.h>
|
||||||
#import <HWPanModal/HWPanModal.h>
|
#import <HWPanModal/HWPanModal.h>
|
||||||
|
#import <MJRefresh/MJRefresh.h>
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
"User Agreement" = "User Agreement";
|
"User Agreement" = "User Agreement";
|
||||||
"Help Center" = "Help Center";
|
"Help Center" = "Help Center";
|
||||||
"About Us" = "About Us";
|
"About Us" = "About Us";
|
||||||
|
"My list" = "My list";
|
||||||
|
"Follow List" = "Follow List";
|
||||||
|
"Play List" = "Play List";
|
||||||
|
|
||||||
///视频详情标题
|
///视频详情标题
|
||||||
"kPlayerDetailTitleString" = "Episode %@ / %@";
|
"kPlayerDetailTitleString" = "Episode %@ / %@";
|
||||||
|