From a30c319c0581bf0f4c21028311f8393e410437a7 Mon Sep 17 00:00:00 2001 From: zjx Date: Mon, 9 Jun 2025 18:27:24 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=9B=B4=E5=A4=9A=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=EF=BC=8CW2A=E7=BB=9F=E8=AE=A1=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8CBug=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Veloria.xcodeproj/project.pbxproj | 8 + Veloria/AppDelegate/AppDelegate+Open.swift | 29 ++- Veloria/AppDelegate/SceneDelegate.swift | 45 ++++- Veloria/Base/Extension/Date+VPAdd.swift | 6 + Veloria/Base/Extension/String+VPAdd.swift | 21 ++ Veloria/Base/Networking/API/VPHomeAPI.swift | 10 + Veloria/Base/Networking/Base/VPNetwork.swift | 11 +- .../WebView/VPWebViewController+Script.swift | 4 + .../Controller/VPExploreViewController.swift | 22 +- .../Controller/VPHomePageViewController.swift | 24 ++- .../VPMoreVideoViewController.swift | 118 +++++++++++ .../Class/Home/Model/VPCategoryModel.swift | 4 +- .../Class/Home/Model/VPHomeModuleItem.swift | 12 +- .../Home/View/VPHomeRankingContentCell.swift | 24 +++ .../View/VPHomeRecommandContentCell.swift | 25 +++ .../Class/Home/View/VPSearchResultCell.swift | 22 +- .../Class/Home/View/VPSearchResultView.swift | 11 +- .../Home/ViewModel/VPHomeViewModel.swift | 31 ++- .../Me/Controller/VPMeViewController.swift | 2 + Veloria/Class/Me/View/VPMeVipCell.swift | 16 +- .../VPCollectListViewController.swift | 6 +- .../Controller/VPMyListViewController.swift | 13 +- .../VPVideoPlayerViewController.swift | 5 +- .../Player/View/VPMutualCollectionView.swift | 188 ++++++++++++++++++ Veloria/Libs/Login/VPLoginManager.swift | 10 +- .../Contents.json | 22 ++ .../arrow_right_icon_03.imageset/Frame@2x.png | Bin 0 -> 248 bytes .../arrow_right_icon_03.imageset/Frame@3x.png | Bin 0 -> 334 bytes .../icon/title_icon_01.imageset/Contents.json | 22 ++ .../icon/title_icon_01.imageset/Frame@2x.png | Bin 0 -> 1265 bytes .../icon/title_icon_01.imageset/Frame@3x.png | Bin 0 -> 2032 bytes .../icon/title_icon_02.imageset/Contents.json | 22 ++ .../icon/title_icon_02.imageset/Frame@2x.png | Bin 0 -> 1257 bytes .../icon/title_icon_02.imageset/Frame@3x.png | Bin 0 -> 1968 bytes Veloria/Source/en.lproj/Localizable.strings | 7 +- Veloria/Veloria.entitlements | 3 +- 36 files changed, 687 insertions(+), 56 deletions(-) create mode 100644 Veloria/Class/Home/Controller/VPMoreVideoViewController.swift create mode 100644 Veloria/Class/Player/View/VPMutualCollectionView.swift create mode 100644 Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Contents.json create mode 100644 Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Frame@2x.png create mode 100644 Veloria/Source/Assets.xcassets/icon/arrow_right_icon_03.imageset/Frame@3x.png create mode 100644 Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Contents.json create mode 100644 Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Frame@2x.png create mode 100644 Veloria/Source/Assets.xcassets/icon/title_icon_01.imageset/Frame@3x.png create mode 100644 Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Contents.json create mode 100644 Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Frame@2x.png create mode 100644 Veloria/Source/Assets.xcassets/icon/title_icon_02.imageset/Frame@3x.png 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 0000000000000000000000000000000000000000..3984fa683213439d38d8a035dcd43755befce5d9 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F$05`DhM-r2B~}i3NjW4 zxjQkeJ16rJ$YDu$^mSxl*x1kgCy^DT(bL5-q=ND4rGuOe3KFaj;$J@4C@6DKP-bDE z)LJ09IC)E>?LqGaPuC0mc%T?nqvU0h>ck;+H_-Xai9@@b!b=`6iVWa*Xt={9b>XA8 z$_m{Fm%VK4^?St_eZhZ1cUYrLNKh(+MOECCcTC2Cu?f#k*nPkMf4b3^n>@8QbR&9n m5|*)cM{>OmU-dYl_z9c+WS<8LFT6mmX7F_Nb6Mw<&;$T*01CCPlFyQ|_AU#Izc2VdBq;nfo}Lp>#*d&DGpl@z&4NX7q|5 z^w}ek_Au0dd41d79o*j@Ok;kM&cO4qcz$`5z4@OrU*AUB#@sPzi#qqg_nTMSuIs-l z#jl%x+24J-IqY!U7Ou1fM-8}jn`W+%Oj|5eD$ksIa|Necl$q8{>02^~AO8`3bKuwB cxkgd%6c<<5tk?170eY9g)78&qol`;+0K@NqGynhq literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..65599fba11eaa0a6f4c9101c70ad589786bc2fa8 GIT binary patch literal 1265 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 com.apple.developer.associated-domains - webcredentials:example.com + applinks:qjwl168.com + applinks:veloriaapp.go.link keychain-access-groups