diff --git a/Veloria.xcodeproj/project.pbxproj b/Veloria.xcodeproj/project.pbxproj index 7c241f6..e05b1da 100644 --- a/Veloria.xcodeproj/project.pbxproj +++ b/Veloria.xcodeproj/project.pbxproj @@ -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 = ""; }; BF0FA7902DE16CBF00C9E5F2 /* VPSearchHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchHistoryView.swift; sourceTree = ""; }; BF0FA7922DE16E9300C9E5F2 /* JXTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXTagView.swift; sourceTree = ""; }; + BF0FA7982DE1951A00C9E5F2 /* VPMyListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMyListViewController.swift; sourceTree = ""; }; + BF0FA79A2DE1984B00C9E5F2 /* VPCollectListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCollectListViewController.swift; sourceTree = ""; }; + BF0FA79C2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWatchHistoryViewController.swift; sourceTree = ""; }; + BF0FA79E2DE1A29A00C9E5F2 /* VPCollectListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCollectListCell.swift; sourceTree = ""; }; + BF0FA7A02DE1AA5100C9E5F2 /* VPTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPTableView.swift; sourceTree = ""; }; + BF0FA7A22DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWatchHistoryCell.swift; sourceTree = ""; }; + BF0FA7A42DE4384100C9E5F2 /* AttributedString+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+VPAdd.swift"; sourceTree = ""; }; 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 = ""; }; /* End PBXFileReference section */ @@ -357,6 +371,7 @@ BF0FA76C2DE053C100C9E5F2 /* VPScrollView.swift */, BF0FA7822DE1533E00C9E5F2 /* VPGradientLabel.swift */, BF0FA7862DE1601200C9E5F2 /* VPTextField.swift */, + BF0FA7A02DE1AA5100C9E5F2 /* VPTableView.swift */, ); path = View; sourceTree = ""; @@ -413,6 +428,7 @@ BF0FA72F2DDEBB1600C9E5F2 /* UIButton+VPAdd.swift */, BF0FA7402DDEFBC700C9E5F2 /* UIScrollView+VPRefresh.swift */, BF0FA77A2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift */, + BF0FA7A42DE4384100C9E5F2 /* AttributedString+VPAdd.swift */, ); path = Extension; sourceTree = ""; @@ -714,8 +730,8 @@ BF0FA7952DE1948A00C9E5F2 /* MyList */ = { isa = PBXGroup; children = ( - BF0FA7972DE1949B00C9E5F2 /* View */, BF0FA7962DE1949300C9E5F2 /* Controller */, + BF0FA7972DE1949B00C9E5F2 /* View */, ); path = MyList; sourceTree = ""; @@ -723,6 +739,9 @@ BF0FA7962DE1949300C9E5F2 /* Controller */ = { isa = PBXGroup; children = ( + BF0FA7982DE1951A00C9E5F2 /* VPMyListViewController.swift */, + BF0FA79A2DE1984B00C9E5F2 /* VPCollectListViewController.swift */, + BF0FA79C2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift */, ); path = Controller; sourceTree = ""; @@ -730,6 +749,8 @@ BF0FA7972DE1949B00C9E5F2 /* View */ = { isa = PBXGroup; children = ( + BF0FA79E2DE1A29A00C9E5F2 /* VPCollectListCell.swift */, + BF0FA7A22DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift */, ); path = View; sourceTree = ""; @@ -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 */, diff --git a/Veloria/Base/Controller/VPTabBarController.swift b/Veloria/Base/Controller/VPTabBarController.swift index 1d25315..82c56fd 100644 --- a/Veloria/Base/Controller/VPTabBarController.swift +++ b/Veloria/Base/Controller/VPTabBarController.swift @@ -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] diff --git a/Veloria/Base/Extension/AttributedString+VPAdd.swift b/Veloria/Base/Extension/AttributedString+VPAdd.swift new file mode 100644 index 0000000..e74b598 --- /dev/null +++ b/Veloria/Base/Extension/AttributedString+VPAdd.swift @@ -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 + ])) + } +} diff --git a/Veloria/Base/Networking/API/VPVideoAPI.swift b/Veloria/Base/Networking/API/VPVideoAPI.swift index bdbc230..bf5afdb 100644 --- a/Veloria/Base/Networking/API/VPVideoAPI.swift +++ b/Veloria/Base/Networking/API/VPVideoAPI.swift @@ -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) in @@ -94,6 +94,51 @@ class VPVideoAPI: NSObject { } } } + + ///收藏列表 + static func requestCollectList(page: Int, completer: ((_ listModel: VPListModel?) -> Void)?) { + var param = VPNetworkParameters(path: "/myCollections") + param.method = .get + param.parameters = [ + "current_page" : page, + "page_size" : 20 + ] + + VPNetwork.request(parameters: param) { (response: VPNetworkResponse>) 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) in + + } + } + + ///历史记录列表 + static func requestPlayHistoryList(page: Int, pageSize: Int = 20, completer: ((_ listModel: VPListModel?) -> Void)?) { + var param = VPNetworkParameters(path: "/myHistorys") + param.method = .get + param.parameters = [ + "current_page" : page, + "page_size" : pageSize + ] + + VPNetwork.request(parameters: param) { (response: VPNetworkResponse>) in + completer?(response.data) + } + } } extension VPVideoAPI { diff --git a/Veloria/Base/View/VPTableView.swift b/Veloria/Base/View/VPTableView.swift new file mode 100644 index 0000000..33641df --- /dev/null +++ b/Veloria/Base/View/VPTableView.swift @@ -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 + } + } + +} diff --git a/Veloria/Class/MyList/Controller/VPCollectListViewController.swift b/Veloria/Class/MyList/Controller/VPCollectListViewController.swift new file mode 100644 index 0000000..d93e8db --- /dev/null +++ b/Veloria/Class/MyList/Controller/VPCollectListViewController.swift @@ -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) + } + } + + +} diff --git a/Veloria/Class/MyList/Controller/VPMyListViewController.swift b/Veloria/Class/MyList/Controller/VPMyListViewController.swift new file mode 100644 index 0000000..bbebbf4 --- /dev/null +++ b/Veloria/Class/MyList/Controller/VPMyListViewController.swift @@ -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) + } + + } + +} diff --git a/Veloria/Class/MyList/Controller/VPWatchHistoryViewController.swift b/Veloria/Class/MyList/Controller/VPWatchHistoryViewController.swift new file mode 100644 index 0000000..f720fe2 --- /dev/null +++ b/Veloria/Class/MyList/Controller/VPWatchHistoryViewController.swift @@ -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?() + } + + } + +} diff --git a/Veloria/Class/MyList/View/VPCollectListCell.swift b/Veloria/Class/MyList/View/VPCollectListCell.swift new file mode 100644 index 0000000..08b9f75 --- /dev/null +++ b/Veloria/Class/MyList/View/VPCollectListCell.swift @@ -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) + } + + } + +} diff --git a/Veloria/Class/MyList/View/VPWatchHistoryCell.swift b/Veloria/Class/MyList/View/VPWatchHistoryCell.swift new file mode 100644 index 0000000..495946f --- /dev/null +++ b/Veloria/Class/MyList/View/VPWatchHistoryCell.swift @@ -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) + } + } +} diff --git a/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift b/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift index 7bb46ba..3231174 100644 --- a/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift +++ b/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift @@ -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) + } } diff --git a/Veloria/Class/Player/Model/VPPlayerProtocol.swift b/Veloria/Class/Player/Model/VPPlayerProtocol.swift index 861cbe7..c558f89 100644 --- a/Veloria/Class/Player/Model/VPPlayerProtocol.swift +++ b/Veloria/Class/Player/Model/VPPlayerProtocol.swift @@ -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 } diff --git a/Veloria/Class/Player/Model/VPShortModel.swift b/Veloria/Class/Player/Model/VPShortModel.swift index 59becdb..6e2398d 100644 --- a/Veloria/Class/Player/Model/VPShortModel.swift +++ b/Veloria/Class/Player/Model/VPShortModel.swift @@ -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? diff --git a/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..d36dba8 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..b630ce1 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/cancel_icon_01.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/Contents.json new file mode 100644 index 0000000..d9e95f1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/Contents.json @@ -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 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@2x.png b/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@2x.png new file mode 100644 index 0000000..1267d65 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@3x.png b/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@3x.png new file mode 100644 index 0000000..ea2a209 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/choice_icon_01.imageset/未选中@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Contents.json new file mode 100644 index 0000000..82c2e67 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Contents.json @@ -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 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@2x.png b/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@2x.png new file mode 100644 index 0000000..2073141 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@3x.png b/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@3x.png new file mode 100644 index 0000000..8307568 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/choice_icon_01_selected.imageset/Frame 80@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@2x.png new file mode 100644 index 0000000..ce71895 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@3x.png new file mode 100644 index 0000000..603f5d3 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/collect_icon_02.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@2x.png new file mode 100644 index 0000000..f1642f3 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@3x.png new file mode 100644 index 0000000..734e5b6 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/collect_icon_02_selected.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@2x.png new file mode 100644 index 0000000..e6ca004 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@3x.png new file mode 100644 index 0000000..a2b010d Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/delete_icon_02.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..93b942c Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..4d1b000 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/editor_icon_01.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..5d23957 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..d5a1e60 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/time_icon_01.imageset/Frame@3x.png differ diff --git a/Veloria/Source/en.lproj/Localizable.strings b/Veloria/Source/en.lproj/Localizable.strings index f4e2c33..b77a96a 100644 --- a/Veloria/Source/en.lproj/Localizable.strings +++ b/Veloria/Source/en.lproj/Localizable.strings @@ -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";