一期
This commit is contained in:
parent
5b2b59ba12
commit
5ee82e3ab0
@ -88,14 +88,17 @@ struct NRNovelAPI {
|
||||
}
|
||||
|
||||
///查询章节数据 10011 金币不足 10005 提示
|
||||
static func requestChapterData(novelId: String, chapterId: String) async -> (NRReadChapterModel?, Int?) {
|
||||
static func requestChapterData(novelId: String, chapterId: String, isToast: Bool = false, isLoding: Bool = false) async -> (NRReadChapterModel?, Int?) {
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = NRNetwork.Parameters(path: "/novel/getChapterInfo")
|
||||
param.method = .get
|
||||
param.isToast = isToast
|
||||
param.isLoding = isLoding
|
||||
param.parameters = [
|
||||
"short_play_id" : novelId,
|
||||
"short_play_video_id" : chapterId,
|
||||
]
|
||||
|
||||
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRReadChapterModel>) in
|
||||
if response.isSuccess {
|
||||
continuation.resume(returning: (response.data, response.code))
|
||||
|
||||
@ -76,7 +76,7 @@ class NRImageView: UIImageView {
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
placeholderImageView.frame = .init(x: 0, y: 0, width: self.bounds.width * (2 / 3), height: self.bounds.height * (2 / 3))
|
||||
placeholderImageView.frame = .init(x: 0, y: 0, width: self.bounds.width * (1 / 3), height: self.bounds.height * (1 / 3))
|
||||
placeholderImageView.center = .init(x: self.bounds.width / 2, y: self.bounds.height / 2)
|
||||
}
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ extension NRExploreNovelContentViewController {
|
||||
|
||||
private func nr_setupUI() {
|
||||
view.addSubview(titleLabel)
|
||||
view.addSubview(moreButton)
|
||||
// view.addSubview(moreButton)
|
||||
view.addSubview(pageMenuView)
|
||||
view.addSubview(pageView)
|
||||
view.addSubview(lineView)
|
||||
@ -98,17 +98,18 @@ extension NRExploreNovelContentViewController {
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerY.equalTo(moreButton)
|
||||
make.top.equalToSuperview().offset(16)
|
||||
make.height.equalTo(24)
|
||||
}
|
||||
|
||||
moreButton.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
make.top.equalToSuperview().offset(16)
|
||||
}
|
||||
// moreButton.snp.makeConstraints { make in
|
||||
// make.right.equalToSuperview().offset(-12)
|
||||
// make.top.equalToSuperview().offset(16)
|
||||
// }
|
||||
|
||||
pageMenuView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalTo(moreButton.snp.bottom).offset(12)
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(12)
|
||||
make.height.equalTo(24)
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
//import JXPagingView
|
||||
import JXSegmentedView
|
||||
|
||||
class NRExploreNovelViewController: NRViewController {
|
||||
|
||||
@ -29,8 +29,25 @@ class NRReadChapterCatalogModel: NSObject, SmartCodable {
|
||||
@IgnoredKey
|
||||
var chapterModel: NRReadChapterModel?
|
||||
|
||||
///解析一个空白页面
|
||||
func parserEmpty() {
|
||||
let chapterModel = NRReadChapterModel()
|
||||
if self.is_lock == true {
|
||||
chapterModel.parserEmpty("Not unlocked yet".localized)
|
||||
} else {
|
||||
chapterModel.parserEmpty("Loading".localized)
|
||||
}
|
||||
self.chapterModel = chapterModel
|
||||
}
|
||||
|
||||
|
||||
///重新解析全部数据数据
|
||||
func parserAllData() {
|
||||
if self.chapterModel?.novel_txt == nil {
|
||||
parserEmpty()
|
||||
} else {
|
||||
self.chapterModel?.parser()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -52,11 +52,6 @@ class NRReadChapterModel: NSObject, SmartCodable {
|
||||
|
||||
///解析数据
|
||||
func parser() {
|
||||
guard novel_txt != nil else {
|
||||
self.parserEmpty()
|
||||
return
|
||||
}
|
||||
|
||||
let tempAttributes = NRNovelReadSetManager.manager.attributes(isTitle: false, isPageing: true)
|
||||
|
||||
guard !NSDictionary(dictionary: attributes).isEqual(to: tempAttributes) else { return }
|
||||
@ -77,8 +72,8 @@ class NRReadChapterModel: NSObject, SmartCodable {
|
||||
}
|
||||
|
||||
///解析一个空白页面
|
||||
func parserEmpty() {
|
||||
fullContent = NSMutableAttributedString(string: "\n\n\n\n\n" + "Not unlocked yet".localized, attributes: NRNovelReadSetManager.manager.attributes(isTitle: true))
|
||||
func parserEmpty(_ text: String) {
|
||||
fullContent = NSMutableAttributedString(string: "\n\n\n\n\n" + text, attributes: NRNovelReadSetManager.manager.attributes(isTitle: true))
|
||||
|
||||
let pageModel = NRReadPageModel()
|
||||
pageModel.content = fullContent
|
||||
|
||||
@ -33,6 +33,8 @@ class NRNovelReadContentTopView: UIView {
|
||||
var configuration = UIButton.Configuration.plain()
|
||||
configuration.contentInsets = .zero
|
||||
configuration.imagePadding = 12
|
||||
configuration.titleAlignment = .center
|
||||
configuration.titleLineBreakMode = .byTruncatingTail
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
@ -99,6 +101,7 @@ extension NRNovelReadContentTopView {
|
||||
backButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -145,6 +145,7 @@ extension NRNovelReadGradeView {
|
||||
nameLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(coverImageView).offset(8)
|
||||
make.left.equalTo(coverImageView.snp.right).offset(12)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||
}
|
||||
|
||||
starView.snp.makeConstraints { make in
|
||||
|
||||
@ -32,6 +32,7 @@ class NRNovelReadTopView: UIView {
|
||||
configuration.contentInsets = .zero
|
||||
configuration.image = UIImage(named: "arrow_left_icon_03")
|
||||
configuration.imagePadding = 12
|
||||
configuration.titleLineBreakMode = .byTruncatingTail
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
@ -62,6 +63,8 @@ class NRNovelReadTopView: UIView {
|
||||
self.viewModel?.showMoreView()
|
||||
}))
|
||||
button.setImage(UIImage(named: "more_icon_01"), for: .normal)
|
||||
button.setContentHuggingPriority(.required, for: .horizontal)
|
||||
button.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
return button
|
||||
}()
|
||||
|
||||
@ -148,6 +151,7 @@ extension NRNovelReadTopView {
|
||||
backButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.right.lessThanOrEqualTo(moreButton.snp.left).offset(-10)
|
||||
}
|
||||
|
||||
moreButton.snp.makeConstraints { make in
|
||||
|
||||
@ -257,13 +257,25 @@ extension NRNovelReaderCatalogView: UITableViewDelegate, UITableViewDataSource {
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
guard let novelId = self.novelModel?.id else { return }
|
||||
let currentModel = self.catalogDataArr[indexPath.row]
|
||||
|
||||
let lastIndex = indexPath.row - 1
|
||||
var lastModel: NRReadChapterCatalogModel?
|
||||
if lastIndex >= 0 {
|
||||
lastModel = self.catalogDataArr[lastIndex]
|
||||
}
|
||||
///上一集加锁状态禁止点击
|
||||
if lastModel?.is_lock == true { return }
|
||||
if lastModel?.is_lock == true {
|
||||
Task {
|
||||
let (_, code) = await NRNovelAPI.requestChapterData(novelId: novelId, chapterId: currentModel.id ?? "", isToast: true, isLoding: true)
|
||||
if code == 200 {
|
||||
self.didSelected?(indexPath.row)
|
||||
self.dismiss()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
self.didSelected?(indexPath.row)
|
||||
self.dismiss()
|
||||
|
||||
@ -142,8 +142,8 @@ extension NRNovelDetailCatalogViewController: UITableViewDelegate, UITableViewDa
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
guard let id = self.novelModel?.id else { return }
|
||||
let model = dataArr[indexPath.row]
|
||||
guard let novelId = self.novelModel?.id else { return }
|
||||
let currentModel = dataArr[indexPath.row]
|
||||
|
||||
let lastIndex = indexPath.row - 1
|
||||
var lastModel: NRReadChapterCatalogModel?
|
||||
@ -152,17 +152,27 @@ extension NRNovelDetailCatalogViewController: UITableViewDelegate, UITableViewDa
|
||||
}
|
||||
|
||||
if lastModel?.is_lock == true {
|
||||
|
||||
|
||||
Task {
|
||||
let (_, code) = await NRNovelAPI.requestChapterData(novelId: novelId, chapterId: currentModel.id ?? "", isToast: true, isLoding: true)
|
||||
if code == 200 {
|
||||
self.pushReadVC(currentModel)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let vc = NRNovelReaderViewController()
|
||||
vc.novelId = id
|
||||
vc.targetCatalogModel = model
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
self.pushReadVC(currentModel)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func pushReadVC(_ model: NRReadChapterCatalogModel) {
|
||||
guard let novelId = self.novelModel?.id else { return }
|
||||
|
||||
let vc = NRNovelReaderViewController()
|
||||
vc.novelId = novelId
|
||||
vc.targetCatalogModel = model
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NRNovelDetailCatalogViewController {
|
||||
|
||||
@ -156,8 +156,14 @@ extension NRNovelReaderViewController {
|
||||
|
||||
///获取下一页控制器
|
||||
func getBelowReadController() -> UIViewController? {
|
||||
let (catalogModel, pageModel) = self.viewModel.getBelowPageData()
|
||||
return getReadController(catalogModel: catalogModel, pageModel: pageModel)
|
||||
let (currentCatalogModel, _) = self.viewModel.getCurrentPageData()
|
||||
|
||||
if currentCatalogModel?.is_lock == true {
|
||||
return nil
|
||||
} else {
|
||||
let (catalogModel, pageModel) = self.viewModel.getBelowPageData()
|
||||
return getReadController(catalogModel: catalogModel, pageModel: pageModel)
|
||||
}
|
||||
}
|
||||
|
||||
///获取上一页控制器
|
||||
|
||||
@ -141,6 +141,11 @@ class NRNovelReaderViewController: NRViewController {
|
||||
self.viewModel.parserAllDataAndReloadPage(dismissMenu: false)
|
||||
}
|
||||
|
||||
func reloadData() {
|
||||
if let vc = self.getCurrentReadController() {
|
||||
setViewController(displayController: vc, isAbove: false, animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NRNovelReaderViewController {
|
||||
@ -227,9 +232,7 @@ extension NRNovelReaderViewController {
|
||||
//校验索引,避免越界
|
||||
self.viewModel.checkCurrentIndexPath()
|
||||
|
||||
if let vc = self.getCurrentReadController() {
|
||||
setViewController(displayController: vc, isAbove: false, animated: false)
|
||||
}
|
||||
self.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ extension NRNovelReadViewModel {
|
||||
func parserAllDataAndReloadPage(dismissMenu: Bool = true) {
|
||||
///重新解析全部数据
|
||||
self.chapterCatalogList.forEach {
|
||||
$0.chapterModel?.parser()
|
||||
$0.parserAllData()
|
||||
}
|
||||
|
||||
self.checkCurrentIndexPath()
|
||||
@ -101,7 +101,7 @@ extension NRNovelReadViewModel {
|
||||
let catalogModel = chapterCatalogList[currentSection]
|
||||
let listCount = catalogModel.chapterModel?.pageList?.count ?? 0
|
||||
|
||||
if listCount <= currentRow {
|
||||
if listCount <= currentRow, listCount > 0 {
|
||||
currentRow = listCount - 1
|
||||
}
|
||||
self.currentPageIndexPath = IndexPath(row: currentRow, section: currentSection)
|
||||
@ -118,7 +118,15 @@ extension NRNovelReadViewModel {
|
||||
|
||||
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) else { return }
|
||||
await MainActor.run {
|
||||
self.vc?.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //没有章节数据,先获取章节数据
|
||||
Task {
|
||||
guard let _ = await self.requestChapterData(catalogModel) else { return }
|
||||
@ -155,19 +163,35 @@ extension NRNovelReadViewModel {
|
||||
model.episode = catalogModel.episode
|
||||
model.page = pageModel.page?.intValue
|
||||
NRKeyedArchiver.archiver(folderName: kNRReadRecordFolderName, fileName: novelId, object: model)
|
||||
NRNovelAPI.requestUploadRecord(novelId, chapterId: catalogModel.id ?? "")
|
||||
|
||||
let lastTime = uploadRecordDate?.timeIntervalSince1970 ?? 0
|
||||
let nowTime = Date().timeIntervalSince1970
|
||||
|
||||
if lastTime == 0 || nowTime - lastTime > 5 {//间隔5秒才能上传一次记录
|
||||
uploadRecordDate = Date()
|
||||
NRNovelAPI.requestUploadRecord(novelId, chapterId: catalogModel.id ?? "")
|
||||
}
|
||||
}
|
||||
|
||||
///获取阅读记录
|
||||
func getReadRecord() -> NRNovelReadRecordModel? {
|
||||
guard novelId.count > 0 else { return nil }
|
||||
var recordModel = NRKeyedArchiver.unarchiver(folderName: kNRReadRecordFolderName, fileName: novelId) as? NRNovelReadRecordModel
|
||||
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: 网络请求
|
||||
@ -186,7 +210,7 @@ extension NRNovelReadViewModel {
|
||||
guard let list = await NRNovelAPI.requestChapterCatalogList(id: self.novelId) else { return }
|
||||
await MainActor.run {
|
||||
self.chapterCatalogList = list
|
||||
self.addUnlockPageData()
|
||||
self.setEmptyData()
|
||||
}
|
||||
}
|
||||
///获取章节数据
|
||||
@ -194,30 +218,29 @@ extension NRNovelReadViewModel {
|
||||
func requestChapterData(_ catalogModel: NRReadChapterCatalogModel) async -> NRReadChapterModel? {
|
||||
guard let chapterId = catalogModel.id else { return nil }
|
||||
|
||||
let myCoins = NRLoginManager.manager.userInfo?.totalCoins ?? 0
|
||||
let lockCoins = catalogModel.coins ?? 0
|
||||
|
||||
//金币不够解锁
|
||||
if catalogModel.is_lock == true, myCoins < lockCoins {
|
||||
return nil
|
||||
}
|
||||
|
||||
let (model, code) = await NRNovelAPI.requestChapterData(novelId: self.novelId, chapterId: chapterId)
|
||||
guard let model = model else { return nil }
|
||||
|
||||
model.parser()
|
||||
///判断为最后一个章节
|
||||
if chapterId == self.chapterCatalogList.last?.id {
|
||||
model.pageList?.append(NRReadPageModel.createReadFinishModel())
|
||||
Task {//开个新的线程更新下用户信息
|
||||
await NRLoginManager.manager.updateUserInfo()
|
||||
}
|
||||
|
||||
catalogModel.chapterModel = model
|
||||
if code == 200 {
|
||||
guard let model = model else { return nil }
|
||||
|
||||
if catalogModel.is_lock == true {
|
||||
catalogModel.is_lock = false
|
||||
self.addUnlockPageData()
|
||||
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 model
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
///预加载上下两页数据
|
||||
@ -249,16 +272,6 @@ extension NRNovelReadViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
///给目录列表中增加未解锁页面数据
|
||||
func addUnlockPageData() {
|
||||
for model in self.chapterCatalogList {
|
||||
if model.is_lock == true {
|
||||
let chapterModel = NRReadChapterModel()
|
||||
chapterModel.parserEmpty()
|
||||
model.chapterModel = chapterModel
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -44,6 +44,9 @@ class NRNovelReadViewModel: NSObject {
|
||||
return tap
|
||||
}()
|
||||
|
||||
///用来记录上报历史记录的时间
|
||||
var uploadRecordDate: Date?
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
import UIKit
|
||||
import IQKeyboardManagerSwift
|
||||
import IQKeyboardToolbarManager
|
||||
import MJRefresh
|
||||
|
||||
|
||||
extension AppDelegate {
|
||||
@ -19,6 +20,8 @@ extension AppDelegate {
|
||||
IQKeyboardManager.shared.resignOnTouchOutside = true
|
||||
IQKeyboardToolbarManager.shared.isEnabled = false
|
||||
|
||||
MJRefreshConfig.default.languageCode = NRLocalizedManager.shared.mjLocalizedKey
|
||||
|
||||
let appearance = UINavigationBar.defaultAppearance()
|
||||
UINavigationBar.appearance().scrollEdgeAppearance = appearance
|
||||
UINavigationBar.appearance().standardAppearance = appearance
|
||||
|
||||
@ -17,21 +17,34 @@ class NRKeyedArchiver: NSObject {
|
||||
class func archiver(folderName:String, fileName:String, object:AnyObject) {
|
||||
|
||||
var path = documentDirectoryPath + "/\(mineFolderName)/\(folderName)"
|
||||
guard creat_file(path: path) else { return } // 创建文件夹成功或者文件夹存在
|
||||
|
||||
if creat_file(path: path) { // 创建文件夹成功或者文件夹存在
|
||||
|
||||
path += "/\(fileName)"
|
||||
|
||||
NSKeyedArchiver.archiveRootObject(object, toFile: path)
|
||||
path += "/\(fileName)"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
do {
|
||||
let data = try NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: true)
|
||||
try data.write(to: url, options: .atomic)
|
||||
} catch let error {
|
||||
nrPrint(message: error)
|
||||
}
|
||||
}
|
||||
|
||||
/// 解档文件
|
||||
class func unarchiver(folderName:String, fileName:String) ->AnyObject? {
|
||||
class func unarchiver<T: NSObject & NSSecureCoding>(folderName:String, fileName:String, as type: T.Type) -> T? {
|
||||
|
||||
let path = documentDirectoryPath + "/\(mineFolderName)/\(folderName)/\(fileName)"
|
||||
|
||||
return NSKeyedUnarchiver.unarchiveObject(withFile: path) as AnyObject?
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
do {
|
||||
let data = try Data(contentsOf: url)
|
||||
let result = try NSKeyedUnarchiver.unarchivedObject(ofClass: type, from: data)
|
||||
return result
|
||||
|
||||
} catch let error {
|
||||
nrPrint(message: error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// 删除归档文件
|
||||
|
||||
@ -23,7 +23,7 @@ class NRLoginManager: NSObject {
|
||||
func updateUserInfo() async {
|
||||
guard let userInfo = await NRUserAPI.requestUserInfo() else { return }
|
||||
self.userInfo = userInfo
|
||||
UserDefaults.nr_setObject(token, forKey: kNRUserInfoDefaultsKey)
|
||||
UserDefaults.nr_setObject(userInfo, forKey: kNRUserInfoDefaultsKey)
|
||||
|
||||
await MainActor.run {
|
||||
NotificationCenter.default.post(name: NRLoginManager.userInfoUpdateNotification, object: nil)
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
"Bonus" = "Bonus";
|
||||
"Top Up" = "Top Up";
|
||||
"Language" = "Language";
|
||||
|
||||
"Loading" = "Loading";
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user