我的播放列表完成
@ -112,6 +112,13 @@
|
||||
BF0FA78F2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA78E2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift */; };
|
||||
BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7902DE16CBF00C9E5F2 /* VPSearchHistoryView.swift */; };
|
||||
BF0FA7942DE16E9300C9E5F2 /* JXTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7922DE16E9300C9E5F2 /* JXTagView.swift */; };
|
||||
BF0FA7992DE1951A00C9E5F2 /* VPMyListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7982DE1951A00C9E5F2 /* VPMyListViewController.swift */; };
|
||||
BF0FA79B2DE1984B00C9E5F2 /* VPCollectListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA79A2DE1984B00C9E5F2 /* VPCollectListViewController.swift */; };
|
||||
BF0FA79D2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA79C2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift */; };
|
||||
BF0FA79F2DE1A29A00C9E5F2 /* VPCollectListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA79E2DE1A29A00C9E5F2 /* VPCollectListCell.swift */; };
|
||||
BF0FA7A12DE1AA5100C9E5F2 /* VPTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7A02DE1AA5100C9E5F2 /* VPTableView.swift */; };
|
||||
BF0FA7A32DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7A22DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift */; };
|
||||
BF0FA7A52DE4384100C9E5F2 /* AttributedString+VPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7A42DE4384100C9E5F2 /* AttributedString+VPAdd.swift */; };
|
||||
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -230,6 +237,13 @@
|
||||
BF0FA78E2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPUserDefaultsKey.swift; sourceTree = "<group>"; };
|
||||
BF0FA7902DE16CBF00C9E5F2 /* VPSearchHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchHistoryView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7922DE16E9300C9E5F2 /* JXTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXTagView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7982DE1951A00C9E5F2 /* VPMyListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMyListViewController.swift; sourceTree = "<group>"; };
|
||||
BF0FA79A2DE1984B00C9E5F2 /* VPCollectListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCollectListViewController.swift; sourceTree = "<group>"; };
|
||||
BF0FA79C2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWatchHistoryViewController.swift; sourceTree = "<group>"; };
|
||||
BF0FA79E2DE1A29A00C9E5F2 /* VPCollectListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCollectListCell.swift; sourceTree = "<group>"; };
|
||||
BF0FA7A02DE1AA5100C9E5F2 /* VPTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPTableView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7A22DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWatchHistoryCell.swift; sourceTree = "<group>"; };
|
||||
BF0FA7A42DE4384100C9E5F2 /* AttributedString+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+VPAdd.swift"; sourceTree = "<group>"; };
|
||||
E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -357,6 +371,7 @@
|
||||
BF0FA76C2DE053C100C9E5F2 /* VPScrollView.swift */,
|
||||
BF0FA7822DE1533E00C9E5F2 /* VPGradientLabel.swift */,
|
||||
BF0FA7862DE1601200C9E5F2 /* VPTextField.swift */,
|
||||
BF0FA7A02DE1AA5100C9E5F2 /* VPTableView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -413,6 +428,7 @@
|
||||
BF0FA72F2DDEBB1600C9E5F2 /* UIButton+VPAdd.swift */,
|
||||
BF0FA7402DDEFBC700C9E5F2 /* UIScrollView+VPRefresh.swift */,
|
||||
BF0FA77A2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift */,
|
||||
BF0FA7A42DE4384100C9E5F2 /* AttributedString+VPAdd.swift */,
|
||||
);
|
||||
path = Extension;
|
||||
sourceTree = "<group>";
|
||||
@ -714,8 +730,8 @@
|
||||
BF0FA7952DE1948A00C9E5F2 /* MyList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA7972DE1949B00C9E5F2 /* View */,
|
||||
BF0FA7962DE1949300C9E5F2 /* Controller */,
|
||||
BF0FA7972DE1949B00C9E5F2 /* View */,
|
||||
);
|
||||
path = MyList;
|
||||
sourceTree = "<group>";
|
||||
@ -723,6 +739,9 @@
|
||||
BF0FA7962DE1949300C9E5F2 /* Controller */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA7982DE1951A00C9E5F2 /* VPMyListViewController.swift */,
|
||||
BF0FA79A2DE1984B00C9E5F2 /* VPCollectListViewController.swift */,
|
||||
BF0FA79C2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift */,
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
@ -730,6 +749,8 @@
|
||||
BF0FA7972DE1949B00C9E5F2 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA79E2DE1A29A00C9E5F2 /* VPCollectListCell.swift */,
|
||||
BF0FA7A22DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -879,6 +900,8 @@
|
||||
BF0FA7792DE075FF00C9E5F2 /* VPSearchHomeView.swift in Sources */,
|
||||
BF0FA7302DDEBB1600C9E5F2 /* UIButton+VPAdd.swift in Sources */,
|
||||
BF0FA74C2DDF060200C9E5F2 /* VPVideoPlayerViewController.swift in Sources */,
|
||||
BF0FA79B2DE1984B00C9E5F2 /* VPCollectListViewController.swift in Sources */,
|
||||
BF0FA7A32DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift in Sources */,
|
||||
BF0FA76D2DE053C100C9E5F2 /* VPScrollView.swift in Sources */,
|
||||
1B056E5D2DDACD8E007EE38D /* UIFont+VPAdd.swift in Sources */,
|
||||
BF0FA7282DDC91F800C9E5F2 /* VPCollectionViewCell.swift in Sources */,
|
||||
@ -887,6 +910,7 @@
|
||||
BF0FA6F42DDC604500C9E5F2 /* VPHUD.swift in Sources */,
|
||||
BF0FA7222DDC859D00C9E5F2 /* NSNumber+VPAdd.swift in Sources */,
|
||||
BF0FA73B2DDED1C700C9E5F2 /* VPHomeListCell.swift in Sources */,
|
||||
BF0FA79F2DE1A29A00C9E5F2 /* VPCollectListCell.swift in Sources */,
|
||||
BF0FA7592DDF1C2800C9E5F2 /* VPPlayerProgressView.swift in Sources */,
|
||||
BF0FA71B2DDC7FF200C9E5F2 /* VPImageView.swift in Sources */,
|
||||
BF0FA7522DDF134700C9E5F2 /* VPVideoPlayerControlView.swift in Sources */,
|
||||
@ -910,6 +934,7 @@
|
||||
BF0FA74A2DDF04E200C9E5F2 /* VPPlayerProtocol.swift in Sources */,
|
||||
BF0FA72C2DDD7B7300C9E5F2 /* VPHomeRankingContentCell.swift in Sources */,
|
||||
BF0FA7942DE16E9300C9E5F2 /* JXTagView.swift in Sources */,
|
||||
BF0FA7A52DE4384100C9E5F2 /* AttributedString+VPAdd.swift in Sources */,
|
||||
BF0FA7652DE00A0E00C9E5F2 /* VPDetailPlayerControlView.swift in Sources */,
|
||||
BF0FA7342DDEC74500C9E5F2 /* VPCategoryModel.swift in Sources */,
|
||||
1B056E4F2DDAC7FC007EE38D /* VPNavigationController.swift in Sources */,
|
||||
@ -917,11 +942,13 @@
|
||||
BF0FA7202DDC83AE00C9E5F2 /* JXButton.swift in Sources */,
|
||||
BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */,
|
||||
BF0FA7072DDC687C00C9E5F2 /* VPHomeDataItem.swift in Sources */,
|
||||
BF0FA7992DE1951A00C9E5F2 /* VPMyListViewController.swift in Sources */,
|
||||
BF0FA7452DDF027900C9E5F2 /* VPPlayer.swift in Sources */,
|
||||
BF0FA70E2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift in Sources */,
|
||||
BF0FA6D72DDC5BE100C9E5F2 /* VPURLPath.swift in Sources */,
|
||||
1B056E5B2DDACD80007EE38D /* UIColor+VPAdd.swift in Sources */,
|
||||
BF0FA76B2DE0533400C9E5F2 /* VPEpisodeMenuView.swift in Sources */,
|
||||
BF0FA79D2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift in Sources */,
|
||||
1B056E6A2DDAD0BF007EE38D /* VPLocalizedManager.swift in Sources */,
|
||||
BF0FA7242DDC888F00C9E5F2 /* VPHomeRecommandContentCell.swift in Sources */,
|
||||
BF0FA78F2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift in Sources */,
|
||||
@ -936,6 +963,7 @@
|
||||
1B056E722DDB022F007EE38D /* VPTabBarItem.swift in Sources */,
|
||||
1B056E412DDAC30A007EE38D /* VPModel.swift in Sources */,
|
||||
BF0FA70A2DDC69C800C9E5F2 /* VPTableViewCell.swift in Sources */,
|
||||
BF0FA7A12DE1AA5100C9E5F2 /* VPTableView.swift in Sources */,
|
||||
1B056E442DDAC355007EE38D /* UIDevice+VPAdd.swift in Sources */,
|
||||
BF0FA7632DE006E700C9E5F2 /* VPDetailPlayerCell.swift in Sources */,
|
||||
BF0FA73F2DDEF26E00C9E5F2 /* VPHomeSearchButton.swift in Sources */,
|
||||
|
@ -88,8 +88,8 @@ extension VPTabBarController {
|
||||
|
||||
let nav1 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_01"), selectedImage: UIImage(named: "tabbar_icon_01_selected"))
|
||||
let nav2 = createNavigationController(viewController: VPExploreViewController(), title: "Explore".localized, image: UIImage(named: "tabbar_icon_02"), selectedImage: UIImage(named: "tabbar_icon_02_selected"))
|
||||
let nav3 = createNavigationController(viewController: VPHomePageViewController(), title: "My List".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
|
||||
let nav4 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
|
||||
let nav3 = createNavigationController(viewController: VPMyListViewController(), title: "My List".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
|
||||
let nav4 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
|
||||
|
||||
viewControllers = [nav1, nav2, nav3, nav4]
|
||||
|
||||
|
18
Veloria/Base/Extension/AttributedString+VPAdd.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// AttributedString+VPAdd.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/26.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension AttributedString {
|
||||
|
||||
static func createAttributedString(string: String, color: UIColor, font: UIFont) -> AttributedString {
|
||||
return AttributedString(string, attributes: AttributeContainer([
|
||||
.foregroundColor: color,
|
||||
.font : font
|
||||
]))
|
||||
}
|
||||
}
|
@ -62,7 +62,7 @@ class VPVideoAPI: NSObject {
|
||||
}
|
||||
|
||||
///收藏短剧
|
||||
static func requestCollectShort(isCollect: Bool, shortPlayId: String, videoId: String?, success: (() -> Void)?, failure: (() -> Void)? = nil) {
|
||||
static func requestCollectShort(isCollect: Bool, shortPlayId: String, videoId: String?, isLoding: Bool = true, success: (() -> Void)?, failure: (() -> Void)? = nil) {
|
||||
let path: String
|
||||
if isCollect {
|
||||
path = "/collect"
|
||||
@ -79,7 +79,7 @@ class VPVideoAPI: NSObject {
|
||||
}
|
||||
|
||||
var param = VPNetworkParameters(path: path)
|
||||
param.isLoding = true
|
||||
param.isLoding = isLoding
|
||||
param.parameters = parameters
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<String>) in
|
||||
@ -94,6 +94,51 @@ class VPVideoAPI: NSObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///收藏列表
|
||||
static func requestCollectList(page: Int, completer: ((_ listModel: VPListModel<VPShortModel>?) -> Void)?) {
|
||||
var param = VPNetworkParameters(path: "/myCollections")
|
||||
param.method = .get
|
||||
param.parameters = [
|
||||
"current_page" : page,
|
||||
"page_size" : 20
|
||||
]
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPListModel<VPShortModel>>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
///创建播放记录
|
||||
static func requestCreatePlayHistory(videoId: String?, shortPlayId: String?) {
|
||||
guard let shortPlayId = shortPlayId else { return }
|
||||
|
||||
var param = VPNetworkParameters(path: "/createHistory")
|
||||
param.isLoding = false
|
||||
param.isToast = false
|
||||
param.parameters = [
|
||||
"video_id" : videoId ?? "0",
|
||||
"short_play_id" : shortPlayId
|
||||
]
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<String>) in
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///历史记录列表
|
||||
static func requestPlayHistoryList(page: Int, pageSize: Int = 20, completer: ((_ listModel: VPListModel<VPShortModel>?) -> Void)?) {
|
||||
var param = VPNetworkParameters(path: "/myHistorys")
|
||||
param.method = .get
|
||||
param.parameters = [
|
||||
"current_page" : page,
|
||||
"page_size" : pageSize
|
||||
]
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPListModel<VPShortModel>>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension VPVideoAPI {
|
||||
|
52
Veloria/Base/View/VPTableView.swift
Normal file
@ -0,0 +1,52 @@
|
||||
//
|
||||
// VPTableView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPTableView: UITableView {
|
||||
|
||||
var insetGroupedMargins: CGFloat = 15
|
||||
|
||||
override init(frame: CGRect, style: UITableView.Style) {
|
||||
super.init(frame: frame, style: style)
|
||||
separatorColor = .colorFFFFFF(alpha: 0.1)
|
||||
separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
self.backgroundColor = .clear
|
||||
self.contentInsetAdjustmentBehavior = .never
|
||||
|
||||
if style == .insetGrouped {
|
||||
sectionFooterHeight = 12
|
||||
sectionHeaderHeight = 0.1
|
||||
} else if style == .plain {
|
||||
if #available(iOS 15.0, *) {
|
||||
sectionHeaderTopPadding = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
///修改 insetGrouped 的边距 参考https://github.com/QMUI/QMUIDemo_iOS/blob/master/QMUI/QMUIKit/UIKitExtensions/UITableView%2BQMUI.m
|
||||
override var layoutMargins: UIEdgeInsets {
|
||||
set {
|
||||
super.layoutMargins = newValue
|
||||
}
|
||||
get {
|
||||
var margins = super.layoutMargins
|
||||
if #available(iOS 13.0, *) {
|
||||
if self.style == .insetGrouped {
|
||||
margins.left = self.safeAreaInsets.left + insetGroupedMargins
|
||||
margins.right = self.safeAreaInsets.right + insetGroupedMargins
|
||||
}
|
||||
}
|
||||
return margins
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,261 @@
|
||||
//
|
||||
// VPCollectListViewController.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPCollectListViewController: VPViewController {
|
||||
|
||||
|
||||
var editState: VPMyListViewController.EditState = .normal {
|
||||
didSet {
|
||||
allSelectedButton.isHidden = editState == .normal
|
||||
if editState == .normal {
|
||||
collectionView.snp.updateConstraints { make in
|
||||
make.top.equalToSuperview().offset(0)
|
||||
}
|
||||
isAllSelected = false
|
||||
allSelectedButton.isSelected = false
|
||||
} else {
|
||||
collectionView.snp.updateConstraints { make in
|
||||
make.top.equalToSuperview().offset(30)
|
||||
}
|
||||
}
|
||||
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
///当前是否全选
|
||||
var isAllSelected: Bool {
|
||||
set {
|
||||
dataArr.forEach {
|
||||
$0.vp_isSelected = newValue
|
||||
}
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
get {
|
||||
if dataArr.count == 0 {
|
||||
return false
|
||||
}
|
||||
var isAllSelected = true
|
||||
for value in dataArr {
|
||||
if value.vp_isSelected != true {
|
||||
isAllSelected = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return isAllSelected
|
||||
}
|
||||
}
|
||||
|
||||
///全选状态发生变化
|
||||
var didChangeAllSelected: (() -> Void)?
|
||||
|
||||
private lazy var deleteGroup = DispatchGroup()
|
||||
|
||||
private lazy var dataArr: [VPShortModel] = []
|
||||
private var page: Int = 1
|
||||
|
||||
|
||||
|
||||
private lazy var allSelectedButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.attributedTitle = AttributedString.createAttributedString(string: "Select All".localized, color: .colorFFFFFF(), font: .fontRegular(ofSize: 15))
|
||||
config.imagePadding = 6
|
||||
config.imagePlacement = .leading
|
||||
config.baseBackgroundColor = .clear
|
||||
config.contentInsets = .init(top: 5, leading: 0, bottom: 5, trailing: 0)
|
||||
|
||||
let button = UIButton(configuration: config)
|
||||
button.isHidden = true
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
if button.isSelected {
|
||||
button.configuration?.image = UIImage(named: "choice_icon_01_selected")
|
||||
} else {
|
||||
button.configuration?.image = UIImage(named: "choice_icon_01")
|
||||
}
|
||||
}
|
||||
button.addTarget(self, action: #selector(handleAllSelectedButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let width = floor((UIScreen.width - 30 - 14) / 3)
|
||||
let height = 148 / 110 * width + 31
|
||||
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: width, height: height)
|
||||
layout.minimumLineSpacing = 16
|
||||
layout.minimumInteritemSpacing = 7
|
||||
layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15)
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: VPCollectionView = {
|
||||
let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.contentInset = .init(top: 5, left: 0, bottom: 0, right: 0)
|
||||
collectionView.vp_addRefreshHeader(insetTop: collectionView.top) { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
collectionView.vp_addRefreshBackFooter { [weak self] in
|
||||
self?.handleFooterRefresh(nil)
|
||||
}
|
||||
|
||||
collectionView.register(VPCollectListCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.bgImageView.isHidden = true
|
||||
self.view.backgroundColor = .clear
|
||||
|
||||
vp_setupUI()
|
||||
|
||||
requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: 1) { [weak self] in
|
||||
self?.collectionView.vp_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: self.page + 1) { [weak self] in
|
||||
self?.collectionView.vp_endFooterRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
func handleDelete() {
|
||||
var count = 0
|
||||
for value in dataArr {
|
||||
if value.vp_isSelected == true {
|
||||
count += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if count > 0 {
|
||||
requestCancelCollect()
|
||||
} else {
|
||||
VPToast.show(text: "kToastText1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension VPCollectListViewController {
|
||||
|
||||
@objc private func handleAllSelectedButton() {
|
||||
// let isSelected = !isAllSelected
|
||||
isAllSelected = !isAllSelected
|
||||
self.allSelectedButton.isSelected = isAllSelected
|
||||
}
|
||||
|
||||
///更新全选按钮状态
|
||||
@objc private func updateAllSelectedButtonState() {
|
||||
self.allSelectedButton.isSelected = isAllSelected
|
||||
self.didChangeAllSelected?()
|
||||
}
|
||||
}
|
||||
|
||||
extension VPCollectListViewController {
|
||||
|
||||
private func vp_setupUI() {
|
||||
view.addSubview(collectionView)
|
||||
view.addSubview(allSelectedButton)
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(0)
|
||||
}
|
||||
|
||||
allSelectedButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource --------------
|
||||
extension VPCollectListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPCollectListCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
cell.editState = self.editState
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = dataArr[indexPath.row]
|
||||
if editState == .normal {
|
||||
let vc = VPDetailPlayerViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
} else {
|
||||
model.vp_isSelected = !(model.vp_isSelected ?? false)
|
||||
|
||||
collectionView.reloadData()
|
||||
self.updateAllSelectedButtonState()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPCollectListViewController {
|
||||
|
||||
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||
|
||||
VPVideoAPI.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()
|
||||
if self.editState == .editing {
|
||||
self.updateAllSelectedButtonState()
|
||||
}
|
||||
}
|
||||
completer?()
|
||||
}
|
||||
}
|
||||
|
||||
private func requestCancelCollect() {
|
||||
VPHUD.show()
|
||||
self.dataArr.forEach {
|
||||
if $0.vp_isSelected == true, let shortPlayId = $0.short_play_id {
|
||||
self.deleteGroup.enter()
|
||||
VPVideoAPI.requestCollectShort(isCollect: false, shortPlayId: shortPlayId, videoId: $0.short_play_video_id, isLoding: false) { [weak self] in
|
||||
self?.deleteGroup.leave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.deleteGroup.notify(queue: .main) { [weak self] in
|
||||
VPHUD.dismiss()
|
||||
guard let self = self else { return }
|
||||
self.requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
171
Veloria/Class/MyList/Controller/VPMyListViewController.swift
Normal file
@ -0,0 +1,171 @@
|
||||
//
|
||||
// VPMyListViewController.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPMyListViewController: VPViewController {
|
||||
|
||||
enum EditState {
|
||||
case normal
|
||||
case editing
|
||||
}
|
||||
|
||||
///0普通状态 1编辑状态
|
||||
private var editState: EditState = .normal {
|
||||
didSet {
|
||||
if editState == .normal {
|
||||
pageView.upSc.mainView.isHidden = false
|
||||
pageView.upSc.dataView.isScrollEnabled = true
|
||||
} else {
|
||||
pageView.upSc.mainView.isHidden = true
|
||||
pageView.upSc.dataView.isScrollEnabled = false
|
||||
}
|
||||
cancelEditButton.isHidden = editState == .normal
|
||||
collectVC.editState = editState
|
||||
editorButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var collectVC = VPCollectListViewController()
|
||||
|
||||
private lazy var viewControllers: [UIViewController] = {
|
||||
let vc2 = VPWatchHistoryViewController()
|
||||
return [collectVC, vc2]
|
||||
}()
|
||||
|
||||
|
||||
private lazy var pageParam: WMZPageParam = {
|
||||
let param = WMZPageParam()
|
||||
param.wTitleArr = ["My List".localized, "History".localized]
|
||||
param.wViewController = { [weak self] index in
|
||||
return self?.viewControllers[index]
|
||||
}
|
||||
param.wMenuTitleColor = .colorFFFFFF(alpha: 0.3)
|
||||
param.wMenuTitleSelectColor = .colorFFFFFF()
|
||||
param.wMenuTitleUIFont = .fontMedium(ofSize: 15)
|
||||
param.wMenuTitleSelectUIFont = .fontMedium(ofSize: 15)
|
||||
param.wMenuHeight = 50
|
||||
param.wMenuBgColor = .clear
|
||||
param.wBgColor = .clear
|
||||
param.wMenuTitleOffset = 25
|
||||
param.wMenuCellMargin = 0
|
||||
param.wMenuInsets = .init(top: 0, left: 15, bottom: 0, right: 15)
|
||||
|
||||
param.wCustomNaviBarY = { _ in
|
||||
return 0
|
||||
}
|
||||
param.wCustomTabbarY = { _ in
|
||||
return 0
|
||||
}
|
||||
param.wCustomDataViewTopOffset = 0
|
||||
param.wEventEndTransferController = { [weak self] (oldVC, newVC, oldIndex, newIndex) in
|
||||
guard let self = self else { return }
|
||||
if newIndex == 1 {
|
||||
self.editorButton.isHidden = true
|
||||
self.editState = .normal
|
||||
} else {
|
||||
self.editorButton.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return param
|
||||
}()
|
||||
|
||||
private lazy var pageView: WMZPageView = {
|
||||
let y = UIScreen.statusBarHeight + 10
|
||||
let height = UIScreen.height - y - UIScreen.customTabBarHeight
|
||||
|
||||
let pageView = WMZPageView(frame: .init(x: 0, y: y, width: UIScreen.width, height: height), param: pageParam, parentReponder: self)
|
||||
pageView.backgroundColor = .clear
|
||||
pageView.downSc?.backgroundColor = .clear
|
||||
return pageView
|
||||
}()
|
||||
|
||||
private lazy var editorButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.baseBackgroundColor = .colorFFFFFF(alpha: 0.05)
|
||||
|
||||
let button = UIButton(configuration: config)
|
||||
button.layer.cornerRadius = 6
|
||||
button.layer.masksToBounds = true
|
||||
button.layer.borderWidth = 0.7
|
||||
button.layer.borderColor = UIColor.colorFFFFFF(alpha: 0.1).cgColor
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
if self.editState == .normal {
|
||||
button.configuration?.image = UIImage(named: "editor_icon_01")
|
||||
} else {
|
||||
button.configuration?.image = UIImage(named: "delete_icon_02")
|
||||
}
|
||||
}
|
||||
button.addTarget(self, action: #selector(handleEditorButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var cancelEditButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.isHidden = true
|
||||
button.setImage(UIImage(named: "cancel_icon_01"), for: .normal)
|
||||
button.addTarget(self, action: #selector(handleCancelEditButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
self.editState = .normal
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPMyListViewController {
|
||||
@objc private func handleEditorButton() {
|
||||
if editState == .normal {
|
||||
editState = .editing
|
||||
} else {
|
||||
self.collectVC.handleDelete()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func handleCancelEditButton() {
|
||||
editState = .normal
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPMyListViewController {
|
||||
private func vp_setupUI() {
|
||||
view.addSubview(pageView)
|
||||
view.addSubview(editorButton)
|
||||
view.addSubview(cancelEditButton)
|
||||
|
||||
editorButton.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(UIScreen.statusBarHeight + 19)
|
||||
make.right.equalToSuperview().offset(-15)
|
||||
make.width.height.equalTo(32)
|
||||
}
|
||||
|
||||
cancelEditButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.centerY.equalTo(editorButton)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
//
|
||||
// VPWatchHistoryViewController.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPWatchHistoryViewController: VPViewController {
|
||||
|
||||
|
||||
private lazy var page = 1
|
||||
private lazy var dataArr: [VPShortModel] = []
|
||||
|
||||
private lazy var tableView: VPTableView = {
|
||||
let tableView = VPTableView(frame: .zero, style: .plain)
|
||||
tableView.showsVerticalScrollIndicator = false
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.separatorStyle = .none
|
||||
tableView.rowHeight = 118
|
||||
tableView.vp_addRefreshHeader { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
tableView.vp_addRefreshBackFooter { [weak self] in
|
||||
self?.handleFooterRefresh(nil)
|
||||
}
|
||||
tableView.register(VPWatchHistoryCell.self, forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.bgImageView.isHidden = true
|
||||
self.view.backgroundColor = .clear
|
||||
|
||||
vp_setupUI()
|
||||
|
||||
requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: 1) { [weak self] in
|
||||
self?.tableView.vp_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: self.page + 1) { [weak self] in
|
||||
self?.tableView.vp_endFooterRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPWatchHistoryViewController {
|
||||
|
||||
private func vp_setupUI() {
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- UITableViewDelegate UITableViewDataSource --------------
|
||||
extension VPWatchHistoryViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! VPWatchHistoryCell
|
||||
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 = dataArr[indexPath.row]
|
||||
let vc = VPDetailPlayerViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension VPWatchHistoryViewController {
|
||||
|
||||
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||
|
||||
VPVideoAPI.requestPlayHistoryList(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.tableView.reloadData()
|
||||
}
|
||||
completer?()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
85
Veloria/Class/MyList/View/VPCollectListCell.swift
Normal file
@ -0,0 +1,85 @@
|
||||
//
|
||||
// VPCollectListCell.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPCollectListCell: VPCollectionViewCell {
|
||||
|
||||
var editState: VPMyListViewController.EditState = .normal {
|
||||
didSet {
|
||||
selectedView.isHidden = editState == .normal
|
||||
}
|
||||
}
|
||||
|
||||
var model: VPShortModel? {
|
||||
didSet {
|
||||
coverImageView.vp_setImage(url: model?.image_url)
|
||||
videoNameLabel.text = model?.name
|
||||
selectedView.isSelected = model?.vp_isSelected ?? false
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var coverImageView: VPImageView = {
|
||||
let imageView = VPImageView()
|
||||
imageView.layer.cornerRadius = 10
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var videoNameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 12)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var selectedView: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.setImage(UIImage(named: "choice_icon_01"), for: .normal)
|
||||
button.setImage(UIImage(named: "choice_icon_01_selected"), for: .selected)
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
extension VPCollectListCell {
|
||||
|
||||
private func vp_setupUI() {
|
||||
contentView.addSubview(coverImageView)
|
||||
contentView.addSubview(videoNameLabel)
|
||||
coverImageView.addSubview(selectedView)
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-31)
|
||||
}
|
||||
|
||||
selectedView.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(5)
|
||||
make.right.equalToSuperview().offset(-5)
|
||||
}
|
||||
|
||||
videoNameLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.top.equalTo(coverImageView.snp.bottom).offset(4)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
186
Veloria/Class/MyList/View/VPWatchHistoryCell.swift
Normal file
@ -0,0 +1,186 @@
|
||||
//
|
||||
// VPWatchHistoryCell.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPWatchHistoryCell: VPTableViewCell {
|
||||
|
||||
var model: VPShortModel? {
|
||||
didSet {
|
||||
coverImageView.vp_setImage(url: model?.image_url)
|
||||
videoNameLabel.text = model?.name
|
||||
|
||||
timeView.setNeedsUpdateConfiguration()
|
||||
|
||||
let epString = NSMutableAttributedString()
|
||||
|
||||
let currentEP = NSMutableAttributedString(string: String(format: "EP.%@".localized, model?.current_episode ?? ""))
|
||||
currentEP.color = .color05CEA0()
|
||||
epString.append(currentEP)
|
||||
|
||||
let totalEp = NSMutableAttributedString()
|
||||
totalEp.appendString(" / ")
|
||||
totalEp.appendString(String(format: "EP.%@".localized, "\(model?.episode_total ?? 0)"))
|
||||
totalEp.color = .colorFFFFFF(alpha: 0.6)
|
||||
epString.append(totalEp)
|
||||
|
||||
epLabel.attributedText = epString
|
||||
|
||||
updateCollectButtonState()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var coverImageView: VPImageView = {
|
||||
let imageView = VPImageView()
|
||||
imageView.layer.cornerRadius = 8
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var videoNameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 14)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var epLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 12)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var collectButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "collect_icon_02"), for: .normal)
|
||||
button.setImage(UIImage(named: "collect_icon_02_selected"), for: .selected)
|
||||
button.setImage(UIImage(named: "collect_icon_02_selected"), for: [.selected, .highlighted])
|
||||
button.setBackgroundImage(UIImage(color: .colorFFFFFF(alpha: 0.1)), for: .normal)
|
||||
button.layer.cornerRadius = 6
|
||||
button.layer.masksToBounds = true
|
||||
button.addTarget(self, action: #selector(handleCollectButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var timeView: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.imagePlacement = .leading
|
||||
config.imagePadding = 4
|
||||
config.image = UIImage(named: "time_icon_01")
|
||||
config.contentInsets = .zero
|
||||
|
||||
let view = UIButton(configuration: config)
|
||||
view.isUserInteractionEnabled = false
|
||||
view.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
var config = button.configuration
|
||||
config?.attributedTitle = AttributedString.createAttributedString(string: self.model?.updated_at ?? "", color: .colorFFFFFF(alpha: 0.6), font: .fontRegular(ofSize: 10))
|
||||
button.configuration = config
|
||||
}
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(updateShortCollectStateNotification), name: VPVideoAPI.updateShortCollectStateNotification, object: nil)
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension VPWatchHistoryCell {
|
||||
|
||||
@objc private func handleCollectButton() {
|
||||
guard let shortPlayId = self.model?.short_play_id else { return }
|
||||
guard let videoId = self.model?.short_play_video_id else { return }
|
||||
|
||||
let isCollect = !(self.model?.is_collect ?? false)
|
||||
|
||||
VPVideoAPI.requestCollectShort(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
var count = self.model?.collect_total ?? 0
|
||||
if isCollect {
|
||||
count += 1
|
||||
} else {
|
||||
count -= 1
|
||||
}
|
||||
if count < 0 {
|
||||
count = 0
|
||||
}
|
||||
self.model?.collect_total = count
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func updateShortCollectStateNotification(sender: Notification) {
|
||||
guard let userInfo = sender.userInfo else { return }
|
||||
guard let shortPlayId = userInfo["id"] as? String else { return }
|
||||
guard let isCollect = userInfo["state"] as? Bool else { return }
|
||||
guard shortPlayId == self.model?.short_play_id else { return }
|
||||
|
||||
self.model?.is_collect = isCollect;
|
||||
updateCollectButtonState()
|
||||
|
||||
}
|
||||
|
||||
private func updateCollectButtonState() {
|
||||
self.collectButton.isSelected = self.model?.is_collect ?? false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPWatchHistoryCell {
|
||||
|
||||
private func vp_setupUI() {
|
||||
contentView.addSubview(coverImageView)
|
||||
contentView.addSubview(videoNameLabel)
|
||||
contentView.addSubview(epLabel)
|
||||
contentView.addSubview(collectButton)
|
||||
contentView.addSubview(timeView)
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.centerY.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(5)
|
||||
make.width.equalTo(84)
|
||||
}
|
||||
|
||||
videoNameLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(coverImageView.snp.right).offset(12)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-75)
|
||||
make.centerY.equalTo(coverImageView.snp.top).offset(21)
|
||||
}
|
||||
|
||||
epLabel.snp.makeConstraints { make in
|
||||
make.height.equalTo(26)
|
||||
make.top.equalTo(coverImageView).offset(47)
|
||||
make.left.equalTo(videoNameLabel)
|
||||
}
|
||||
|
||||
collectButton.snp.makeConstraints { make in
|
||||
make.width.height.equalTo(28)
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-15)
|
||||
}
|
||||
|
||||
timeView.snp.makeConstraints { make in
|
||||
make.left.equalTo(videoNameLabel)
|
||||
make.bottom.equalTo(coverImageView).offset(-4)
|
||||
}
|
||||
}
|
||||
}
|
@ -55,6 +55,14 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||
}
|
||||
|
||||
|
||||
override func play() {
|
||||
guard let videoInfo = self.viewModel.currentPlayer?.videoInfo else { return }
|
||||
super.play()
|
||||
|
||||
VPVideoAPI.requestCreatePlayHistory(videoId: videoInfo.short_play_video_id, shortPlayId: videoInfo.short_play_id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ import UIKit
|
||||
var playerFinishHadle: (() -> Void)? { get set }
|
||||
|
||||
// var model: Any? { get set }
|
||||
// var videoInfo: VPVideoInfoModel? { get set }
|
||||
var videoInfo: VPVideoInfoModel? { get set }
|
||||
|
||||
var isCurrent: Bool { get set }
|
||||
|
||||
|
@ -37,6 +37,7 @@ class VPShortModel: VPModel, SmartCodable {
|
||||
var watch_total: Int?
|
||||
var current_episode: String?
|
||||
var video_url: String?
|
||||
var updated_at: String?
|
||||
|
||||
@IgnoredKey
|
||||
var titleAttributedString: NSAttributedString?
|
||||
|
22
Veloria/Source/Assets.xcassets/icon/cancel_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
Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 498 B |
BIN
Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 729 B |
22
Veloria/Source/Assets.xcassets/icon/choice_icon_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
Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@2x.png
vendored
Normal file
After Width: | Height: | Size: 958 B |
BIN
Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
22
Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 80@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 80@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@2x.png
vendored
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@3x.png
vendored
Normal file
After Width: | Height: | Size: 3.8 KiB |
22
Veloria/Source/Assets.xcassets/icon/collect_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
Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 529 B |
BIN
Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 735 B |
22
Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.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
Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.0 KiB |
22
Veloria/Source/Assets.xcassets/icon/delete_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
Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 527 B |
BIN
Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 748 B |
22
Veloria/Source/Assets.xcassets/icon/editor_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
Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.2 KiB |
22
Veloria/Source/Assets.xcassets/icon/time_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
Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 593 B |
BIN
Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 863 B |
@ -18,9 +18,14 @@
|
||||
"Search Results" = "Search Results";
|
||||
"Recent Searches" = "Recent Searches";
|
||||
"My List" = "My List";
|
||||
"History" = "History";
|
||||
"Select All" = "Select All";
|
||||
|
||||
|
||||
"kHomeTitleText" = "10,000+ addictive shorts await!";
|
||||
"kSearchPlaceholderText1" = "Search dramas";
|
||||
"kSearchPlaceholderText2" = "#Recersal of fate";
|
||||
"kHomeMenuTitle" = "Select Categories";
|
||||
|
||||
//请选择需要删除的短剧
|
||||
"kToastText1" = "Please select the short plays that need to be deleted";
|
||||
|