历史记录

This commit is contained in:
zeng 2025-10-16 16:02:30 +08:00
parent d1a1bde3aa
commit f0628bd609
12 changed files with 308 additions and 11 deletions

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
B8B1DA3824F2148CEEF9F162 /* Pods_Fableon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4958FEE55B4555A94F11F00 /* Pods_Fableon.framework */; }; B8B1DA3824F2148CEEF9F162 /* Pods_Fableon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4958FEE55B4555A94F11F00 /* Pods_Fableon.framework */; };
F301F6472E974B6300E76A90 /* FARecommendPlayerControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F301F6462E974B6300E76A90 /* FARecommendPlayerControlView.swift */; }; 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 */; }; F37103312E978F8C00E7F171 /* FACollectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37103302E978F8C00E7F171 /* FACollectViewController.swift */; };
F37103352E97929F00E7F171 /* FACollectCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F37103342E97929F00E7F171 /* FACollectCell.xib */; }; F37103352E97929F00E7F171 /* FACollectCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F37103342E97929F00E7F171 /* FACollectCell.xib */; };
F37103362E97929F00E7F171 /* FACollectCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37103332E97929F00E7F171 /* FACollectCell.swift */; }; 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; }; 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 = "<group>"; }; 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 = "<group>"; };
F301F6462E974B6300E76A90 /* FARecommendPlayerControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARecommendPlayerControlView.swift; sourceTree = "<group>"; }; F301F6462E974B6300E76A90 /* FARecommendPlayerControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARecommendPlayerControlView.swift; sourceTree = "<group>"; };
F34296912EA0C60200A58F99 /* FAHomePlayHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAHomePlayHistoryView.swift; sourceTree = "<group>"; };
F37103302E978F8C00E7F171 /* FACollectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectViewController.swift; sourceTree = "<group>"; }; F37103302E978F8C00E7F171 /* FACollectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectViewController.swift; sourceTree = "<group>"; };
F37103332E97929F00E7F171 /* FACollectCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectCell.swift; sourceTree = "<group>"; }; F37103332E97929F00E7F171 /* FACollectCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectCell.swift; sourceTree = "<group>"; };
F37103342E97929F00E7F171 /* FACollectCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FACollectCell.xib; sourceTree = "<group>"; }; F37103342E97929F00E7F171 /* FACollectCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FACollectCell.xib; sourceTree = "<group>"; };
@ -556,6 +558,7 @@
F371035D2E9E2E7400E7F171 /* FASearchRecommendCell.xib */, F371035D2E9E2E7400E7F171 /* FASearchRecommendCell.xib */,
F37103642E9E3ABC00E7F171 /* FASearchResultCell.swift */, F37103642E9E3ABC00E7F171 /* FASearchResultCell.swift */,
F37103652E9E3ABC00E7F171 /* FASearchResultCell.xib */, F37103652E9E3ABC00E7F171 /* FASearchResultCell.xib */,
F34296912EA0C60200A58F99 /* FAHomePlayHistoryView.swift */,
); );
path = V; path = V;
sourceTree = "<group>"; sourceTree = "<group>";
@ -852,10 +855,14 @@
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks-${CONFIGURATION}-input-files.xcfilelist",
); );
inputPaths = (
);
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks-${CONFIGURATION}-output-files.xcfilelist",
); );
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks.sh\"\n";
@ -923,6 +930,7 @@
F3DCC0572E8A8EE800D58007 /* FAMeViewController.swift in Sources */, F3DCC0572E8A8EE800D58007 /* FAMeViewController.swift in Sources */,
F3A792E82E77F8590097E0BC /* FAHomeModuleItem.swift in Sources */, F3A792E82E77F8590097E0BC /* FAHomeModuleItem.swift in Sources */,
F3DCC0452E89530200D58007 /* CGMutablePath+FARoundedCorner.swift in Sources */, F3DCC0452E89530200D58007 /* CGMutablePath+FARoundedCorner.swift in Sources */,
F34296922EA0C60200A58F99 /* FAHomePlayHistoryView.swift in Sources */,
F37103882EA08B6F00E7F171 /* FANetworkMonitor.swift in Sources */, F37103882EA08B6F00E7F171 /* FANetworkMonitor.swift in Sources */,
F37103672E9E3ABC00E7F171 /* FASearchResultCell.swift in Sources */, F37103672E9E3ABC00E7F171 /* FASearchResultCell.swift in Sources */,
F371037B2EA0820C00E7F171 /* FASettingViewController.swift in Sources */, F371037B2EA0820C00E7F171 /* FASettingViewController.swift in Sources */,

View File

