292 lines
11 KiB
Swift
292 lines
11 KiB
Swift
//
|
||
// NRNovelReadViewModel+Data.swift
|
||
// ReaderHive
|
||
//
|
||
// Created by 澜声世纪 on 2025/12/5.
|
||
//
|
||
|
||
import UIKit
|
||
|
||
///阅读历史文件目录
|
||
var kNRReadRecordFolderName: String {
|
||
let userId = NRLoginManager.manager.userInfo?.customer_id ?? ""
|
||
return "novel_read_record/\(userId)"
|
||
}
|
||
|
||
|
||
//MARK: 页面数据处理
|
||
extension NRNovelReadViewModel {
|
||
|
||
///获取指定页面的数据
|
||
func getPageData(_ indexPath: IndexPath) -> (NRReadChapterCatalogModel?, NRReadPageModel?) {
|
||
let section = indexPath.section
|
||
let row = indexPath.row
|
||
guard section >= 0, row >= 0 else { return (nil, nil) }
|
||
|
||
guard chapterCatalogList.count > section else { return (nil, nil) }
|
||
let catalogModel = chapterCatalogList[section]
|
||
guard let chapterModel = catalogModel.chapterModel else { return (catalogModel, nil) }
|
||
let pageCount = chapterModel.pageList?.count ?? 0
|
||
|
||
guard pageCount > row, let pageModel = chapterModel.pageList?[row] else { return (catalogModel, nil) }
|
||
pageModel.indexPath = indexPath
|
||
return (catalogModel, pageModel)
|
||
}
|
||
|
||
///获取当前页面的数据
|
||
func getCurrentPageData() -> (NRReadChapterCatalogModel?, NRReadPageModel?) {
|
||
return getPageData(self.currentPageIndexPath)
|
||
}
|
||
|
||
///获取下一页的数据
|
||
func getBelowPageData() -> (NRReadChapterCatalogModel?, NRReadPageModel?) {
|
||
var section = self.currentPageIndexPath.section
|
||
var row = self.currentPageIndexPath.row + 1
|
||
|
||
let (catalogModel, pageModel) = getPageData(IndexPath(row: row, section: section))
|
||
//下一页正常返回说明有下一页
|
||
if let catalogModel = catalogModel, let pageModel = pageModel {
|
||
return (catalogModel, pageModel)
|
||
}
|
||
//没有下一页,进入下一章节
|
||
section += 1
|
||
row = 0
|
||
return getPageData(IndexPath(row: row, section: section))
|
||
}
|
||
|
||
///获取上一页的数据
|
||
func getAbovePageData() -> (NRReadChapterCatalogModel?, NRReadPageModel?) {
|
||
var section = self.currentPageIndexPath.section
|
||
var row = self.currentPageIndexPath.row - 1
|
||
|
||
///没有上一页,进入上一章节的最后一页
|
||
if row < 0 {
|
||
section -= 1
|
||
guard section >= 0 else { return (nil, nil) }
|
||
guard chapterCatalogList.count > section else { return (nil, nil) }
|
||
let catalogModel = chapterCatalogList[section]
|
||
row = (catalogModel.chapterModel?.pageList?.count ?? 0) - 1
|
||
}
|
||
///没有上一章节,说明已经是第一页
|
||
if section < 0 {
|
||
return (nil, nil)
|
||
}
|
||
return getPageData(IndexPath(row: row, section: section))
|
||
}
|
||
|
||
///重新解析全部数据 并更新页面
|
||
func parserAllDataAndReloadPage(dismissMenu: Bool = true) {
|
||
///重新解析全部数据
|
||
self.chapterCatalogList.forEach {
|
||
$0.parserAllData()
|
||
}
|
||
|
||
self.checkCurrentIndexPath(haveText: true)
|
||
|
||
if let vc = self.vc?.getCurrentReadController() {
|
||
self.vc?.setViewController(displayController: vc, isAbove: false, animated: false, dismissMenu: dismissMenu)
|
||
}
|
||
}
|
||
|
||
///检查当前索引是否合法,不合法修改至合法
|
||
///主要用于更新全部数据
|
||
func checkCurrentIndexPath(haveText: Bool = false) {
|
||
var currentRow = self.currentPageIndexPath.row
|
||
var currentSection = self.currentPageIndexPath.section
|
||
|
||
if chapterCatalogList.count <= currentSection {
|
||
currentSection = chapterCatalogList.count - 1
|
||
}
|
||
|
||
let catalogModel = chapterCatalogList[currentSection]
|
||
let listCount = catalogModel.chapterModel?.pageList?.count ?? 0
|
||
|
||
if listCount <= currentRow, listCount > 0 {
|
||
currentRow = listCount - 1
|
||
}
|
||
if haveText {
|
||
let currentPage = catalogModel.chapterModel?.pageList?[currentRow]
|
||
if currentPage?.pageType != .textPart {
|
||
currentRow = currentRow - 1
|
||
}
|
||
}
|
||
|
||
self.currentPageIndexPath = IndexPath(row: currentRow, section: currentSection)
|
||
|
||
}
|
||
|
||
///跳转至指定章节的指定进度 进度为0-1的小数
|
||
func skip(chapterIndex: Int, chapterProgress: CGFloat = 0, dismissMenu: Bool = true) {
|
||
let (catalogModel, _) = getPageData(IndexPath(row: 0, section: chapterIndex))
|
||
|
||
guard let catalogModel = catalogModel else { return }
|
||
|
||
if let chapterModel = catalogModel.chapterModel {
|
||
|
||
guard let displayController = vc?.getReadController(catalogModel: catalogModel, pageModel: chapterModel.pageList?.first) else { return }
|
||
self.vc?.setViewController(displayController: displayController, isAbove: false, animated: false, dismissMenu: dismissMenu)
|
||
//缺少内容数据时,需要加载下真实数据
|
||
if chapterModel.novel_txt == nil {
|
||
Task {
|
||
guard let _ = await self.requestChapterData(catalogModel, isToast: true) else { return }
|
||
await MainActor.run {
|
||
self.vc?.reloadData()
|
||
}
|
||
}
|
||
}
|
||
} else { //没有章节数据,先获取章节数据
|
||
Task {
|
||
guard let _ = await self.requestChapterData(catalogModel, isToast: true) else { return }
|
||
await MainActor.run {
|
||
self.skip(chapterIndex: chapterIndex, chapterProgress: chapterProgress, dismissMenu: dismissMenu)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
///跳转至下一章节
|
||
func skipToNextChapter() {
|
||
let section = self.currentPageIndexPath.section + 1
|
||
self.skip(chapterIndex: section, dismissMenu: false)
|
||
}
|
||
|
||
///跳转至上一章节
|
||
func skipToPrevChapter() {
|
||
let section = self.currentPageIndexPath.section - 1
|
||
self.skip(chapterIndex: section, dismissMenu: false)
|
||
}
|
||
|
||
///保存阅读记录
|
||
func saveReadRecord() {
|
||
guard novelId.count > 0 else { return }
|
||
let (catalogModel, pageModel) = getCurrentPageData()
|
||
//未解锁章节不保存阅读记录
|
||
guard catalogModel?.is_lock == false else { return }
|
||
guard let catalogModel = catalogModel, let pageModel = pageModel else { return }
|
||
guard pageModel.pageType == .textPart else { return }
|
||
|
||
let model = NRNovelReadRecordModel()
|
||
model.short_play_video_id = catalogModel.id
|
||
model.episode = catalogModel.episode
|
||
model.page = pageModel.page?.intValue
|
||
NRKeyedArchiver.archiver(folderName: kNRReadRecordFolderName, fileName: novelId, object: model)
|
||
|
||
if self.lastUploadCatalogId == nil || self.lastUploadCatalogId != catalogModel.id {
|
||
self.lastUploadCatalogId = catalogModel.id
|
||
Task {
|
||
let result = await NRNovelAPI.requestUploadRecord(novelId, chapterId: catalogModel.id ?? "")
|
||
if !result {
|
||
self.lastUploadCatalogId = nil
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
///获取阅读记录
|
||
func getReadRecord() -> NRNovelReadRecordModel? {
|
||
guard novelId.count > 0 else { return nil }
|
||
var recordModel = NRKeyedArchiver.unarchiver(folderName: kNRReadRecordFolderName, fileName: novelId, as: NRNovelReadRecordModel.self)
|
||
//匹配本地记录与网络记录
|
||
if self.novelModel?.progress?.short_play_video_id != "0", self.novelModel?.progress?.short_play_video_id != recordModel?.short_play_video_id {
|
||
recordModel = self.novelModel?.progress
|
||
}
|
||
return recordModel
|
||
}
|
||
|
||
///设置空白页数据
|
||
func setEmptyData() {
|
||
for model in self.chapterCatalogList {
|
||
if model.chapterModel == nil {
|
||
model.parserEmpty()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//MARK: 网络请求
|
||
extension NRNovelReadViewModel {
|
||
///获取小说数据
|
||
func requestNovelDetail() async {
|
||
let (model, _, _) = await NRNovelAPI.requestDetail(self.novelId)
|
||
guard let model = model else { return }
|
||
await MainActor.run {
|
||
self.novelModel = model
|
||
}
|
||
}
|
||
|
||
///获取章节目录
|
||
func requestChapterCatalogList() async {
|
||
guard let list = await NRNovelAPI.requestChapterCatalogList(id: self.novelId) else { return }
|
||
await MainActor.run {
|
||
self.chapterCatalogList = list
|
||
self.setEmptyData()
|
||
}
|
||
}
|
||
///获取章节数据
|
||
@discardableResult
|
||
func requestChapterData(_ catalogModel: NRReadChapterCatalogModel, isToast: Bool = false) async -> NRReadChapterModel? {
|
||
guard let chapterId = catalogModel.id else { return nil }
|
||
|
||
let (model, code) = await NRNovelAPI.requestChapterData(novelId: self.novelId, chapterId: chapterId, isToast: isToast)
|
||
Task {//开个新的线程更新下用户信息
|
||
await NRLoginManager.manager.updateUserInfo()
|
||
}
|
||
|
||
if code == 200 {
|
||
guard let model = model else { return nil }
|
||
|
||
model.parser()
|
||
///判断为最后一个章节
|
||
if chapterId == self.chapterCatalogList.last?.id {
|
||
model.pageList?.append(NRReadPageModel.createReadFinishModel())
|
||
}
|
||
|
||
catalogModel.chapterModel = model
|
||
|
||
if catalogModel.is_lock == true {
|
||
catalogModel.is_lock = false
|
||
}
|
||
return model
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
///预加载上下两页数据
|
||
func preloadChapterData() {
|
||
Task {
|
||
await loadBelowChapterData()
|
||
await loadAboveChapterData()
|
||
}
|
||
}
|
||
|
||
///加载下一章节数据
|
||
func loadBelowChapterData() async {
|
||
//确保当前章节已解锁的情况下,才能加载下一章节
|
||
let (currentCatalogModel, _) = getCurrentPageData()
|
||
guard let currentCatalogModel = currentCatalogModel else { return }
|
||
guard currentCatalogModel.chapterModel?.novel_txt != nil else { return }
|
||
|
||
let (catalogModel, _) = getPageData(IndexPath(row: 0, section: self.currentPageIndexPath.section + 1))
|
||
guard let catalogModel = catalogModel else { return }
|
||
|
||
if catalogModel.chapterModel?.novel_txt == nil {
|
||
await requestChapterData(catalogModel)
|
||
}
|
||
|
||
}
|
||
|
||
///加载上一章节数据
|
||
func loadAboveChapterData() async {
|
||
let (catalogModel, _) = getPageData(IndexPath(row: 0, section: self.currentPageIndexPath.section - 1))
|
||
guard let catalogModel = catalogModel else { return }
|
||
|
||
if catalogModel.chapterModel?.novel_txt == nil {
|
||
await requestChapterData(catalogModel)
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|