diff --git a/Veloria.xcodeproj/project.pbxproj b/Veloria.xcodeproj/project.pbxproj index b65550c..b9ec04b 100644 --- a/Veloria.xcodeproj/project.pbxproj +++ b/Veloria.xcodeproj/project.pbxproj @@ -217,6 +217,8 @@ BFF5B26E2DF297680044227A /* VPOpenAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B26D2DF297680044227A /* VPOpenAppModel.swift */; }; BFF5B2752DF2C3750044227A /* VPDetailRecommandView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2742DF2C3750044227A /* VPDetailRecommandView.swift */; }; BFF5B2772DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2762DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift */; }; + BFF5B2792DF679720044227A /* VPMoreVideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2782DF679720044227A /* VPMoreVideoViewController.swift */; }; + BFF5B4AF2DF6B6630044227A /* VPMutualCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B4AE2DF6B6630044227A /* VPMutualCollectionView.swift */; }; F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; }; /* End PBXBuildFile section */ @@ -439,6 +441,8 @@ BFF5B26D2DF297680044227A /* VPOpenAppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPOpenAppModel.swift; sourceTree = ""; }; BFF5B2742DF2C3750044227A /* VPDetailRecommandView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDetailRecommandView.swift; sourceTree = ""; }; BFF5B2762DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDetailRecommandBannerCell.swift; sourceTree = ""; }; + BFF5B2782DF679720044227A /* VPMoreVideoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMoreVideoViewController.swift; sourceTree = ""; }; + BFF5B4AE2DF6B6630044227A /* VPMutualCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMutualCollectionView.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 */ @@ -676,6 +680,7 @@ 1B056E562DDACC6B007EE38D /* VPHomePageViewController.swift */, BF0FA7382DDECF8900C9E5F2 /* VPHomeListViewController.swift */, BF0FA7742DE071B500C9E5F2 /* VPSearchViewController.swift */, + BFF5B2782DF679720044227A /* VPMoreVideoViewController.swift */, ); path = Controller; sourceTree = ""; @@ -909,6 +914,7 @@ BFF5AFE12DEED2960044227A /* VPPlayerCoinBuyView.swift */, BFF5B2742DF2C3750044227A /* VPDetailRecommandView.swift */, BFF5B2762DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift */, + BFF5B4AE2DF6B6630044227A /* VPMutualCollectionView.swift */, ); path = View; sourceTree = ""; @@ -1433,6 +1439,7 @@ BFF5AFD42DE9A5FB0044227A /* VPVIPRecordCell.swift in Sources */, BFF5AFD62DE9A8D70044227A /* VPWalletHeaderView.swift in Sources */, BF0FA6EE2DDC5F8700C9E5F2 /* JXUUID.m in Sources */, + BFF5B2792DF679720044227A /* VPMoreVideoViewController.swift in Sources */, BF5E75B12DE4656600DE9DFE /* VPCampaignWebViewController.swift in Sources */, BF5E75BC2DE546AD00DE9DFE /* VPAboutUsCell.swift in Sources */, BFF5AFD02DE9A0370044227A /* VPCoinRecordCell.swift in Sources */, @@ -1522,6 +1529,7 @@ BF0FA7162DDC78FF00C9E5F2 /* ZKCycleScrollViewFlowLayout.swift in Sources */, BFF5B2612DF16B430044227A /* JXIAPManager.swift in Sources */, BF0FA7172DDC78FF00C9E5F2 /* ZKCycleScrollView.swift in Sources */, + BFF5B4AF2DF6B6630044227A /* VPMutualCollectionView.swift in Sources */, BF0FA7612DDFFE7100C9E5F2 /* VPVideoDetailModel.swift in Sources */, BFF5AFD22DE9A58A0044227A /* VPVIPRecordViewController.swift in Sources */, BFF5AFDA2DEE90350044227A /* VPVideoLockView.swift in Sources */, diff --git a/Veloria/AppDelegate/AppDelegate+Open.swift b/Veloria/AppDelegate/AppDelegate+Open.swift index 1e905eb..c8b670d 100644 --- a/Veloria/AppDelegate/AppDelegate+Open.swift +++ b/Veloria/AppDelegate/AppDelegate+Open.swift @@ -16,7 +16,7 @@ extension SceneDelegate { } //facebook - var result = ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation]) + let result = ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation]) if !result { vp_handleOpenAppMessage(webpageURL: url) @@ -33,13 +33,17 @@ extension SceneDelegate { extension SceneDelegate { static var hasOpenMessage = false + ///是否需要重试 + static var isNeedRetry = false func vp_handleOpenAppMessage(webpageURL: URL?) { - guard VPNetworkReachabilityManager.manager.isReachable == true else { return } + guard VPNetworkReachabilityManager.manager.isReachable == true else { + Self.isNeedRetry = true + return + } + Self.isNeedRetry = false - - - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self._handleOpenAppMessage(webpageURL: webpageURL) } @@ -50,7 +54,7 @@ extension SceneDelegate { Self.hasOpenMessage = true - DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { Self.hasOpenMessage = false } @@ -58,7 +62,8 @@ extension SceneDelegate { var statUrlStr: String? = webpageURL?.absoluteString var data: [String : Any]? = webpageURL?.query?.vp_urlQuryToDictionary() - if let pasteStr = UIPasteboard.general.string { + + if let pasteStr = UIPasteboard.general.string, pasteStr.contains("veloriaapp") { UIPasteboard.general.string = nil let tempArr = pasteStr.components(separatedBy: "?") let query = tempArr.last @@ -70,6 +75,10 @@ extension SceneDelegate { } } + + + + if let urlStr = statUrlStr {//上报结果 VPStatAPI.requestStatW2a(data: urlStr) } @@ -86,4 +95,10 @@ extension SceneDelegate { } + ///重试 + func vp_retryHandleOpenAppMessage() { + guard Self.isNeedRetry else { return } + vp_handleOpenAppMessage(webpageURL: nil) + } + } diff --git a/Veloria/AppDelegate/SceneDelegate.swift b/Veloria/AppDelegate/SceneDelegate.swift index 0de7150..f00302f 100644 --- a/Veloria/AppDelegate/SceneDelegate.swift +++ b/Veloria/AppDelegate/SceneDelegate.swift @@ -30,25 +30,55 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } func sceneDidDisconnect(_ scene: UIScene) { + } func sceneDidBecomeActive(_ scene: UIScene) { - VPStatAPI.requestEnterApp() - vp_handleOpenAppMessage(webpageURL: nil) +// vpLog(message: "++++++++++++++sceneDidBecomeActive") + enterForeground() } func sceneWillResignActive(_ scene: UIScene) { - VPStatAPI.requestLeaveApp() +// vpLog(message: "++++++++++++++sceneWillResignActive") + enterBackground() } func sceneWillEnterForeground(_ scene: UIScene) { - +// vpLog(message: "++++++++++++++sceneWillEnterForeground") +// enterForeground() + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + self.vp_handleOpenAppMessage(webpageURL: nil) + } } func sceneDidEnterBackground(_ scene: UIScene) { +// vpLog(message: "++++++++++++++sceneDidEnterBackground") +// enterBackground() } - +// private var isEnterForeground = false + + private func enterForeground() { +// if !isEnterForeground { +// vpLog(message: "++++++++++++++enterForeground") +// } +// isEnterForeground = true + + handleOnLine() + VPStatAPI.requestEnterApp() + + } + + private func enterBackground() { +// if isEnterForeground { +// } +// vpLog(message: "++++++++++++++enterBackground") +// isEnterForeground = false + VPStatAPI.requestLeaveApp() + } + + } extension SceneDelegate { @@ -59,8 +89,11 @@ extension SceneDelegate { @objc private func reachabilityDidChangeNotification() { - vp_handleOpenAppMessage(webpageURL: nil) + vp_retryHandleOpenAppMessage() + if VPNetworkReachabilityManager.manager.isReachable == true { + handleOnLine() + } } } diff --git a/Veloria/Base/Extension/Date+VPAdd.swift b/Veloria/Base/Extension/Date+VPAdd.swift index 49d3c8e..72dbd20 100644 --- a/Veloria/Base/Extension/Date+VPAdd.swift +++ b/Veloria/Base/Extension/Date+VPAdd.swift @@ -15,4 +15,10 @@ extension Date { return dateComponents.day ?? 0 } + func formatString(dateFormat: String) -> String { + let formatter = DateFormatter() + formatter.dateFormat = dateFormat + return formatter.string(from: self) + } + } diff --git a/Veloria/Base/Extension/String+VPAdd.swift b/Veloria/Base/Extension/String+VPAdd.swift index 4eeee52..0775d26 100644 --- a/Veloria/Base/Extension/String+VPAdd.swift +++ b/Veloria/Base/Extension/String+VPAdd.swift @@ -51,3 +51,24 @@ extension String { } } +extension String { + + func vp_range(of searchString: String) -> [NSRange] { + + do { + let newSearch = searchString.lowercased() + let newText = self.lowercased() + + let regex = try NSRegularExpression(pattern: newSearch) + let matches = regex.matches(in: newText, range: NSRange(self.startIndex..., in: newText)) + + let ranges = matches.map { $0.range } + + return ranges + } catch { + return [] + } + } + +} + diff --git a/Veloria/Base/Networking/API/VPHomeAPI.swift b/Veloria/Base/Networking/API/VPHomeAPI.swift index c86ef59..86d2558 100644 --- a/Veloria/Base/Networking/API/VPHomeAPI.swift +++ b/Veloria/Base/Networking/API/VPHomeAPI.swift @@ -53,4 +53,14 @@ class VPHomeAPI: NSObject { } } + + static func requestCategories(completer: ((_ list: [VPCategoryModel]?) -> Void)?) { + var param = VPNetworkParameters(path: "/getCategories") + param.method = .get + + VPNetwork.request(parameters: param) { (response: VPNetworkResponse>) in + completer?(response.data?.list) + } + + } } diff --git a/Veloria/Base/Networking/Base/VPNetwork.swift b/Veloria/Base/Networking/Base/VPNetwork.swift index 081788c..0960191 100644 --- a/Veloria/Base/Networking/Base/VPNetwork.swift +++ b/Veloria/Base/Networking/Base/VPNetwork.swift @@ -80,8 +80,15 @@ class VPNetwork: NSObject { } completion?(res) } else { + if code == 402, parameters.isToast { + VPToast.show(text: "kNetworkToast02".localized) + } ///重新获取token - self.requestToken(completer: nil) + self.requestToken { token in + if token != nil { + VPLoginManager.manager.updateUserInfo(completer: nil) + } + } ///将请求失败数据重新请求 if let tokenOperation = self.tokenOperation, parameters.path != "/customer/register" { @@ -137,7 +144,7 @@ class VPNetwork: NSObject { var res = VPNetworkResponse() res.code = -1 if parameters.isToast { - VPToast.show(text: "network_toast_01".localized) + VPToast.show(text: "kNetworkToast01".localized) } completion?(res) break diff --git a/Veloria/Base/WebView/VPWebViewController+Script.swift b/Veloria/Base/WebView/VPWebViewController+Script.swift index 2de958b..1bd765b 100644 --- a/Veloria/Base/WebView/VPWebViewController+Script.swift +++ b/Veloria/Base/WebView/VPWebViewController+Script.swift @@ -34,7 +34,11 @@ extension VPWebViewController { self.navigationController?.pushViewController(vc, animated: true) case VPWebMessageOpenFeedbackDetail: + guard let body = body as? [String : Any] else { return } + guard let id = body["id"] as? Int else { return } + let vc = VPCampaignWebViewController() + vc.id = "\(id)" vc.bgImageView.isHidden = true vc.urlStr = kVPFeedBackDetailWebUrl self.navigationController?.pushViewController(vc, animated: true) diff --git a/Veloria/Class/Explore/Controller/VPExploreViewController.swift b/Veloria/Class/Explore/Controller/VPExploreViewController.swift index eff00f3..c7595cb 100644 --- a/Veloria/Class/Explore/Controller/VPExploreViewController.swift +++ b/Veloria/Class/Explore/Controller/VPExploreViewController.swift @@ -22,7 +22,8 @@ class VPExploreViewController: VPVideoPlayerViewController { override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(loginStateDidChangeNotification), name: VPLoginManager.loginStateDidChangeNotification, object: nil) - + self.collectionView.vp_onRefrsh = true + self.collectionView.vp_refreshDelegate = self self.delegate = self self.dataSource = self @@ -75,22 +76,37 @@ extension VPExploreViewController: VPPlayerListViewControllerDataSource { } +//MARK: -------------- VPMutualCollectionViewDelegate -------------- +extension VPExploreViewController: VPMutualCollectionViewDelegate { + + func vp_loadNewData(collectionView: VPMutualCollectionView) { + collectionView.endRefresh() + + requestDataArr(page: 1) { [weak self] in + guard let self = self else { return } + self.collectionView.endRefresh() + } + } +} + extension VPExploreViewController { - private func requestDataArr(page: Int) { + private func requestDataArr(page: Int, completer: (() -> Void)? = nil) { VPVideoAPI.requestRecommandsVideo(page: page) { [weak self] listModel in guard let self = self else { return } if let listModel = listModel, let list = listModel.list { if page == 1 { self.setDataArr(dataArr: list) { [weak self] in - self?.play() + self?.scrollToItem(indexPath: IndexPath(row: 0, section: 0), animated: false) +// self?.play() } } else { self.addDataArr(dataArr: list) } self.pagination = listModel.pagination } + completer?() } } diff --git a/Veloria/Class/Home/Controller/VPHomePageViewController.swift b/Veloria/Class/Home/Controller/VPHomePageViewController.swift index 82149f3..9e1cc17 100644 --- a/Veloria/Class/Home/Controller/VPHomePageViewController.swift +++ b/Veloria/Class/Home/Controller/VPHomePageViewController.swift @@ -18,7 +18,7 @@ class VPHomePageViewController: VPViewController { param.wViewController = { [weak self] index in let categoryModel = self?.viewModel.categoryList[index] let vc = VPHomeListViewController() - vc.categoryId = categoryModel?.category_id + vc.categoryId = categoryModel?.id return vc } @@ -128,6 +128,7 @@ class VPHomePageViewController: VPViewController { NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: VPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil) requestHomeData() + requestCategories() setupPageView() vp_setupUI() @@ -147,6 +148,7 @@ class VPHomePageViewController: VPViewController { self.pageView.downSc?.vp_endHeaderRefreshing() } self.requestHomeData() + self.requestCategories() } @@ -187,6 +189,7 @@ extension VPHomePageViewController { if self.viewModel.oldModuleList == nil { requestHomeData() } + requestCategories() } } @@ -247,18 +250,25 @@ extension VPHomePageViewController { guard let self = self else { return } if let list = list { self.viewModel.oldModuleList = list - if self.viewModel.needUpdateCategory { - self.viewModel.needUpdateCategory = false - self.pageParam.wTitleArr = self.viewModel.categoryTitleList - self.pageView.updateMenuData() - self.setupPageView() - } self.searchButton.marqueeArr = self.viewModel.marqueeArr self.pageView.downSc?.reloadData() } } + } + + private func requestCategories() { + if self.viewModel.rawCategoryList.count > 0 { return } + VPHomeAPI.requestCategories { [weak self] list in + guard let self = self else { return } + if let list = list { + self.viewModel.rawCategoryList = list + self.pageParam.wTitleArr = self.viewModel.categoryTitleList + self.pageView.updateMenuData() + self.setupPageView() + } + } } } diff --git a/Veloria/Class/Home/Controller/VPMoreVideoViewController.swift b/Veloria/Class/Home/Controller/VPMoreVideoViewController.swift new file mode 100644 index 0000000..b2b8c57 --- /dev/null +++ b/Veloria/Class/Home/Controller/VPMoreVideoViewController.swift @@ -0,0 +1,118 @@ +// +// VPMoreVideoViewController.swift +// Veloria +// +// Created by 湖南秦九 on 2025/6/9. +// + +import UIKit + +class VPMoreVideoViewController: VPViewController { + + var dataArr: [VPShortModel] = [] { + didSet { + self.collectionView.reloadData() + } + } + + private lazy var titleLeftImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "title_icon_01")) + return imageView + }() + + private lazy var titleRightImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "title_icon_02")) + return imageView + }() + + private(set) lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .boldSystemFont(ofSize: 18) + label.textColor = .colorFFFFFF() + return label + }() +// VPSearchResultCell + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { + let layout = UICollectionViewFlowLayout() + layout.itemSize = .init(width: UIScreen.width - 30, height: 108) + layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15) + layout.minimumLineSpacing = 10 + return layout + }() + + private lazy var collectionView: VPCollectionView = { + let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.tabbarSafeBottomMargin + 10, right: 0) + collectionView.register(VPSearchResultCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + override func viewDidLoad() { + super.viewDidLoad() + + vp_setupUI() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.setNavigationBarHidden(false, animated: true) + setNavigationNormalStyle() + } + + +} + +extension VPMoreVideoViewController { + + private func vp_setupUI() { + view.addSubview(titleLeftImageView) + view.addSubview(titleRightImageView) + view.addSubview(titleLabel) + view.addSubview(collectionView) + + titleLeftImageView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(15) + make.top.equalToSuperview().offset(UIScreen.navBarHeight + 10) + } + + titleLabel.snp.makeConstraints { make in + make.left.equalTo(titleLeftImageView.snp.right).offset(1) + make.centerY.equalTo(titleLeftImageView) + } + + titleRightImageView.snp.makeConstraints { make in + make.centerY.equalTo(titleLeftImageView) + make.left.equalTo(titleLabel.snp.right).offset(1) + } + + collectionView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalToSuperview().offset(UIScreen.navBarHeight + 60) + } + + } + +} + +//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource -------------- +extension VPMoreVideoViewController: UICollectionViewDelegate, UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPSearchResultCell + cell.model = dataArr[indexPath.row] + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return self.dataArr.count + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let model = dataArr[indexPath.row] + + let vc = VPDetailPlayerViewController() + vc.shortPlayId = model.short_play_id + self.navigationController?.pushViewController(vc, animated: true) + } +} diff --git a/Veloria/Class/Home/Model/VPCategoryModel.swift b/Veloria/Class/Home/Model/VPCategoryModel.swift index 16bc881..5ede816 100644 --- a/Veloria/Class/Home/Model/VPCategoryModel.swift +++ b/Veloria/Class/Home/Model/VPCategoryModel.swift @@ -10,6 +10,6 @@ import SmartCodable class VPCategoryModel: VPModel, SmartCodable { - var category_name: String? - var category_id: String? + var name: String? + var id: String? } diff --git a/Veloria/Class/Home/Model/VPHomeModuleItem.swift b/Veloria/Class/Home/Model/VPHomeModuleItem.swift index 04ba290..bbf8396 100644 --- a/Veloria/Class/Home/Model/VPHomeModuleItem.swift +++ b/Veloria/Class/Home/Model/VPHomeModuleItem.swift @@ -16,7 +16,7 @@ class VPHomeModuleItem: VPModel, SmartCodable { ///分类推荐 case cagetory_recommand = "home_cagetory_recommand" case week_ranking = "week_ranking" - case category_navigation = "category_navigation" +// case category_navigation = "category_navigation" ///跑马灯 case marquee = "marquee" } @@ -33,11 +33,11 @@ class VPHomeModuleItem: VPModel, SmartCodable { func didFinishMapping() { if let data = data as? [[String : Any]] { - if module_key == .category_navigation { - self.categoryList = [VPCategoryModel].deserialize(from: data) - } else { - self.list = [VPShortModel].deserialize(from: data) - } +// if module_key == .category_navigation { +// self.categoryList = [VPCategoryModel].deserialize(from: data) +// } else { +// } + self.list = [VPShortModel].deserialize(from: data) } else if let data = data as? [String : Any] { var dataList: [[String : Any]]? if let list = data["list"] as? [[String : Any]] { diff --git a/Veloria/Class/Home/View/VPHomeRankingContentCell.swift b/Veloria/Class/Home/View/VPHomeRankingContentCell.swift index dd2d390..ee9a5a8 100644 --- a/Veloria/Class/Home/View/VPHomeRankingContentCell.swift +++ b/Veloria/Class/Home/View/VPHomeRankingContentCell.swift @@ -38,6 +38,18 @@ class VPHomeRankingContentCell: VPHomeItemContentCell { return label }() + private lazy var moreButton: UIButton = { + var config = UIButton.Configuration.plain() + config.imagePadding = 1 + config.imagePlacement = .trailing + config.contentInsets = .init(top: 5, leading: 0, bottom: 5, trailing: 0) + config.image = UIImage(named: "arrow_right_icon_03") + config.attributedTitle = AttributedString.createAttributedString(string: "More".localized, color: .colorFFFFFF(alpha: 0.5), font: .fontRegular(ofSize: 12)) + let button = UIButton(configuration: config) + button.addTarget(self, action: #selector(handleMoreButton), for: .touchUpInside) + return button + }() + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal @@ -67,6 +79,13 @@ class VPHomeRankingContentCell: VPHomeItemContentCell { fatalError("init(coder:) has not been implemented") } + @objc private func handleMoreButton() { + let vc = VPMoreVideoViewController() + vc.titleLabel.text = titleLabel.text + vc.dataArr = self.item?.list ?? [] + self.viewController?.navigationController?.pushViewController(vc, animated: true) + } + } extension VPHomeRankingContentCell { @@ -75,6 +94,7 @@ extension VPHomeRankingContentCell { containerView.addSubview(iconImageView) containerView.addSubview(titleLabel) containerView.addSubview(collectionView) + containerView.addSubview(moreButton) iconImageView.snp.makeConstraints { make in make.left.equalToSuperview().offset(15) @@ -92,6 +112,10 @@ extension VPHomeRankingContentCell { make.height.equalTo(collectionViewLayout.itemSize.height * 3 + collectionViewLayout.minimumInteritemSpacing * 2) } + moreButton.snp.makeConstraints { make in + make.centerY.equalTo(titleLabel) + make.right.equalToSuperview().offset(-13) + } } } diff --git a/Veloria/Class/Home/View/VPHomeRecommandContentCell.swift b/Veloria/Class/Home/View/VPHomeRecommandContentCell.swift index a058546..d15da5c 100644 --- a/Veloria/Class/Home/View/VPHomeRecommandContentCell.swift +++ b/Veloria/Class/Home/View/VPHomeRecommandContentCell.swift @@ -32,6 +32,18 @@ class VPHomeRecommandContentCell: VPHomeItemContentCell { return label }() + private lazy var moreButton: UIButton = { + var config = UIButton.Configuration.plain() + config.imagePadding = 1 + config.imagePlacement = .trailing + config.contentInsets = .init(top: 5, leading: 0, bottom: 5, trailing: 0) + config.image = UIImage(named: "arrow_right_icon_03") + config.attributedTitle = AttributedString.createAttributedString(string: "More".localized, color: .colorFFFFFF(alpha: 0.5), font: .fontRegular(ofSize: 12)) + let button = UIButton(configuration: config) + button.addTarget(self, action: #selector(handleMoreButton), for: .touchUpInside) + return button + }() + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal @@ -60,6 +72,13 @@ class VPHomeRecommandContentCell: VPHomeItemContentCell { fatalError("init(coder:) has not been implemented") } + @objc private func handleMoreButton() { + let vc = VPMoreVideoViewController() + vc.titleLabel.text = titleLabel.text + vc.dataArr = self.item?.list ?? [] + self.viewController?.navigationController?.pushViewController(vc, animated: true) + } + } extension VPHomeRecommandContentCell { @@ -67,6 +86,7 @@ extension VPHomeRecommandContentCell { private func vp_setupUI() { containerView.addSubview(titleLabel) containerView.addSubview(collectionView) + containerView.addSubview(moreButton) if Self.moduleKey == .v3_recommand { @@ -97,6 +117,11 @@ extension VPHomeRecommandContentCell { make.top.equalToSuperview().offset(32) make.height.equalTo(collectionViewLayout.itemSize.height) } + + moreButton.snp.makeConstraints { make in + make.centerY.equalTo(titleLabel) + make.right.equalToSuperview().offset(-13) + } } } diff --git a/Veloria/Class/Home/View/VPSearchResultCell.swift b/Veloria/Class/Home/View/VPSearchResultCell.swift index b2a3274..257d665 100644 --- a/Veloria/Class/Home/View/VPSearchResultCell.swift +++ b/Veloria/Class/Home/View/VPSearchResultCell.swift @@ -9,18 +9,28 @@ import UIKit class VPSearchResultCell: VPCollectionViewCell { - var searchText: String? { - didSet { - - } - } + var searchText: String? var model: VPShortModel? { didSet { coverImageView.vp_setImage(url: model?.image_url) - videoNameLabel.text = model?.name desLabel.text = model?.vp_description + + let name = model?.name ?? "" + let ranges = name.vp_range(of: searchText ?? "") + let nameString = NSMutableAttributedString(string: name) + + ranges.forEach { + nameString.setColor(.colorBE0069(), range: $0) + } + + videoNameLabel.attributedText = nameString + +// videoNameLabel.text = model?.name + + + let watchCount = model?.watch_total ?? 0 if watchCount > 1000 { let numStr = NSNumber(floatLiteral: CGFloat(watchCount) / 1000).toString(maximumFractionDigits: 1) diff --git a/Veloria/Class/Home/View/VPSearchResultView.swift b/Veloria/Class/Home/View/VPSearchResultView.swift index 55d5124..8f22116 100644 --- a/Veloria/Class/Home/View/VPSearchResultView.swift +++ b/Veloria/Class/Home/View/VPSearchResultView.swift @@ -12,8 +12,13 @@ class VPSearchResultView: UIView { var viewModel: VPSearchViewModel? private lazy var dataArr: [VPShortModel] = [] + ///当前数据对应的词 + private lazy var currentDataText = "" + private(set) lazy var searchText: String = "" + + //MARK: UI属性 private lazy var titleLabel: UILabel = { let label = UILabel() @@ -26,7 +31,7 @@ class VPSearchResultView: UIView { private lazy var collectionViewLayout: UICollectionViewFlowLayout = { let layout = UICollectionViewFlowLayout() layout.itemSize = .init(width: UIScreen.width - 30, height: 108) - layout.sectionInset = .init(top: 0, left: 15, bottom: UIScreen.tabbarSafeBottomMargin + 10, right: 15) + layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15) layout.minimumLineSpacing = 10 return layout }() @@ -35,6 +40,7 @@ class VPSearchResultView: UIView { let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) collectionView.delegate = self collectionView.dataSource = self + collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.tabbarSafeBottomMargin + 10, right: 0) collectionView.register(VPSearchResultCell.self, forCellWithReuseIdentifier: "cell") collectionView.vp_addNormalEmpty(image: UIImage(named: "empty_image_02")) collectionView.keyboardDismissMode = .onDrag @@ -80,7 +86,7 @@ extension VPSearchResultView { extension VPSearchResultView: UICollectionViewDataSource, UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPSearchResultCell - cell.searchText = self.searchText + cell.searchText = self.currentDataText cell.model = dataArr[indexPath.row] return cell } @@ -109,6 +115,7 @@ extension VPSearchResultView { if let list = list { self.dataArr = list + self.currentDataText = text self.collectionView.reloadData() } } diff --git a/Veloria/Class/Home/ViewModel/VPHomeViewModel.swift b/Veloria/Class/Home/ViewModel/VPHomeViewModel.swift index da32db5..f467ca6 100644 --- a/Veloria/Class/Home/ViewModel/VPHomeViewModel.swift +++ b/Veloria/Class/Home/ViewModel/VPHomeViewModel.swift @@ -26,6 +26,25 @@ class VPHomeViewModel: VPModel { private(set) lazy var categoryList: [VPCategoryModel] = [] private(set) lazy var categoryTitleList: [String] = [] + var rawCategoryList: [VPCategoryModel] = [] { + didSet { + let allCategory = VPCategoryModel() + allCategory.name = "All".localized + allCategory.id = "0" + + categoryList.removeAll() + categoryTitleList.removeAll() + + categoryList.append(allCategory) + categoryList += rawCategoryList + + categoryList.forEach { model in + categoryTitleList.append(model.name ?? "") + } + } + } + + ///跑马灯数据 private(set) lazy var marqueeArr: [VPShortModel] = [] @@ -39,23 +58,25 @@ class VPHomeViewModel: VPModel { if key == .banner { newModuleList.insert($0, at: 0) - } else if key == .category_navigation { //分类数据 + } + /* else if key == .category_navigation { //分类数据 if needUpdateCategory { categoryList.removeAll() categoryTitleList.removeAll() let allCategory = VPCategoryModel() - allCategory.category_name = "All".localized - allCategory.category_id = "0" + allCategory.name = "All".localized + allCategory.id = "0" categoryList.append(allCategory) categoryList += ($0.categoryList ?? []) categoryList.forEach { model in - categoryTitleList.append(model.category_name ?? "") + categoryTitleList.append(model.name ?? "") } } - } else if key == .marquee { //跑马灯数据 + }*/ + else if key == .marquee { //跑马灯数据 marqueeArr = $0.list ?? [] } else { newModuleList.append($0) diff --git a/Veloria/Class/Me/Controller/VPMeViewController.swift b/Veloria/Class/Me/Controller/VPMeViewController.swift index a192aa1..3b1c93a 100644 --- a/Veloria/Class/Me/Controller/VPMeViewController.swift +++ b/Veloria/Class/Me/Controller/VPMeViewController.swift @@ -115,6 +115,8 @@ extension VPMeViewController: UITableViewDelegate, UITableViewDataSource { cell.userInfo = VPLoginManager.manager.userInfo } else if let cell = cell as? VPMeCoinCell { cell.userInfo = VPLoginManager.manager.userInfo + } else if let cell = cell as? VPMeVipCell { + cell.userInfo = VPLoginManager.manager.userInfo } return cell diff --git a/Veloria/Class/Me/View/VPMeVipCell.swift b/Veloria/Class/Me/View/VPMeVipCell.swift index 28a36fc..c31cb91 100644 --- a/Veloria/Class/Me/View/VPMeVipCell.swift +++ b/Veloria/Class/Me/View/VPMeVipCell.swift @@ -9,6 +9,20 @@ import UIKit class VPMeVipCell: VPTableViewCell { + + var userInfo: VPUserInfo? { + didSet { + if userInfo?.is_vip == true { + let date = Date(timeIntervalSince1970: userInfo?.vip_end_time ?? 0) + subtitleLabel.text = String(format: "kVipTipText2".localized, date.formatString(dateFormat: "yyyy-MM-dd")) + titleLabel.text = "VIP Active".localized + } else { + subtitleLabel.text = "kVipTipText1".localized + titleLabel.text = "Join VIP".localized + } + } + } + private lazy var bgView: UIView = { let view = VPGradientView() view.colors = [UIColor.color06DEAD(alpha: 0.32).cgColor, UIColor.colorFFFFFF(alpha: 0.05).cgColor] @@ -36,7 +50,6 @@ class VPMeVipCell: VPTableViewCell { let label = UILabel() label.font = .fontBold(ofSize: 15) label.textColor = .colorFFFFFF() - label.text = "Join VIP".localized return label }() @@ -44,7 +57,6 @@ class VPMeVipCell: VPTableViewCell { let label = UILabel() label.font = .fontRegular(ofSize: 12) label.textColor = .colorFFFFFF() - label.text = "kVipTipText1".localized return label }() diff --git a/Veloria/Class/MyList/Controller/VPCollectListViewController.swift b/Veloria/Class/MyList/Controller/VPCollectListViewController.swift index e6abda3..b023f65 100644 --- a/Veloria/Class/MyList/Controller/VPCollectListViewController.swift +++ b/Veloria/Class/MyList/Controller/VPCollectListViewController.swift @@ -59,9 +59,12 @@ class VPCollectListViewController: VPViewController { ///全选状态发生变化 var didChangeAllSelected: (() -> Void)? + ///取消编辑 + var cancelEditBlock: (() -> Void)? + private lazy var deleteGroup = DispatchGroup() - private lazy var dataArr: [VPShortModel] = [] + private(set) lazy var dataArr: [VPShortModel] = [] private var page: Int = 1 ///更新节点,当节点大于1时,下次进入页面会更新列表 @@ -287,6 +290,7 @@ extension VPCollectListViewController { self.deleteGroup.notify(queue: .main) { [weak self] in VPHUD.dismiss() guard let self = self else { return } + self.cancelEditBlock?() self.requestDataArr(page: 1, completer: nil) } } diff --git a/Veloria/Class/MyList/Controller/VPMyListViewController.swift b/Veloria/Class/MyList/Controller/VPMyListViewController.swift index 29a2c4f..95973bc 100644 --- a/Veloria/Class/MyList/Controller/VPMyListViewController.swift +++ b/Veloria/Class/MyList/Controller/VPMyListViewController.swift @@ -17,6 +17,11 @@ class VPMyListViewController: VPViewController { ///0普通状态 1编辑状态 private var editState: EditState = .normal { didSet { + if collectVC.dataArr.count <= 0, editState != .normal { + editState = .normal + return + } + if editState == .normal { pageView.upSc.mainView.isHidden = false pageView.upSc.dataView.isScrollEnabled = true @@ -30,7 +35,13 @@ class VPMyListViewController: VPViewController { } } - private lazy var collectVC = VPCollectListViewController() + private lazy var collectVC: VPCollectListViewController = { + let vc = VPCollectListViewController() + vc.cancelEditBlock = { [weak self] in + self?.editState = .normal + } + return vc + }() private lazy var viewControllers: [UIViewController] = { let vc2 = VPWatchHistoryViewController() diff --git a/Veloria/Class/Player/Controller/VPVideoPlayerViewController.swift b/Veloria/Class/Player/Controller/VPVideoPlayerViewController.swift index 4ec2844..45cdcd0 100644 --- a/Veloria/Class/Player/Controller/VPVideoPlayerViewController.swift +++ b/Veloria/Class/Player/Controller/VPVideoPlayerViewController.swift @@ -65,8 +65,8 @@ class VPVideoPlayerViewController: VPViewController { return layout }() - private(set) lazy var collectionView: VPCollectionView = { - let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + private(set) lazy var collectionView: VPMutualCollectionView = { + let collectionView = VPMutualCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) collectionView.delegate = self collectionView.dataSource = self collectionView.isPagingEnabled = true @@ -74,7 +74,6 @@ class VPVideoPlayerViewController: VPViewController { collectionView.showsHorizontalScrollIndicator = false collectionView.bounces = false collectionView.scrollsToTop = false -// PlayerCellClass.registerCell(collectionView: collectionView) collectionView.register(PlayerCellClass.self, forCellWithReuseIdentifier: "cell") return collectionView }() diff --git a/Veloria/Class/Player/View/VPMutualCollectionView.swift b/Veloria/Class/Player/View/VPMutualCollectionView.swift new file mode 100644 index 0000000..f0384cb --- /dev/null +++ b/Veloria/Class/Player/View/VPMutualCollectionView.swift @@ -0,0 +1,188 @@ +// +// VPMutualCollectionView.swift +// Veloria +// +// Created by 湖南秦九 on 2025/6/9. +// + +import UIKit + +@objc protocol VPMutualCollectionViewDelegate: NSObjectProtocol { + @objc optional func vp_loadNewData(collectionView: VPMutualCollectionView) +} + +class VPMutualCollectionView: VPCollectionView { + + enum RefrshStatus { + ///闲置状态 + case normal + ///松开就可以进行刷新的状态 + case pulling + ///刷新中 + case refreshing + } + + ///刷新状态 + var refreshStatus = RefrshStatus.normal + + weak var vp_refreshDelegate: VPMutualCollectionViewDelegate? + + ///刷新手势 + lazy var refreshPanGesture: UIPanGestureRecognizer = { + let pan = UIPanGestureRecognizer(target: self, action: #selector(handleRefreshPanGesture(sender:))) + pan.delegate = self + return pan + }() + ///刷新视图 + lazy var refreshView: UIActivityIndicatorView = { + let view = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 20, height: 20)) + view.isHidden = true +// view.tintColor = .colorFFFFFF() + view.color = .colorFFFFFF() + return view + }() + + ///刷新开关 + var vp_onRefrsh = false + + override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) { + super.init(frame: frame, collectionViewLayout: layout) + + self.addGestureRecognizer(refreshPanGesture) + + addSubview(refreshView) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + override func layoutSubviews() { + super.layoutSubviews() + refreshView.centerX = self.width / 2 + } + + @objc func handleRefreshPanGesture(sender: UIPanGestureRecognizer) { + if !vp_onRefrsh {return} + if refreshStatus == .refreshing {return} + + switch sender.state { + case .began: + refreshStatus = .normal + refreshView.isHidden = false + refreshView.top = -20 + bringSubviewToFront(refreshView) + sender.setTranslation(.zero, in: self) + case .changed: + let point = sender.translation(in: self) + var top = refreshView.top + point.y + if top > UIScreen.tabbarSafeBottomMargin + 70 { + top = UIScreen.tabbarSafeBottomMargin + 70 + } + if top >= UIScreen.tabbarSafeBottomMargin + 60 { + refreshStatus = .pulling + } else { + refreshStatus = .normal + } + refreshView.top = top + + sender.setTranslation(.zero, in: self) + + case .cancelled, .ended, .failed: + if refreshStatus == .pulling { + beginRefresh() + } else { + endRefresh() + } + default: + break + } + } + + func beginRefresh() { + self.refreshStatus = .refreshing + self.refreshView.startAnimating() + + UIView.animate(withDuration: 0.5) { [weak self] in + self?.refreshView.top = UIScreen.tabbarSafeBottomMargin + 60 + } completion: { [weak self] (finish) in + guard let self = self else {return} + self.vp_refreshDelegate?.vp_loadNewData?(collectionView: self) + } + + } + + func endRefresh() { + self.refreshStatus = .normal + self.refreshView.stopAnimating() + UIView.animate(withDuration: 0.5) { [weak self] in + self?.refreshView.top = -20 + } completion: { [weak self] (finish) in + if self?.refreshStatus == .none { + self?.refreshView.isHidden = true + } + } + + } +} + +extension VPMutualCollectionView { + + override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + + // return panBack(gestureRecognizer: gestureRecognizer) + if gestureRecognizer == self.refreshPanGesture { + if !vp_onRefrsh { return false } +// if self.isScrollEnabled == false { return false } + + + let point = self.refreshPanGesture.translation(in: self) + let state = gestureRecognizer.state + + if state == .began || state == .possible { + ///向下滑 + if point.y > 0 && self.contentOffset.y == 0 { + return true + } + } + return false + } else { + return super.gestureRecognizerShouldBegin(gestureRecognizer) + } + } + + func panBack(gestureRecognizer: UIGestureRecognizer) -> Bool { + if gestureRecognizer == self.refreshPanGesture { + if !vp_onRefrsh { return false } +// if self.isScrollEnabled == false { return false } + + let point = self.refreshPanGesture.translation(in: self) + let state = gestureRecognizer.state + + if state == .began || state == .possible { + ///向下滑 + if point.y > 0 && self.contentOffset.y == 0 { + return true + } + } + return false + } else if (gestureRecognizer == self.panGestureRecognizer) { + + let point = self.panGestureRecognizer.translation(in: self) + let state = gestureRecognizer.state + + + if state == .began || state == .possible { + ///向下滑 + if point.y > 0 && self.contentOffset.y == 0 { + return false + } + } + return true + } else { + return true + } + } + +} diff --git a/Veloria/Libs/Login/VPLoginManager.swift b/Veloria/Libs/Login/VPLoginManager.swift index df3b288..5785521 100644 --- a/Veloria/Libs/Login/VPLoginManager.swift +++ b/Veloria/Libs/Login/VPLoginManager.swift @@ -63,12 +63,15 @@ class VPLoginManager: NSObject { ///退出登录 func logout(completer: ((_ isFinish: Bool) -> Void)?) { + VPStatAPI.requestLeaveApp() VPUserAPI.requestLogout { [weak self] token in guard let self = self else { return } if let token = token { self.setLoginToken(token: token) self.userInfo?.is_tourist = true self.updateUserInfo(completer: nil) + VPStatAPI.requestStatOnLine() + VPStatAPI.requestEnterApp() completer?(true) NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil) NotificationCenter.default.post(name: VPLoginManager.loginStateDidChangeNotification, object: nil) @@ -80,12 +83,15 @@ class VPLoginManager: NSObject { ///删除账号 func deleteAccount(completer: ((_ isFinish: Bool) -> Void)?) { + VPStatAPI.requestLeaveApp() VPUserAPI.requestDelete { [weak self] isFinish in guard let self = self else { return } if isFinish { self.setLoginToken(token: nil) self.userInfo?.is_tourist = true self.updateUserInfo(completer: nil) + VPStatAPI.requestStatOnLine() + VPStatAPI.requestEnterApp() completer?(true) NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil) NotificationCenter.default.post(name: VPLoginManager.loginStateDidChangeNotification, object: nil) @@ -120,7 +126,7 @@ extension VPLoginManager { completer?(false) return } - + VPStatAPI.requestLeaveApp() VPUserAPI.requestThirdLogin(model: thirdSignModel) { [weak self] token in guard let self = self else { return } guard let token = token else { @@ -130,6 +136,8 @@ extension VPLoginManager { self.setLoginToken(token: token) self.userInfo?.is_tourist = false self.updateUserInfo(completer: nil) + VPStatAPI.requestStatOnLine() + VPStatAPI.requestEnterApp() completer?(true) NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil) NotificationCenter.default.post(name: VPLoginManager.loginStateDidChangeNotification, object: nil) diff --git a/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.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/arrow_right_icon_03.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Frame@2x.png new file mode 100644 index 0000000..3984fa6 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Frame@3x.png new file mode 100644 index 0000000..2f39e26 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/title_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/title_icon_01.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..65599fb Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..148b844 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/title_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/title_icon_02.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Frame@2x.png new file mode 100644 index 0000000..0d3a4f7 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Frame@3x.png new file mode 100644 index 0000000..2b32279 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Frame@3x.png differ diff --git a/Veloria/Source/en.lproj/Localizable.strings b/Veloria/Source/en.lproj/Localizable.strings index bc355fe..e32c7ac 100644 --- a/Veloria/Source/en.lproj/Localizable.strings +++ b/Veloria/Source/en.lproj/Localizable.strings @@ -37,6 +37,7 @@ "Feedback Details" = "Feedback Details"; "Rewards" = "Rewards"; "Join VIP" = "Join VIP"; +"VIP Active" = "VIP Active"; "Conins" = "Conins"; "Donate" = "Donate"; "Wallet" = "Wallet"; @@ -87,13 +88,16 @@ "Success" = "Success"; "Restore" = "Restore"; "Watch Now" = "Watch Now"; +"More" = "More"; + "kDetailRecommandTitle" = "Picked Just for You"; "kHomeTitleText" = "10,000+ addictive shorts await!"; "kSearchPlaceholderText1" = "Search dramas"; "kSearchPlaceholderText2" = "#Recersal of fate"; "kHomeMenuTitle" = "Select Categories"; -"kVipTipText1" = "unlock 1000+ exclusive dramas"; +"kVipTipText1" = "unlock exclusive dramas"; +"kVipTipText2" = "vip expires: %@"; "kVipPrivilegeText1" = "Ad-Free\nStreaming"; "kVipPrivilegeText2" = "Exclusive\nEpisodes"; "kVipPrivilegeText3" = "Daily free\ncoins"; @@ -104,6 +108,7 @@ "kVideoLockTipText" = "Please unlock the previous episode"; //无网提示 "kNetworkToast01" = "The service is abnormal. Check the network."; +"kNetworkToast02" = "Your account is already logged in on another device~"; //解锁上一集提示 "kLockPreviousEpisodeText" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series"; //解锁失败 diff --git a/Veloria/Veloria.entitlements b/Veloria/Veloria.entitlements index df0f60e..02275d0 100644 --- a/Veloria/Veloria.entitlements +++ b/Veloria/Veloria.entitlements @@ -8,7 +8,8 @@ com.apple.developer.associated-domains - webcredentials:example.com + applinks:qjwl168.com + applinks:veloriaapp.go.link keychain-access-groups