From f0628bd6097b273a37a8087da00e981c986c20b6 Mon Sep 17 00:00:00 2001 From: zeng Date: Thu, 16 Oct 2025 16:02:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Fableon.xcodeproj/project.pbxproj | 8 ++ Fableon/Base/Request/FAAPI/FAAPI.swift | 13 ++ .../Class/Home/C/FAHomeViewController.swift | 52 +++++-- .../Class/Home/V/FAHomePlayHistoryView.swift | 128 ++++++++++++++++++ Fableon/Class/Home/VM/FAHomeViewModel.swift | 13 ++ .../Class/Player/V/FAPlayerDetailCell.swift | 14 ++ .../Player/VM/FAShortDetailViewModel.swift | 48 ++++++- .../color/#BDCEFF.colorset/Contents.json | 20 +++ .../image/Group 2420.imageset/Contents.json | 22 +++ .../Group 2420.imageset/Group 2420@2x.png | Bin 0 -> 5766 bytes .../Group 2420.imageset/Group 2420@3x.png | Bin 0 -> 11456 bytes Fableon/Source/en.lproj/Localizable.strings | 1 + 12 files changed, 308 insertions(+), 11 deletions(-) create mode 100644 Fableon/Class/Home/V/FAHomePlayHistoryView.swift create mode 100644 Fableon/Source/Assets.xcassets/color/#BDCEFF.colorset/Contents.json create mode 100644 Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Contents.json create mode 100644 Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Group 2420@2x.png create mode 100644 Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Group 2420@3x.png diff --git a/Fableon.xcodeproj/project.pbxproj b/Fableon.xcodeproj/project.pbxproj index 847eadf..4178b1a 100644 --- a/Fableon.xcodeproj/project.pbxproj +++ b/Fableon.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ B8B1DA3824F2148CEEF9F162 /* Pods_Fableon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4958FEE55B4555A94F11F00 /* Pods_Fableon.framework */; }; F301F6472E974B6300E76A90 /* FARecommendPlayerControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F301F6462E974B6300E76A90 /* FARecommendPlayerControlView.swift */; }; + F34296922EA0C60200A58F99 /* FAHomePlayHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296912EA0C60200A58F99 /* FAHomePlayHistoryView.swift */; }; F37103312E978F8C00E7F171 /* FACollectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37103302E978F8C00E7F171 /* FACollectViewController.swift */; }; F37103352E97929F00E7F171 /* FACollectCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F37103342E97929F00E7F171 /* FACollectCell.xib */; }; F37103362E97929F00E7F171 /* FACollectCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37103332E97929F00E7F171 /* FACollectCell.swift */; }; @@ -127,6 +128,7 @@ C4958FEE55B4555A94F11F00 /* Pods_Fableon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Fableon.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DC14083E24B746ED3DE2FE0C /* Pods-Fableon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fableon.release.xcconfig"; path = "Target Support Files/Pods-Fableon/Pods-Fableon.release.xcconfig"; sourceTree = ""; }; F301F6462E974B6300E76A90 /* FARecommendPlayerControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARecommendPlayerControlView.swift; sourceTree = ""; }; + F34296912EA0C60200A58F99 /* FAHomePlayHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAHomePlayHistoryView.swift; sourceTree = ""; }; F37103302E978F8C00E7F171 /* FACollectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectViewController.swift; sourceTree = ""; }; F37103332E97929F00E7F171 /* FACollectCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectCell.swift; sourceTree = ""; }; F37103342E97929F00E7F171 /* FACollectCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FACollectCell.xib; sourceTree = ""; }; @@ -556,6 +558,7 @@ F371035D2E9E2E7400E7F171 /* FASearchRecommendCell.xib */, F37103642E9E3ABC00E7F171 /* FASearchResultCell.swift */, F37103652E9E3ABC00E7F171 /* FASearchResultCell.xib */, + F34296912EA0C60200A58F99 /* FAHomePlayHistoryView.swift */, ); path = V; sourceTree = ""; @@ -852,10 +855,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks.sh\"\n"; @@ -923,6 +930,7 @@ F3DCC0572E8A8EE800D58007 /* FAMeViewController.swift in Sources */, F3A792E82E77F8590097E0BC /* FAHomeModuleItem.swift in Sources */, F3DCC0452E89530200D58007 /* CGMutablePath+FARoundedCorner.swift in Sources */, + F34296922EA0C60200A58F99 /* FAHomePlayHistoryView.swift in Sources */, F37103882EA08B6F00E7F171 /* FANetworkMonitor.swift in Sources */, F37103672E9E3ABC00E7F171 /* FASearchResultCell.swift in Sources */, F371037B2EA0820C00E7F171 /* FASettingViewController.swift in Sources */, diff --git a/Fableon/Base/Request/FAAPI/FAAPI.swift b/Fableon/Base/Request/FAAPI/FAAPI.swift index 71fe0f2..d5b34cf 100644 --- a/Fableon/Base/Request/FAAPI/FAAPI.swift +++ b/Fableon/Base/Request/FAAPI/FAAPI.swift @@ -68,6 +68,19 @@ struct FAAPI { } } + ///上报播放时长 + static func requestUploadPlayTime(shortPlayId: String, videoId: String, seconds: Int) { + let parameters: [String : Any] = [ + "video_id" : videoId, + "short_play_id" : shortPlayId, + "play_seconds" : seconds + ] + + FANetworkManager.manager.request(FABaseURL + "/uploadHistorySeconds", method: .post, parameters: parameters, isToast: false) { (response: FANetworkManager.Response) in + + } + } + ///收藏 static func requestShortCollect(isCollect: Bool, shortPlayId: String, videoId: String?, isLoding: Bool = true, success: (() -> Void)?, failure: (() -> Void)? = nil) { let path: String diff --git a/Fableon/Class/Home/C/FAHomeViewController.swift b/Fableon/Class/Home/C/FAHomeViewController.swift index b93db5c..f64ec44 100644 --- a/Fableon/Class/Home/C/FAHomeViewController.swift +++ b/Fableon/Class/Home/C/FAHomeViewController.swift @@ -55,6 +55,12 @@ class FAHomeViewController: FAViewController { button.setImage(UIImage(named: "首页搜索i_ic"), for: .normal) return button }() + + private lazy var playHistoryView: FAHomePlayHistoryView = { + let view = FAHomePlayHistoryView() + view.isHidden = true + return view + }() deinit { NotificationCenter.default.removeObserver(self) @@ -65,9 +71,7 @@ class FAHomeViewController: FAViewController { NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil) fa_setupLayout() - self.viewModel.requestHomeData { [weak self] in - self?.collectionView.reloadData() - } + requestAllData(completer: nil) } override func viewWillAppear(_ animated: Bool) { @@ -75,18 +79,20 @@ class FAHomeViewController: FAViewController { self.navigationController?.setNavigationBarHidden(true, animated: true) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + requestPlayHistory() + } + override func handleHeaderRefresh(_ completer: (() -> Void)?) { - self.viewModel.requestHomeData { [weak self] in - self?.collectionView.reloadData() + requestAllData { [weak self] in self?.collectionView.fa_endHeaderRefreshing() } } @objc private func networkStatusDidChangeNotification() { if self.viewModel.dataArr.isEmpty, FANetworkMonitor.manager.isReachable == true { - self.viewModel.requestHomeData { [weak self] in - self?.collectionView.reloadData() - } + requestAllData(completer: nil) } } } @@ -97,6 +103,7 @@ extension FAHomeViewController { view.addSubview(titleView) view.addSubview(searchButton) view.addSubview(collectionView) + view.addSubview(playHistoryView) titleView.snp.makeConstraints { make in make.left.equalToSuperview().offset(16) @@ -112,6 +119,12 @@ extension FAHomeViewController { make.left.right.bottom.equalToSuperview() make.top.equalToSuperview().offset(UIScreen.navBarHeight) } + + playHistoryView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-10) + } } } @@ -245,3 +258,26 @@ extension FAHomeViewController: FAWaterfallMutiSectionDelegate { } } + + +extension FAHomeViewController { + + private func requestAllData(completer: (() -> Void)?) { + self.viewModel.requestHomeData { [weak self] in + self?.collectionView.reloadData() + completer?() + } + requestPlayHistory() + } + + private func requestPlayHistory() { + self.viewModel.requestPlayHistory { [weak self] in + guard let self = self else { return } + if let playHistory = self.viewModel.playHistory { + self.playHistoryView.model = playHistory + self.playHistoryView.isHidden = false + } + } + } + +} diff --git a/Fableon/Class/Home/V/FAHomePlayHistoryView.swift b/Fableon/Class/Home/V/FAHomePlayHistoryView.swift new file mode 100644 index 0000000..268f924 --- /dev/null +++ b/Fableon/Class/Home/V/FAHomePlayHistoryView.swift @@ -0,0 +1,128 @@ +// +// FAHomePlayHistoryView.swift +// Fableon +// +// Created by 长沙鸿瑶 on 2025/10/16. +// + +import UIKit + +class FAHomePlayHistoryView: UIView { + + var model: FAShortPlayModel? { + didSet { + coverImageView.fa_setImage(model?.image_url) + titleLabel.text = model?.name + epLabel.text = "Last Watch:Ep.##".localizedReplace(text: model?.current_episode ?? "") + } + } + + private lazy var coverImageView: FAImageView = { + let imageView = FAImageView() + imageView.layer.cornerRadius = 6 + return imageView + }() + + private lazy var bgView: UIView = { + let view = UIView() + view.layer.cornerRadius = 12 + view.layer.masksToBounds = true + view.layer.borderWidth = 1 + view.layer.borderColor = UIColor.BDCEFF.cgColor + view.fa_addEffectView(style: .light) + return view + }() + + private lazy var bgColorView: UIView = { + let view = UIView() + view.backgroundColor = ._5_CA_8_FF_0_2 + return view + }() + + private lazy var playView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "Group 2420")) + imageView.setContentHuggingPriority(.required, for: .horizontal) + imageView.setContentCompressionResistancePriority(.required, for: .horizontal) + return imageView + }() + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .medium) + label.textColor = .FFFFFF + return label + }() + + private lazy var epLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 10, weight: .regular) + label.textColor = .FFFFFF + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + fa_setupLayout() + + let tap = UITapGestureRecognizer(target: self, action: #selector(handleBg)) + addGestureRecognizer(tap) + + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func handleBg() { + let vc = FAPlayerDetailViewController() + vc.shortPlayId = self.model?.short_play_id + self.viewController?.navigationController?.pushViewController(vc, animated: true) + } + +} + +extension FAHomePlayHistoryView { + private func fa_setupLayout() { + addSubview(bgView) + bgView.addSubview(bgColorView) + addSubview(coverImageView) + bgView.addSubview(playView) + bgView.addSubview(titleLabel) + bgView.addSubview(epLabel) + + bgView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalToSuperview().offset(24) + make.height.equalTo(57) + } + + bgColorView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + coverImageView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.left.equalToSuperview().offset(25) + make.width.equalTo(56) + make.height.equalTo(74) + } + + playView.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-10) + } + + titleLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(96) + make.top.equalToSuperview().offset(12) + make.right.lessThanOrEqualTo(playView.snp.left).offset(-10) + } + + epLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.bottom.equalToSuperview().offset(-12) + } + + } +} diff --git a/Fableon/Class/Home/VM/FAHomeViewModel.swift b/Fableon/Class/Home/VM/FAHomeViewModel.swift index ae64c98..fab74f3 100644 --- a/Fableon/Class/Home/VM/FAHomeViewModel.swift +++ b/Fableon/Class/Home/VM/FAHomeViewModel.swift @@ -17,6 +17,9 @@ class FAHomeViewModel: ObservableObject { @Published var homeNewItem: FAHomeModuleItem? @Published var recommendedItem: FAHomeModuleItem? + ///播放历史 + var playHistory: FAShortPlayModel? + func requestHomeData(completer: (() -> Void)?) { FAAPI.requestHomeModulesData { [weak self] list in guard let self = self else { return } @@ -100,6 +103,16 @@ class FAHomeViewModel: ObservableObject { completer?() } } + + func requestPlayHistory(completer: (() -> Void)?) { + FAAPI.requestPlayHistorys(page: 1, pageSize: 1) { [weak self] listModel in + guard let self = self else { return } + if let model = listModel?.list?.first { + self.playHistory = model + } + completer?() + } + } } extension FAHomeViewModel { diff --git a/Fableon/Class/Player/V/FAPlayerDetailCell.swift b/Fableon/Class/Player/V/FAPlayerDetailCell.swift index 4fb60d5..ae930bd 100644 --- a/Fableon/Class/Player/V/FAPlayerDetailCell.swift +++ b/Fableon/Class/Player/V/FAPlayerDetailCell.swift @@ -40,3 +40,17 @@ class FAPlayerDetailCell: JXPlayerListCell { } + +extension FAPlayerDetailCell { + + override func jx_playerReadyToPlay(_ player: JXPlayer) { + super.jx_playerReadyToPlay(player) + guard let videoInfo = self.model as? FAVideoInfoModel else { return } + + let time = TimeInterval(videoInfo.play_seconds ?? 0) / 1000 + let durationTime = self.durationTime + if time > 1, durationTime > 0 { + self.seekTo(progress: Float(time) / Float(durationTime)) + } + } +} diff --git a/Fableon/Class/Player/VM/FAShortDetailViewModel.swift b/Fableon/Class/Player/VM/FAShortDetailViewModel.swift index 0273f5e..f297f69 100644 --- a/Fableon/Class/Player/VM/FAShortDetailViewModel.swift +++ b/Fableon/Class/Player/VM/FAShortDetailViewModel.swift @@ -14,8 +14,9 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject { private(set) var dataArr: [FAShortDetailModel] = [] var shortPlayId: String = "" - + ///上一次上报播放时长的节点 + private var lastUploadTime: TimeInterval = 0 var previousEpisode: FAVideoInfoModel? { guard dataArr.count > 0 else { return nil } @@ -43,14 +44,55 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject { if let model = model { self.dataArr.removeAll() self.dataArr.append(model) - self.playerListVC?.reloadData { - self.playerListVC?.play() + self.playerListVC?.reloadData { [weak self] in + guard let self = self else { return } + var targetIndexPath = IndexPath(row: 0, section: 0) + + if let videoInfo = model.video_info { + var row: Int? + model.episodeList?.enumerated().forEach { + if $1.short_play_video_id == videoInfo.short_play_video_id { + row = $0 + } + } + if let row = row { + targetIndexPath = .init(row: row, section: 0) + } + } + + self.playerListVC?.scrollToItem(indexPath: targetIndexPath, animated: false) } } completer?(code ?? -1) } } + + override func playProgressDidChange(player: any JXPlayerCell, time: TimeInterval) { + if time > 1 { + (player.model as? FAVideoInfoModel)?.play_seconds = Int(time) * 1000 + } + + if (time >= lastUploadTime + 5 || time < lastUploadTime) && time >= 5 { + lastUploadTime = time + uploadPlayTime() + } + } + + private func uploadPlayTime() { + let videoInfo = self.currentCell?.model as? FAVideoInfoModel + let currentTime = self.currentCell?.currentTime ?? 0 + let duration = self.currentCell?.durationTime ?? 0 + + var time = currentTime + if currentTime >= duration { + time = 0 + } + + guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return } + FAAPI.requestUploadPlayTime(shortPlayId: shortPlayId, videoId: videoId, seconds: Int(time) * 1000) + } + } extension FAShortDetailViewModel { diff --git a/Fableon/Source/Assets.xcassets/color/#BDCEFF.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#BDCEFF.colorset/Contents.json new file mode 100644 index 0000000..b866ea5 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#BDCEFF.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xCE", + "red" : "0xBD" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Contents.json new file mode 100644 index 0000000..2dd0c49 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 2420@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 2420@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Group 2420@2x.png b/Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Group 2420@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e3dac5abf1869bbecd6e0962fb712d08c70a0629 GIT binary patch literal 5766 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 Eg0SigcmMzZ literal 0 HcmV?d00001 diff --git a/Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Group 2420@3x.png b/Fableon/Source/Assets.xcassets/image/Group 2420.imageset/Group 2420@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..3da70fe2cf3c13986c3f178f2eebce75f3a8f173 GIT binary patch literal 11456 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 a${zrEJ1Nt$dvwzP0000