1
@ -87,6 +87,15 @@
|
||||
85606A9A2EEBC26F005D989D /* NRCoinsPackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A992EEBC26F005D989D /* NRCoinsPackViewController.swift */; };
|
||||
85606A9C2EEBE243005D989D /* NRCoinsPackHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A9B2EEBE243005D989D /* NRCoinsPackHeaderView.swift */; };
|
||||
85606A9F2EEBE95A005D989D /* NRDashedLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A9E2EEBE95A005D989D /* NRDashedLineView.swift */; };
|
||||
85CF941D2EEBFEA6006467E3 /* NRCoinsPackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */; };
|
||||
85CF941F2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */; };
|
||||
85CF94212EEC050D006467E3 /* NRCoinsPackBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */; };
|
||||
85CF94232EEC08F4006467E3 /* NRCoinsPackClaimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94222EEC08F4006467E3 /* NRCoinsPackClaimView.swift */; };
|
||||
85CF94252EEC09AE006467E3 /* NRCoinsPackClaimCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94242EEC09AE006467E3 /* NRCoinsPackClaimCell.swift */; };
|
||||
85CF94272EED1734006467E3 /* NRHomeCoinsPackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94262EED1734006467E3 /* NRHomeCoinsPackButton.swift */; };
|
||||
85CF94292EED4664006467E3 /* NRVipRetainAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */; };
|
||||
85CF942B2EED47F2006467E3 /* NRVipRetainItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */; };
|
||||
85CF942D2EED5204006467E3 /* NRPayAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */; };
|
||||
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */; };
|
||||
F34348B12ED5B9A400AA7E70 /* NRExploreNovelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */; };
|
||||
F34348B32ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B22ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift */; };
|
||||
@ -309,6 +318,15 @@
|
||||
85606A992EEBC26F005D989D /* NRCoinsPackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackViewController.swift; sourceTree = "<group>"; };
|
||||
85606A9B2EEBE243005D989D /* NRCoinsPackHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackHeaderView.swift; sourceTree = "<group>"; };
|
||||
85606A9E2EEBE95A005D989D /* NRDashedLineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRDashedLineView.swift; sourceTree = "<group>"; };
|
||||
85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackModel.swift; sourceTree = "<group>"; };
|
||||
85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackReceiveModel.swift; sourceTree = "<group>"; };
|
||||
85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackBuyView.swift; sourceTree = "<group>"; };
|
||||
85CF94222EEC08F4006467E3 /* NRCoinsPackClaimView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackClaimView.swift; sourceTree = "<group>"; };
|
||||
85CF94242EEC09AE006467E3 /* NRCoinsPackClaimCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackClaimCell.swift; sourceTree = "<group>"; };
|
||||
85CF94262EED1734006467E3 /* NRHomeCoinsPackButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRHomeCoinsPackButton.swift; sourceTree = "<group>"; };
|
||||
85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainAlert.swift; sourceTree = "<group>"; };
|
||||
85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainItemView.swift; sourceTree = "<group>"; };
|
||||
85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRPayAlertModel.swift; sourceTree = "<group>"; };
|
||||
C3BEE224CB3F55939653D26D /* Pods-NovelReader.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NovelReader.debug.xcconfig"; path = "Target Support Files/Pods-NovelReader/Pods-NovelReader.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreViewController.swift; sourceTree = "<group>"; };
|
||||
F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreNovelViewController.swift; sourceTree = "<group>"; };
|
||||
@ -501,6 +519,7 @@
|
||||
F34349042ED9442300AA7E70 /* NRReadPageModel.swift */,
|
||||
F34990BE2EDEDDCF0039E939 /* NRCategoryModel.swift */,
|
||||
F34991282EE285660039E939 /* NRShowRecommendPop.swift */,
|
||||
85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */,
|
||||
);
|
||||
path = M;
|
||||
sourceTree = "<group>";
|
||||
@ -515,6 +534,8 @@
|
||||
F34348E02ED70A2200AA7E70 /* NRNovelDetailHeaderView+NovelCoverInfo.swift */,
|
||||
F34348E22ED70D2300AA7E70 /* NRNovelDetailHeaderView+Data.swift */,
|
||||
F3B859302EE66B950095A9CC /* NRDetailRechargeView.swift */,
|
||||
85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */,
|
||||
85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -797,6 +818,7 @@
|
||||
0373D95D2ED59C430017DCC7 /* NRSearchResultView.swift */,
|
||||
0373D95F2ED59DA10017DCC7 /* NRSearchResultCell.swift */,
|
||||
F34990BC2EDEC24E0039E939 /* NRStarGradeView.swift */,
|
||||
85CF94262EED1734006467E3 /* NRHomeCoinsPackButton.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -1091,6 +1113,9 @@
|
||||
85606A932EEBB3FE005D989D /* NRCoinsPackConfirmTitleView.swift */,
|
||||
85606A952EEBB733005D989D /* NRCoinsPackConfirmTipView.swift */,
|
||||
85606A9B2EEBE243005D989D /* NRCoinsPackHeaderView.swift */,
|
||||
85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */,
|
||||
85CF94222EEC08F4006467E3 /* NRCoinsPackClaimView.swift */,
|
||||
85CF94242EEC09AE006467E3 /* NRCoinsPackClaimCell.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -1102,6 +1127,8 @@
|
||||
F3B859802EE9716E0095A9CC /* NRBuyRecordsModel.swift */,
|
||||
F3B8598A2EEA51540095A9CC /* NRRewardCoinsModel.swift */,
|
||||
F3B859922EEA63CD0095A9CC /* NROrderRecordsModel.swift */,
|
||||
85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */,
|
||||
85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */,
|
||||
);
|
||||
path = M;
|
||||
sourceTree = "<group>";
|
||||
@ -1250,10 +1277,14 @@
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks.sh\"\n";
|
||||
@ -1283,6 +1314,7 @@
|
||||
F34349142EDA9AE900AA7E70 /* NRNovelReadSettingView.swift in Sources */,
|
||||
F3B859632EE91B850095A9CC /* NRStoreCoinsView.swift in Sources */,
|
||||
F34348BD2ED68F2B00AA7E70 /* NRExploreNovelViewModel.swift in Sources */,
|
||||
85CF94212EEC050D006467E3 /* NRCoinsPackBuyView.swift in Sources */,
|
||||
F3B8595F2EE910020095A9CC /* NRPayDataRequest.swift in Sources */,
|
||||
F3B859692EE91BD70095A9CC /* NRStoreCoinsPackCell.swift in Sources */,
|
||||
F34991102EE1708C0039E939 /* NRWebViewController+Script.swift in Sources */,
|
||||
@ -1290,6 +1322,8 @@
|
||||
F34348BF2ED691C100AA7E70 /* NRExploreNovelGenresViewController.swift in Sources */,
|
||||
039810B02ED3F50C0006E317 /* NRHomeNovelMustReadTodayCell.swift in Sources */,
|
||||
0373D9452ED57B7B0017DCC7 /* NRNovelDetailViewModel.swift in Sources */,
|
||||
85CF942D2EED5204006467E3 /* NRPayAlertModel.swift in Sources */,
|
||||
85CF942B2EED47F2006467E3 /* NRVipRetainItemView.swift in Sources */,
|
||||
0398107C2ED055260006E317 /* AppDelegate+Config.swift in Sources */,
|
||||
F34348B52ED5C6F800AA7E70 /* NRTableView.swift in Sources */,
|
||||
F34348DB2ED6F80A00AA7E70 /* NRNovelReaderViewController.swift in Sources */,
|
||||
@ -1299,6 +1333,7 @@
|
||||
85606A922EEBB336005D989D /* NRCoinsPackConfirmItemView.swift in Sources */,
|
||||
0398106A2ED0505D0006E317 /* NRNetworkReachableManager.swift in Sources */,
|
||||
F34348C32ED6A20700AA7E70 /* NRExploreNovelContentViewController.swift in Sources */,
|
||||
85CF94232EEC08F4006467E3 /* NRCoinsPackClaimView.swift in Sources */,
|
||||
F34991292EE285660039E939 /* NRShowRecommendPop.swift in Sources */,
|
||||
0373D9642ED5ABBC0017DCC7 /* NREmpty.swift in Sources */,
|
||||
F3B859572EE9072C0095A9CC /* NRIapManager.swift in Sources */,
|
||||
@ -1309,6 +1344,7 @@
|
||||
F3B859862EE972F70095A9CC /* NRConsumptionRecordsCell.swift in Sources */,
|
||||
F34990C72EDFCE500039E939 /* NRNovelReadGradeView.swift in Sources */,
|
||||
039810B42ED428F20006E317 /* NRHomeNovelNewArrivalsView.swift in Sources */,
|
||||
85CF94272EED1734006467E3 /* NRHomeCoinsPackButton.swift in Sources */,
|
||||
F34991012EE1593A0039E939 /* NRMeHeaderView.swift in Sources */,
|
||||
F3B8598F2EEA5B1C0095A9CC /* NROrderRecordsPageViewController.swift in Sources */,
|
||||
F34991052EE165EA0039E939 /* NRMeItem.swift in Sources */,
|
||||
@ -1331,6 +1367,7 @@
|
||||
039810D02ED54D370006E317 /* NRHomeCategoryTagView.swift in Sources */,
|
||||
F34348E32ED70D2F00AA7E70 /* NRNovelDetailHeaderView+Data.swift in Sources */,
|
||||
0398107F2ED055D10006E317 /* NRLoginManager.swift in Sources */,
|
||||
85CF941D2EEBFEA6006467E3 /* NRCoinsPackModel.swift in Sources */,
|
||||
F34348D52ED6E16500AA7E70 /* NRMyListNovelViewController.swift in Sources */,
|
||||
F34991162EE176640039E939 /* NRNovelHistoryViewController.swift in Sources */,
|
||||
F34348F52ED848EC00AA7E70 /* NRNovelReadPageViewController.swift in Sources */,
|
||||
@ -1338,10 +1375,12 @@
|
||||
F349910E2EE1707C0039E939 /* NRWebViewController.swift in Sources */,
|
||||
F34990BB2EDEB2080039E939 /* NRHomeNovelViewModel.swift in Sources */,
|
||||
F34990BD2EDEC24E0039E939 /* NRStarGradeView.swift in Sources */,
|
||||
85CF941F2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift in Sources */,
|
||||
F34348C12ED693E900AA7E70 /* NRExploreNovelGenresCell.swift in Sources */,
|
||||
0373D94B2ED582EE0017DCC7 /* NRNovelAPI.swift in Sources */,
|
||||
039810832ED0563D0006E317 /* NRUserInfo.swift in Sources */,
|
||||
0373D9472ED57F3F0017DCC7 /* UINavigationBar+NRAdd.swift in Sources */,
|
||||
85CF94252EEC09AE006467E3 /* NRCoinsPackClaimCell.swift in Sources */,
|
||||
0373D94D2ED583A80017DCC7 /* NRNovelModel.swift in Sources */,
|
||||
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */,
|
||||
F3B859732EE94A760095A9CC /* NRAppWebViewController.swift in Sources */,
|
||||
@ -1375,6 +1414,7 @@
|
||||
F343492C2EDE72F300AA7E70 /* NRHomeAPI.swift in Sources */,
|
||||
F3B859372EE6750B0095A9CC /* NRLanguageViewController.swift in Sources */,
|
||||
F34348E12ED70A2700AA7E70 /* NRNovelDetailHeaderView+NovelCoverInfo.swift in Sources */,
|
||||
85CF94292EED4664006467E3 /* NRVipRetainAlert.swift in Sources */,
|
||||
F3B859522EE906A90095A9CC /* JXIAPManager.swift in Sources */,
|
||||
F34349012ED93A9B00AA7E70 /* NRReadChapterModel.swift in Sources */,
|
||||
F34348DF2ED7049E00AA7E70 /* NRNovelDetailHeaderView.swift in Sources */,
|
||||
|
||||
@ -127,4 +127,52 @@ struct NRStoreAPI {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///金币包数据
|
||||
static func requestCoinsPackData(completer: ((_ model: NRCoinsPackModel?) -> Void)?) {
|
||||
|
||||
var param = NRNetwork.Parameters(path: "/getReceiveDayCoinInfo")
|
||||
param.method = .get
|
||||
|
||||
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRCoinsPackModel>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
///领取金币包金币
|
||||
static func requestReceiveCoinsPackCoins(id: String?, completer: ((_ finish: Bool) -> Void)?) {
|
||||
|
||||
var param = NRNetwork.Parameters(path: "/receiveDayCoin")
|
||||
param.method = .post
|
||||
param.isLoding = true
|
||||
if let id = id {
|
||||
param.parameters = [
|
||||
"id" : id
|
||||
]
|
||||
}
|
||||
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<String>) in
|
||||
if response.isSuccess {
|
||||
completer?(true)
|
||||
} else {
|
||||
completer?(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///挽留支付项
|
||||
static func requestVipRetainPayInfo(completer: ((_ model: NRPayAlertModel?) -> Void)?) {
|
||||
|
||||
var param = NRNetwork.Parameters(path: "/getRetainVipPaySetting")
|
||||
param.method = .get
|
||||
param.isLoding = true
|
||||
|
||||
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRPayAlertModel>) in
|
||||
if let _ = response.data?.info {
|
||||
completer?(response.data)
|
||||
} else {
|
||||
completer?(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ let NRBaseURL = "https://api-readerhive.readerhive.net"
|
||||
|
||||
let NRWebBaseURL = "https://www.readerhive.net"
|
||||
|
||||
let NRCampaignWebURL = "https://campaign.readerhive.com"
|
||||
let NRCampaignWebURL = "https://campaign.readerhive.net"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -9,11 +9,56 @@ import UIKit
|
||||
|
||||
class NRDashedLineView: UIView {
|
||||
|
||||
var isHorizontal: Bool = true // 控制是横向还是纵向绘制
|
||||
enum Direction : Int {
|
||||
case vertical = 0
|
||||
case horizontal = 1
|
||||
}
|
||||
|
||||
var lineWidth: CGFloat = 1.0
|
||||
var direction: Direction = .horizontal {
|
||||
didSet {
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
var lineColor: UIColor = .black.withAlphaComponent(0.25)
|
||||
var lineColor: UIColor = .black.withAlphaComponent(0.25) {
|
||||
didSet {
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
var lineWidth: CGFloat = 1.0 {
|
||||
didSet {
|
||||
invalidateIntrinsicContentSize()
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
// 控制虚线线段长度的属性
|
||||
var dashLength: CGFloat = 2 {
|
||||
didSet {
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
// 控制虚线间隔长度的属性
|
||||
var dashGap: CGFloat = 2 {
|
||||
didSet {
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return CGSize(width: lineWidth, height: lineWidth)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.backgroundColor = .clear
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
@ -22,21 +67,22 @@ class NRDashedLineView: UIView {
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
// 设置线条颜色和宽度
|
||||
context.setStrokeColor(UIColor.red.cgColor)
|
||||
context.setStrokeColor(lineColor.cgColor)
|
||||
context.setLineWidth(lineWidth)
|
||||
|
||||
// 设置虚线样式
|
||||
context.setLineDash(phase: 0, lengths: [2, 2]) // 长度为6的线段和间隔为3的空白
|
||||
context.setLineDash(phase: 0, lengths: [dashLength, dashGap])
|
||||
|
||||
// 根据方向绘制路径
|
||||
if isHorizontal {
|
||||
// 横向绘制
|
||||
context.move(to: CGPoint(x: 0, y: self.bounds.midY))
|
||||
context.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.midY))
|
||||
} else {
|
||||
// 纵向绘制
|
||||
context.move(to: CGPoint(x: self.bounds.midX, y: 0))
|
||||
context.addLine(to: CGPoint(x: self.bounds.midX, y: self.bounds.height))
|
||||
switch direction {
|
||||
case .horizontal:
|
||||
let y = self.bounds.midY
|
||||
context.move(to: CGPoint(x: 0, y: y))
|
||||
context.addLine(to: CGPoint(x: self.bounds.width, y: y))
|
||||
case .vertical:
|
||||
let x = self.bounds.midX
|
||||
context.move(to: CGPoint(x: x, y: 0))
|
||||
context.addLine(to: CGPoint(x: x, y: self.bounds.height))
|
||||
}
|
||||
|
||||
// 绘制路径
|
||||
|
||||
@ -14,7 +14,7 @@ class NRAppWebViewController: NRWebViewController {
|
||||
|
||||
private var receiveDataCount = 0
|
||||
|
||||
var theme: String? = "theme_3"
|
||||
var theme: String? = "theme_2"
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
@ -45,8 +45,7 @@ extension NRAppWebViewController {
|
||||
receiveDataCount += 1
|
||||
if receiveDataCount > 10 { return }
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
var dic = [
|
||||
"token" : NRLoginManager.manager.token?.token ?? "",
|
||||
"time_zone" : NRTargetType.timeZone(),
|
||||
@ -68,6 +67,8 @@ extension NRAppWebViewController {
|
||||
self.webView.evaluateJavaScript(js) { [weak self] _, error in
|
||||
guard let self = self else { return }
|
||||
if error != nil {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.receiveDataFromNative()
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,16 @@ class NRHomeViewController: NRViewController {
|
||||
|
||||
lazy var novelVC = NRHomeNovelViewController()
|
||||
|
||||
lazy var coinsPackButton: NRHomeCoinsPackButton = {
|
||||
let button = NRHomeCoinsPackButton()
|
||||
button.addAction(UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = NRCoinsPackViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
@ -47,6 +57,7 @@ extension NRHomeViewController {
|
||||
view.addSubview(titleView)
|
||||
addChild(novelVC)
|
||||
view.addSubview(novelVC.view)
|
||||
view.addSubview(coinsPackButton)
|
||||
|
||||
searchButton.snp.makeConstraints { make in
|
||||
make.height.equalTo(44)
|
||||
@ -63,6 +74,11 @@ extension NRHomeViewController {
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
|
||||
coinsPackButton.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-16)
|
||||
make.bottom.equalToSuperview().offset(-50)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -50,7 +50,6 @@ class NRSearchViewController: NRViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.backgroundImageView.isHidden = true
|
||||
textView.becomeFirstResponder()
|
||||
|
||||
|
||||
nr_setupUI()
|
||||
@ -61,6 +60,11 @@ class NRSearchViewController: NRViewController {
|
||||
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
textView.becomeFirstResponder()
|
||||
}
|
||||
|
||||
private func search(_ text: String) {
|
||||
if text.isEmpty {
|
||||
homeView.isHidden = false
|
||||
|
||||
85
ReaderHive/Class/Home/V/NRHomeCoinsPackButton.swift
Normal file
@ -0,0 +1,85 @@
|
||||
//
|
||||
// NRHomeCoinsPackButton.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/13.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYCategories
|
||||
|
||||
class NRHomeCoinsPackButton: UIControl {
|
||||
|
||||
private lazy var bgImageView = UIImageView(image: UIImage(named: "calendar_icon_03"))
|
||||
|
||||
private lazy var borderView: UIView = {
|
||||
let view = UIView()
|
||||
view.layer.cornerRadius = 14
|
||||
view.layer.masksToBounds = true
|
||||
view.backgroundColor = UIColor.black.withAlphaComponent(0.25)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var textBgView: UIImageView = {
|
||||
let view = UIImageView(image: UIImage(named: "gradient_color_01"))
|
||||
view.layer.cornerRadius = 12
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var textLabel: UILabel = {
|
||||
let label = NRLabel()
|
||||
label.font = .font(ofSize: 12, weight: .bold).withBoldItalic()
|
||||
label.textColors = [UIColor.FFEECA.cgColor, UIColor.FECE_62.cgColor]
|
||||
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||
label.text = "Daily Coins".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NRHomeCoinsPackButton {
|
||||
|
||||
private func nr_setupUI() {
|
||||
addSubview(bgImageView)
|
||||
addSubview(borderView)
|
||||
borderView.addSubview(textBgView)
|
||||
textBgView.addSubview(textLabel)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-1)
|
||||
}
|
||||
|
||||
borderView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
textBgView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(2)
|
||||
make.top.equalToSuperview().offset(2)
|
||||
make.center.equalToSuperview()
|
||||
make.height.equalTo(24)
|
||||
make.width.equalTo(84)
|
||||
}
|
||||
|
||||
textLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(8)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,7 +13,8 @@ class NRSearchResultCell: UICollectionViewCell {
|
||||
var model: NRNovelModel? {
|
||||
didSet {
|
||||
coverImageView.nr_setImage(model?.image_url)
|
||||
desLabel.text = model?.name
|
||||
nameLabel.text = model?.name
|
||||
desLabel.text = model?.nr_description
|
||||
|
||||
tagStackView.nr_removeAllArrangedSubview()
|
||||
|
||||
@ -85,13 +86,6 @@ class NRSearchResultCell: UICollectionViewCell {
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
categoryView.text = "Satisfying"
|
||||
nameLabel.text = "My Dark Romeo"
|
||||
desLabel.text = "Haunted by fading memories, a man navigates a labyrinth of dreams and reality, uncovering truths that blur the line between past and present."
|
||||
|
||||
tagStackView.addArrangedSubview(categoryView)
|
||||
tagStackView.addArrangedSubview(hotView)
|
||||
// categoryView.addSubview(hotView)
|
||||
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
22
ReaderHive/Class/Novel/M/NRPayAlertModel.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// NRPayAlertModel.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/13.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class NRPayAlertModel: NSObject, SmartCodable {
|
||||
|
||||
required override init() { }
|
||||
|
||||
var coins_modal_easy_close: Bool?
|
||||
|
||||
var info: NRPayItem?
|
||||
|
||||
var forced_recharge: Bool?
|
||||
|
||||
var close_label: String?
|
||||
}
|
||||
@ -7,17 +7,218 @@
|
||||
|
||||
import UIKit
|
||||
import HWPanModal
|
||||
import SnapKit
|
||||
|
||||
class NRDetailRechargeView: NRPanModalContentView {
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
var didDismissHandle: (() -> Void)?
|
||||
|
||||
var payModel: NRPayDateModel? {
|
||||
didSet {
|
||||
self.stackView.nr_removeAllArrangedSubview()
|
||||
self.vipView.dataArr = payModel?.list_sub_vip ?? []
|
||||
self.coinsView.setDataArr(payModel?.list_coins ?? [])
|
||||
|
||||
if let sort = payModel?.sort, sort.count > 0 {
|
||||
sort.forEach {
|
||||
if $0 == .vip, payModel?.list_sub_vip?.isEmpty == false {
|
||||
self.stackView.addArrangedSubview(self.vipView)
|
||||
} else if $0 == .coin, payModel?.list_coins?.isEmpty == false {
|
||||
self.stackView.addArrangedSubview(self.coinsView)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if payModel?.list_sub_vip?.isEmpty == false {
|
||||
self.stackView.addArrangedSubview(self.vipView)
|
||||
}
|
||||
if payModel?.list_coins?.isEmpty == false {
|
||||
self.stackView.addArrangedSubview(self.coinsView)
|
||||
}
|
||||
}
|
||||
|
||||
// self.stackView.addArrangedSubview(self.tipView)
|
||||
|
||||
self.setNeedsLayoutUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
var worksId: String? {
|
||||
didSet {
|
||||
coinsView.shortPlayId = worksId
|
||||
vipView.shortPlayId = worksId
|
||||
}
|
||||
}
|
||||
|
||||
var chapterId: String? {
|
||||
didSet {
|
||||
coinsView.videoId = chapterId
|
||||
vipView.videoId = chapterId
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private lazy var bgView: UIView = {
|
||||
let view = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsBgView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white
|
||||
view.layer.cornerRadius = 12
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .regular)
|
||||
label.textColor = .black
|
||||
label.text = "Balance".localized + ":"
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinsIconView: UIImageView = UIImageView(image: UIImage(named: "coins_icon_04"))
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .bold)
|
||||
label.textColor = .F_9710_D
|
||||
label.text = "\(NRLoginManager.manager.userInfo?.totalCoins ?? 0)"
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var closeButton: UIButton = {
|
||||
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
Task {
|
||||
await self.dismiss(animated: true)
|
||||
}
|
||||
self.didDismissHandle?()
|
||||
}))
|
||||
button.setImage(UIImage(named: "close_icon_02"), for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var scrollView: NRScrollView = {
|
||||
let scrollView = NRScrollView()
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.spacing = 12
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView: NRStoreCoinsView = {
|
||||
let view = NRStoreCoinsView()
|
||||
view.isShowTitle = false
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
self?.buyFinish()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var vipView: NRStoreVipView = {
|
||||
let view = NRStoreVipView()
|
||||
view.isShowTitle = false
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
self?.buyFinish()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
@MainActor deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.backgroundColor = .red
|
||||
contentHeight = UIScreen.height - UIScreen.navBarHeight
|
||||
mainScrollView = self.scrollView
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: NRLoginManager.userInfoUpdateNotification, object: nil)
|
||||
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func userInfoUpdateNotification() {
|
||||
coinsLabel.text = "\(NRLoginManager.manager.userInfo?.totalCoins ?? 0)"
|
||||
}
|
||||
|
||||
private func buyFinish() {
|
||||
Task {
|
||||
await self.dismiss(animated: true)
|
||||
}
|
||||
Task {
|
||||
await NRLoginManager.manager.updateUserInfo()
|
||||
self.buyFinishHandle?()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NRDetailRechargeView {
|
||||
|
||||
private func nr_setupUI() {
|
||||
addSubview(bgView)
|
||||
addSubview(coinsBgView)
|
||||
coinsBgView.addSubview(coinsTitleLabel)
|
||||
coinsBgView.addSubview(coinsIconView)
|
||||
coinsBgView.addSubview(coinsLabel)
|
||||
addSubview(closeButton)
|
||||
addSubview(scrollView)
|
||||
scrollView.addSubview(stackView)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
coinsBgView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.equalToSuperview().offset(16)
|
||||
make.height.equalTo(24)
|
||||
}
|
||||
|
||||
coinsTitleLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(12)
|
||||
}
|
||||
|
||||
coinsIconView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalTo(coinsTitleLabel.snp.right).offset(8)
|
||||
}
|
||||
|
||||
coinsLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalTo(coinsIconView.snp.right).offset(4)
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
}
|
||||
|
||||
closeButton.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsBgView)
|
||||
make.right.equalToSuperview().offset(-6)
|
||||
make.width.height.equalTo(44)
|
||||
}
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(52)
|
||||
}
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
150
ReaderHive/Class/Novel/V/NRVipRetainAlert.swift
Normal file
@ -0,0 +1,150 @@
|
||||
//
|
||||
// NRVipRetainAlert.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/13.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYCategories
|
||||
|
||||
class NRVipRetainAlert: NRBaseAlert {
|
||||
|
||||
var worksId: String?
|
||||
|
||||
var chapterId: String?
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
|
||||
var model: NRPayAlertModel? {
|
||||
didSet {
|
||||
let payItem = model?.info
|
||||
titleLabel.text = payItem?.getVipTitle()
|
||||
itemView.model = payItem
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = NRLabel()
|
||||
label.font = .font(ofSize: 24, weight: .black)
|
||||
label.textColorImage = UIImage(named: "gradient_color_01")
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var itemView: NRVipRetainItemView = {
|
||||
let view = NRVipRetainItemView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var textLabel: UILabel = {
|
||||
let label = NRLabel()
|
||||
label.font = .font(ofSize: 18, weight: .black).withBoldItalic()
|
||||
label.textColors = [UIColor.FFEECA.cgColor, UIColor.FECE_62.cgColor]
|
||||
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||
label.text = "retain_alert_text".localized
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var buyButton: UIButton = {
|
||||
var configuration = UIButton.Configuration.plain()
|
||||
configuration.background.cornerRadius = 18
|
||||
configuration.background.image = UIImage(named: "gradient_color_01")
|
||||
configuration.attributedTitle = AttributedString("Buy Now".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .medium),
|
||||
.foregroundColor : UIColor.white
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.buyVip()
|
||||
}))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var closeButton: UIButton = {
|
||||
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.dismiss()
|
||||
}))
|
||||
button.setImage(UIImage(named: "close_icon_03"), for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
titleLabel.text = "Weekly VIP"
|
||||
|
||||
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func buyVip() {
|
||||
guard let payItem = self.model?.info else { return }
|
||||
|
||||
NRIapManager.manager.start(model: payItem, shortPlayId: worksId, videoId: chapterId) { [weak self] finish in
|
||||
guard let self = self else { return }
|
||||
if finish {
|
||||
Task {
|
||||
await NRLoginManager.manager.updateUserInfo()
|
||||
}
|
||||
self.dismiss()
|
||||
self.buyFinishHandle?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NRVipRetainAlert {
|
||||
|
||||
private func nr_setupUI() {
|
||||
contentView.addSubview(titleLabel)
|
||||
contentView.addSubview(itemView)
|
||||
contentView.addSubview(textLabel)
|
||||
contentView.addSubview(buyButton)
|
||||
contentView.addSubview(closeButton)
|
||||
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
|
||||
itemView.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(35)
|
||||
make.left.equalToSuperview().offset(28)
|
||||
make.right.equalToSuperview().offset(-28)
|
||||
make.width.equalTo(UIScreen.width - 56)
|
||||
make.height.equalTo(84)
|
||||
}
|
||||
|
||||
textLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(itemView.snp.bottom).offset(12)
|
||||
make.centerX.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview().offset(-45)
|
||||
}
|
||||
|
||||
buyButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(45)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(textLabel.snp.bottom).offset(12)
|
||||
make.height.equalTo(36)
|
||||
}
|
||||
|
||||
closeButton.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(buyButton.snp.bottom).offset(36)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
177
ReaderHive/Class/Novel/V/NRVipRetainItemView.swift
Normal file
@ -0,0 +1,177 @@
|
||||
//
|
||||
// NRVipRetainItemView.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/13.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYCategories
|
||||
internal import StoreKit
|
||||
|
||||
class NRVipRetainItemView: UIView {
|
||||
|
||||
var model: NRPayItem? {
|
||||
didSet {
|
||||
nameLabel.text = model?.getVipTitle()
|
||||
|
||||
priceView.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bg_image_06"))
|
||||
imageView.layer.cornerRadius = 12
|
||||
imageView.layer.masksToBounds = true
|
||||
imageView.layer.borderWidth = 1
|
||||
imageView.layer.borderColor = UIColor.black.withAlphaComponent(0.05).cgColor
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var bgIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "coins_icon_03"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var vipIconImageView = UIImageView(image: UIImage(named: "vip_icon_year"))
|
||||
|
||||
private lazy var nameLabel: UILabel = {
|
||||
let label = NRLabel()
|
||||
label.font = .font(ofSize: 16, weight: .semibold).withBoldItalic()
|
||||
label.textColors = [UIColor.BA_8_A_2_A.cgColor, UIColor._8_B_5801.cgColor]
|
||||
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var textLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = ._8_B_5801
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var priceView: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.titleAlignment = .center
|
||||
config.titlePadding = 0
|
||||
config.contentInsets = .init(top: 0, leading: 10, bottom: 0, trailing: 10)
|
||||
|
||||
let button = NRGradientButton(configuration: config)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.layer.masksToBounds = true
|
||||
button.layer.cornerRadius = 24
|
||||
button.layer.borderWidth = 1
|
||||
button.layer.borderColor = UIColor.black.withAlphaComponent(0.15).cgColor
|
||||
button.colors = [UIColor.white.cgColor, UIColor.FDE_9_CB.cgColor]
|
||||
button.startPoint = .init(x: 0, y: 0.5)
|
||||
button.endPoint = .init(x: 1, y: 0.5)
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
|
||||
let currency = self.model?.currency ?? ""
|
||||
let timeText = model?.getTimeString() ?? ""
|
||||
let oldPrice = self.model?.price ?? ""
|
||||
var discountPrice: String? = nil
|
||||
|
||||
if self.model?.discount_type == 1, let introductoryPrice = self.model?.introductionaryOffer {
|
||||
discountPrice = introductoryPrice.price.stringValue
|
||||
} else if self.model?.discount_type == 2, let discount = self.model?.promotionalOffers?.first {
|
||||
discountPrice = discount.price.stringValue
|
||||
}
|
||||
|
||||
if let discountPrice = discountPrice {
|
||||
|
||||
let priceString = AttributedString("\(currency)\(discountPrice)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 18, weight: .bold),
|
||||
.foregroundColor : UIColor._946_A_37
|
||||
]))
|
||||
|
||||
|
||||
button.configuration?.attributedTitle = priceString
|
||||
|
||||
var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||
.foregroundColor : UIColor.black.withAlphaComponent(0.05),
|
||||
.strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
||||
.strikethroughColor: UIColor.black.withAlphaComponent(0.05)
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = subtitle
|
||||
|
||||
} else {
|
||||
|
||||
button.configuration?.attributedTitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 18, weight: .bold),
|
||||
.foregroundColor : UIColor._946_A_37
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = AttributedString("/\(timeText)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||
.foregroundColor : UIColor.black.withAlphaComponent(0.5)
|
||||
]))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
textLabel.text = "vip_tip_01".localized
|
||||
nameLabel.text = "Weekly Refill"
|
||||
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension NRVipRetainItemView {
|
||||
|
||||
private func nr_setupUI() {
|
||||
addSubview(bgView)
|
||||
bgView.addSubview(bgIconImageView)
|
||||
bgView.addSubview(vipIconImageView)
|
||||
bgView.addSubview(nameLabel)
|
||||
bgView.addSubview(textLabel)
|
||||
bgView.addSubview(priceView)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
bgIconImageView.snp.makeConstraints { make in
|
||||
make.top.bottom.left.equalToSuperview()
|
||||
}
|
||||
|
||||
vipIconImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.top.equalToSuperview().offset(18)
|
||||
}
|
||||
|
||||
nameLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(vipIconImageView)
|
||||
make.left.equalTo(vipIconImageView.snp.right).offset(4)
|
||||
}
|
||||
|
||||
textLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.bottom.equalToSuperview().offset(-20)
|
||||
}
|
||||
|
||||
priceView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
make.height.equalTo(48)
|
||||
make.width.greaterThanOrEqualTo(88)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -220,7 +220,8 @@ extension NRNovelDetailViewController {
|
||||
private func tableViewMaxContentOffsetY() -> CGFloat {
|
||||
let contentSizeH = tableView.contentSize.height
|
||||
let maxOffsetY = contentSizeH - tableView.bounds.height
|
||||
return maxOffsetY
|
||||
// return maxOffsetY
|
||||
return floor(maxOffsetY)
|
||||
}
|
||||
|
||||
func setMainTableViewToMaxContentOffsetY() {
|
||||
|
||||
@ -184,15 +184,18 @@ extension NRNovelReaderViewController {
|
||||
extension NRNovelReaderViewController {
|
||||
|
||||
///装载数据
|
||||
private func loadData() {
|
||||
func loadData() {
|
||||
Task {
|
||||
NRHud.show()
|
||||
//获取小说数据
|
||||
await self.viewModel.requestNovelDetail()
|
||||
//获取目录数据
|
||||
await self.viewModel.requestChapterCatalogList()
|
||||
|
||||
guard !self.viewModel.chapterCatalogList.isEmpty else { return }
|
||||
|
||||
guard !self.viewModel.chapterCatalogList.isEmpty else {
|
||||
NRHud.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
let indexPath = self.indexPathToReadRecord()
|
||||
let section = indexPath.section
|
||||
@ -208,6 +211,7 @@ extension NRNovelReaderViewController {
|
||||
self.viewModel.checkCurrentIndexPath()
|
||||
|
||||
self.reloadData()
|
||||
NRHud.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,9 @@ class NRNovelReadViewModel: NSObject {
|
||||
///用来记录上报历史记录的时间
|
||||
var uploadRecordDate: Date?
|
||||
|
||||
weak var popView: UIView?
|
||||
|
||||
private var payDataRequest = NRPayDataRequest()
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +60,7 @@ extension NRNovelReadViewModel {
|
||||
func backReadPage() {
|
||||
Task {
|
||||
guard let isShowModel = await NRNovelAPI.requestShowRecommendPop(id: self.novelId), isShowModel.is_pop_up == true else {
|
||||
await _backReadPage()
|
||||
_backReadPage()
|
||||
return
|
||||
}
|
||||
|
||||
@ -157,10 +160,74 @@ extension NRNovelReadViewModel {
|
||||
|
||||
///打开充值页面
|
||||
func openRechargeView() {
|
||||
// let view = NRDetailRechargeView()
|
||||
// view.present(in: nil)
|
||||
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 }
|
||||
|
||||
|
||||
let view = NRDetailRechargeView()
|
||||
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
|
||||
|
||||
27
ReaderHive/Class/Store/M/NRCoinsPackModel.swift
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// NRCoinsPackModel.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class NRCoinsPackModel: NSObject, SmartCodable {
|
||||
override required init() { }
|
||||
|
||||
//当前可领取订阅数
|
||||
var receive_count: Int?
|
||||
//已领取累计金币总数
|
||||
var week_total: Int?
|
||||
//剩余可领取金币数
|
||||
var week_remaining_total: Int?
|
||||
//订阅可领取累计金币总数
|
||||
var week_max_total: Int?
|
||||
//当前可领取金币总数
|
||||
var receive_coins: Int?
|
||||
|
||||
var receive_list: [NRCoinsPackReceiveModel]?
|
||||
|
||||
}
|
||||
28
ReaderHive/Class/Store/M/NRCoinsPackReceiveModel.swift
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// NRCoinsPackReceiveModel.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class NRCoinsPackReceiveModel: NSObject, SmartCodable {
|
||||
|
||||
override required init() { }
|
||||
|
||||
var id: String?
|
||||
var title: String?
|
||||
//剩余可领取金币数
|
||||
var week_remaining_total: Int?
|
||||
//已领取累计金币总数
|
||||
var week_total: Int?
|
||||
//领取天数文本
|
||||
var day_text: String?
|
||||
//当前可领取金币数
|
||||
var receive_coins: Int?
|
||||
//可领取累计金币总数
|
||||
var week_max_total: Int?
|
||||
|
||||
}
|
||||
116
ReaderHive/Class/Store/V/NRCoinsPackBuyView.swift
Normal file
@ -0,0 +1,116 @@
|
||||
//
|
||||
// NRCoinsPackBuyView.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import HWPanModal
|
||||
|
||||
class NRCoinsPackBuyView: UIView {
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
|
||||
var dataArr: [NRPayItem] = []
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 16, weight: .semibold)
|
||||
label.textColor = ._714_A_1_B
|
||||
label.text = "Weekly Refills".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: UIScreen.width - 32, height: 84)
|
||||
layout.minimumLineSpacing = 12
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: NRCollectionView = {
|
||||
let collectionView = NRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
collectionView.register(NRStoreCoinsPackCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
@MainActor deinit {
|
||||
collectionView.removeObserver(self, forKeyPath: "contentSize")
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
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 NRCoinsPackBuyView {
|
||||
|
||||
private func nr_setupUI() {
|
||||
addSubview(titleLabel)
|
||||
addSubview(collectionView)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(16)
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(36)
|
||||
make.height.equalTo(1)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension NRCoinsPackBuyView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! NRStoreCoinsPackCell
|
||||
cell.model = self.dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = self.dataArr[indexPath.row]
|
||||
|
||||
let view = NRCoinsPackConfirmView()
|
||||
view.model = model
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
Task {
|
||||
await NRLoginManager.manager.updateUserInfo()
|
||||
}
|
||||
self.buyFinishHandle?()
|
||||
}
|
||||
view.present(in: nil)
|
||||
}
|
||||
|
||||
}
|
||||
261
ReaderHive/Class/Store/V/NRCoinsPackClaimCell.swift
Normal file
@ -0,0 +1,261 @@
|
||||
//
|
||||
// NRCoinsPackClaimCell.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYText
|
||||
|
||||
class NRCoinsPackClaimCell: UICollectionViewCell {
|
||||
|
||||
var clickClaimButton: ((_ id: String?) -> Void)?
|
||||
|
||||
var model: NRCoinsPackReceiveModel? {
|
||||
didSet {
|
||||
coinsView1.coins = model?.week_max_total
|
||||
coinsView2.coins = model?.week_remaining_total
|
||||
|
||||
claimButton.isEnabled = (model?.receive_coins ?? 0) > 0
|
||||
claimButton.setNeedsUpdateConfiguration()
|
||||
|
||||
let titleAtt = NSMutableAttributedString(string: "\(model?.title ?? "")")
|
||||
titleAtt.yy_color = ._714_A_1_B
|
||||
titleAtt.yy_font = .font(ofSize: 14, weight: .bold)
|
||||
|
||||
let day = "Day".localized
|
||||
let dayAtt = NSMutableAttributedString(string: " (\(day) \(model?.day_text ?? ""))")
|
||||
dayAtt.yy_color = ._946_A_37
|
||||
dayAtt.yy_font = .font(ofSize: 14, weight: .regular)
|
||||
titleAtt.append(dayAtt)
|
||||
|
||||
titleLabel.attributedText = titleAtt
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgView: UIView = {
|
||||
let view = UIImageView(image: UIImage(named: "bg_image_07"))
|
||||
view.layer.cornerRadius = 12
|
||||
view.layer.masksToBounds = true
|
||||
view.layer.borderWidth = 1
|
||||
view.layer.borderColor = UIColor.black.withAlphaComponent(0.05).cgColor
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var lineView1: UIView = {
|
||||
let view = NRDashedLineView()
|
||||
view.direction = .horizontal
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var lineView2: UIView = {
|
||||
let view = NRDashedLineView()
|
||||
view.direction = .vertical
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView1: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "Total Reward".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView2: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "Remaining".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var claimButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.titleAlignment = .center
|
||||
|
||||
let button = NRGradientButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.clickClaimButton?(self.model?.id)
|
||||
}))
|
||||
button.layer.masksToBounds = true
|
||||
button.layer.cornerRadius = 24
|
||||
button.layer.borderWidth = 1
|
||||
|
||||
button.startPoint = .init(x: 0, y: 0.5)
|
||||
button.endPoint = .init(x: 1, y: 0.5)
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
guard let button = button as? NRGradientButton else { return }
|
||||
|
||||
if button.isEnabled {
|
||||
button.colors = [UIColor.white.cgColor, UIColor.FDE_9_CB.cgColor]
|
||||
button.layer.borderColor = UIColor.black.withAlphaComponent(0.15).cgColor
|
||||
|
||||
let coinImage = UIImage(named: "coins_icon_01")!
|
||||
let coinText = NSTextAttachment(image: coinImage)
|
||||
coinText.bounds = .init(x: 0, y: -3, width: coinImage.size.width, height: coinImage.size.height)
|
||||
let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .bold),
|
||||
.foregroundColor : UIColor._946_A_37.withAlphaComponent(0.5)
|
||||
]))
|
||||
|
||||
|
||||
button.configuration?.attributedTitle = AttributedString("Claim".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor._714_A_1_B
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = coinAtt + countAtt
|
||||
|
||||
} else {
|
||||
button.colors = [UIColor.E_0_E_0_E_0.cgColor, UIColor.E_0_E_0_E_0.cgColor]
|
||||
button.layer.borderColor = UIColor.clear.cgColor
|
||||
|
||||
button.configuration?.attributedTitle = AttributedString("Claimed".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.black.withAlphaComponent(0.25)
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = nil
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
extension NRCoinsPackClaimCell {
|
||||
|
||||
private func nr_setupUI() {
|
||||
contentView.addSubview(bgView)
|
||||
contentView.addSubview(titleLabel)
|
||||
contentView.addSubview(lineView1)
|
||||
contentView.addSubview(lineView2)
|
||||
contentView.addSubview(coinsView1)
|
||||
contentView.addSubview(coinsView2)
|
||||
contentView.addSubview(claimButton)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerY.equalTo(self.bgView.snp.top).offset(25)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-12)
|
||||
}
|
||||
|
||||
lineView1.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(48)
|
||||
}
|
||||
|
||||
coinsView1.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.bottom.equalToSuperview().offset(-17)
|
||||
}
|
||||
|
||||
lineView2.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsView1)
|
||||
make.left.equalTo(coinsView1.snp.right).offset(12)
|
||||
make.height.equalTo(32)
|
||||
}
|
||||
|
||||
coinsView2.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsView1)
|
||||
make.left.equalTo(lineView2.snp.right).offset(12)
|
||||
}
|
||||
|
||||
claimButton.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
make.centerY.equalTo(coinsView1)
|
||||
make.height.equalTo(48)
|
||||
make.width.equalTo(120)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension NRCoinsPackClaimCell {
|
||||
|
||||
class CoinsView: UIView {
|
||||
|
||||
var title: String? {
|
||||
didSet {
|
||||
titleLabel.text = title
|
||||
}
|
||||
}
|
||||
|
||||
var coins: Int? {
|
||||
didSet {
|
||||
coinsLabel.text = "\(coins ?? 0)"
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .bold)
|
||||
label.textColor = ._946_A_37
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var iconImageView = UIImageView(image: UIImage(named: "coins_icon_01"))
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .bold)
|
||||
label.textColor = ._946_A_37
|
||||
label.text = "0"
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
addSubview(titleLabel)
|
||||
addSubview(iconImageView)
|
||||
addSubview(coinsLabel)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||
}
|
||||
|
||||
coinsLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(iconImageView)
|
||||
make.left.equalTo(iconImageView.snp.right).offset(4)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
107
ReaderHive/Class/Store/V/NRCoinsPackClaimView.swift
Normal file
@ -0,0 +1,107 @@
|
||||
//
|
||||
// NRCoinsPackClaimView.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class NRCoinsPackClaimView: UIView {
|
||||
|
||||
var clickClaimButton: ((_ id: String?) -> Void)?
|
||||
|
||||
var dataArr: [NRCoinsPackReceiveModel] = [] {
|
||||
didSet {
|
||||
collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 16, weight: .semibold)
|
||||
label.textColor = ._714_A_1_B
|
||||
label.text = "Active Refills".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: UIScreen.width - 32, height: 122)
|
||||
layout.minimumLineSpacing = 12
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: NRCollectionView = {
|
||||
let collectionView = NRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
collectionView.register(NRCoinsPackClaimCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
deinit {
|
||||
collectionView.removeObserver(self, forKeyPath: "contentSize")
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
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 NRCoinsPackClaimView {
|
||||
|
||||
private func nr_setupUI() {
|
||||
addSubview(titleLabel)
|
||||
addSubview(collectionView)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(16)
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(36)
|
||||
make.height.equalTo(1)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension NRCoinsPackClaimView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! NRCoinsPackClaimCell
|
||||
cell.model = self.dataArr[indexPath.row]
|
||||
cell.clickClaimButton = { [weak self] id in
|
||||
self?.clickClaimButton?(id)
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -7,11 +7,28 @@
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYCategories
|
||||
|
||||
|
||||
class NRCoinsPackHeaderView: UIView {
|
||||
|
||||
var clickClaimButton: (() -> Void)?
|
||||
|
||||
var model: NRCoinsPackModel? {
|
||||
didSet {
|
||||
coinsView1.coins = model?.week_max_total
|
||||
coinsView2.coins = model?.week_total
|
||||
|
||||
countLabel.text = "\(model?.receive_count ?? 0)"
|
||||
|
||||
if let coin = model?.receive_coins, coin > 0 {
|
||||
claimButton.isEnabled = true
|
||||
} else {
|
||||
claimButton.isEnabled = false
|
||||
}
|
||||
claimButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
@ -28,12 +45,6 @@ class NRCoinsPackHeaderView: UIView {
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var lineView1: NRDashedLineView = {
|
||||
let view = NRDashedLineView()
|
||||
view.isHorizontal = false
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView2: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "Claimable Coins".localized
|
||||
@ -41,6 +52,78 @@ class NRCoinsPackHeaderView: UIView {
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var countTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = .black.withAlphaComponent(0.5)
|
||||
label.text = "Active Refills".localized + ": "
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var countLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = .F_9710_D
|
||||
label.text = "0"
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var claimButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.background.cornerRadius = 24
|
||||
let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
self?.clickClaimButton?()
|
||||
}))
|
||||
button.isEnabled = false
|
||||
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
if button.isEnabled {
|
||||
button.configuration?.background.image = UIImage(named: "gradient_color_01")
|
||||
|
||||
let coinImage = UIImage(named: "coins_icon_06")!
|
||||
let coinText = NSTextAttachment(image: coinImage)
|
||||
coinText.bounds = .init(x: 0, y: -3, width: coinImage.size.width, height: coinImage.size.height)
|
||||
let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||
|
||||
let textAtt = AttributedString("Claim All".localized + " ", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .semibold),
|
||||
.foregroundColor : UIColor.white
|
||||
]))
|
||||
|
||||
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .semibold),
|
||||
.foregroundColor : UIColor.white
|
||||
]))
|
||||
|
||||
button.configuration?.attributedTitle = textAtt + coinAtt + countAtt
|
||||
|
||||
|
||||
} else {
|
||||
button.configuration?.background.image = UIImage(color: .E_0_E_0_E_0)
|
||||
|
||||
button.configuration?.attributedTitle = AttributedString("Claimed".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .semibold),
|
||||
.foregroundColor : UIColor.black.withAlphaComponent(0.25)
|
||||
]))
|
||||
}
|
||||
|
||||
}
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var lineView1: NRDashedLineView = {
|
||||
let view = NRDashedLineView()
|
||||
view.direction = .vertical
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var lineView2: NRDashedLineView = {
|
||||
let view = NRDashedLineView()
|
||||
view.direction = .horizontal
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
@ -60,6 +143,10 @@ extension NRCoinsPackHeaderView {
|
||||
addSubview(coinsView1)
|
||||
addSubview(coinsView2)
|
||||
addSubview(lineView1)
|
||||
addSubview(countTitleLabel)
|
||||
addSubview(countLabel)
|
||||
addSubview(claimButton)
|
||||
addSubview(lineView2)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
@ -74,13 +161,35 @@ extension NRCoinsPackHeaderView {
|
||||
lineView1.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsView1)
|
||||
make.left.equalTo(coinsView1.snp.right).offset(18)
|
||||
make.width.equalTo(1)
|
||||
make.height.equalTo(32)
|
||||
}
|
||||
|
||||
coinsView2.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(lineView1)
|
||||
make.left.equalTo(lineView1.snp.right).offset(18)
|
||||
}
|
||||
|
||||
countTitleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(28)
|
||||
make.top.equalTo(coinsView1.snp.bottom).offset(22)
|
||||
}
|
||||
|
||||
countLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(countTitleLabel)
|
||||
make.left.equalTo(countTitleLabel.snp.right)
|
||||
}
|
||||
|
||||
claimButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(28)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(countTitleLabel.snp.bottom).offset(12)
|
||||
make.height.equalTo(48)
|
||||
make.bottom.equalToSuperview().offset(-16)
|
||||
}
|
||||
|
||||
lineView2.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(28)
|
||||
make.centerX.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
|
||||
@ -111,20 +111,20 @@ class NRStoreCoinsPackCell: NRStoreCoinsCell {
|
||||
|
||||
let priceString = AttributedString("\(currency)\(discountPrice)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 18, weight: .bold),
|
||||
// .foregroundColor : UIColor._114_CEE
|
||||
.foregroundColor : UIColor._946_A_37
|
||||
]))
|
||||
|
||||
|
||||
// button.configuration?.attributedTitle = priceString
|
||||
//
|
||||
// var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||
// .font : UIFont.font(ofSize: 12, weight: .regular),
|
||||
// .foregroundColor : UIColor._636_F_7_B.withAlphaComponent(0.05),
|
||||
// .strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
||||
// .strikethroughColor: UIColor._636_F_7_B.withAlphaComponent(0.05)
|
||||
// ]))
|
||||
//
|
||||
// button.configuration?.attributedSubtitle = subtitle
|
||||
button.configuration?.attributedTitle = priceString
|
||||
|
||||
var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||
.foregroundColor : UIColor.black.withAlphaComponent(0.05),
|
||||
.strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
||||
.strikethroughColor: UIColor.black.withAlphaComponent(0.05)
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = subtitle
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
@ -7,10 +7,33 @@
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYText
|
||||
|
||||
class NRCoinsPackViewController: NRViewController {
|
||||
|
||||
|
||||
private var model: NRCoinsPackModel? {
|
||||
didSet {
|
||||
headerView.model = model
|
||||
claimView.dataArr = model?.receive_list ?? []
|
||||
}
|
||||
}
|
||||
|
||||
private var payDataModel :NRPayDateModel? {
|
||||
didSet {
|
||||
var arr: [NRPayItem] = []
|
||||
|
||||
payDataModel?.list_coins?.forEach {
|
||||
if $0.buy_type == .subCoins {
|
||||
arr.append($0)
|
||||
}
|
||||
}
|
||||
self.buyView.dataArr = arr
|
||||
}
|
||||
}
|
||||
|
||||
private var payDataRequest: NRPayDataRequest = NRPayDataRequest()
|
||||
|
||||
private lazy var bgIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "calendar_icon_02"))
|
||||
return imageView
|
||||
@ -23,15 +46,87 @@ class NRCoinsPackViewController: NRViewController {
|
||||
|
||||
private lazy var headerView: NRCoinsPackHeaderView = {
|
||||
let view = NRCoinsPackHeaderView()
|
||||
view.clickClaimButton = { [weak self] in
|
||||
self?.requestReceiveCoins(nil)
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .vertical
|
||||
stackView.spacing = 12
|
||||
return stackView
|
||||
}()
|
||||
|
||||
private lazy var buyView: NRCoinsPackBuyView = {
|
||||
let view = NRCoinsPackBuyView()
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
self?.requestCoinsPackData()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var claimView: NRCoinsPackClaimView = {
|
||||
let view = NRCoinsPackClaimView()
|
||||
view.clickClaimButton = { [weak self] id in
|
||||
guard let self = self else { return }
|
||||
self.requestReceiveCoins(id)
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tipView: UIView = {
|
||||
let view = UIView()
|
||||
view.addSubview(tipTitleLabel)
|
||||
view.addSubview(tipTextLabel)
|
||||
|
||||
tipTitleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(16)
|
||||
}
|
||||
|
||||
tipTextLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||
make.top.equalTo(tipTitleLabel.snp.bottom).offset(4)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tipTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .black.withAlphaComponent(0.25)
|
||||
label.text = "coins_pack_tips_title".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var tipTextLabel: UILabel = {
|
||||
let att = NSMutableAttributedString(string: "coins_pack_tips".localized)
|
||||
att.yy_lineSpacing = 3
|
||||
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 10, weight: .regular)
|
||||
label.textColor = .black.withAlphaComponent(0.25)
|
||||
label.attributedText = att
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "My Refills".localized
|
||||
configNavigationBack("arrow_left_icon_05")
|
||||
|
||||
payDataModel = NRIapManager.manager.payDateModel
|
||||
|
||||
nr_setupUI()
|
||||
|
||||
updateLayout()
|
||||
|
||||
requestCoinsPackData()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@ -40,6 +135,18 @@ class NRCoinsPackViewController: NRViewController {
|
||||
self.nr_setNavigationStyle(titleColor: UINavigationBar.titleBlackColor)
|
||||
}
|
||||
|
||||
private func updateLayout() {
|
||||
stackView.nr_removeAllArrangedSubview()
|
||||
|
||||
if self.claimView.dataArr.count > 0 {
|
||||
stackView.addArrangedSubview(self.claimView)
|
||||
} else if self.buyView.dataArr.count > 0 {
|
||||
stackView.addArrangedSubview(self.buyView)
|
||||
}
|
||||
|
||||
stackView.addArrangedSubview(tipView)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NRCoinsPackViewController {
|
||||
@ -48,6 +155,7 @@ extension NRCoinsPackViewController {
|
||||
view.addSubview(bgIconImageView)
|
||||
view.addSubview(scrollView)
|
||||
scrollView.addSubview(headerView)
|
||||
scrollView.addSubview(stackView)
|
||||
|
||||
|
||||
bgIconImageView.snp.makeConstraints { make in
|
||||
@ -65,6 +173,51 @@ extension NRCoinsPackViewController {
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalTo(headerView.snp.bottom).offset(16)
|
||||
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NRCoinsPackViewController {
|
||||
|
||||
private func requestCoinsPackData() {
|
||||
NRStoreAPI.requestCoinsPackData { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else { return }
|
||||
self.model = model
|
||||
|
||||
if (model.receive_list?.count ?? 0) == 0 {
|
||||
self.requestPayData()
|
||||
}
|
||||
|
||||
self.updateLayout()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func requestPayData() {
|
||||
|
||||
self.payDataRequest.requestProducts { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else { return }
|
||||
self.payDataModel = model
|
||||
|
||||
self.updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private func requestReceiveCoins(_ id: String?) {
|
||||
NRStoreAPI.requestReceiveCoinsPackCoins(id: id) { [weak self] finish in
|
||||
guard let self = self else { return }
|
||||
self.requestCoinsPackData()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -45,11 +45,39 @@ class NRStoreViewController: NRViewController {
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tipView: UIView = {
|
||||
let view = UIView()
|
||||
|
||||
view.addSubview(tipTextLabel)
|
||||
|
||||
|
||||
tipTextLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||
make.top.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tipTextLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 10, weight: .regular)
|
||||
label.textColor = .black.withAlphaComponent(0.5)
|
||||
label.text = "store_tips".localized
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Store".localized
|
||||
configNavigationBack("arrow_left_icon_05")
|
||||
|
||||
let barButtonItem = UIBarButtonItem(title: "Restore".localized, style: .plain, target: self, action: #selector(handleRestore))
|
||||
barButtonItem.tintColor = .black.withAlphaComponent(0.5)
|
||||
self.navigationItem.rightBarButtonItem = barButtonItem
|
||||
|
||||
nr_setupUI()
|
||||
|
||||
restore(isLoding: false)
|
||||
@ -96,7 +124,7 @@ class NRStoreViewController: NRViewController {
|
||||
self.addVipView()
|
||||
self.addCoinsView()
|
||||
}
|
||||
// self.stackView.addArrangedSubview(tipView)
|
||||
self.stackView.addArrangedSubview(tipView)
|
||||
}
|
||||
|
||||
private func addCoinsView() {
|
||||
|
||||
@ -11,12 +11,11 @@ internal import StoreKit
|
||||
class NRPayDataRequest: NSObject {
|
||||
|
||||
private var oldTemplateModel: NRPayDateModel?
|
||||
private(set) var newTemplateModel: NRPayDateModel?
|
||||
|
||||
// private var payAlertModel: NRPayAlertModel?
|
||||
private var payAlertModel: NRPayAlertModel?
|
||||
|
||||
private var completerBlock: ((_ model: NRPayDateModel?) -> Void)?
|
||||
// private var payAlertBlock: ((_ model: FAPayAlertModel?) -> Void)?
|
||||
private var payAlertBlock: ((_ model: NRPayAlertModel?) -> Void)?
|
||||
|
||||
private var isLoding = false
|
||||
private var isToast = false
|
||||
@ -80,26 +79,26 @@ class NRPayDataRequest: NSObject {
|
||||
// }
|
||||
|
||||
///挽留信息
|
||||
// func requestVipRetainPayInfo(completer: ((_ model: FAPayAlertModel?) -> Void)?) {
|
||||
// self.completerBlock = nil
|
||||
// self.payAlertBlock = completer
|
||||
//
|
||||
// FAStoreAPI.requestVipRetainPayInfo { [weak self] model in
|
||||
// guard let self = self else { return }
|
||||
// guard let model = model else {
|
||||
// self.payAlertBlock?(nil)
|
||||
// return
|
||||
// }
|
||||
// self.payAlertModel = model
|
||||
//
|
||||
// let productId = FAIapManager.manager.getProductId(templateId: model.info?.ios_template_id) ?? ""
|
||||
//
|
||||
// let set = Set([productId])
|
||||
// let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
// productsRequest.delegate = self
|
||||
// productsRequest.start()
|
||||
// }
|
||||
// }
|
||||
func requestVipRetainPayInfo(completer: ((_ model: NRPayAlertModel?) -> Void)?) {
|
||||
self.completerBlock = nil
|
||||
self.payAlertBlock = completer
|
||||
|
||||
NRStoreAPI.requestVipRetainPayInfo { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else {
|
||||
self.payAlertBlock?(nil)
|
||||
return
|
||||
}
|
||||
self.payAlertModel = model
|
||||
|
||||
let productId = NRIapManager.manager.getProductId(templateId: model.info?.ios_template_id) ?? ""
|
||||
|
||||
let set = Set([productId])
|
||||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
productsRequest.delegate = self
|
||||
productsRequest.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: SKProductsRequestDelegate
|
||||
@ -148,31 +147,29 @@ extension NRPayDataRequest: SKProductsRequestDelegate {
|
||||
templateModel.list_coins = newCoinList
|
||||
templateModel.list_sub_vip = newVipList
|
||||
|
||||
self.newTemplateModel = templateModel
|
||||
NRIapManager.manager.payDateModel = templateModel
|
||||
|
||||
DispatchQueue.main.async {
|
||||
block(templateModel)
|
||||
}
|
||||
|
||||
} else if let block = self.payAlertBlock {
|
||||
guard let coinalertModel = self.payAlertModel else { return }
|
||||
let productId = NRIapManager.manager.getProductId(templateId: coinalertModel.info?.ios_template_id) ?? ""
|
||||
|
||||
for product in products {
|
||||
if productId == product.productIdentifier {
|
||||
coinalertModel.info?.price = product.price.stringValue
|
||||
coinalertModel.info?.currency = product.priceLocale.currencySymbol
|
||||
coinalertModel.info?.product = product
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
block(coinalertModel)
|
||||
}
|
||||
}
|
||||
// else if let block = self.payAlertBlock {
|
||||
// guard let coinalertModel = self.payAlertModel else { return }
|
||||
// let productId = FAIapManager.manager.getProductId(templateId: coinalertModel.info?.ios_template_id) ?? ""
|
||||
//
|
||||
// for product in products {
|
||||
// if productId == product.productIdentifier {
|
||||
// coinalertModel.info?.price = product.price.stringValue
|
||||
// coinalertModel.info?.currency = product.priceLocale.currencySymbol
|
||||
// coinalertModel.info?.product = product
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// DispatchQueue.main.async {
|
||||
// block(coinalertModel)
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x62",
|
||||
"green" : "0xCE",
|
||||
"red" : "0xFE"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xCA",
|
||||
"green" : "0xEE",
|
||||
"red" : "0xFF"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
ReaderHive/Source/Assets.xcassets/Image/bg_image_07.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "背景部分@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "背景部分@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ReaderHive/Source/Assets.xcassets/Image/bg_image_07.imageset/背景部分@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/bg_image_07.imageset/背景部分@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 320 KiB |
22
ReaderHive/Source/Assets.xcassets/Image/calendar_icon_03.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "插画@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "插画@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ReaderHive/Source/Assets.xcassets/Image/calendar_icon_03.imageset/插画@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/calendar_icon_03.imageset/插画@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 108 KiB |
22
ReaderHive/Source/Assets.xcassets/Image/close_icon_03.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "关闭按钮@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "关闭按钮@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ReaderHive/Source/Assets.xcassets/Image/close_icon_03.imageset/关闭按钮@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/close_icon_03.imageset/关闭按钮@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/coins_icon_06.imageset/Coins@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/coins_icon_06.imageset/Coins@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
22
ReaderHive/Source/Assets.xcassets/Image/coins_icon_06.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Coins@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Coins@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -117,7 +117,27 @@
|
||||
"Rewards Overview" = "Rewards Overview";
|
||||
"Weekly Total" = "Weekly Total";
|
||||
"Claimable Coins" = "Claimable Coins";
|
||||
"Active Refills" = "Active Refills";
|
||||
"Claim All" = "Claim All";
|
||||
"Claimed" = "Claimed";
|
||||
"Weekly Refills" = "Weekly Refills";
|
||||
"Total Reward" = "Total Reward";
|
||||
"Remaining" = "Remaining";
|
||||
"Claim" = "Claim";
|
||||
"Day" = "Day";
|
||||
"Restore" = "Restore";
|
||||
"Balance" = "Balance";
|
||||
"Daily Coins" = "Daily Coins";
|
||||
"Buy Now" = "Buy Now";
|
||||
|
||||
"retain_alert_text" = "Unlock every show you love!";
|
||||
|
||||
"vip_tip_01" = "Unlimited access to all series";
|
||||
|
||||
"coins_pack_tips_title" = "Subscription Rules";
|
||||
"coins_pack_tips" = "1.Coins are delivered instantly upon purchase.<br>2.Daily bonus coins available from the next day.<br>3.All coins will be revoked when the subscription expires, including both initial and daily coins.";
|
||||
|
||||
"store_tips" = "1. Coins are virtual items and cannot be refunded. Use it for this product.<br>2. Both the coins and the reward coins will never expire.<br>3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used.<br>4. The purchase has not been credited, click <Restore> torefresh.<br>5. For other questions, contact us via Profile > Feedback.";
|
||||
|
||||
"pay_error_1" = "You are already a member!";
|
||||
"pay_error_2" = "You have unfinished in-app purchases, please restore them first.";
|
||||
|
||||