@ -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<String>) in
}
}
/// ///
static func requestShortCollect(isCollect: Bool, shortPlayId: String, videoId: String?, isLoding: Bool = true, success: (() -> Void)?, failure: (() -> Void)? = nil) { static func requestShortCollect(isCollect: Bool, shortPlayId: String, videoId: String?, isLoding: Bool = true, success: (() -> Void)?, failure: (() -> Void)? = nil) {
let path: String let path: String

View File

@ -55,6 +55,12 @@ class FAHomeViewController: FAViewController {
button.setImage(UIImage(named: "首页搜索i_ic"), for: .normal) button.setImage(UIImage(named: "首页搜索i_ic"), for: .normal)
return button return button
}() }()
private lazy var playHistoryView: FAHomePlayHistoryView = {
let view = FAHomePlayHistoryView()
view.isHidden = true
return view
}()
deinit { deinit {
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
@ -65,9 +71,7 @@ class FAHomeViewController: FAViewController {
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil)
fa_setupLayout() fa_setupLayout()
self.viewModel.requestHomeData { [weak self] in requestAllData(completer: nil)
self?.collectionView.reloadData()
}
} }
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
@ -75,18 +79,20 @@ class FAHomeViewController: FAViewController {
self.navigationController?.setNavigationBarHidden(true, animated: true) self.navigationController?.setNavigationBarHidden(true, animated: true)
} }
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
requestPlayHistory()
}
override func handleHeaderRefresh(_ completer: (() -> Void)?) { override func handleHeaderRefresh(_ completer: (() -> Void)?) {
self.viewModel.requestHomeData { [weak self] in requestAllData { [weak self] in
self?.collectionView.reloadData()
self?.collectionView.fa_endHeaderRefreshing() self?.collectionView.fa_endHeaderRefreshing()
} }
} }
@objc private func networkStatusDidChangeNotification() { @objc private func networkStatusDidChangeNotification() {
if self.viewModel.dataArr.isEmpty, FANetworkMonitor.manager.isReachable == true { if self.viewModel.dataArr.isEmpty, FANetworkMonitor.manager.isReachable == true {
self.viewModel.requestHomeData { [weak self] in requestAllData(completer: nil)
self?.collectionView.reloadData()
}
} }
} }
} }
@ -97,6 +103,7 @@ extension FAHomeViewController {
view.addSubview(titleView) view.addSubview(titleView)
view.addSubview(searchButton) view.addSubview(searchButton)
view.addSubview(collectionView) view.addSubview(collectionView)
view.addSubview(playHistoryView)
titleView.snp.makeConstraints { make in titleView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16) make.left.equalToSuperview().offset(16)
@ -112,6 +119,12 @@ extension FAHomeViewController {
make.left.right.bottom.equalToSuperview() make.left.right.bottom.equalToSuperview()
make.top.equalToSuperview().offset(UIScreen.navBarHeight) 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
}
}
}
}

View File

@ -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 WatchEp.##".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)
}
}
}

View File

@ -17,6 +17,9 @@ class FAHomeViewModel: ObservableObject {
@Published var homeNewItem: FAHomeModuleItem? @Published var homeNewItem: FAHomeModuleItem?
@Published var recommendedItem: FAHomeModuleItem? @Published var recommendedItem: FAHomeModuleItem?
///
var playHistory: FAShortPlayModel?
func requestHomeData(completer: (() -> Void)?) { func requestHomeData(completer: (() -> Void)?) {
FAAPI.requestHomeModulesData { [weak self] list in FAAPI.requestHomeModulesData { [weak self] list in
guard let self = self else { return } guard let self = self else { return }
@ -100,6 +103,16 @@ class FAHomeViewModel: ObservableObject {
completer?() 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 { extension FAHomeViewModel {

View File

@ -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))
}
}
}

View File

@ -14,8 +14,9 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
private(set) var dataArr: [FAShortDetailModel] = [] private(set) var dataArr: [FAShortDetailModel] = []
var shortPlayId: String = "" var shortPlayId: String = ""
///
private var lastUploadTime: TimeInterval = 0
var previousEpisode: FAVideoInfoModel? { var previousEpisode: FAVideoInfoModel? {
guard dataArr.count > 0 else { return nil } guard dataArr.count > 0 else { return nil }
@ -43,14 +44,55 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
if let model = model { if let model = model {
self.dataArr.removeAll() self.dataArr.removeAll()
self.dataArr.append(model) self.dataArr.append(model)
self.playerListVC?.reloadData { self.playerListVC?.reloadData { [weak self] in
self.playerListVC?.play() 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) 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 { extension FAShortDetailViewModel {

View File

@ -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
}
}

View File

@ -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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -16,3 +16,4 @@
"Visit Website" = "Visit Website"; "Visit Website" = "Visit Website";
"Setting" = "Setting"; "Setting" = "Setting";
"Settings" = "Settings"; "Settings" = "Settings";
"Last WatchEp.##" = "Last WatchEp.##";