增加上报阅读时长,修复BUG
This commit is contained in:
parent
1b625064e6
commit
82ec2a370f
@ -90,6 +90,7 @@
|
|||||||
85859E5C2EF3FC5F0020D282 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 85859E552EF3FC5F0020D282 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
85859E5C2EF3FC5F0020D282 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 85859E552EF3FC5F0020D282 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
85859E662EF3FC6E0020D282 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85859E632EF3FC6E0020D282 /* NotificationService.swift */; };
|
85859E662EF3FC6E0020D282 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85859E632EF3FC6E0020D282 /* NotificationService.swift */; };
|
||||||
85859E682EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85859E672EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift */; };
|
85859E682EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85859E672EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift */; };
|
||||||
|
85ACA3F92F28A7CD009D52B0 /* NRNovelReadViewModel+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85ACA3F82F28A7C8009D52B0 /* NRNovelReadViewModel+View.swift */; };
|
||||||
85C1786B2F050AA400A8A76E /* Poppins-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85C178682F050AA400A8A76E /* Poppins-Medium.ttf */; };
|
85C1786B2F050AA400A8A76E /* Poppins-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85C178682F050AA400A8A76E /* Poppins-Medium.ttf */; };
|
||||||
85C1786C2F050AA400A8A76E /* Poppins-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85C1786A2F050AA400A8A76E /* Poppins-SemiBold.ttf */; };
|
85C1786C2F050AA400A8A76E /* Poppins-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85C1786A2F050AA400A8A76E /* Poppins-SemiBold.ttf */; };
|
||||||
85C1786D2F050AA400A8A76E /* Poppins-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85C178672F050AA400A8A76E /* Poppins-Bold.ttf */; };
|
85C1786D2F050AA400A8A76E /* Poppins-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85C178672F050AA400A8A76E /* Poppins-Bold.ttf */; };
|
||||||
@ -600,6 +601,7 @@
|
|||||||
85859E622EF3FC6E0020D282 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
85859E622EF3FC6E0020D282 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
85859E632EF3FC6E0020D282 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
85859E632EF3FC6E0020D282 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||||
85859E672EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRHomeMustReadTodayTransformer.swift; sourceTree = "<group>"; };
|
85859E672EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRHomeMustReadTodayTransformer.swift; sourceTree = "<group>"; };
|
||||||
|
85ACA3F82F28A7C8009D52B0 /* NRNovelReadViewModel+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NRNovelReadViewModel+View.swift"; sourceTree = "<group>"; };
|
||||||
85C178672F050AA400A8A76E /* Poppins-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-Bold.ttf"; sourceTree = "<group>"; };
|
85C178672F050AA400A8A76E /* Poppins-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-Bold.ttf"; sourceTree = "<group>"; };
|
||||||
85C178682F050AA400A8A76E /* Poppins-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-Medium.ttf"; sourceTree = "<group>"; };
|
85C178682F050AA400A8A76E /* Poppins-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-Medium.ttf"; sourceTree = "<group>"; };
|
||||||
85C178692F050AA400A8A76E /* Poppins-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-Regular.ttf"; sourceTree = "<group>"; };
|
85C178692F050AA400A8A76E /* Poppins-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-Regular.ttf"; sourceTree = "<group>"; };
|
||||||
@ -1088,6 +1090,7 @@
|
|||||||
0373D9442ED57B7B0017DCC7 /* NRNovelDetailViewModel.swift */,
|
0373D9442ED57B7B0017DCC7 /* NRNovelDetailViewModel.swift */,
|
||||||
F34348EF2ED8381E00AA7E70 /* NRNovelReadViewModel.swift */,
|
F34348EF2ED8381E00AA7E70 /* NRNovelReadViewModel.swift */,
|
||||||
F34991262EE282660039E939 /* NRNovelReadViewModel+Data.swift */,
|
F34991262EE282660039E939 /* NRNovelReadViewModel+Data.swift */,
|
||||||
|
85ACA3F82F28A7C8009D52B0 /* NRNovelReadViewModel+View.swift */,
|
||||||
);
|
);
|
||||||
path = VM;
|
path = VM;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2615,6 +2618,7 @@
|
|||||||
039810B62ED42D840006E317 /* NRHomeNovelNewArrivalsCell.swift in Sources */,
|
039810B62ED42D840006E317 /* NRHomeNovelNewArrivalsCell.swift in Sources */,
|
||||||
0373D95A2ED593D50017DCC7 /* NRSearchRecordCell.swift in Sources */,
|
0373D95A2ED593D50017DCC7 /* NRSearchRecordCell.swift in Sources */,
|
||||||
0373D9582ED5935D0017DCC7 /* NRSearchRecordView.swift in Sources */,
|
0373D9582ED5935D0017DCC7 /* NRSearchRecordView.swift in Sources */,
|
||||||
|
85ACA3F92F28A7CD009D52B0 /* NRNovelReadViewModel+View.swift in Sources */,
|
||||||
F343490C2ED9751800AA7E70 /* NRReadChapterCatalogModel.swift in Sources */,
|
F343490C2ED9751800AA7E70 /* NRReadChapterCatalogModel.swift in Sources */,
|
||||||
F3B859862EE972F70095A9CC /* NRConsumptionRecordsCell.swift in Sources */,
|
F3B859862EE972F70095A9CC /* NRConsumptionRecordsCell.swift in Sources */,
|
||||||
F34990C72EDFCE500039E939 /* NRNovelReadGradeView.swift in Sources */,
|
F34990C72EDFCE500039E939 /* NRNovelReadGradeView.swift in Sources */,
|
||||||
|
|||||||
@ -162,6 +162,25 @@ struct NRStatAPI {
|
|||||||
|
|
||||||
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<String>) in }
|
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<String>) in }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///统计用户观看时长
|
||||||
|
static func nr_requestWatchNovelDuration(novelId: String, duration: Int, percent: Int) {
|
||||||
|
|
||||||
|
let parameters: [String : Any] = [
|
||||||
|
"request_id": "\(Int(Date().timeIntervalSince1970))",
|
||||||
|
"short_play_id" : novelId,
|
||||||
|
"duration" : duration,
|
||||||
|
"percent" : percent //观看百分比
|
||||||
|
]
|
||||||
|
|
||||||
|
var param = NRNetwork.Parameters(path: "/watchShortDuration")
|
||||||
|
param.method = .post
|
||||||
|
param.isLoding = false
|
||||||
|
param.isToast = false
|
||||||
|
param.parameters = parameters
|
||||||
|
|
||||||
|
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<String>) in }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NRStatAPI {
|
extension NRStatAPI {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ extension NRTargetType: TargetType {
|
|||||||
var path: String {
|
var path: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .request(let param):
|
case .request(let param):
|
||||||
return "/readerhive" + param.path
|
return NRBaseURLPrefix + param.path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,17 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
let NRBaseURL = "https://api-novel-test.guyantv.com"
|
||||||
|
let NRBaseURLPrefix = ""
|
||||||
|
//let NRBaseURL = "https://api-readerhive.readerhive.net"
|
||||||
|
//let NRBaseURLPrefix = "/readerhive"
|
||||||
|
#else
|
||||||
let NRBaseURL = "https://api-readerhive.readerhive.net"
|
let NRBaseURL = "https://api-readerhive.readerhive.net"
|
||||||
|
let NRBaseURLPrefix = "/readerhive"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let NRWebBaseURL = "https://www.readerhive.net"
|
let NRWebBaseURL = "https://www.readerhive.net"
|
||||||
|
|
||||||
|
|||||||
@ -153,9 +153,9 @@ extension UIViewController {
|
|||||||
titleColor: UIColor = UINavigationBar.titleWhiteColor,
|
titleColor: UIColor = UINavigationBar.titleWhiteColor,
|
||||||
isTranslucent: Bool = true
|
isTranslucent: Bool = true
|
||||||
) {
|
) {
|
||||||
self.navigationController?.navigationBar.nr_setTranslucent(isTranslucent: isTranslucent)
|
self.navigationController?.navigationBar.nr_setTranslucent(isTranslucent)
|
||||||
self.navigationController?.navigationBar.nr_setBackgroundColor(backgroundColor: backgroundColor)
|
self.navigationController?.navigationBar.nr_setBackgroundColor(backgroundColor)
|
||||||
self.navigationController?.navigationBar.nr_setTitleTextAttributes(titleTextAttributes: [
|
self.navigationController?.navigationBar.nr_setTitleTextAttributes([
|
||||||
NSAttributedString.Key.font : titleFont,
|
NSAttributedString.Key.font : titleFont,
|
||||||
NSAttributedString.Key.foregroundColor : titleColor
|
NSAttributedString.Key.foregroundColor : titleColor
|
||||||
])
|
])
|
||||||
|
|||||||
@ -22,10 +22,9 @@ class NRHomeNovelNextView: NRHomeNovelHeaderContentView {
|
|||||||
let itemHeight = 150 / 100 * itemWidth + 68
|
let itemHeight = 150 / 100 * itemWidth + 68
|
||||||
|
|
||||||
let layout = UICollectionViewFlowLayout()
|
let layout = UICollectionViewFlowLayout()
|
||||||
layout.scrollDirection = .horizontal
|
layout.itemSize = .init(width: floor(itemWidth), height: itemHeight)
|
||||||
layout.itemSize = .init(width: itemWidth, height: itemHeight)
|
layout.minimumLineSpacing = 18
|
||||||
layout.minimumLineSpacing = 15
|
layout.minimumInteritemSpacing = 15
|
||||||
layout.minimumInteritemSpacing = 18
|
|
||||||
return layout
|
return layout
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -36,10 +35,15 @@ class NRHomeNovelNextView: NRHomeNovelHeaderContentView {
|
|||||||
collectionView.dataSource = self
|
collectionView.dataSource = self
|
||||||
collectionView.showsHorizontalScrollIndicator = false
|
collectionView.showsHorizontalScrollIndicator = false
|
||||||
collectionView.contentInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
collectionView.contentInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||||
|
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
collectionView.register(NRHomeNovelNextViewCell.self, forCellWithReuseIdentifier: "cell")
|
collectionView.register(NRHomeNovelNextViewCell.self, forCellWithReuseIdentifier: "cell")
|
||||||
return collectionView
|
return collectionView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@MainActor deinit {
|
||||||
|
self.collectionView.removeObserver(self, forKeyPath: "contentSize")
|
||||||
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
self.titleLabel.text = "reader_home_title3".localized
|
self.titleLabel.text = "reader_home_title3".localized
|
||||||
@ -51,6 +55,16 @@ class NRHomeNovelNextView: NRHomeNovelHeaderContentView {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
let height = self.collectionView.contentSize.height + 1
|
||||||
|
|
||||||
|
collectionView.snp.updateConstraints { make in
|
||||||
|
make.height.equalTo(height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NRHomeNovelNextView {
|
extension NRHomeNovelNextView {
|
||||||
@ -60,7 +74,7 @@ extension NRHomeNovelNextView {
|
|||||||
|
|
||||||
collectionView.snp.makeConstraints { make in
|
collectionView.snp.makeConstraints { make in
|
||||||
make.edges.equalToSuperview()
|
make.edges.equalToSuperview()
|
||||||
make.height.equalTo(collectionViewLayout.itemSize.height * 2 + collectionViewLayout.minimumInteritemSpacing)
|
make.height.equalTo(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,8 @@ class NRStarGradeView: UIView {
|
|||||||
|
|
||||||
private lazy var cosmosView: CosmosView = {
|
private lazy var cosmosView: CosmosView = {
|
||||||
let view = CosmosView(settings: settings)
|
let view = CosmosView(settings: settings)
|
||||||
|
view.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
view.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
view.didTouchCosmos = { [weak self] rating in
|
view.didTouchCosmos = { [weak self] rating in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.didTouch?(rating)
|
self.didTouch?(rating)
|
||||||
|
|||||||
@ -21,7 +21,12 @@ class NRMeCoinsPackView: UIView {
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var iconImageView = UIImageView(image: UIImage(named: "gift_icon_01"))
|
private lazy var iconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "gift_icon_01"))
|
||||||
|
imageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
private lazy var titleLabel: UILabel = {
|
private lazy var titleLabel: UILabel = {
|
||||||
let label = NRLabel()
|
let label = NRLabel()
|
||||||
@ -41,7 +46,12 @@ class NRMeCoinsPackView: UIView {
|
|||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var indicatorImageView = UIImageView(image: UIImage(named: "arrow_right_icon_07"))
|
private lazy var indicatorImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "arrow_right_icon_07"))
|
||||||
|
imageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|||||||
@ -109,7 +109,7 @@ class NRDetailRechargeView: NRPanModalContentView {
|
|||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 12, weight: .regular)
|
label.font = .font(ofSize: 12, weight: .regular)
|
||||||
label.textColor = .black
|
label.textColor = .black
|
||||||
label.text = "Chapter Price".localized + ":"
|
label.text = "reader_chapter_price".localized + ":"
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@ -115,7 +115,11 @@ extension NRNovelDetailHeaderView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateNumLabel() {
|
private func updateNumLabel() {
|
||||||
|
if num < 1000 {
|
||||||
numLabel.text = NSNumber(value: num).toString(minimumFractionDigits: minimumFractionDigits)
|
numLabel.text = NSNumber(value: num).toString(minimumFractionDigits: minimumFractionDigits)
|
||||||
|
} else {
|
||||||
|
numLabel.text = NSNumber(value: num).formattedNumber()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class NRNovelReadBottomView: UIView {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var catalogButton: UIButton = {
|
lazy var catalogButton: UIButton = {
|
||||||
let button = self.createButton(title: "Catalog".localized, icon: UIImage(named: "catalog_icon_01"), nightIcon: UIImage(named: "catalog_icon_02"))
|
let button = self.createButton(title: "reader_book_catalog".localized, icon: UIImage(named: "catalog_icon_01"), nightIcon: UIImage(named: "catalog_icon_02"))
|
||||||
button.addAction(UIAction(handler: { [weak self] _ in
|
button.addAction(UIAction(handler: { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.viewModel?.showCatalogView()
|
self.viewModel?.showCatalogView()
|
||||||
|
|||||||
@ -18,6 +18,13 @@ class NRNovelReadFinishHeaderView: UICollectionReusableView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var didChangeContentHeight: ((_ height: CGFloat) -> Void)?
|
||||||
|
|
||||||
|
private lazy var contentView: NRScrollView = {
|
||||||
|
let contentView = NRScrollView()
|
||||||
|
contentView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
|
return contentView
|
||||||
|
}()
|
||||||
|
|
||||||
private lazy var coverBgView: UIView = {
|
private lazy var coverBgView: UIView = {
|
||||||
let view = NRGradientView()
|
let view = NRGradientView()
|
||||||
@ -55,6 +62,8 @@ class NRNovelReadFinishHeaderView: UICollectionReusableView {
|
|||||||
label.textColors = [UIColor.F_3912_F.cgColor, UIColor.FF_4_A_4_A.cgColor, UIColor.FA_9_B_1_F.cgColor]
|
label.textColors = [UIColor.F_3912_F.cgColor, UIColor.FF_4_A_4_A.cgColor, UIColor.FA_9_B_1_F.cgColor]
|
||||||
label.textStartPoint = .init(x: 0, y: 0.5)
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
label.textEndPoint = .init(x: 1, y: 0.5)
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
label.numberOfLines = 0
|
||||||
|
label.textAlignment = .center
|
||||||
label.text = "reader_book_finished".localized
|
label.text = "reader_book_finished".localized
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
@ -84,10 +93,14 @@ class NRNovelReadFinishHeaderView: UICollectionReusableView {
|
|||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 16, weight: .semibold)
|
label.font = .font(ofSize: 16, weight: .semibold)
|
||||||
label.textColor = .black
|
label.textColor = .black
|
||||||
label.text = "read_finish_list_title".localized
|
label.text = "reader_book_finished_list_title".localized
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.contentView.removeObserver(self, forKeyPath: "contentSize")
|
||||||
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
nr_setupUI()
|
nr_setupUI()
|
||||||
@ -103,19 +116,31 @@ class NRNovelReadFinishHeaderView: UICollectionReusableView {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
let height = self.contentView.contentSize.height + 1
|
||||||
|
self.didChangeContentHeight?(height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NRNovelReadFinishHeaderView {
|
extension NRNovelReadFinishHeaderView {
|
||||||
|
|
||||||
private func nr_setupUI() {
|
private func nr_setupUI() {
|
||||||
addSubview(coverBgView)
|
addSubview(contentView)
|
||||||
|
contentView.addSubview(coverBgView)
|
||||||
coverBgView.addSubview(coverImageView)
|
coverBgView.addSubview(coverImageView)
|
||||||
addSubview(coverDecorateView)
|
contentView.addSubview(coverDecorateView)
|
||||||
addSubview(titleLabel)
|
contentView.addSubview(titleLabel)
|
||||||
addSubview(textLabel)
|
contentView.addSubview(textLabel)
|
||||||
addSubview(gradeView)
|
contentView.addSubview(gradeView)
|
||||||
addSubview(lineView)
|
contentView.addSubview(lineView)
|
||||||
addSubview(listTitleLabel)
|
contentView.addSubview(listTitleLabel)
|
||||||
|
|
||||||
|
contentView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
coverBgView.snp.makeConstraints { make in
|
coverBgView.snp.makeConstraints { make in
|
||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
@ -138,12 +163,14 @@ extension NRNovelReadFinishHeaderView {
|
|||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
make.top.equalTo(coverBgView.snp.bottom).offset(20)
|
make.top.equalTo(coverBgView.snp.bottom).offset(20)
|
||||||
|
// make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||||
|
make.right.lessThanOrEqualTo(gradeView)
|
||||||
}
|
}
|
||||||
|
|
||||||
textLabel.snp.makeConstraints { make in
|
textLabel.snp.makeConstraints { make in
|
||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
make.right.lessThanOrEqualToSuperview().offset(16)
|
|
||||||
make.top.equalTo(titleLabel.snp.bottom).offset(6)
|
make.top.equalTo(titleLabel.snp.bottom).offset(6)
|
||||||
|
make.right.lessThanOrEqualTo(gradeView)
|
||||||
}
|
}
|
||||||
|
|
||||||
gradeView.snp.makeConstraints { make in
|
gradeView.snp.makeConstraints { make in
|
||||||
@ -162,6 +189,7 @@ extension NRNovelReadFinishHeaderView {
|
|||||||
listTitleLabel.snp.makeConstraints { make in
|
listTitleLabel.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(16)
|
make.left.equalToSuperview().offset(16)
|
||||||
make.top.equalTo(lineView.snp.bottom).offset(16)
|
make.top.equalTo(lineView.snp.bottom).offset(16)
|
||||||
|
make.bottom.equalToSuperview().offset(-16)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@ class NRNovelReadStarGradeView: UIView {
|
|||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 12, weight: .medium)
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
label.textColor = .black
|
label.textColor = .black
|
||||||
|
label.numberOfLines = 0
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -46,8 +47,11 @@ class NRNovelReadStarGradeView: UIView {
|
|||||||
view.filledImage = UIImage(named: "star_icon_04")
|
view.filledImage = UIImage(named: "star_icon_04")
|
||||||
view.emptyImage = UIImage(named: "star_icon_05")
|
view.emptyImage = UIImage(named: "star_icon_05")
|
||||||
view.updateOnTouch = true
|
view.updateOnTouch = true
|
||||||
view.fillMode = .full
|
// view.fillMode = .full
|
||||||
|
view.fillMode = .precise
|
||||||
view.didFinishTouching = self.didFinishTouchingGrade
|
view.didFinishTouching = self.didFinishTouchingGrade
|
||||||
|
view.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
view.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -102,6 +106,7 @@ extension NRNovelReadStarGradeView {
|
|||||||
|
|
||||||
label.snp.makeConstraints { make in
|
label.snp.makeConstraints { make in
|
||||||
make.centerY.equalToSuperview()
|
make.centerY.equalToSuperview()
|
||||||
|
make.right.lessThanOrEqualTo(gradeView.snp.left).offset(-10)
|
||||||
make.left.equalToSuperview().offset(12)
|
make.left.equalToSuperview().offset(12)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -119,6 +119,10 @@ extension NRNovelReadFinishViewController: UICollectionViewDelegate, UICollectio
|
|||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
||||||
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath) as! NRNovelReadFinishHeaderView
|
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath) as! NRNovelReadFinishHeaderView
|
||||||
|
view.didChangeContentHeight = { [weak self] height in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.collectionViewLayout.headerReferenceSize = .init(width: UIScreen.width, height: height)
|
||||||
|
}
|
||||||
view.novelModel = self.viewModel?.novelModel
|
view.novelModel = self.viewModel?.novelModel
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,7 @@ extension NRNovelReaderViewController {
|
|||||||
|
|
||||||
if let vc = viewController as? NRNovelReadBaseViewController {
|
if let vc = viewController as? NRNovelReadBaseViewController {
|
||||||
let model = vc.catalogModel
|
let model = vc.catalogModel
|
||||||
|
let pageModel = vc.pageModel
|
||||||
let lockCoins = model?.coins ?? 0
|
let lockCoins = model?.coins ?? 0
|
||||||
let myCoins = NRLoginManager.manager.userInfo?.totalCoins ?? 0
|
let myCoins = NRLoginManager.manager.userInfo?.totalCoins ?? 0
|
||||||
if model?.is_lock == true {
|
if model?.is_lock == true {
|
||||||
@ -59,6 +60,13 @@ extension NRNovelReaderViewController {
|
|||||||
self.viewModel.openRechargeView()
|
self.viewModel.openRechargeView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pageModel?.pageType != .textPart {
|
||||||
|
self.viewModel.statWatchNovelDuration()
|
||||||
|
} else {
|
||||||
|
self.viewModel.startWatchStartDate()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -114,6 +114,8 @@ class NRNovelReaderViewController: NRViewController {
|
|||||||
UIApplication.shared.isIdleTimerDisabled = true
|
UIApplication.shared.isIdleTimerDisabled = true
|
||||||
|
|
||||||
UIScreen.main.brightness = NRNovelReadSetManager.manager.brightness
|
UIScreen.main.brightness = NRNovelReadSetManager.manager.brightness
|
||||||
|
|
||||||
|
self.viewModel.startWatchStartDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillDisappear(_ animated: Bool) {
|
override func viewWillDisappear(_ animated: Bool) {
|
||||||
@ -124,6 +126,7 @@ class NRNovelReaderViewController: NRViewController {
|
|||||||
override func viewDidDisappear(_ animated: Bool) {
|
override func viewDidDisappear(_ animated: Bool) {
|
||||||
super.viewDidDisappear(animated)
|
super.viewDidDisappear(animated)
|
||||||
UIScreen.main.brightness = oldBrightness
|
UIScreen.main.brightness = oldBrightness
|
||||||
|
self.viewModel.statWatchNovelDuration()
|
||||||
}
|
}
|
||||||
|
|
||||||
override var prefersStatusBarHidden: Bool {
|
override var prefersStatusBarHidden: Bool {
|
||||||
@ -217,6 +220,8 @@ extension NRNovelReaderViewController {
|
|||||||
///装载数据
|
///装载数据
|
||||||
func loadData() {
|
func loadData() {
|
||||||
Task {
|
Task {
|
||||||
|
self.viewModel.statWatchNovelDuration()
|
||||||
|
|
||||||
NRHud.show()
|
NRHud.show()
|
||||||
//获取小说数据
|
//获取小说数据
|
||||||
await self.viewModel.requestNovelDetail()
|
await self.viewModel.requestNovelDetail()
|
||||||
@ -324,11 +329,13 @@ extension NRNovelReaderViewController {
|
|||||||
@objc private func willResignActiveNotification() {
|
@objc private func willResignActiveNotification() {
|
||||||
guard self.isViewDidAppear else { return }
|
guard self.isViewDidAppear else { return }
|
||||||
UIScreen.main.brightness = oldBrightness
|
UIScreen.main.brightness = oldBrightness
|
||||||
|
self.viewModel.statWatchNovelDuration()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func didBecomeActiveNotification() {
|
@objc private func didBecomeActiveNotification() {
|
||||||
guard self.isViewDidAppear else { return }
|
guard self.isViewDidAppear else { return }
|
||||||
UIScreen.main.brightness = NRNovelReadSetManager.manager.brightness
|
UIScreen.main.brightness = NRNovelReadSetManager.manager.brightness
|
||||||
|
self.viewModel.startWatchStartDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class NRNovelDetailViewModel: NSObject {
|
|||||||
var recommandDataArr: [NRNovelModel]?
|
var recommandDataArr: [NRNovelModel]?
|
||||||
|
|
||||||
func requestDetailData() async {
|
func requestDetailData() async {
|
||||||
let (model, id, msg) = await NRNovelAPI.requestDetail(novelId)
|
let (model, _, _) = await NRNovelAPI.requestDetail(novelId)
|
||||||
|
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
if let model = model {
|
if let model = model {
|
||||||
|
|||||||
@ -286,6 +286,33 @@ extension NRNovelReadViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func startWatchStartDate() {
|
||||||
|
let (model, pageModel) = self.getCurrentPageData()
|
||||||
|
guard let model = model else { return }
|
||||||
|
guard let pageModel = pageModel else { return }
|
||||||
|
if model.is_lock == false, self.watchStartDate == nil, pageModel.pageType == .textPart {
|
||||||
|
if self.vc?.isViewDidAppear == true {
|
||||||
|
self.watchStartDate = Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///统计观看时长
|
||||||
|
func statWatchNovelDuration() {
|
||||||
|
guard let watchStartDate = self.watchStartDate else { return }
|
||||||
|
self.watchStartDate = nil
|
||||||
|
let (catalogModel, _) = getCurrentPageData()
|
||||||
|
|
||||||
|
// guard let chapterModel = catalogModel?.chapterModel else { return }
|
||||||
|
let totalEp = CGFloat(self.novelModel?.episode_total ?? 1)
|
||||||
|
// let currentEp = CGFloat(NSNumber(pointer: chapterModel.episode ?? "0").floatValue)
|
||||||
|
let currentEp = CGFloat(self.currentPageIndexPath.section)
|
||||||
|
|
||||||
|
let nowDate = Date()
|
||||||
|
let duration = Int(nowDate.timeIntervalSince1970 - watchStartDate.timeIntervalSince1970)
|
||||||
|
let percent = currentEp / totalEp * 100
|
||||||
|
|
||||||
|
NRStatAPI.nr_requestWatchNovelDuration(novelId: self.novelId, duration: duration, percent: Int(percent))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
193
ReaderHive/Class/Novel/VM/NRNovelReadViewModel+View.swift
Normal file
193
ReaderHive/Class/Novel/VM/NRNovelReadViewModel+View.swift
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
//
|
||||||
|
// NRNovelReadViewModel+View.swift
|
||||||
|
// ReaderHive
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2026/1/27.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import HWPanModal
|
||||||
|
import YYCategories
|
||||||
|
|
||||||
|
extension NRNovelReadViewModel {
|
||||||
|
|
||||||
|
///退出阅读页面
|
||||||
|
func backReadPage() {
|
||||||
|
Task {
|
||||||
|
guard let isShowModel = await NRNovelAPI.requestShowRecommendPop(id: self.novelId), isShowModel.is_pop_up == true else {
|
||||||
|
_backReadPage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await MainActor.run {
|
||||||
|
let alert = NRAlert(title: "reader_recommend_book".localized, detail: "reader_recommend_book_tip".localized, topIconImage: UIImage(named: "alert_top_icon_01"), highlightButtonText: "reader_recommend_book_ok".localized)
|
||||||
|
alert.closeHandle = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self._backReadPage()
|
||||||
|
}
|
||||||
|
alert.highlightHandle = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
NRNovelAPI.requestConfirmRecommend(self.novelId)
|
||||||
|
self._backReadPage()
|
||||||
|
}
|
||||||
|
alert.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private func _backReadPage() {
|
||||||
|
self.vc?.navigationController?.popViewController(animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func showAllMenuView(isShow: Bool) {
|
||||||
|
self.showTopView(isShow: isShow)
|
||||||
|
self.showBottomView(isShow: isShow)
|
||||||
|
}
|
||||||
|
|
||||||
|
///显示顶部视图
|
||||||
|
func showTopView(isShow: Bool) {
|
||||||
|
guard showTop != isShow else { return }
|
||||||
|
self.showTop = isShow
|
||||||
|
self.vc?.setNeedsStatusBarAppearanceUpdate()
|
||||||
|
|
||||||
|
UIView.animate(withDuration: NRNovelReadSetManager.manager.animateDuration) { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if isShow {
|
||||||
|
self.topView?.transform = CGAffineTransform(translationX: 0, y: NRNovelReadSetManager.manager.topViewHeight)
|
||||||
|
} else {
|
||||||
|
self.topView?.transform = CGAffineTransform.identity
|
||||||
|
}
|
||||||
|
} completion: { _ in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///显示底部视图
|
||||||
|
func showBottomView(isShow: Bool) {
|
||||||
|
|
||||||
|
UIView.animate(withDuration: NRNovelReadSetManager.manager.animateDuration) { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if isShow {
|
||||||
|
self.bottomView?.transform = CGAffineTransform(translationX: 0, y: -NRNovelReadSetManager.manager.bottomViewHeight)
|
||||||
|
} else {
|
||||||
|
self.bottomView?.transform = CGAffineTransform.identity
|
||||||
|
}
|
||||||
|
} completion: { _ in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///显示更多工具栏
|
||||||
|
func showMoreView() {
|
||||||
|
guard let model = self.novelModel else { return }
|
||||||
|
|
||||||
|
let view = NRNovelReadGradeView()
|
||||||
|
view.model = model
|
||||||
|
view.present(in: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
///展示设置页面
|
||||||
|
func showSettingView() {
|
||||||
|
|
||||||
|
let view = NRNovelReadSettingView()
|
||||||
|
view.present(in: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
///展示目录
|
||||||
|
func showCatalogView() {
|
||||||
|
let (catalogModel, _) = self.getCurrentPageData()
|
||||||
|
|
||||||
|
let view = NRNovelReaderCatalogView()
|
||||||
|
view.novelModel = self.novelModel
|
||||||
|
view.currentCatalogModel = catalogModel
|
||||||
|
view.catalogDataArr = self.chapterCatalogList
|
||||||
|
view.didSelected = { [weak self] index in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if index != self.currentPageIndexPath.section {
|
||||||
|
self.skip(chapterIndex: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
///打开充值页面
|
||||||
|
func openRechargeView() {
|
||||||
|
guard self.popView == nil else { return }
|
||||||
|
let (catalogModel, _) = self.getCurrentPageData()
|
||||||
|
guard let catalogModel = catalogModel else { return }
|
||||||
|
self.statWatchNovelDuration()
|
||||||
|
|
||||||
|
self.payDataRequest = NRPayDataRequest()
|
||||||
|
if let model = NRIapManager.manager.payDateModel {
|
||||||
|
_openRechargeView(model, catalogModel)
|
||||||
|
self.payDataRequest?.requestProducts(isLoding: false) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
if let view = self.popView as? NRDetailRechargeView {
|
||||||
|
view.payModel = model
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.payDataRequest?.requestProducts(isLoding: true) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
self._openRechargeView(model, catalogModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func _openRechargeView(_ payModel: NRPayDateModel, _ catalogModel: NRReadChapterCatalogModel) {
|
||||||
|
guard self.popView == nil else { return }
|
||||||
|
|
||||||
|
NRStatAPI.nr_requestEventStat(orderCode: nil, shortPlayId: self.novelId, videoId: catalogModel.id, eventKey: .payTemplateDialog, errorMsg: nil, otherParamenters: [
|
||||||
|
"event_name" : "pay open"
|
||||||
|
])
|
||||||
|
|
||||||
|
let view = NRDetailRechargeView()
|
||||||
|
view.price = catalogModel.coins
|
||||||
|
view.payModel = payModel
|
||||||
|
view.worksId = self.novelId
|
||||||
|
view.chapterId = catalogModel.id
|
||||||
|
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.targetCatalogModel = catalogModel
|
||||||
|
self.vc?.loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// view.didDismissHandle = { [weak self] in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// self.showVipRetainAlert(catalogModel)
|
||||||
|
// }
|
||||||
|
view.present(in: nil)
|
||||||
|
|
||||||
|
self.popView = view
|
||||||
|
}
|
||||||
|
|
||||||
|
///展示挽留弹窗
|
||||||
|
private func showVipRetainAlert(_ catalogModel: NRReadChapterCatalogModel) {
|
||||||
|
payDataRequest = NRPayDataRequest()
|
||||||
|
|
||||||
|
payDataRequest?.requestVipRetainPayInfo { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
|
||||||
|
let view = NRVipRetainAlert()
|
||||||
|
view.model = model
|
||||||
|
view.worksId = self.novelId
|
||||||
|
view.chapterId = catalogModel.id
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.targetCatalogModel = catalogModel
|
||||||
|
self.vc?.loadData()
|
||||||
|
}
|
||||||
|
view.show(in: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -27,7 +27,7 @@ class NRNovelReadViewModel: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private(set) var showTop = false
|
var showTop = false
|
||||||
///章节目录列表
|
///章节目录列表
|
||||||
lazy var chapterCatalogList: [NRReadChapterCatalogModel] = []
|
lazy var chapterCatalogList: [NRReadChapterCatalogModel] = []
|
||||||
|
|
||||||
@ -49,190 +49,13 @@ class NRNovelReadViewModel: NSObject {
|
|||||||
|
|
||||||
weak var popView: UIView?
|
weak var popView: UIView?
|
||||||
|
|
||||||
private var payDataRequest = NRPayDataRequest()
|
var payDataRequest: NRPayDataRequest?
|
||||||
|
///用来统计观看时长
|
||||||
|
var watchStartDate: Date?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extension NRNovelReadViewModel {
|
|
||||||
|
|
||||||
///退出阅读页面
|
|
||||||
func backReadPage() {
|
|
||||||
Task {
|
|
||||||
guard let isShowModel = await NRNovelAPI.requestShowRecommendPop(id: self.novelId), isShowModel.is_pop_up == true else {
|
|
||||||
_backReadPage()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
await MainActor.run {
|
|
||||||
let alert = NRAlert(title: "reader_recommend_book".localized, detail: "reader_recommend_book_tip".localized, topIconImage: UIImage(named: "alert_top_icon_01"), highlightButtonText: "reader_recommend_book_ok".localized)
|
|
||||||
alert.closeHandle = { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
self._backReadPage()
|
|
||||||
}
|
|
||||||
alert.highlightHandle = { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
NRNovelAPI.requestConfirmRecommend(self.novelId)
|
|
||||||
self._backReadPage()
|
|
||||||
}
|
|
||||||
alert.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainActor
|
|
||||||
private func _backReadPage() {
|
|
||||||
self.vc?.navigationController?.popViewController(animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func showAllMenuView(isShow: Bool) {
|
|
||||||
self.showTopView(isShow: isShow)
|
|
||||||
self.showBottomView(isShow: isShow)
|
|
||||||
}
|
|
||||||
|
|
||||||
///显示顶部视图
|
|
||||||
func showTopView(isShow: Bool) {
|
|
||||||
guard showTop != isShow else { return }
|
|
||||||
self.showTop = isShow
|
|
||||||
self.vc?.setNeedsStatusBarAppearanceUpdate()
|
|
||||||
|
|
||||||
UIView.animate(withDuration: NRNovelReadSetManager.manager.animateDuration) { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
if isShow {
|
|
||||||
self.topView?.transform = CGAffineTransform(translationX: 0, y: NRNovelReadSetManager.manager.topViewHeight)
|
|
||||||
} else {
|
|
||||||
self.topView?.transform = CGAffineTransform.identity
|
|
||||||
}
|
|
||||||
} completion: { _ in
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///显示底部视图
|
|
||||||
func showBottomView(isShow: Bool) {
|
|
||||||
|
|
||||||
UIView.animate(withDuration: NRNovelReadSetManager.manager.animateDuration) { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
if isShow {
|
|
||||||
self.bottomView?.transform = CGAffineTransform(translationX: 0, y: -NRNovelReadSetManager.manager.bottomViewHeight)
|
|
||||||
} else {
|
|
||||||
self.bottomView?.transform = CGAffineTransform.identity
|
|
||||||
}
|
|
||||||
} completion: { _ in
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///显示更多工具栏
|
|
||||||
func showMoreView() {
|
|
||||||
guard let model = self.novelModel else { return }
|
|
||||||
|
|
||||||
let view = NRNovelReadGradeView()
|
|
||||||
view.model = model
|
|
||||||
view.present(in: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
///展示设置页面
|
|
||||||
func showSettingView() {
|
|
||||||
|
|
||||||
let view = NRNovelReadSettingView()
|
|
||||||
view.present(in: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
///展示目录
|
|
||||||
func showCatalogView() {
|
|
||||||
let (catalogModel, _) = self.getCurrentPageData()
|
|
||||||
|
|
||||||
let view = NRNovelReaderCatalogView()
|
|
||||||
view.novelModel = self.novelModel
|
|
||||||
view.currentCatalogModel = catalogModel
|
|
||||||
view.catalogDataArr = self.chapterCatalogList
|
|
||||||
view.didSelected = { [weak self] index in
|
|
||||||
guard let self = self else { return }
|
|
||||||
if index != self.currentPageIndexPath.section {
|
|
||||||
self.skip(chapterIndex: index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
view.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
///打开充值页面
|
|
||||||
func openRechargeView() {
|
|
||||||
guard self.popView == nil else { return }
|
|
||||||
let (catalogModel, _) = self.getCurrentPageData()
|
|
||||||
guard let catalogModel = catalogModel else { return }
|
|
||||||
|
|
||||||
if let model = NRIapManager.manager.payDateModel {
|
|
||||||
_openRechargeView(model, catalogModel)
|
|
||||||
|
|
||||||
self.payDataRequest.requestProducts(isLoding: false) { [weak self] model in
|
|
||||||
guard let self = self else { return }
|
|
||||||
guard let model = model else { return }
|
|
||||||
if let view = self.popView as? NRDetailRechargeView {
|
|
||||||
view.payModel = model
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.payDataRequest.requestProducts(isLoding: true) { [weak self] model in
|
|
||||||
guard let self = self else { return }
|
|
||||||
guard let model = model else { return }
|
|
||||||
self._openRechargeView(model, catalogModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func _openRechargeView(_ payModel: NRPayDateModel, _ catalogModel: NRReadChapterCatalogModel) {
|
|
||||||
guard self.popView == nil else { return }
|
|
||||||
|
|
||||||
NRStatAPI.nr_requestEventStat(orderCode: nil, shortPlayId: self.novelId, videoId: catalogModel.id, eventKey: .payTemplateDialog, errorMsg: nil, otherParamenters: [
|
|
||||||
"event_name" : "pay open"
|
|
||||||
])
|
|
||||||
|
|
||||||
let view = NRDetailRechargeView()
|
|
||||||
view.price = catalogModel.coins
|
|
||||||
view.payModel = payModel
|
|
||||||
view.worksId = self.novelId
|
|
||||||
view.chapterId = catalogModel.id
|
|
||||||
|
|
||||||
view.buyFinishHandle = { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
self.targetCatalogModel = catalogModel
|
|
||||||
self.vc?.loadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// view.didDismissHandle = { [weak self] in
|
|
||||||
// guard let self = self else { return }
|
|
||||||
// self.showVipRetainAlert(catalogModel)
|
|
||||||
// }
|
|
||||||
view.present(in: nil)
|
|
||||||
|
|
||||||
self.popView = view
|
|
||||||
}
|
|
||||||
|
|
||||||
///展示挽留弹窗
|
|
||||||
private func showVipRetainAlert(_ catalogModel: NRReadChapterCatalogModel) {
|
|
||||||
|
|
||||||
payDataRequest.requestVipRetainPayInfo { [weak self] model in
|
|
||||||
guard let self = self else { return }
|
|
||||||
guard let model = model else { return }
|
|
||||||
|
|
||||||
let view = NRVipRetainAlert()
|
|
||||||
view.model = model
|
|
||||||
view.worksId = self.novelId
|
|
||||||
view.chapterId = catalogModel.id
|
|
||||||
view.buyFinishHandle = { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
self.targetCatalogModel = catalogModel
|
|
||||||
self.vc?.loadData()
|
|
||||||
}
|
|
||||||
view.show(in: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: UIGestureRecognizerDelegate
|
//MARK: UIGestureRecognizerDelegate
|
||||||
extension NRNovelReadViewModel: UIGestureRecognizerDelegate {
|
extension NRNovelReadViewModel: UIGestureRecognizerDelegate {
|
||||||
|
|||||||
@ -85,7 +85,7 @@ class NRCoinsPackConfirmView: NRPanModalContentView {
|
|||||||
var configuration = UIButton.Configuration.plain()
|
var configuration = UIButton.Configuration.plain()
|
||||||
configuration.background.image = UIImage(named: "gradient_color_01")
|
configuration.background.image = UIImage(named: "gradient_color_01")
|
||||||
configuration.background.cornerRadius = 24
|
configuration.background.cornerRadius = 24
|
||||||
configuration.attributedTitle = AttributedString("Continue".localized, attributes: AttributeContainer([
|
configuration.attributedTitle = AttributedString("reader_continue".localized, attributes: AttributeContainer([
|
||||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||||
.foregroundColor : UIColor.white
|
.foregroundColor : UIColor.white
|
||||||
]))
|
]))
|
||||||
|
|||||||
@ -15,7 +15,8 @@ class NRStoreVipCell: UICollectionViewCell {
|
|||||||
var model: NRPayItem? {
|
var model: NRPayItem? {
|
||||||
didSet {
|
didSet {
|
||||||
titleLabel.text = model?.brief
|
titleLabel.text = model?.brief
|
||||||
desLabel.text = model?.nr_description
|
// desLabel.text = model?.nr_description
|
||||||
|
desLabel.text = "reader_my_vip_tips".localized
|
||||||
|
|
||||||
if let coins = model?.send_coins, coins > 0 {
|
if let coins = model?.send_coins, coins > 0 {
|
||||||
extraLabel.text = "+\(coins) \("reader_extra".localized)"
|
extraLabel.text = "+\(coins) \("reader_extra".localized)"
|
||||||
@ -35,10 +36,6 @@ class NRStoreVipCell: UICollectionViewCell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let price = offerPrice {
|
if let price = offerPrice {
|
||||||
// let priceString = NSMutableAttributedString(string: currency + price)
|
|
||||||
// priceString.yy_font = .font(ofSize: 28, weight: .init(800))
|
|
||||||
// priceLabel.attributedText = priceString
|
|
||||||
//
|
|
||||||
let oldPriceStr = NSMutableAttributedString(string: oldPrice)
|
let oldPriceStr = NSMutableAttributedString(string: oldPrice)
|
||||||
oldPriceStr.yy_strikethroughColor = oldPriceLabel.textColor
|
oldPriceStr.yy_strikethroughColor = oldPriceLabel.textColor
|
||||||
oldPriceStr.yy_strikethroughStyle = .double
|
oldPriceStr.yy_strikethroughStyle = .double
|
||||||
|
|||||||
@ -18,6 +18,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
nr_registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
|
nr_registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: NRNetworkReachableManager.networkStatusDidChangeNotification, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: NRNetworkReachableManager.networkStatusDidChangeNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(localizedDidChangeNotification), name: NRLocalizedManager.localizedDidChangeNotification, object: nil)
|
||||||
|
|
||||||
setConfig()
|
setConfig()
|
||||||
|
|
||||||
@ -51,6 +52,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
self.refreshAppData()
|
self.refreshAppData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func localizedDidChangeNotification() {
|
||||||
|
self.refreshAppData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension AppDelegate {
|
private extension AppDelegate {
|
||||||
@ -63,5 +67,7 @@ private extension AppDelegate {
|
|||||||
NRIapManager.manager.preloadingProducts()
|
NRIapManager.manager.preloadingProducts()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class NRCoinsPackAlert: NRAlert {
|
|||||||
titleLabel.numberOfLines = 0
|
titleLabel.numberOfLines = 0
|
||||||
titleLabel.font = .font(ofSize: 20, weight: .medium)
|
titleLabel.font = .font(ofSize: 20, weight: .medium)
|
||||||
titleLabel.textColor = .F_9710_D
|
titleLabel.textColor = .F_9710_D
|
||||||
titleLabel.text = "coins_pack_alert_title".localized
|
titleLabel.text = "reader_my_daily_reward".localized
|
||||||
|
|
||||||
let coinsView = UIView()
|
let coinsView = UIView()
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,7 @@ struct NREmpty {
|
|||||||
view?.actionBtnBackGroundColor = .clear
|
view?.actionBtnBackGroundColor = .clear
|
||||||
view?.actionBtnMargin = 16
|
view?.actionBtnMargin = 16
|
||||||
view?.actionBtnHorizontalMargin = 25
|
view?.actionBtnHorizontalMargin = 25
|
||||||
|
view?.actionBtnWidth = 0
|
||||||
|
|
||||||
return view!
|
return view!
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class NRUserInfo: NSObject, SmartCodable, NSSecureCoding {
|
|||||||
if let name = family_name, !name.isEmpty {
|
if let name = family_name, !name.isEmpty {
|
||||||
return name
|
return name
|
||||||
} else {
|
} else {
|
||||||
return "Visitor"
|
return "reader_visitor".localized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,11 +62,11 @@ class NRNovelReadSetManager: NSObject {
|
|||||||
var paragraphSpacing: CGFloat {
|
var paragraphSpacing: CGFloat {
|
||||||
switch self.readSet.paragraphSpacingType {
|
switch self.readSet.paragraphSpacingType {
|
||||||
case .small:
|
case .small:
|
||||||
return 15
|
return 6
|
||||||
case .standard:
|
case .standard:
|
||||||
return 17
|
return 8
|
||||||
case .large:
|
case .large:
|
||||||
return 19
|
return 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -149,13 +149,15 @@
|
|||||||
"reader_open_notification_later" = "Later";
|
"reader_open_notification_later" = "Later";
|
||||||
"reader_default" = "Default";
|
"reader_default" = "Default";
|
||||||
"reader_login" = "Log in";
|
"reader_login" = "Log in";
|
||||||
"Chapter Price" = "Chapter Price";
|
"reader_chapter_price" = "Chapter Price";
|
||||||
|
"reader_my_vip_tips" = "Unrestricted access to all series!";
|
||||||
|
"reader_visitor" = "Visitor";
|
||||||
|
|
||||||
"vip_retain_alert_text" = "Unlock every show you love!";
|
"vip_retain_alert_text" = "Unlock every show you love!";
|
||||||
"reader_log_out_content" = "Are you sure you want to log out?";
|
"reader_log_out_content" = "Are you sure you want to log out?";
|
||||||
"detail_collect_alert_title" = "Delete This Book?";
|
"detail_collect_alert_title" = "Delete This Book?";
|
||||||
"detail_collect_alert_text" = "Confirm to delete this book from the list";
|
"detail_collect_alert_text" = "Confirm to delete this book from the list";
|
||||||
"coins_pack_alert_title" = "Daily Reward is waiting!";
|
"reader_my_daily_reward" = "Daily Reward is waiting!";
|
||||||
"reader_open_notification" = "Enable Notifications";
|
"reader_open_notification" = "Enable Notifications";
|
||||||
"reader_open_notification_info" = "Stay informed with popular recommendations and latest updates!";
|
"reader_open_notification_info" = "Stay informed with popular recommendations and latest updates!";
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user