1
@ -87,6 +87,15 @@
|
|||||||
85606A9A2EEBC26F005D989D /* NRCoinsPackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A992EEBC26F005D989D /* NRCoinsPackViewController.swift */; };
|
85606A9A2EEBC26F005D989D /* NRCoinsPackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A992EEBC26F005D989D /* NRCoinsPackViewController.swift */; };
|
||||||
85606A9C2EEBE243005D989D /* NRCoinsPackHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A9B2EEBE243005D989D /* NRCoinsPackHeaderView.swift */; };
|
85606A9C2EEBE243005D989D /* NRCoinsPackHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A9B2EEBE243005D989D /* NRCoinsPackHeaderView.swift */; };
|
||||||
85606A9F2EEBE95A005D989D /* NRDashedLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A9E2EEBE95A005D989D /* NRDashedLineView.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 */; };
|
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */; };
|
||||||
F34348B12ED5B9A400AA7E70 /* NRExploreNovelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */; };
|
F34348B12ED5B9A400AA7E70 /* NRExploreNovelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */; };
|
||||||
F34348B32ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B22ED5BB6100AA7E70 /* NRExploreNovelMenuView.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreNovelViewController.swift; sourceTree = "<group>"; };
|
||||||
@ -501,6 +519,7 @@
|
|||||||
F34349042ED9442300AA7E70 /* NRReadPageModel.swift */,
|
F34349042ED9442300AA7E70 /* NRReadPageModel.swift */,
|
||||||
F34990BE2EDEDDCF0039E939 /* NRCategoryModel.swift */,
|
F34990BE2EDEDDCF0039E939 /* NRCategoryModel.swift */,
|
||||||
F34991282EE285660039E939 /* NRShowRecommendPop.swift */,
|
F34991282EE285660039E939 /* NRShowRecommendPop.swift */,
|
||||||
|
85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */,
|
||||||
);
|
);
|
||||||
path = M;
|
path = M;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -515,6 +534,8 @@
|
|||||||
F34348E02ED70A2200AA7E70 /* NRNovelDetailHeaderView+NovelCoverInfo.swift */,
|
F34348E02ED70A2200AA7E70 /* NRNovelDetailHeaderView+NovelCoverInfo.swift */,
|
||||||
F34348E22ED70D2300AA7E70 /* NRNovelDetailHeaderView+Data.swift */,
|
F34348E22ED70D2300AA7E70 /* NRNovelDetailHeaderView+Data.swift */,
|
||||||
F3B859302EE66B950095A9CC /* NRDetailRechargeView.swift */,
|
F3B859302EE66B950095A9CC /* NRDetailRechargeView.swift */,
|
||||||
|
85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */,
|
||||||
|
85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */,
|
||||||
);
|
);
|
||||||
path = V;
|
path = V;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -797,6 +818,7 @@
|
|||||||
0373D95D2ED59C430017DCC7 /* NRSearchResultView.swift */,
|
0373D95D2ED59C430017DCC7 /* NRSearchResultView.swift */,
|
||||||
0373D95F2ED59DA10017DCC7 /* NRSearchResultCell.swift */,
|
0373D95F2ED59DA10017DCC7 /* NRSearchResultCell.swift */,
|
||||||
F34990BC2EDEC24E0039E939 /* NRStarGradeView.swift */,
|
F34990BC2EDEC24E0039E939 /* NRStarGradeView.swift */,
|
||||||
|
85CF94262EED1734006467E3 /* NRHomeCoinsPackButton.swift */,
|
||||||
);
|
);
|
||||||
path = V;
|
path = V;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1091,6 +1113,9 @@
|
|||||||
85606A932EEBB3FE005D989D /* NRCoinsPackConfirmTitleView.swift */,
|
85606A932EEBB3FE005D989D /* NRCoinsPackConfirmTitleView.swift */,
|
||||||
85606A952EEBB733005D989D /* NRCoinsPackConfirmTipView.swift */,
|
85606A952EEBB733005D989D /* NRCoinsPackConfirmTipView.swift */,
|
||||||
85606A9B2EEBE243005D989D /* NRCoinsPackHeaderView.swift */,
|
85606A9B2EEBE243005D989D /* NRCoinsPackHeaderView.swift */,
|
||||||
|
85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */,
|
||||||
|
85CF94222EEC08F4006467E3 /* NRCoinsPackClaimView.swift */,
|
||||||
|
85CF94242EEC09AE006467E3 /* NRCoinsPackClaimCell.swift */,
|
||||||
);
|
);
|
||||||
path = V;
|
path = V;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1102,6 +1127,8 @@
|
|||||||
F3B859802EE9716E0095A9CC /* NRBuyRecordsModel.swift */,
|
F3B859802EE9716E0095A9CC /* NRBuyRecordsModel.swift */,
|
||||||
F3B8598A2EEA51540095A9CC /* NRRewardCoinsModel.swift */,
|
F3B8598A2EEA51540095A9CC /* NRRewardCoinsModel.swift */,
|
||||||
F3B859922EEA63CD0095A9CC /* NROrderRecordsModel.swift */,
|
F3B859922EEA63CD0095A9CC /* NROrderRecordsModel.swift */,
|
||||||
|
85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */,
|
||||||
|
85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */,
|
||||||
);
|
);
|
||||||
path = M;
|
path = M;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1250,10 +1277,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReaderHive/Pods-ReaderHive-frameworks.sh\"\n";
|
||||||
@ -1283,6 +1314,7 @@
|
|||||||
F34349142EDA9AE900AA7E70 /* NRNovelReadSettingView.swift in Sources */,
|
F34349142EDA9AE900AA7E70 /* NRNovelReadSettingView.swift in Sources */,
|
||||||
F3B859632EE91B850095A9CC /* NRStoreCoinsView.swift in Sources */,
|
F3B859632EE91B850095A9CC /* NRStoreCoinsView.swift in Sources */,
|
||||||
F34348BD2ED68F2B00AA7E70 /* NRExploreNovelViewModel.swift in Sources */,
|
F34348BD2ED68F2B00AA7E70 /* NRExploreNovelViewModel.swift in Sources */,
|
||||||
|
85CF94212EEC050D006467E3 /* NRCoinsPackBuyView.swift in Sources */,
|
||||||
F3B8595F2EE910020095A9CC /* NRPayDataRequest.swift in Sources */,
|
F3B8595F2EE910020095A9CC /* NRPayDataRequest.swift in Sources */,
|
||||||
F3B859692EE91BD70095A9CC /* NRStoreCoinsPackCell.swift in Sources */,
|
F3B859692EE91BD70095A9CC /* NRStoreCoinsPackCell.swift in Sources */,
|
||||||
F34991102EE1708C0039E939 /* NRWebViewController+Script.swift in Sources */,
|
F34991102EE1708C0039E939 /* NRWebViewController+Script.swift in Sources */,
|
||||||
@ -1290,6 +1322,8 @@
|
|||||||
F34348BF2ED691C100AA7E70 /* NRExploreNovelGenresViewController.swift in Sources */,
|
F34348BF2ED691C100AA7E70 /* NRExploreNovelGenresViewController.swift in Sources */,
|
||||||
039810B02ED3F50C0006E317 /* NRHomeNovelMustReadTodayCell.swift in Sources */,
|
039810B02ED3F50C0006E317 /* NRHomeNovelMustReadTodayCell.swift in Sources */,
|
||||||
0373D9452ED57B7B0017DCC7 /* NRNovelDetailViewModel.swift in Sources */,
|
0373D9452ED57B7B0017DCC7 /* NRNovelDetailViewModel.swift in Sources */,
|
||||||
|
85CF942D2EED5204006467E3 /* NRPayAlertModel.swift in Sources */,
|
||||||
|
85CF942B2EED47F2006467E3 /* NRVipRetainItemView.swift in Sources */,
|
||||||
0398107C2ED055260006E317 /* AppDelegate+Config.swift in Sources */,
|
0398107C2ED055260006E317 /* AppDelegate+Config.swift in Sources */,
|
||||||
F34348B52ED5C6F800AA7E70 /* NRTableView.swift in Sources */,
|
F34348B52ED5C6F800AA7E70 /* NRTableView.swift in Sources */,
|
||||||
F34348DB2ED6F80A00AA7E70 /* NRNovelReaderViewController.swift in Sources */,
|
F34348DB2ED6F80A00AA7E70 /* NRNovelReaderViewController.swift in Sources */,
|
||||||
@ -1299,6 +1333,7 @@
|
|||||||
85606A922EEBB336005D989D /* NRCoinsPackConfirmItemView.swift in Sources */,
|
85606A922EEBB336005D989D /* NRCoinsPackConfirmItemView.swift in Sources */,
|
||||||
0398106A2ED0505D0006E317 /* NRNetworkReachableManager.swift in Sources */,
|
0398106A2ED0505D0006E317 /* NRNetworkReachableManager.swift in Sources */,
|
||||||
F34348C32ED6A20700AA7E70 /* NRExploreNovelContentViewController.swift in Sources */,
|
F34348C32ED6A20700AA7E70 /* NRExploreNovelContentViewController.swift in Sources */,
|
||||||
|
85CF94232EEC08F4006467E3 /* NRCoinsPackClaimView.swift in Sources */,
|
||||||
F34991292EE285660039E939 /* NRShowRecommendPop.swift in Sources */,
|
F34991292EE285660039E939 /* NRShowRecommendPop.swift in Sources */,
|
||||||
0373D9642ED5ABBC0017DCC7 /* NREmpty.swift in Sources */,
|
0373D9642ED5ABBC0017DCC7 /* NREmpty.swift in Sources */,
|
||||||
F3B859572EE9072C0095A9CC /* NRIapManager.swift in Sources */,
|
F3B859572EE9072C0095A9CC /* NRIapManager.swift in Sources */,
|
||||||
@ -1309,6 +1344,7 @@
|
|||||||
F3B859862EE972F70095A9CC /* NRConsumptionRecordsCell.swift in Sources */,
|
F3B859862EE972F70095A9CC /* NRConsumptionRecordsCell.swift in Sources */,
|
||||||
F34990C72EDFCE500039E939 /* NRNovelReadGradeView.swift in Sources */,
|
F34990C72EDFCE500039E939 /* NRNovelReadGradeView.swift in Sources */,
|
||||||
039810B42ED428F20006E317 /* NRHomeNovelNewArrivalsView.swift in Sources */,
|
039810B42ED428F20006E317 /* NRHomeNovelNewArrivalsView.swift in Sources */,
|
||||||
|
85CF94272EED1734006467E3 /* NRHomeCoinsPackButton.swift in Sources */,
|
||||||
F34991012EE1593A0039E939 /* NRMeHeaderView.swift in Sources */,
|
F34991012EE1593A0039E939 /* NRMeHeaderView.swift in Sources */,
|
||||||
F3B8598F2EEA5B1C0095A9CC /* NROrderRecordsPageViewController.swift in Sources */,
|
F3B8598F2EEA5B1C0095A9CC /* NROrderRecordsPageViewController.swift in Sources */,
|
||||||
F34991052EE165EA0039E939 /* NRMeItem.swift in Sources */,
|
F34991052EE165EA0039E939 /* NRMeItem.swift in Sources */,
|
||||||
@ -1331,6 +1367,7 @@
|
|||||||
039810D02ED54D370006E317 /* NRHomeCategoryTagView.swift in Sources */,
|
039810D02ED54D370006E317 /* NRHomeCategoryTagView.swift in Sources */,
|
||||||
F34348E32ED70D2F00AA7E70 /* NRNovelDetailHeaderView+Data.swift in Sources */,
|
F34348E32ED70D2F00AA7E70 /* NRNovelDetailHeaderView+Data.swift in Sources */,
|
||||||
0398107F2ED055D10006E317 /* NRLoginManager.swift in Sources */,
|
0398107F2ED055D10006E317 /* NRLoginManager.swift in Sources */,
|
||||||
|
85CF941D2EEBFEA6006467E3 /* NRCoinsPackModel.swift in Sources */,
|
||||||
F34348D52ED6E16500AA7E70 /* NRMyListNovelViewController.swift in Sources */,
|
F34348D52ED6E16500AA7E70 /* NRMyListNovelViewController.swift in Sources */,
|
||||||
F34991162EE176640039E939 /* NRNovelHistoryViewController.swift in Sources */,
|
F34991162EE176640039E939 /* NRNovelHistoryViewController.swift in Sources */,
|
||||||
F34348F52ED848EC00AA7E70 /* NRNovelReadPageViewController.swift in Sources */,
|
F34348F52ED848EC00AA7E70 /* NRNovelReadPageViewController.swift in Sources */,
|
||||||
@ -1338,10 +1375,12 @@
|
|||||||
F349910E2EE1707C0039E939 /* NRWebViewController.swift in Sources */,
|
F349910E2EE1707C0039E939 /* NRWebViewController.swift in Sources */,
|
||||||
F34990BB2EDEB2080039E939 /* NRHomeNovelViewModel.swift in Sources */,
|
F34990BB2EDEB2080039E939 /* NRHomeNovelViewModel.swift in Sources */,
|
||||||
F34990BD2EDEC24E0039E939 /* NRStarGradeView.swift in Sources */,
|
F34990BD2EDEC24E0039E939 /* NRStarGradeView.swift in Sources */,
|
||||||
|
85CF941F2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift in Sources */,
|
||||||
F34348C12ED693E900AA7E70 /* NRExploreNovelGenresCell.swift in Sources */,
|
F34348C12ED693E900AA7E70 /* NRExploreNovelGenresCell.swift in Sources */,
|
||||||
0373D94B2ED582EE0017DCC7 /* NRNovelAPI.swift in Sources */,
|
0373D94B2ED582EE0017DCC7 /* NRNovelAPI.swift in Sources */,
|
||||||
039810832ED0563D0006E317 /* NRUserInfo.swift in Sources */,
|
039810832ED0563D0006E317 /* NRUserInfo.swift in Sources */,
|
||||||
0373D9472ED57F3F0017DCC7 /* UINavigationBar+NRAdd.swift in Sources */,
|
0373D9472ED57F3F0017DCC7 /* UINavigationBar+NRAdd.swift in Sources */,
|
||||||
|
85CF94252EEC09AE006467E3 /* NRCoinsPackClaimCell.swift in Sources */,
|
||||||
0373D94D2ED583A80017DCC7 /* NRNovelModel.swift in Sources */,
|
0373D94D2ED583A80017DCC7 /* NRNovelModel.swift in Sources */,
|
||||||
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */,
|
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */,
|
||||||
F3B859732EE94A760095A9CC /* NRAppWebViewController.swift in Sources */,
|
F3B859732EE94A760095A9CC /* NRAppWebViewController.swift in Sources */,
|
||||||
@ -1375,6 +1414,7 @@
|
|||||||
F343492C2EDE72F300AA7E70 /* NRHomeAPI.swift in Sources */,
|
F343492C2EDE72F300AA7E70 /* NRHomeAPI.swift in Sources */,
|
||||||
F3B859372EE6750B0095A9CC /* NRLanguageViewController.swift in Sources */,
|
F3B859372EE6750B0095A9CC /* NRLanguageViewController.swift in Sources */,
|
||||||
F34348E12ED70A2700AA7E70 /* NRNovelDetailHeaderView+NovelCoverInfo.swift in Sources */,
|
F34348E12ED70A2700AA7E70 /* NRNovelDetailHeaderView+NovelCoverInfo.swift in Sources */,
|
||||||
|
85CF94292EED4664006467E3 /* NRVipRetainAlert.swift in Sources */,
|
||||||
F3B859522EE906A90095A9CC /* JXIAPManager.swift in Sources */,
|
F3B859522EE906A90095A9CC /* JXIAPManager.swift in Sources */,
|
||||||
F34349012ED93A9B00AA7E70 /* NRReadChapterModel.swift in Sources */,
|
F34349012ED93A9B00AA7E70 /* NRReadChapterModel.swift in Sources */,
|
||||||
F34348DF2ED7049E00AA7E70 /* NRNovelDetailHeaderView.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 NRWebBaseURL = "https://www.readerhive.net"
|
||||||
|
|
||||||
let NRCampaignWebURL = "https://campaign.readerhive.com"
|
let NRCampaignWebURL = "https://campaign.readerhive.net"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,12 +8,57 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class NRDashedLineView: UIView {
|
class NRDashedLineView: UIView {
|
||||||
|
|
||||||
var isHorizontal: Bool = true // 控制是横向还是纵向绘制
|
|
||||||
|
|
||||||
var lineWidth: CGFloat = 1.0
|
enum Direction : Int {
|
||||||
|
case vertical = 0
|
||||||
|
case horizontal = 1
|
||||||
|
}
|
||||||
|
|
||||||
var lineColor: UIColor = .black.withAlphaComponent(0.25)
|
var direction: Direction = .horizontal {
|
||||||
|
didSet {
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
override func draw(_ rect: CGRect) {
|
||||||
super.draw(rect)
|
super.draw(rect)
|
||||||
@ -22,21 +67,22 @@ class NRDashedLineView: UIView {
|
|||||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||||
|
|
||||||
// 设置线条颜色和宽度
|
// 设置线条颜色和宽度
|
||||||
context.setStrokeColor(UIColor.red.cgColor)
|
context.setStrokeColor(lineColor.cgColor)
|
||||||
context.setLineWidth(lineWidth)
|
context.setLineWidth(lineWidth)
|
||||||
|
|
||||||
// 设置虚线样式
|
// 设置虚线样式
|
||||||
context.setLineDash(phase: 0, lengths: [2, 2]) // 长度为6的线段和间隔为3的空白
|
context.setLineDash(phase: 0, lengths: [dashLength, dashGap])
|
||||||
|
|
||||||
// 根据方向绘制路径
|
// 根据方向绘制路径
|
||||||
if isHorizontal {
|
switch direction {
|
||||||
// 横向绘制
|
case .horizontal:
|
||||||
context.move(to: CGPoint(x: 0, y: self.bounds.midY))
|
let y = self.bounds.midY
|
||||||
context.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.midY))
|
context.move(to: CGPoint(x: 0, y: y))
|
||||||
} else {
|
context.addLine(to: CGPoint(x: self.bounds.width, y: y))
|
||||||
// 纵向绘制
|
case .vertical:
|
||||||
context.move(to: CGPoint(x: self.bounds.midX, y: 0))
|
let x = self.bounds.midX
|
||||||
context.addLine(to: CGPoint(x: self.bounds.midX, y: self.bounds.height))
|
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
|
private var receiveDataCount = 0
|
||||||
|
|
||||||
var theme: String? = "theme_3"
|
var theme: String? = "theme_2"
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
@ -45,29 +45,30 @@ extension NRAppWebViewController {
|
|||||||
receiveDataCount += 1
|
receiveDataCount += 1
|
||||||
if receiveDataCount > 10 { return }
|
if receiveDataCount > 10 { return }
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
||||||
guard let self = self else { return }
|
var dic = [
|
||||||
var dic = [
|
"token" : NRLoginManager.manager.token?.token ?? "",
|
||||||
"token" : NRLoginManager.manager.token?.token ?? "",
|
"time_zone" : NRTargetType.timeZone(),
|
||||||
"time_zone" : NRTargetType.timeZone(),
|
"lang" : NRLocalizedManager.shared.currentLocalizedKey,
|
||||||
"lang" : NRLocalizedManager.shared.currentLocalizedKey,
|
"type" : "ios",
|
||||||
"type" : "ios",
|
"device-id" : NRDeviceId.shared.id
|
||||||
"device-id" : NRDeviceId.shared.id
|
]
|
||||||
]
|
|
||||||
|
if let theme = theme {
|
||||||
if let theme = theme {
|
dic["theme"] = theme
|
||||||
dic["theme"] = theme
|
}
|
||||||
}
|
|
||||||
|
if let id = id {
|
||||||
if let id = id {
|
dic["id"] = id
|
||||||
dic["id"] = id
|
}
|
||||||
}
|
|
||||||
|
if let json = dic.toJsonString() {
|
||||||
if let json = dic.toJsonString() {
|
let js = "receiveDataFromNative(\(json))"
|
||||||
let js = "receiveDataFromNative(\(json))"
|
self.webView.evaluateJavaScript(js) { [weak self] _, error in
|
||||||
self.webView.evaluateJavaScript(js) { [weak self] _, error in
|
guard let self = self else { return }
|
||||||
guard let self = self else { return }
|
if error != nil {
|
||||||
if error != nil {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
self.receiveDataFromNative()
|
self.receiveDataFromNative()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,16 @@ class NRHomeViewController: NRViewController {
|
|||||||
|
|
||||||
lazy var novelVC = NRHomeNovelViewController()
|
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() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
@ -47,6 +57,7 @@ extension NRHomeViewController {
|
|||||||
view.addSubview(titleView)
|
view.addSubview(titleView)
|
||||||
addChild(novelVC)
|
addChild(novelVC)
|
||||||
view.addSubview(novelVC.view)
|
view.addSubview(novelVC.view)
|
||||||
|
view.addSubview(coinsPackButton)
|
||||||
|
|
||||||
searchButton.snp.makeConstraints { make in
|
searchButton.snp.makeConstraints { make in
|
||||||
make.height.equalTo(44)
|
make.height.equalTo(44)
|
||||||
@ -63,6 +74,11 @@ extension NRHomeViewController {
|
|||||||
make.left.right.bottom.equalToSuperview()
|
make.left.right.bottom.equalToSuperview()
|
||||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
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() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.backgroundImageView.isHidden = true
|
self.backgroundImageView.isHidden = true
|
||||||
textView.becomeFirstResponder()
|
|
||||||
|
|
||||||
|
|
||||||
nr_setupUI()
|
nr_setupUI()
|
||||||
@ -61,6 +60,11 @@ class NRSearchViewController: NRViewController {
|
|||||||
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
textView.becomeFirstResponder()
|
||||||
|
}
|
||||||
|
|
||||||
private func search(_ text: String) {
|
private func search(_ text: String) {
|
||||||
if text.isEmpty {
|
if text.isEmpty {
|
||||||
homeView.isHidden = false
|
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? {
|
var model: NRNovelModel? {
|
||||||
didSet {
|
didSet {
|
||||||
coverImageView.nr_setImage(model?.image_url)
|
coverImageView.nr_setImage(model?.image_url)
|
||||||
desLabel.text = model?.name
|
nameLabel.text = model?.name
|
||||||
|
desLabel.text = model?.nr_description
|
||||||
|
|
||||||
tagStackView.nr_removeAllArrangedSubview()
|
tagStackView.nr_removeAllArrangedSubview()
|
||||||
|
|
||||||
@ -85,13 +86,6 @@ class NRSearchResultCell: UICollectionViewCell {
|
|||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
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()
|
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 UIKit
|
||||||
import HWPanModal
|
import HWPanModal
|
||||||
|
import SnapKit
|
||||||
|
|
||||||
class NRDetailRechargeView: NRPanModalContentView {
|
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) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
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) {
|
@MainActor required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
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 {
|
private func tableViewMaxContentOffsetY() -> CGFloat {
|
||||||
let contentSizeH = tableView.contentSize.height
|
let contentSizeH = tableView.contentSize.height
|
||||||
let maxOffsetY = contentSizeH - tableView.bounds.height
|
let maxOffsetY = contentSizeH - tableView.bounds.height
|
||||||
return maxOffsetY
|
// return maxOffsetY
|
||||||
|
return floor(maxOffsetY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMainTableViewToMaxContentOffsetY() {
|
func setMainTableViewToMaxContentOffsetY() {
|
||||||
|
|||||||
@ -184,15 +184,18 @@ extension NRNovelReaderViewController {
|
|||||||
extension NRNovelReaderViewController {
|
extension NRNovelReaderViewController {
|
||||||
|
|
||||||
///装载数据
|
///装载数据
|
||||||
private func loadData() {
|
func loadData() {
|
||||||
Task {
|
Task {
|
||||||
|
NRHud.show()
|
||||||
//获取小说数据
|
//获取小说数据
|
||||||
await self.viewModel.requestNovelDetail()
|
await self.viewModel.requestNovelDetail()
|
||||||
//获取目录数据
|
//获取目录数据
|
||||||
await self.viewModel.requestChapterCatalogList()
|
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 indexPath = self.indexPathToReadRecord()
|
||||||
let section = indexPath.section
|
let section = indexPath.section
|
||||||
@ -208,6 +211,7 @@ extension NRNovelReaderViewController {
|
|||||||
self.viewModel.checkCurrentIndexPath()
|
self.viewModel.checkCurrentIndexPath()
|
||||||
|
|
||||||
self.reloadData()
|
self.reloadData()
|
||||||
|
NRHud.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,9 @@ class NRNovelReadViewModel: NSObject {
|
|||||||
///用来记录上报历史记录的时间
|
///用来记录上报历史记录的时间
|
||||||
var uploadRecordDate: Date?
|
var uploadRecordDate: Date?
|
||||||
|
|
||||||
|
weak var popView: UIView?
|
||||||
|
|
||||||
|
private var payDataRequest = NRPayDataRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -57,7 +60,7 @@ extension NRNovelReadViewModel {
|
|||||||
func backReadPage() {
|
func backReadPage() {
|
||||||
Task {
|
Task {
|
||||||
guard let isShowModel = await NRNovelAPI.requestShowRecommendPop(id: self.novelId), isShowModel.is_pop_up == true else {
|
guard let isShowModel = await NRNovelAPI.requestShowRecommendPop(id: self.novelId), isShowModel.is_pop_up == true else {
|
||||||
await _backReadPage()
|
_backReadPage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,10 +160,74 @@ extension NRNovelReadViewModel {
|
|||||||
|
|
||||||
///打开充值页面
|
///打开充值页面
|
||||||
func openRechargeView() {
|
func openRechargeView() {
|
||||||
// let view = NRDetailRechargeView()
|
guard self.popView == nil else { return }
|
||||||
// view.present(in: nil)
|
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
|
//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 UIKit
|
||||||
import SnapKit
|
import SnapKit
|
||||||
|
import YYCategories
|
||||||
|
|
||||||
|
|
||||||
class NRCoinsPackHeaderView: UIView {
|
class NRCoinsPackHeaderView: UIView {
|
||||||
|
|
||||||
var clickClaimButton: (() -> Void)?
|
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 = {
|
private lazy var titleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
@ -28,19 +45,85 @@ class NRCoinsPackHeaderView: UIView {
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var lineView1: NRDashedLineView = {
|
|
||||||
let view = NRDashedLineView()
|
|
||||||
view.isHorizontal = false
|
|
||||||
return view
|
|
||||||
}()
|
|
||||||
|
|
||||||
private lazy var coinsView2: CoinsView = {
|
private lazy var coinsView2: CoinsView = {
|
||||||
let view = CoinsView()
|
let view = CoinsView()
|
||||||
view.title = "Claimable Coins".localized
|
view.title = "Claimable Coins".localized
|
||||||
view.coins = 0
|
view.coins = 0
|
||||||
return view
|
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) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
@ -60,6 +143,10 @@ extension NRCoinsPackHeaderView {
|
|||||||
addSubview(coinsView1)
|
addSubview(coinsView1)
|
||||||
addSubview(coinsView2)
|
addSubview(coinsView2)
|
||||||
addSubview(lineView1)
|
addSubview(lineView1)
|
||||||
|
addSubview(countTitleLabel)
|
||||||
|
addSubview(countLabel)
|
||||||
|
addSubview(claimButton)
|
||||||
|
addSubview(lineView2)
|
||||||
|
|
||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(16)
|
make.left.equalToSuperview().offset(16)
|
||||||
@ -74,13 +161,35 @@ extension NRCoinsPackHeaderView {
|
|||||||
lineView1.snp.makeConstraints { make in
|
lineView1.snp.makeConstraints { make in
|
||||||
make.centerY.equalTo(coinsView1)
|
make.centerY.equalTo(coinsView1)
|
||||||
make.left.equalTo(coinsView1.snp.right).offset(18)
|
make.left.equalTo(coinsView1.snp.right).offset(18)
|
||||||
make.width.equalTo(1)
|
|
||||||
make.height.equalTo(32)
|
make.height.equalTo(32)
|
||||||
}
|
}
|
||||||
|
|
||||||
coinsView2.snp.makeConstraints { make in
|
coinsView2.snp.makeConstraints { make in
|
||||||
make.centerY.equalTo(lineView1)
|
make.centerY.equalTo(lineView1)
|
||||||
make.left.equalTo(lineView1.snp.right).offset(18)
|
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()
|
make.bottom.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -111,20 +111,20 @@ class NRStoreCoinsPackCell: NRStoreCoinsCell {
|
|||||||
|
|
||||||
let priceString = AttributedString("\(currency)\(discountPrice)", attributes: AttributeContainer([
|
let priceString = AttributedString("\(currency)\(discountPrice)", attributes: AttributeContainer([
|
||||||
.font : UIFont.font(ofSize: 18, weight: .bold),
|
.font : UIFont.font(ofSize: 18, weight: .bold),
|
||||||
// .foregroundColor : UIColor._114_CEE
|
.foregroundColor : UIColor._946_A_37
|
||||||
]))
|
]))
|
||||||
|
|
||||||
|
|
||||||
// button.configuration?.attributedTitle = priceString
|
button.configuration?.attributedTitle = priceString
|
||||||
//
|
|
||||||
// var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||||
// .font : UIFont.font(ofSize: 12, weight: .regular),
|
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||||
// .foregroundColor : UIColor._636_F_7_B.withAlphaComponent(0.05),
|
.foregroundColor : UIColor.black.withAlphaComponent(0.05),
|
||||||
// .strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
.strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
||||||
// .strikethroughColor: UIColor._636_F_7_B.withAlphaComponent(0.05)
|
.strikethroughColor: UIColor.black.withAlphaComponent(0.05)
|
||||||
// ]))
|
]))
|
||||||
//
|
|
||||||
// button.configuration?.attributedSubtitle = subtitle
|
button.configuration?.attributedSubtitle = subtitle
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|||||||
@ -7,9 +7,32 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SnapKit
|
import SnapKit
|
||||||
|
import YYText
|
||||||
|
|
||||||
class NRCoinsPackViewController: NRViewController {
|
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 = {
|
private lazy var bgIconImageView: UIImageView = {
|
||||||
let imageView = UIImageView(image: UIImage(named: "calendar_icon_02"))
|
let imageView = UIImageView(image: UIImage(named: "calendar_icon_02"))
|
||||||
@ -23,15 +46,87 @@ class NRCoinsPackViewController: NRViewController {
|
|||||||
|
|
||||||
private lazy var headerView: NRCoinsPackHeaderView = {
|
private lazy var headerView: NRCoinsPackHeaderView = {
|
||||||
let view = NRCoinsPackHeaderView()
|
let view = NRCoinsPackHeaderView()
|
||||||
|
view.clickClaimButton = { [weak self] in
|
||||||
|
self?.requestReceiveCoins(nil)
|
||||||
|
}
|
||||||
return view
|
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() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.title = "My Refills".localized
|
self.title = "My Refills".localized
|
||||||
configNavigationBack("arrow_left_icon_05")
|
configNavigationBack("arrow_left_icon_05")
|
||||||
|
|
||||||
|
payDataModel = NRIapManager.manager.payDateModel
|
||||||
|
|
||||||
nr_setupUI()
|
nr_setupUI()
|
||||||
|
|
||||||
|
updateLayout()
|
||||||
|
|
||||||
|
requestCoinsPackData()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
@ -39,6 +134,18 @@ class NRCoinsPackViewController: NRViewController {
|
|||||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||||
self.nr_setNavigationStyle(titleColor: UINavigationBar.titleBlackColor)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +155,7 @@ extension NRCoinsPackViewController {
|
|||||||
view.addSubview(bgIconImageView)
|
view.addSubview(bgIconImageView)
|
||||||
view.addSubview(scrollView)
|
view.addSubview(scrollView)
|
||||||
scrollView.addSubview(headerView)
|
scrollView.addSubview(headerView)
|
||||||
|
scrollView.addSubview(stackView)
|
||||||
|
|
||||||
|
|
||||||
bgIconImageView.snp.makeConstraints { make in
|
bgIconImageView.snp.makeConstraints { make in
|
||||||
@ -65,6 +173,51 @@ extension NRCoinsPackViewController {
|
|||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
make.top.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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -44,12 +44,40 @@ class NRStoreViewController: NRViewController {
|
|||||||
}
|
}
|
||||||
return view
|
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() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.title = "Store".localized
|
self.title = "Store".localized
|
||||||
configNavigationBack("arrow_left_icon_05")
|
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()
|
nr_setupUI()
|
||||||
|
|
||||||
restore(isLoding: false)
|
restore(isLoding: false)
|
||||||
@ -96,7 +124,7 @@ class NRStoreViewController: NRViewController {
|
|||||||
self.addVipView()
|
self.addVipView()
|
||||||
self.addCoinsView()
|
self.addCoinsView()
|
||||||
}
|
}
|
||||||
// self.stackView.addArrangedSubview(tipView)
|
self.stackView.addArrangedSubview(tipView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addCoinsView() {
|
private func addCoinsView() {
|
||||||
|
|||||||
@ -11,12 +11,11 @@ internal import StoreKit
|
|||||||
class NRPayDataRequest: NSObject {
|
class NRPayDataRequest: NSObject {
|
||||||
|
|
||||||
private var oldTemplateModel: NRPayDateModel?
|
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 completerBlock: ((_ model: NRPayDateModel?) -> Void)?
|
||||||
// private var payAlertBlock: ((_ model: FAPayAlertModel?) -> Void)?
|
private var payAlertBlock: ((_ model: NRPayAlertModel?) -> Void)?
|
||||||
|
|
||||||
private var isLoding = false
|
private var isLoding = false
|
||||||
private var isToast = false
|
private var isToast = false
|
||||||
@ -80,26 +79,26 @@ class NRPayDataRequest: NSObject {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
///挽留信息
|
///挽留信息
|
||||||
// func requestVipRetainPayInfo(completer: ((_ model: FAPayAlertModel?) -> Void)?) {
|
func requestVipRetainPayInfo(completer: ((_ model: NRPayAlertModel?) -> Void)?) {
|
||||||
// self.completerBlock = nil
|
self.completerBlock = nil
|
||||||
// self.payAlertBlock = completer
|
self.payAlertBlock = completer
|
||||||
//
|
|
||||||
// FAStoreAPI.requestVipRetainPayInfo { [weak self] model in
|
NRStoreAPI.requestVipRetainPayInfo { [weak self] model in
|
||||||
// guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
// guard let model = model else {
|
guard let model = model else {
|
||||||
// self.payAlertBlock?(nil)
|
self.payAlertBlock?(nil)
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// self.payAlertModel = model
|
self.payAlertModel = model
|
||||||
//
|
|
||||||
// let productId = FAIapManager.manager.getProductId(templateId: model.info?.ios_template_id) ?? ""
|
let productId = NRIapManager.manager.getProductId(templateId: model.info?.ios_template_id) ?? ""
|
||||||
//
|
|
||||||
// let set = Set([productId])
|
let set = Set([productId])
|
||||||
// let productsRequest = SKProductsRequest(productIdentifiers: set)
|
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||||
// productsRequest.delegate = self
|
productsRequest.delegate = self
|
||||||
// productsRequest.start()
|
productsRequest.start()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: SKProductsRequestDelegate
|
//MARK: SKProductsRequestDelegate
|
||||||
@ -148,31 +147,29 @@ extension NRPayDataRequest: SKProductsRequestDelegate {
|
|||||||
templateModel.list_coins = newCoinList
|
templateModel.list_coins = newCoinList
|
||||||
templateModel.list_sub_vip = newVipList
|
templateModel.list_sub_vip = newVipList
|
||||||
|
|
||||||
self.newTemplateModel = templateModel
|
|
||||||
NRIapManager.manager.payDateModel = templateModel
|
NRIapManager.manager.payDateModel = templateModel
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
block(templateModel)
|
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";
|
"Rewards Overview" = "Rewards Overview";
|
||||||
"Weekly Total" = "Weekly Total";
|
"Weekly Total" = "Weekly Total";
|
||||||
"Claimable Coins" = "Claimable Coins";
|
"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_1" = "You are already a member!";
|
||||||
"pay_error_2" = "You have unfinished in-app purchases, please restore them first.";
|
"pay_error_2" = "You have unfinished in-app purchases, please restore them first.";
|
||||||
|
|||||||