1
1
Podfile
@ -24,6 +24,7 @@ target 'XSeri' do
|
||||
pod 'MJRefresh'
|
||||
pod 'HWPanModal'
|
||||
pod 'ZLPhotoBrowser'
|
||||
pod 'JXIAPManager', :git => 'https://git.qinjiu8.com/zengjx/JXIAPManager.git', :tag => '0.0.3'
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
50DCF656E93DB15465B55F09 /* Pods_XSeri.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 161AA91CBF35A7C2C85D6649 /* Pods_XSeri.framework */; };
|
||||
F304E6102F67A9B600E9B0A6 /* XSShortDetailLockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F304E60F2F67A9B600E9B0A6 /* XSShortDetailLockView.swift */; };
|
||||
F304E6122F67D74A00E9B0A6 /* XSVideoUnlockResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F304E6112F67D74A00E9B0A6 /* XSVideoUnlockResult.swift */; };
|
||||
F347D28D2F03709200786648 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F347D2832F03709200786648 /* AppDelegate.swift */; };
|
||||
F347D28E2F03709200786648 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F347D28A2F03709200786648 /* SceneDelegate.swift */; };
|
||||
F347D2902F03709200786648 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F347D2842F03709200786648 /* Assets.xcassets */; };
|
||||
@ -135,6 +137,33 @@
|
||||
F3B312BD2F30B0A10093B180 /* XSSearchSuggestionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3B312B82F30B0A10093B180 /* XSSearchSuggestionCell.swift */; };
|
||||
F3B312BE2F30B0A10093B180 /* XSSearchResultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3B312B92F30B0A10093B180 /* XSSearchResultCell.swift */; };
|
||||
F3B312BF2F30B2000093B180 /* XSSearchHistoryHotView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3B312B52F30B2000093B180 /* XSSearchHistoryHotView.swift */; };
|
||||
F3F388D52F67DDBC001B0E15 /* XSMineWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388D42F67DDBC001B0E15 /* XSMineWalletView.swift */; };
|
||||
F3F388D72F67EDEC001B0E15 /* XSMineCoinsPackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388D62F67EDEC001B0E15 /* XSMineCoinsPackView.swift */; };
|
||||
F3F388D92F67F9E1001B0E15 /* XSMineVipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388D82F67F9E1001B0E15 /* XSMineVipView.swift */; };
|
||||
F3F388DF2F67FE6D001B0E15 /* XSStoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388DE2F67FE6D001B0E15 /* XSStoreViewController.swift */; };
|
||||
F3F388E12F680090001B0E15 /* XSScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388E02F68008F001B0E15 /* XSScrollView.swift */; };
|
||||
F3F388E32F680316001B0E15 /* XSStoreCoinsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388E22F680316001B0E15 /* XSStoreCoinsView.swift */; };
|
||||
F3F388E52F68032A001B0E15 /* XSStoreVipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388E42F68032A001B0E15 /* XSStoreVipView.swift */; };
|
||||
F3F388E72F6805DE001B0E15 /* XSPayItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388E62F6805DE001B0E15 /* XSPayItem.swift */; };
|
||||
F3F388E92F68062F001B0E15 /* XSPayDateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388E82F68062F001B0E15 /* XSPayDateModel.swift */; };
|
||||
F3F388EC2F680CEE001B0E15 /* XSIapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388EB2F680CEE001B0E15 /* XSIapManager.swift */; };
|
||||
F3F388EE2F68E6EB001B0E15 /* XSWaitRestoreModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388ED2F68E6EB001B0E15 /* XSWaitRestoreModel.swift */; };
|
||||
F3F388F02F68E737001B0E15 /* XSStoreAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388EF2F68E737001B0E15 /* XSStoreAPI.swift */; };
|
||||
F3F388F22F68E9BE001B0E15 /* XSIapVerifyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388F12F68E9BE001B0E15 /* XSIapVerifyModel.swift */; };
|
||||
F3F388F42F68F2CD001B0E15 /* XSIapOrderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388F32F68F2CD001B0E15 /* XSIapOrderModel.swift */; };
|
||||
F3F388F62F68F746001B0E15 /* XSPayDataRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388F52F68F746001B0E15 /* XSPayDataRequest.swift */; };
|
||||
F3F388F82F692031001B0E15 /* XSWalletViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388F72F692031001B0E15 /* XSWalletViewController.swift */; };
|
||||
F3F388FA2F69240E001B0E15 /* XSWalletHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388F92F69240E001B0E15 /* XSWalletHeaderView.swift */; };
|
||||
F3F388FC2F692CEF001B0E15 /* XSWalletCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388FB2F692CEF001B0E15 /* XSWalletCell.swift */; };
|
||||
F3F388FE2F6931D1001B0E15 /* XSConsumptionRecordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388FD2F6931D1001B0E15 /* XSConsumptionRecordsViewController.swift */; };
|
||||
F3F389002F693293001B0E15 /* XSConsumptionRecordsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F388FF2F693293001B0E15 /* XSConsumptionRecordsCell.swift */; };
|
||||
F3F389022F693785001B0E15 /* XSBuyRecordsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F389012F693785001B0E15 /* XSBuyRecordsModel.swift */; };
|
||||
F3F389042F6939C7001B0E15 /* XSOrderRecordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F389032F6939C7001B0E15 /* XSOrderRecordsViewController.swift */; };
|
||||
F3F389062F6939EE001B0E15 /* XSRewardCoinsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F389052F6939EE001B0E15 /* XSRewardCoinsViewController.swift */; };
|
||||
F3F389082F6940BB001B0E15 /* XSRewardCoinsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F389072F6940BB001B0E15 /* XSRewardCoinsCell.swift */; };
|
||||
F3F3890A2F694109001B0E15 /* XSSendCoinRecordModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F389092F694109001B0E15 /* XSSendCoinRecordModel.swift */; };
|
||||
F3F3890C2F695055001B0E15 /* FACoinsRecordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F3890B2F695055001B0E15 /* FACoinsRecordViewController.swift */; };
|
||||
F3F3890E2F695068001B0E15 /* FAVipRecordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F3890D2F695068001B0E15 /* FAVipRecordViewController.swift */; };
|
||||
F3F683ED2F56C380008AF250 /* XSHomeHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F683EC2F56C380008AF250 /* XSHomeHistoryView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -142,6 +171,8 @@
|
||||
161AA91CBF35A7C2C85D6649 /* Pods_XSeri.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_XSeri.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3711C91B5F8043B3213F7116 /* Pods-XSeri.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XSeri.debug.xcconfig"; path = "Target Support Files/Pods-XSeri/Pods-XSeri.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A9C8E3A3362E04C75537A56F /* Pods-XSeri.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XSeri.release.xcconfig"; path = "Target Support Files/Pods-XSeri/Pods-XSeri.release.xcconfig"; sourceTree = "<group>"; };
|
||||
F304E60F2F67A9B600E9B0A6 /* XSShortDetailLockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSShortDetailLockView.swift; sourceTree = "<group>"; };
|
||||
F304E6112F67D74A00E9B0A6 /* XSVideoUnlockResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSVideoUnlockResult.swift; sourceTree = "<group>"; };
|
||||
F347D26B2F03708600786648 /* XSeri.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XSeri.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F347D2832F03709200786648 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
F347D2842F03709200786648 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
@ -271,6 +302,33 @@
|
||||
F3B312B62F319CBE0093B180 /* XSEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSEmpty.swift; sourceTree = "<group>"; };
|
||||
F3B312B82F30B0A10093B180 /* XSSearchSuggestionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSSearchSuggestionCell.swift; sourceTree = "<group>"; };
|
||||
F3B312B92F30B0A10093B180 /* XSSearchResultCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSSearchResultCell.swift; sourceTree = "<group>"; };
|
||||
F3F388D42F67DDBC001B0E15 /* XSMineWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSMineWalletView.swift; sourceTree = "<group>"; };
|
||||
F3F388D62F67EDEC001B0E15 /* XSMineCoinsPackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSMineCoinsPackView.swift; sourceTree = "<group>"; };
|
||||
F3F388D82F67F9E1001B0E15 /* XSMineVipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSMineVipView.swift; sourceTree = "<group>"; };
|
||||
F3F388DE2F67FE6D001B0E15 /* XSStoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSStoreViewController.swift; sourceTree = "<group>"; };
|
||||
F3F388E02F68008F001B0E15 /* XSScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSScrollView.swift; sourceTree = "<group>"; };
|
||||
F3F388E22F680316001B0E15 /* XSStoreCoinsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSStoreCoinsView.swift; sourceTree = "<group>"; };
|
||||
F3F388E42F68032A001B0E15 /* XSStoreVipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSStoreVipView.swift; sourceTree = "<group>"; };
|
||||
F3F388E62F6805DE001B0E15 /* XSPayItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSPayItem.swift; sourceTree = "<group>"; };
|
||||
F3F388E82F68062F001B0E15 /* XSPayDateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSPayDateModel.swift; sourceTree = "<group>"; };
|
||||
F3F388EB2F680CEE001B0E15 /* XSIapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSIapManager.swift; sourceTree = "<group>"; };
|
||||
F3F388ED2F68E6EB001B0E15 /* XSWaitRestoreModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSWaitRestoreModel.swift; sourceTree = "<group>"; };
|
||||
F3F388EF2F68E737001B0E15 /* XSStoreAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSStoreAPI.swift; sourceTree = "<group>"; };
|
||||
F3F388F12F68E9BE001B0E15 /* XSIapVerifyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSIapVerifyModel.swift; sourceTree = "<group>"; };
|
||||
F3F388F32F68F2CD001B0E15 /* XSIapOrderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSIapOrderModel.swift; sourceTree = "<group>"; };
|
||||
F3F388F52F68F746001B0E15 /* XSPayDataRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSPayDataRequest.swift; sourceTree = "<group>"; };
|
||||
F3F388F72F692031001B0E15 /* XSWalletViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSWalletViewController.swift; sourceTree = "<group>"; };
|
||||
F3F388F92F69240E001B0E15 /* XSWalletHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSWalletHeaderView.swift; sourceTree = "<group>"; };
|
||||
F3F388FB2F692CEF001B0E15 /* XSWalletCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSWalletCell.swift; sourceTree = "<group>"; };
|
||||
F3F388FD2F6931D1001B0E15 /* XSConsumptionRecordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSConsumptionRecordsViewController.swift; sourceTree = "<group>"; };
|
||||
F3F388FF2F693293001B0E15 /* XSConsumptionRecordsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSConsumptionRecordsCell.swift; sourceTree = "<group>"; };
|
||||
F3F389012F693785001B0E15 /* XSBuyRecordsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSBuyRecordsModel.swift; sourceTree = "<group>"; };
|
||||
F3F389032F6939C7001B0E15 /* XSOrderRecordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSOrderRecordsViewController.swift; sourceTree = "<group>"; };
|
||||
F3F389052F6939EE001B0E15 /* XSRewardCoinsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSRewardCoinsViewController.swift; sourceTree = "<group>"; };
|
||||
F3F389072F6940BB001B0E15 /* XSRewardCoinsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSRewardCoinsCell.swift; sourceTree = "<group>"; };
|
||||
F3F389092F694109001B0E15 /* XSSendCoinRecordModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSSendCoinRecordModel.swift; sourceTree = "<group>"; };
|
||||
F3F3890B2F695055001B0E15 /* FACoinsRecordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsRecordViewController.swift; sourceTree = "<group>"; };
|
||||
F3F3890D2F695068001B0E15 /* FAVipRecordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAVipRecordViewController.swift; sourceTree = "<group>"; };
|
||||
F3F683EC2F56C380008AF250 /* XSHomeHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSHomeHistoryView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -375,6 +433,7 @@
|
||||
F347D2AD2F03AE3E00786648 /* Home */,
|
||||
F347D3172F0A53FE00786648 /* Discover */,
|
||||
F347D3112F0A41FC00786648 /* Player */,
|
||||
F3F388DA2F67FDFF001B0E15 /* Store */,
|
||||
);
|
||||
path = Class;
|
||||
sourceTree = "<group>";
|
||||
@ -404,6 +463,7 @@
|
||||
F35547F92F4E9F0A006F28CD /* XSView.swift */,
|
||||
F35547FB2F4EA069006F28CD /* XSButton.swift */,
|
||||
F355480D2F50485E006F28CD /* XSPanModalContentView.swift */,
|
||||
F3F388E02F68008F001B0E15 /* XSScrollView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -422,6 +482,7 @@
|
||||
F347D29C2F03A5A100786648 /* Libs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3F388EA2F680CC7001B0E15 /* IapManager */,
|
||||
F3B312B52F319CA50093B180 /* Empty */,
|
||||
F347D3042F0A12DB00786648 /* HUD */,
|
||||
F347D29E2F03A6B100786648 /* XSTool.swift */,
|
||||
@ -563,6 +624,7 @@
|
||||
F347D3212F0A58BE00786648 /* XSVideoAPI.swift */,
|
||||
F347D30D2F0A39D500786648 /* XSHomeAPI.swift */,
|
||||
F347D3002F0A0D7E00786648 /* XSUserAPI.swift */,
|
||||
F3F388EF2F68E737001B0E15 /* XSStoreAPI.swift */,
|
||||
);
|
||||
path = API;
|
||||
sourceTree = "<group>";
|
||||
@ -593,6 +655,7 @@
|
||||
F347D3132F0A429C00786648 /* XSShortModel.swift */,
|
||||
F347D3152F0A430300786648 /* XSVideoInfoModel.swift */,
|
||||
F3585C462F14EAE700EEC469 /* XSShortDetailModel.swift */,
|
||||
F304E6112F67D74A00E9B0A6 /* XSVideoUnlockResult.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@ -652,6 +715,9 @@
|
||||
F35548072F4FD703006F28CD /* XSMineUserInfoView.swift */,
|
||||
F35548052F4FD6DA006F28CD /* XSMinePlayHistoryView.swift */,
|
||||
F35548092F4FE99F006F28CD /* XSMinePlayHistoryCell.swift */,
|
||||
F3F388D42F67DDBC001B0E15 /* XSMineWalletView.swift */,
|
||||
F3F388D62F67EDEC001B0E15 /* XSMineCoinsPackView.swift */,
|
||||
F3F388D82F67F9E1001B0E15 /* XSMineVipView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -720,6 +786,7 @@
|
||||
children = (
|
||||
F3585C482F14EE8D00EEC469 /* XSShortDetailPlayerCell.swift */,
|
||||
F3585C4A2F14FD1000EEC469 /* XSShortDetailPlayerControlView.swift */,
|
||||
F304E60F2F67A9B600E9B0A6 /* XSShortDetailLockView.swift */,
|
||||
F3585C3E2F14C83700EEC469 /* XSPlayerEpButton.swift */,
|
||||
F355480F2F504D74006F28CD /* XSEpSelectorView.swift */,
|
||||
F35548112F5129F2006F28CD /* XSEpSelectorCell.swift */,
|
||||
@ -761,6 +828,66 @@
|
||||
path = Empty;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F3F388DA2F67FDFF001B0E15 /* Store */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3F388DB2F67FE13001B0E15 /* Controller */,
|
||||
F3F388DC2F67FE2E001B0E15 /* View */,
|
||||
F3F388DD2F67FE36001B0E15 /* Model */,
|
||||
);
|
||||
path = Store;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F3F388DB2F67FE13001B0E15 /* Controller */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3F388DE2F67FE6D001B0E15 /* XSStoreViewController.swift */,
|
||||
F3F388F72F692031001B0E15 /* XSWalletViewController.swift */,
|
||||
F3F388FD2F6931D1001B0E15 /* XSConsumptionRecordsViewController.swift */,
|
||||
F3F389052F6939EE001B0E15 /* XSRewardCoinsViewController.swift */,
|
||||
F3F389032F6939C7001B0E15 /* XSOrderRecordsViewController.swift */,
|
||||
F3F3890B2F695055001B0E15 /* FACoinsRecordViewController.swift */,
|
||||
F3F3890D2F695068001B0E15 /* FAVipRecordViewController.swift */,
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F3F388DC2F67FE2E001B0E15 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3F388E22F680316001B0E15 /* XSStoreCoinsView.swift */,
|
||||
F3F388E42F68032A001B0E15 /* XSStoreVipView.swift */,
|
||||
F3F388F92F69240E001B0E15 /* XSWalletHeaderView.swift */,
|
||||
F3F388FB2F692CEF001B0E15 /* XSWalletCell.swift */,
|
||||
F3F388FF2F693293001B0E15 /* XSConsumptionRecordsCell.swift */,
|
||||
F3F389072F6940BB001B0E15 /* XSRewardCoinsCell.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F3F388DD2F67FE36001B0E15 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3F388E82F68062F001B0E15 /* XSPayDateModel.swift */,
|
||||
F3F388E62F6805DE001B0E15 /* XSPayItem.swift */,
|
||||
F3F389012F693785001B0E15 /* XSBuyRecordsModel.swift */,
|
||||
F3F389092F694109001B0E15 /* XSSendCoinRecordModel.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F3F388EA2F680CC7001B0E15 /* IapManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3F388EB2F680CEE001B0E15 /* XSIapManager.swift */,
|
||||
F3F388F52F68F746001B0E15 /* XSPayDataRequest.swift */,
|
||||
F3F388ED2F68E6EB001B0E15 /* XSWaitRestoreModel.swift */,
|
||||
F3F388F12F68E9BE001B0E15 /* XSIapVerifyModel.swift */,
|
||||
F3F388F32F68F2CD001B0E15 /* XSIapOrderModel.swift */,
|
||||
);
|
||||
path = IapManager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -898,6 +1025,7 @@
|
||||
F347D2F32F0A083500786648 /* XSDeviceId.swift in Sources */,
|
||||
F35547E22F3DCB82006F28CD /* UINavigationBar+XS.swift in Sources */,
|
||||
F347D30A2F0A162800786648 /* XSNetworkPlugin.swift in Sources */,
|
||||
F3F388EC2F680CEE001B0E15 /* XSIapManager.swift in Sources */,
|
||||
F347D3082F0A134500786648 /* XSHud.swift in Sources */,
|
||||
F347D29E2F03750000786648 /* XSTabBarItemContentView.swift in Sources */,
|
||||
F347D2FE2F0A0D0700786648 /* XSUserDefaultsKey.swift in Sources */,
|
||||
@ -912,16 +1040,25 @@
|
||||
F347D30C2F0A36E200786648 /* XSNetworkMonitorManager.swift in Sources */,
|
||||
F347D2D82F04CB0300786648 /* XSLabel.swift in Sources */,
|
||||
F35548082F4FD703006F28CD /* XSMineUserInfoView.swift in Sources */,
|
||||
F3F388FC2F692CEF001B0E15 /* XSWalletCell.swift in Sources */,
|
||||
F347D2E82F0A03AB00786648 /* XSNetworkModel.swift in Sources */,
|
||||
F35547FE2F4EC450006F28CD /* XSMyCollectViewController.swift in Sources */,
|
||||
F347D29B2F03740000786648 /* XSConfig.swift in Sources */,
|
||||
F3F388DF2F67FE6D001B0E15 /* XSStoreViewController.swift in Sources */,
|
||||
F35547F42F3EFC37006F28CD /* XSMyListCollectsCell.swift in Sources */,
|
||||
F347D2A72F03AAD700786648 /* XSViewController.swift in Sources */,
|
||||
F3585C342F148F0800EEC469 /* XSHomeViewModel.swift in Sources */,
|
||||
F347D2B02F03AE6700786648 /* XSHomeViewController.swift in Sources */,
|
||||
F304E6102F67A9B600E9B0A6 /* XSShortDetailLockView.swift in Sources */,
|
||||
F3585C3A2F14999700EEC469 /* XSProgressView.swift in Sources */,
|
||||
F3F389062F6939EE001B0E15 /* XSRewardCoinsViewController.swift in Sources */,
|
||||
F3585C382F1497AF00EEC469 /* XSDiscoverControlView.swift in Sources */,
|
||||
F3F388D52F67DDBC001B0E15 /* XSMineWalletView.swift in Sources */,
|
||||
F3F388D92F67F9E1001B0E15 /* XSMineVipView.swift in Sources */,
|
||||
F347D2D42F04BF3D00786648 /* XSHomeNewTitleView.swift in Sources */,
|
||||
F304E6122F67D74A00E9B0A6 /* XSVideoUnlockResult.swift in Sources */,
|
||||
F3F388FE2F6931D1001B0E15 /* XSConsumptionRecordsViewController.swift in Sources */,
|
||||
F3F3890C2F695055001B0E15 /* FACoinsRecordViewController.swift in Sources */,
|
||||
F347D28D2F03709200786648 /* AppDelegate.swift in Sources */,
|
||||
F3585C492F14EE8D00EEC469 /* XSShortDetailPlayerCell.swift in Sources */,
|
||||
F35548412F52BE6D006F28CD /* XSBaseWebViewController+Script.swift in Sources */,
|
||||
@ -931,6 +1068,7 @@
|
||||
F355480E2F50485E006F28CD /* XSPanModalContentView.swift in Sources */,
|
||||
F347D2C82F03DBD300786648 /* UIView+XS.swift in Sources */,
|
||||
F355483B2F52BA4A006F28CD /* XSFeedbackViewController.swift in Sources */,
|
||||
F3F388F22F68E9BE001B0E15 /* XSIapVerifyModel.swift in Sources */,
|
||||
F347D2FA2F0A0C5600786648 /* XSLoginManager.swift in Sources */,
|
||||
F35547DC2F3DB33C006F28CD /* XSMineHeaderView.swift in Sources */,
|
||||
F347D2B52F03B2B500786648 /* UIFont+XS.swift in Sources */,
|
||||
@ -939,18 +1077,26 @@
|
||||
F347D2EA2F0A047A00786648 /* XSNetwork.swift in Sources */,
|
||||
F347D2A32F03A93200786648 /* XSDefine.swift in Sources */,
|
||||
F3585C3C2F14BFAB00EEC469 /* XSCustomTabBar.swift in Sources */,
|
||||
F3F388EE2F68E6EB001B0E15 /* XSWaitRestoreModel.swift in Sources */,
|
||||
F3585C422F14E99C00EEC469 /* XSShortDetailViewController.swift in Sources */,
|
||||
F347D2DE2F04F54400786648 /* XSHomeCategoriesViewController.swift in Sources */,
|
||||
F347D3012F0A0D8200786648 /* XSUserAPI.swift in Sources */,
|
||||
F3F388F02F68E737001B0E15 /* XSStoreAPI.swift in Sources */,
|
||||
F3585C452F14EA0A00EEC469 /* XSShortDetailViewModel.swift in Sources */,
|
||||
F35547D02F3DA6CA006F28CD /* XSMineViewController.swift in Sources */,
|
||||
F347D2D22F04B97600786648 /* XSHomeNewBigCell.swift in Sources */,
|
||||
F3F388F42F68F2CD001B0E15 /* XSIapOrderModel.swift in Sources */,
|
||||
F3F389022F693785001B0E15 /* XSBuyRecordsModel.swift in Sources */,
|
||||
F35548102F504D74006F28CD /* XSEpSelectorView.swift in Sources */,
|
||||
F3F388FA2F69240E001B0E15 /* XSWalletHeaderView.swift in Sources */,
|
||||
F35548122F5129F2006F28CD /* XSEpSelectorCell.swift in Sources */,
|
||||
F3F388E32F680316001B0E15 /* XSStoreCoinsView.swift in Sources */,
|
||||
F355480C2F50398B006F28CD /* NSNumber+XS.swift in Sources */,
|
||||
F347D2E02F04F7ED00786648 /* XSHomeCategoriesCell.swift in Sources */,
|
||||
F3F3890A2F694109001B0E15 /* XSSendCoinRecordModel.swift in Sources */,
|
||||
F347D3032F0A10B600786648 /* XSCryptorService.swift in Sources */,
|
||||
F35547D42F3DA7A8006F28CD /* XSTableViewCell.swift in Sources */,
|
||||
F3F388F62F68F746001B0E15 /* XSPayDataRequest.swift in Sources */,
|
||||
F347D30E2F0A39DE00786648 /* XSHomeAPI.swift in Sources */,
|
||||
F3B312B72F319CBE0093B180 /* XSEmpty.swift in Sources */,
|
||||
F347D2F62F0A0B0B00786648 /* XSLoginToken.swift in Sources */,
|
||||
@ -958,11 +1104,14 @@
|
||||
F347D2BE2F03C24B00786648 /* XSCollectionView.swift in Sources */,
|
||||
F35547DA2F3DAACB006F28CD /* XSMineItem.swift in Sources */,
|
||||
F347D2D62F04C7D500786648 /* XSHomeNewCell.swift in Sources */,
|
||||
F3F388E92F68062F001B0E15 /* XSPayDateModel.swift in Sources */,
|
||||
F347D2CC2F03E04400786648 /* AppDelegate+Config.swift in Sources */,
|
||||
F347D3202F0A57A300786648 /* XSDiscoverPlayerCell.swift in Sources */,
|
||||
F35548022F4ECD5C006F28CD /* UIScrollView+Refresh.swift in Sources */,
|
||||
F347D2EC2F0A060E00786648 /* XSNetworkTarget.swift in Sources */,
|
||||
F3F388E12F680090001B0E15 /* XSScrollView.swift in Sources */,
|
||||
F35547E92F3DDBDD006F28CD /* XSWebView.swift in Sources */,
|
||||
F3F389042F6939C7001B0E15 /* XSOrderRecordsViewController.swift in Sources */,
|
||||
F347D31A2F0A545000786648 /* XSDiscoverViewController.swift in Sources */,
|
||||
F355483D2F52BC81006F28CD /* XSSettingAPI.swift in Sources */,
|
||||
F3B312A42F30AC9B0093B180 /* XSSearchData.swift in Sources */,
|
||||
@ -973,11 +1122,14 @@
|
||||
F3F683ED2F56C380008AF250 /* XSHomeHistoryView.swift in Sources */,
|
||||
F347D2A12F03A84300786648 /* XSScreen.swift in Sources */,
|
||||
F35548062F4FD6DA006F28CD /* XSMinePlayHistoryView.swift in Sources */,
|
||||
F3F3890E2F695068001B0E15 /* FAVipRecordViewController.swift in Sources */,
|
||||
F3F388E72F6805DE001B0E15 /* XSPayItem.swift in Sources */,
|
||||
F347D2992F03730E00786648 /* XSTabBarController.swift in Sources */,
|
||||
F35547D22F3DA757006F28CD /* XSTableView.swift in Sources */,
|
||||
F355480A2F4FE99F006F28CD /* XSMinePlayHistoryCell.swift in Sources */,
|
||||
F3B312AD2F30ACF60093B180 /* XSSearchHotSectionView.swift in Sources */,
|
||||
F3B312AE2F30ACF60093B180 /* XSSearchTagsView.swift in Sources */,
|
||||
F3F389082F6940BB001B0E15 /* XSRewardCoinsCell.swift in Sources */,
|
||||
F3B312AF2F30ACF60093B180 /* XSSearchTagCell.swift in Sources */,
|
||||
F3B312B02F30ACF60093B180 /* XSSearchRecentView.swift in Sources */,
|
||||
F35548042F4EDF27006F28CD /* UIStackView+XS.swift in Sources */,
|
||||
@ -995,17 +1147,21 @@
|
||||
F35547EB2F3DDCCE006F28CD /* XSBaseWebViewController.swift in Sources */,
|
||||
F35547EF2F3EF606006F28CD /* XSMyListViewController.swift in Sources */,
|
||||
F347D2D02F04B5BB00786648 /* XSHomeNewViewController.swift in Sources */,
|
||||
F3F389002F693293001B0E15 /* XSConsumptionRecordsCell.swift in Sources */,
|
||||
F3B312A22F30A7DA0093B180 /* XSSearchViewController.swift in Sources */,
|
||||
F347D3222F0A58C300786648 /* XSVideoAPI.swift in Sources */,
|
||||
F347D29F2F03A6B100786648 /* XSTool.swift in Sources */,
|
||||
F35548372F52B86C006F28CD /* XSAppWebViewController.swift in Sources */,
|
||||
F3585C472F14EAE700EEC469 /* XSShortDetailModel.swift in Sources */,
|
||||
F347D2B32F03AF7500786648 /* XSHomeSearchButton.swift in Sources */,
|
||||
F3F388D72F67EDEC001B0E15 /* XSMineCoinsPackView.swift in Sources */,
|
||||
F35547E42F3DCCDE006F28CD /* XSAboutCell.swift in Sources */,
|
||||
F3F388F82F692031001B0E15 /* XSWalletViewController.swift in Sources */,
|
||||
F347D2C22F03C59B00786648 /* XSWaterfallFlowLayout.swift in Sources */,
|
||||
F35547DE2F3DBAF6006F28CD /* XSAboutViewController.swift in Sources */,
|
||||
F35547D72F3DA8B5006F28CD /* XSMineCell.swift in Sources */,
|
||||
F347D2AC2F03ADC800786648 /* String+XS.swift in Sources */,
|
||||
F3F388E52F68032A001B0E15 /* XSStoreVipView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@ -48,6 +48,7 @@ extension AppDelegate {
|
||||
Task {
|
||||
await XSLoginManager.manager.updateUserInfo()
|
||||
}
|
||||
XSIapManager.manager.preloadingProducts()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -9,3 +9,5 @@
|
||||
let kXSLoginTokenDefaultsKey = "kXSLoginTokenDefaultsKey"
|
||||
///用户信息
|
||||
let kXSUserInfoDefaultsKey = "kXSUserInfoDefaultsKey"
|
||||
|
||||
let kXSWaitRestoreIAPDefaultsKey = "kXSWaitRestoreIAPDefaultsKey"
|
||||
|
||||
@ -14,6 +14,9 @@ class XSTabBarController: ESTabBarController {
|
||||
super.viewDidLoad()
|
||||
self.view.backgroundColor = .black
|
||||
|
||||
///预加载支付数据
|
||||
XSIapManager.manager.preloadingProducts()
|
||||
|
||||
setupCustomTabBar()
|
||||
setupTabBarAppearance()
|
||||
setupViewControllers()
|
||||
|
||||
131
XSeri/Base/Networking/API/XSStoreAPI.swift
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// XSStoreAPI.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
import JXIAPManager
|
||||
|
||||
struct XSStoreAPI {
|
||||
enum BuyType: String, SmartCaseDefaultable {
|
||||
case coins = "coins"
|
||||
case subVip = "sub_vip"
|
||||
case subCoins = "sub_coins"
|
||||
case vip = "vip"
|
||||
}
|
||||
|
||||
///创建内购订单
|
||||
static func requestCreateOrder(payId: String, shortPlayId: String, videoId: String, isDiscount: Bool = false, identifierDiscount: String? = nil) async -> XSIapOrderModel? {
|
||||
|
||||
let parameters: [String : Any] = [
|
||||
"payment_channel" : "apple",
|
||||
"short_play_id" : shortPlayId,
|
||||
"video_id" : videoId,
|
||||
"pay_setting_id" : payId,
|
||||
"is_discount" : isDiscount ? 1 : 0,
|
||||
"product_discount" : identifierDiscount ?? "",
|
||||
]
|
||||
|
||||
var param = XSNetwork.Parameters(path: "/createOrder")
|
||||
param.method = .post
|
||||
param.isLoding = false
|
||||
param.isToast = false
|
||||
param.parameters = parameters
|
||||
let response: XSNetwork.Response<XSIapOrderModel> = await XSNetwork.request(parameters: param)
|
||||
guard let data = response.data else {
|
||||
XSToast.show("network_error_2".localized)
|
||||
return nil
|
||||
}
|
||||
if let message = data.message, message.count > 0 {
|
||||
if response.data?.code == 30007 {
|
||||
XSToast.show("pay_error_1".localized)
|
||||
} else {
|
||||
XSToast.show(message)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return response.data
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///校验订单
|
||||
static func requestVerifyOrder(_ parameters: [String : Any]) async -> XSNetwork.Response<XSIapVerifyModel> {
|
||||
var param = XSNetwork.Parameters(path: "/applePaid")
|
||||
param.method = .post
|
||||
param.isLoding = false
|
||||
param.parameters = parameters
|
||||
let response: XSNetwork.Response<XSIapVerifyModel> = await XSNetwork.request(parameters: param)
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
///获取支付模版
|
||||
static func requestPayTemplate(isLoding: Bool = false, isToast: Bool = true) async -> XSPayDateModel? {
|
||||
let parameters = [
|
||||
"discount" : "1",
|
||||
"purchases_token" : JXIAPManager.manager.getAppStoreReceipt() ?? "",
|
||||
]
|
||||
|
||||
var param = XSNetwork.Parameters(path: "/paySettingsV4")
|
||||
param.method = .post
|
||||
param.isLoding = isLoding
|
||||
param.isToast = isToast
|
||||
param.parameters = parameters
|
||||
|
||||
let response: XSNetwork.Response<XSPayDateModel> = await XSNetwork.request(parameters: param)
|
||||
return response.data
|
||||
}
|
||||
|
||||
///挽留支付项
|
||||
static func requestPayRetainInfo() async -> XSPayDateModel? {
|
||||
let parameters = [
|
||||
"purchases_token" : JXIAPManager.manager.getAppStoreReceipt() ?? "",
|
||||
"discount" : "1",
|
||||
]
|
||||
|
||||
var param = XSNetwork.Parameters(path: "/payRetrieveSettings")
|
||||
param.method = .post
|
||||
param.isLoding = false
|
||||
param.isToast = false
|
||||
param.parameters = parameters
|
||||
|
||||
let response: XSNetwork.Response<XSPayDateModel> = await XSNetwork.request(parameters: param)
|
||||
if (response.data?.list_coins?.count ?? 0) > 0 || (response.data?.list_sub_vip?.count ?? 0) > 0 {
|
||||
return response.data
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func requestBuyRecords(page: Int) async -> XSNetwork.List<XSBuyRecordsModel>? {
|
||||
let parameters = [
|
||||
"page_size" : 20,
|
||||
"current_page" : page,
|
||||
]
|
||||
|
||||
var param = XSNetwork.Parameters(path: "/getCustomerBuyRecords")
|
||||
param.method = .get
|
||||
param.parameters = parameters
|
||||
|
||||
let response: XSNetwork.Response<XSNetwork.List<XSBuyRecordsModel>> = await XSNetwork.request(parameters: param)
|
||||
return response.data
|
||||
}
|
||||
|
||||
static func reuqestSendCoinRecord(page: Int) async -> XSNetwork.List<XSSendCoinRecordModel>? {
|
||||
let parameters = [
|
||||
"page_size" : 20,
|
||||
"current_page" : page,
|
||||
]
|
||||
|
||||
var param = XSNetwork.Parameters(path: "/sendCoinList")
|
||||
param.method = .post
|
||||
param.parameters = parameters
|
||||
|
||||
let response: XSNetwork.Response<XSNetwork.List<XSSendCoinRecordModel>> = await XSNetwork.request(parameters: param)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
@ -105,6 +105,23 @@ struct XSVideoAPI {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func requestCoinUnlockVideo(shortPlayId: String, videoId: String) async -> XSVideoUnlockResult? {
|
||||
let parameters: [String : Any] = [
|
||||
"short_play_id" : shortPlayId,
|
||||
"video_id" : videoId,
|
||||
]
|
||||
var param = XSNetwork.Parameters(path: "/buy_video")
|
||||
param.method = .post
|
||||
param.isLoding = true
|
||||
param.parameters = parameters
|
||||
let response: XSNetwork.Response<XSVideoUnlockResult> = await XSNetwork.request(parameters: param)
|
||||
if response.isSuccess {
|
||||
return response.data
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension XSVideoAPI {
|
||||
|
||||
21
XSeri/Base/View/XSScrollView.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// XSScrollView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class XSScrollView: UIScrollView {
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.contentInsetAdjustmentBehavior = .never
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
@ -25,6 +25,7 @@ class XSMineViewController: XSCommonViewController {
|
||||
tableView.dataSource = self
|
||||
tableView.separatorStyle = .none
|
||||
tableView.rowHeight = 44
|
||||
tableView.contentInset = .init(top: 0, left: 0, bottom: XSScreen.customTabBarHeight, right: 0)
|
||||
tableView.xs_addRefreshHeader { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.handleHeaderRefresh(nil)
|
||||
|
||||
@ -15,6 +15,12 @@ struct XSMineItem {
|
||||
case feedback
|
||||
case web
|
||||
case safari
|
||||
///消费记录
|
||||
case consumptionRecords
|
||||
///购买记录
|
||||
case purchaseRecords
|
||||
///金币奖励
|
||||
case rewardCoins
|
||||
}
|
||||
|
||||
|
||||
|
||||
93
XSeri/Class/Mine/View/XSMineCoinsPackView.swift
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// XSMineCoinsPackView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYCategories
|
||||
|
||||
class XSMineCoinsPackView: UIView {
|
||||
|
||||
|
||||
private lazy var bgView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "coins_pack_bg_image_01"))
|
||||
imageView.isUserInteractionEnabled = true
|
||||
imageView.layer.cornerRadius = 12
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var giftsIconImageView = UIImageView(image: UIImage(named: "gifts_icon_01"))
|
||||
|
||||
private lazy var titleLabel: XSLabel = {
|
||||
let label = XSLabel()
|
||||
label.textColors = [UIColor.F_6564_A.cgColor, UIColor.F_98_C_36.cgColor]
|
||||
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||
label.font = .font(ofSize: 16, weight: .bold).withBoldItalic()
|
||||
label.text = "me_daily_1".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var subtitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular).withBoldItalic()
|
||||
label.textColor = ._523927
|
||||
label.text = "me_daily_2".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var indicatorImageView = UIImageView(image: UIImage(named: "arrow_right_icon_05"))
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSMineCoinsPackView {
|
||||
|
||||
private func xs_setupUI() {
|
||||
addSubview(bgView)
|
||||
bgView.addSubview(giftsIconImageView)
|
||||
bgView.addSubview(titleLabel)
|
||||
bgView.addSubview(subtitleLabel)
|
||||
bgView.addSubview(indicatorImageView)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.height.equalTo(60)
|
||||
make.top.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
giftsIconImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(12)
|
||||
make.left.equalTo(giftsIconImageView.snp.right).offset(8)
|
||||
}
|
||||
|
||||
subtitleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(titleLabel)
|
||||
make.bottom.equalToSuperview().offset(-12)
|
||||
}
|
||||
|
||||
indicatorImageView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,6 +13,8 @@ class XSMineHeaderView: UITableViewHeaderFooterView {
|
||||
var userInfo: XSUserInfo? {
|
||||
didSet {
|
||||
userInfoView.userInfo = userInfo
|
||||
walletView.userInfo = userInfo
|
||||
vipView.userInfo = userInfo
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +43,21 @@ class XSMineHeaderView: UITableViewHeaderFooterView {
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var walletView: XSMineWalletView = {
|
||||
let view = XSMineWalletView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsPackView: XSMineCoinsPackView = {
|
||||
let view = XSMineCoinsPackView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var vipView: XSMineVipView = {
|
||||
let view = XSMineVipView()
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(reuseIdentifier: String?) {
|
||||
super.init(reuseIdentifier: reuseIdentifier)
|
||||
|
||||
@ -55,6 +72,10 @@ class XSMineHeaderView: UITableViewHeaderFooterView {
|
||||
stackView.xs_removeAllArrangedSubview()
|
||||
|
||||
stackView.addArrangedSubview(userInfoView)
|
||||
stackView.addArrangedSubview(walletView)
|
||||
stackView.addArrangedSubview(coinsPackView)
|
||||
|
||||
stackView.addArrangedSubview(vipView)
|
||||
|
||||
if !historyDataArr.isEmpty {
|
||||
stackView.addArrangedSubview(historyView)
|
||||
|
||||
55
XSeri/Class/Mine/View/XSMineVipView.swift
Normal file
@ -0,0 +1,55 @@
|
||||
//
|
||||
// XSMineVipView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSMineVipView: UIView {
|
||||
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return .init(width: XSScreen.width, height: 15)
|
||||
}
|
||||
|
||||
var userInfo: XSUserInfo? {
|
||||
didSet {
|
||||
titleLabel.text = "VIP Expiration Time:2023-11-23"
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var iconImageView = UIImageView(image: UIImage(named: "time_icon_01"))
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = .FFDAA_4
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
addSubview(iconImageView)
|
||||
addSubview(titleLabel)
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(titleLabel)
|
||||
make.left.equalToSuperview().offset(16)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(iconImageView.snp.right).offset(5)
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
248
XSeri/Class/Mine/View/XSMineWalletView.swift
Normal file
@ -0,0 +1,248 @@
|
||||
//
|
||||
// XSMineWalletView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSMineWalletView: UIView {
|
||||
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return .init(width: XSScreen.width, height: 36 + 87)
|
||||
}
|
||||
|
||||
var userInfo: XSUserInfo? {
|
||||
didSet {
|
||||
coinsView.coins = userInfo?.coin_left_total
|
||||
sendCoinsView.coins = userInfo?.send_coin_left_total
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var contentView: UIView = {
|
||||
let view = UIView()
|
||||
view.layer.cornerRadius = 12
|
||||
view.layer.masksToBounds = true
|
||||
view.layer.borderWidth = 1
|
||||
view.layer.borderColor = UIColor.white.withAlphaComponent(0.25).cgColor
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var titleBgView: UIView = {
|
||||
let view = UIImageView(image: UIImage(named: "wallet_bg_image_01"))
|
||||
view.isUserInteractionEnabled = true
|
||||
view.layer.cornerRadius = 12
|
||||
view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||
view.layer.masksToBounds = true
|
||||
view.layer.borderColor = UIColor.FFDAA_4.cgColor
|
||||
view.layer.borderWidth = 1
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 16, weight: .bold)
|
||||
label.textColor = .white
|
||||
label.text = "My Wallet".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var walletButton: UIButton = {
|
||||
var configuration = UIButton.Configuration.plain()
|
||||
configuration.contentInsets = .zero
|
||||
configuration.imagePadding = 4
|
||||
configuration.imagePlacement = .trailing
|
||||
configuration.image = UIImage(named: "arrow_right_icon_04")
|
||||
configuration.attributedTitle = AttributedString("Details".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||
.foregroundColor : UIColor.white.withAlphaComponent(0.5)
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = XSWalletViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var storeButton: UIButton = {
|
||||
var configuration = UIButton.Configuration.plain()
|
||||
configuration.background.image = UIImage(named: "gradient_color_image_01")
|
||||
configuration.background.cornerRadius = 18
|
||||
configuration.attributedTitle = AttributedString("Top Up".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .semibold),
|
||||
.foregroundColor : UIColor._482_B_00
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = XSStoreViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var coinsView: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "Coins".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsLineView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white.withAlphaComponent(0.1)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var sendCoinsView: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "Bonus".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSMineWalletView {
|
||||
|
||||
private func xs_setupUI() {
|
||||
addSubview(contentView)
|
||||
addSubview(titleBgView)
|
||||
titleBgView.addSubview(titleLabel)
|
||||
titleBgView.addSubview(walletButton)
|
||||
contentView.addSubview(storeButton)
|
||||
contentView.addSubview(coinsView)
|
||||
contentView.addSubview(coinsLineView)
|
||||
contentView.addSubview(sendCoinsView)
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
titleBgView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalTo(contentView)
|
||||
make.height.equalTo(36)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(12)
|
||||
}
|
||||
|
||||
walletButton.snp.makeConstraints { make in
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
}
|
||||
|
||||
storeButton.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
make.width.equalTo(108)
|
||||
make.height.equalTo(36)
|
||||
make.bottom.equalToSuperview().offset(-26)
|
||||
}
|
||||
|
||||
coinsView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerY.equalTo(storeButton)
|
||||
}
|
||||
|
||||
coinsLineView.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(storeButton)
|
||||
make.left.equalTo(coinsView.snp.right).offset(25)
|
||||
make.width.equalTo(1)
|
||||
make.height.equalTo(36)
|
||||
}
|
||||
|
||||
sendCoinsView.snp.makeConstraints { make in
|
||||
make.left.equalTo(coinsLineView.snp.right).offset(25)
|
||||
make.centerY.equalTo(storeButton)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension XSMineWalletView {
|
||||
|
||||
private class CoinsView: UIView {
|
||||
|
||||
var title: String? {
|
||||
set {
|
||||
titleLabel.text = newValue
|
||||
}
|
||||
get {
|
||||
return titleLabel.text
|
||||
}
|
||||
}
|
||||
|
||||
var coins: Int? {
|
||||
didSet {
|
||||
coinsLabel.text = "\(coins ?? 0)"
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .bold)
|
||||
label.textColor = .white.withAlphaComponent(0.5)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinsImageView = UIImageView(image: UIImage(named: "coins_icon_01"))
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 18, weight: .regular)
|
||||
label.textColor = .FFDAA_4
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
addSubview(titleLabel)
|
||||
addSubview(coinsImageView)
|
||||
addSubview(coinsLabel)
|
||||
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
|
||||
coinsImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(6)
|
||||
}
|
||||
|
||||
coinsLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsImageView)
|
||||
make.left.equalTo(coinsImageView.snp.right).offset(6)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -72,12 +72,32 @@ class XSShortDetailViewController: JXPlayerListViewController {
|
||||
}
|
||||
|
||||
override func play() {
|
||||
super.play()
|
||||
let videoInfo = self.xs_viewModel.currentCell?.model as? XSVideoInfoModel
|
||||
|
||||
if videoInfo?.is_lock != true {
|
||||
super.play()
|
||||
Task {
|
||||
await XSVideoAPI.requestAddPlayHistory(shortPlayId: videoInfo?.short_play_id, videoId: videoInfo?.short_play_video_id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
self.pause()
|
||||
|
||||
let myCoins = XSLoginManager.manager.userInfo?.totalCoins ?? 0
|
||||
let lockCoins = videoInfo?.coins ?? 0
|
||||
|
||||
if myCoins < lockCoins, (self.xs_viewModel.currentCell as? XSShortDetailPlayerCell)?.hasLastEpisodeUnlocked != true {
|
||||
self.xs_viewModel.openRechargeView()
|
||||
} else {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if (self.xs_viewModel.currentCell as? XSShortDetailPlayerCell)?.hasLastEpisodeUnlocked != true {
|
||||
self.xs_viewModel.handleUnlockVideo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
XSeri/Class/Player/Model/XSVideoUnlockResult.swift
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// XSVideoUnlockResult.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct XSVideoUnlockResult: SmartCodable {
|
||||
|
||||
enum Status: String, SmartCaseDefaultable {
|
||||
///前面还有没购买的剧
|
||||
case jump = "jump"
|
||||
///没找到视频
|
||||
case noPlay = "no_play"
|
||||
///金币不足跳充值
|
||||
case notEnough = "not_enough"
|
||||
///购买成功
|
||||
case success = "success"
|
||||
}
|
||||
|
||||
var status: Status?
|
||||
}
|
||||
@ -14,6 +14,7 @@ class XSEpSelectorCell: UICollectionViewCell {
|
||||
var model: XSVideoInfoModel? {
|
||||
didSet {
|
||||
epLabel.text = model?.episode
|
||||
lockImageView.isHidden = !(model?.is_lock ?? false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +52,11 @@ class XSEpSelectorCell: UICollectionViewCell {
|
||||
|
||||
private lazy var playImageView = UIImageView(image: UIImage(named: "play_icon_02"))
|
||||
|
||||
private lazy var lockImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "lock_icon_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
xs_setupUI()
|
||||
@ -66,8 +72,9 @@ extension XSEpSelectorCell {
|
||||
|
||||
private func xs_setupUI() {
|
||||
contentView.addSubview(bgView)
|
||||
contentView.addSubview(epLabel)
|
||||
contentView.addSubview(playImageView)
|
||||
bgView.addSubview(epLabel)
|
||||
bgView.addSubview(playImageView)
|
||||
bgView.addSubview(lockImageView)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
@ -81,6 +88,10 @@ extension XSEpSelectorCell {
|
||||
make.left.equalToSuperview().offset(6)
|
||||
make.bottom.equalToSuperview().offset(-5)
|
||||
}
|
||||
|
||||
lockImageView.snp.makeConstraints { make in
|
||||
make.right.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
84
XSeri/Class/Player/View/XSShortDetailLockView.swift
Normal file
@ -0,0 +1,84 @@
|
||||
//
|
||||
// XSShortDetailLockView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSShortDetailLockView: UIView {
|
||||
|
||||
var clickUnlockButton: (() -> Void)?
|
||||
|
||||
var videoInfo: XSVideoInfoModel? {
|
||||
didSet {
|
||||
unlockButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
var hasLastEpisodeUnlocked = false {
|
||||
didSet {
|
||||
unlockButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var lockIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "lock_icon_03"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var unlockButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.background.image = UIImage(named: "button_bg_image_01")
|
||||
config.image = UIImage(named: "lock_icon_02")
|
||||
config.imagePadding = 8
|
||||
|
||||
let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.clickUnlockButton?()
|
||||
}))
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
let attributeContainer = AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 16, weight: .medium),
|
||||
.foregroundColor : UIColor._712_A_03
|
||||
])
|
||||
if hasLastEpisodeUnlocked {
|
||||
button.configuration?.attributedTitle = .init("video_lock_tip_text".localized, attributes: attributeContainer)
|
||||
} else {
|
||||
button.configuration?.attributedTitle = .init("unlocking_coins_notice".localizedReplace(text: "\(videoInfo?.coins ?? 0)"), attributes: attributeContainer)
|
||||
}
|
||||
}
|
||||
button.layer.cornerRadius = 27
|
||||
button.layer.masksToBounds = true
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
backgroundColor = .black.withAlphaComponent(0.6)
|
||||
|
||||
addSubview(unlockButton)
|
||||
addSubview(lockIconImageView)
|
||||
|
||||
unlockButton.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(18)
|
||||
make.height.equalTo(54)
|
||||
make.centerY.equalToSuperview().offset(30)
|
||||
}
|
||||
|
||||
lockIconImageView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.bottom.equalTo(unlockButton.snp.top).offset(-34)
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
import UIKit
|
||||
import JXPlayer
|
||||
import SnapKit
|
||||
|
||||
class XSShortDetailPlayerCell: JXPlayerListCell {
|
||||
|
||||
@ -20,8 +21,8 @@ class XSShortDetailPlayerCell: JXPlayerListCell {
|
||||
let model = self.model as? XSVideoInfoModel
|
||||
self.player.setPlayUrl(url: model?.video_url ?? "")
|
||||
|
||||
// self.lockView.isHidden = !(model?.is_lock ?? true)
|
||||
// lockView.videoInfo = model
|
||||
self.lockView.isHidden = !(model?.is_lock ?? true)
|
||||
lockView.videoInfo = model
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,11 +36,32 @@ class XSShortDetailPlayerCell: JXPlayerListCell {
|
||||
|
||||
var hasLastEpisodeUnlocked: Bool = false {
|
||||
didSet {
|
||||
// self.lockView.hasLastEpisodeUnlocked = hasLastEpisodeUnlocked
|
||||
self.lockView.hasLastEpisodeUnlocked = hasLastEpisodeUnlocked
|
||||
}
|
||||
}
|
||||
|
||||
var xs_controlView: XSShortDetailPlayerControlView {
|
||||
return self.controlView as! XSShortDetailPlayerControlView
|
||||
}
|
||||
|
||||
|
||||
private lazy var lockView: XSShortDetailLockView = {
|
||||
let view = XSShortDetailLockView()
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
addSubview(lockView)
|
||||
|
||||
lockView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,4 +94,53 @@ extension XSShortDetailViewModel {
|
||||
self.popView = view
|
||||
}
|
||||
|
||||
///解锁视频
|
||||
func handleUnlockVideo() {
|
||||
Task {
|
||||
if await self.unlockVideo() {
|
||||
await self.playerListVC?.reloadData { [weak self] in
|
||||
self?.playerListVC?.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///打开充值页面
|
||||
func openRechargeView() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension XSShortDetailViewModel {
|
||||
|
||||
private func unlockVideo() async -> Bool {
|
||||
guard let videoInfo = self.currentCell?.model as? XSVideoInfoModel else { return false }
|
||||
guard let shortPlayId = videoInfo.short_play_id else { return false }
|
||||
guard let videoId = videoInfo.short_play_video_id else { return false }
|
||||
|
||||
guard let model = await XSVideoAPI.requestCoinUnlockVideo(shortPlayId: shortPlayId, videoId: videoId) else { return false }
|
||||
|
||||
|
||||
switch model.status {
|
||||
case .jump:
|
||||
XSToast.show("buy_fail_toast_02".localized)
|
||||
case .noPlay:
|
||||
XSToast.show("buy_fail_toast_01".localized)
|
||||
case .notEnough:
|
||||
self.openRechargeView()
|
||||
default: break
|
||||
}
|
||||
|
||||
if model.status == .success {
|
||||
await XSLoginManager.manager.updateUserInfo()
|
||||
videoInfo.is_lock = false
|
||||
XSToast.show("Success".localized)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
//
|
||||
// FACoinsRecordViewController.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FACoinsRecordViewController: XSViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
// Get the new view controller using segue.destination.
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
29
XSeri/Class/Store/Controller/FAVipRecordViewController.swift
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// FAVipRecordViewController.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAVipRecordViewController: XSViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
// Get the new view controller using segue.destination.
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
//
|
||||
// XSConsumptionRecordsViewController.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSConsumptionRecordsViewController: XSViewController {
|
||||
|
||||
private lazy var dataArr: [XSBuyRecordsModel] = []
|
||||
private lazy var page = 1
|
||||
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var tableView: XSTableView = {
|
||||
let tableView = XSTableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 71
|
||||
tableView.separatorColor = .white.withAlphaComponent(0.1)
|
||||
tableView.separatorInset = .init(top: 0, left: 32, bottom: 0, right: 32)
|
||||
tableView.contentInset = .init(top: 10, left: 0, bottom: XSScreen.safeBottom + 10, right: 0)
|
||||
tableView.register(XSConsumptionRecordsCell.self, forCellReuseIdentifier: "cell")
|
||||
tableView.ly_emptyView = XSEmpty.xs_emptyView()
|
||||
|
||||
tableView.xs_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
tableView.xs_addRefreshFooter(insetBottom: tableView.contentInset.bottom) { [weak self] in
|
||||
self?.handleFooterRefresh(nil)
|
||||
}
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Consumption Records".localized
|
||||
self.view.backgroundColor = .black
|
||||
|
||||
xs_setupUI()
|
||||
|
||||
Task {
|
||||
await requestDataArr(page: 1)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
xs_setNavigationStyle()
|
||||
}
|
||||
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
Task {
|
||||
await requestDataArr(page: 1)
|
||||
self.tableView.xs_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||
Task {
|
||||
await requestDataArr(page: self.page + 1)
|
||||
self.tableView.xs_endFooterRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSConsumptionRecordsViewController {
|
||||
|
||||
private func xs_setupUI() {
|
||||
view.addSubview(bgImageView)
|
||||
view.addSubview(tableView)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(self.view.safeAreaLayoutGuide)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate UITableViewDataSource
|
||||
extension XSConsumptionRecordsViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! XSConsumptionRecordsCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return self.dataArr.count
|
||||
}
|
||||
}
|
||||
|
||||
extension XSConsumptionRecordsViewController {
|
||||
|
||||
private func requestDataArr(page: Int) async {
|
||||
|
||||
guard let listModel = await XSStoreAPI.requestBuyRecords(page: page) else { return }
|
||||
guard let list = listModel.list else { return }
|
||||
|
||||
if page == 1 {
|
||||
self.dataArr.removeAll()
|
||||
}
|
||||
self.dataArr += list
|
||||
self.page = page
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
|
||||
}
|
||||
104
XSeri/Class/Store/Controller/XSOrderRecordsViewController.swift
Normal file
@ -0,0 +1,104 @@
|
||||
//
|
||||
// XSOrderRecordsViewController.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import JXSegmentedView
|
||||
|
||||
class XSOrderRecordsViewController: XSViewController {
|
||||
|
||||
|
||||
private lazy var viewControllers: [XSViewController] = {
|
||||
return [FACoinsRecordViewController(), FAVipRecordViewController()]
|
||||
}()
|
||||
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
/// Segmented 数据源
|
||||
private lazy var segmentedDataSource: JXSegmentedTitleDataSource = {
|
||||
let dataSource = JXSegmentedTitleDataSource()
|
||||
dataSource.titles = ["Coin Record".localized, "VIP Record".localized]
|
||||
dataSource.titleNormalColor = UIColor.white.withAlphaComponent(0.55)
|
||||
dataSource.titleSelectedColor = .white
|
||||
dataSource.titleNormalFont = .font(ofSize: 16, weight: .medium)
|
||||
dataSource.titleSelectedFont = .font(ofSize: 16, weight: .semibold)
|
||||
dataSource.isTitleColorGradientEnabled = true
|
||||
dataSource.itemSpacing = 24
|
||||
return dataSource
|
||||
}()
|
||||
|
||||
/// Segmented 视图 (Tab 栏)
|
||||
private lazy var segmentedView: JXSegmentedView = {
|
||||
let view = JXSegmentedView()
|
||||
view.dataSource = segmentedDataSource
|
||||
view.delegate = self
|
||||
view.listContainer = listContainerView
|
||||
view.contentEdgeInsetLeft = 16
|
||||
view.contentEdgeInsetRight = 16
|
||||
view.backgroundColor = .clear
|
||||
return view
|
||||
}()
|
||||
|
||||
/// 列表容器 (内容展示)
|
||||
private lazy var listContainerView: JXSegmentedListContainerView = {
|
||||
return JXSegmentedListContainerView(dataSource: self)
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
xs_setNavigationStyle()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension XSOrderRecordsViewController {
|
||||
|
||||
private func xs_setupUI() {
|
||||
view.addSubview(bgImageView)
|
||||
view.addSubview(listContainerView)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
listContainerView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(self.view.safeAreaLayoutGuide)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - JXSegmentedViewDelegate
|
||||
extension XSOrderRecordsViewController: JXSegmentedViewDelegate {
|
||||
func segmentedView(_ segmentedView: JXSegmentedView, didSelectedItemAt index: Int) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - JXSegmentedListContainerViewDataSource
|
||||
extension XSOrderRecordsViewController: JXSegmentedListContainerViewDataSource {
|
||||
func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int {
|
||||
return segmentedDataSource.titles.count
|
||||
}
|
||||
|
||||
func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> JXSegmentedListContainerViewListDelegate {
|
||||
return viewControllers[index]
|
||||
}
|
||||
}
|
||||
124
XSeri/Class/Store/Controller/XSRewardCoinsViewController.swift
Normal file
@ -0,0 +1,124 @@
|
||||
//
|
||||
// XSRewardCoinsViewController.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSRewardCoinsViewController: XSViewController {
|
||||
|
||||
private lazy var dataArr: [XSSendCoinRecordModel] = []
|
||||
private lazy var page = 1
|
||||
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var tableView: XSTableView = {
|
||||
let tableView = XSTableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 96
|
||||
tableView.separatorColor = .white.withAlphaComponent(0.1)
|
||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
tableView.contentInset = .init(top: 10, left: 0, bottom: XSScreen.safeBottom + 10, right: 0)
|
||||
tableView.register(XSRewardCoinsCell.self, forCellReuseIdentifier: "cell")
|
||||
tableView.ly_emptyView = XSEmpty.xs_emptyView()
|
||||
|
||||
tableView.xs_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
tableView.xs_addRefreshFooter(insetBottom: tableView.contentInset.bottom) { [weak self] in
|
||||
self?.handleFooterRefresh(nil)
|
||||
}
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Reward Coins".localized
|
||||
self.view.backgroundColor = .black
|
||||
xs_setupUI()
|
||||
|
||||
Task {
|
||||
await requestDataArr(page: 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
xs_setNavigationStyle()
|
||||
}
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
Task {
|
||||
await requestDataArr(page: 1)
|
||||
self.tableView.xs_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||
Task {
|
||||
await requestDataArr(page: self.page + 1)
|
||||
self.tableView.xs_endFooterRefreshing()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension XSRewardCoinsViewController {
|
||||
|
||||
private func xs_setupUI() {
|
||||
view.addSubview(bgImageView)
|
||||
view.addSubview(tableView)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(self.view.safeAreaLayoutGuide).offset(10)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate UITableViewDataSource
|
||||
extension XSRewardCoinsViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! XSRewardCoinsCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return self.dataArr.count
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSRewardCoinsViewController {
|
||||
|
||||
private func requestDataArr(page: Int) async {
|
||||
|
||||
guard let listModel = await XSStoreAPI.reuqestSendCoinRecord(page: page) else { return }
|
||||
guard let list = listModel.list else { return }
|
||||
|
||||
if page == 1 {
|
||||
self.dataArr.removeAll()
|
||||
}
|
||||
self.dataArr += list
|
||||
self.page = page
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
60
XSeri/Class/Store/Controller/XSStoreViewController.swift
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// XSStoreViewController.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class XSStoreViewController: XSViewController {
|
||||
|
||||
|
||||
private lazy var scrollView: XSScrollView = {
|
||||
let scrollView = XSScrollView()
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.spacing = 12
|
||||
return view
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Store".localized
|
||||
|
||||
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
xs_setNavigationStyle()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSStoreViewController {
|
||||
|
||||
private func xs_setupUI() {
|
||||
view.addSubview(scrollView)
|
||||
scrollView.addSubview(stackView)
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(XSScreen.navBarHeight)
|
||||
}
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(12)
|
||||
make.bottom.equalToSuperview().offset(-(XSScreen.safeBottom + 10))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
135
XSeri/Class/Store/Controller/XSWalletViewController.swift
Normal file
@ -0,0 +1,135 @@
|
||||
//
|
||||
// XSWalletViewController.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSWalletViewController: XSViewController {
|
||||
|
||||
private lazy var dataArr: [XSMineItem] = [
|
||||
XSMineItem(type: .consumptionRecords, iconImage: UIImage(named: "order_icon_01"), title: "Consumption records".localized),
|
||||
XSMineItem(type: .purchaseRecords, iconImage: UIImage(named: "order_icon_02"), title: "Purchase records".localized),
|
||||
XSMineItem(type: .rewardCoins, iconImage: UIImage(named: "order_icon_03"), title: "Reward Coins".localized),
|
||||
XSMineItem(type: .feedback, iconImage: UIImage(named: "feedback_icon_03"), title: "feedback".localized),
|
||||
]
|
||||
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var headerView: XSWalletHeaderView = {
|
||||
let view = XSWalletHeaderView()
|
||||
view.userInfo = XSLoginManager.manager.userInfo
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tableView: XSTableView = {
|
||||
let tableView = XSTableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 52
|
||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
tableView.contentInset = .init(top: 0, left: 0, bottom: XSScreen.safeBottom, right: 0)
|
||||
tableView.register(XSWalletCell.self, forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Details".localized
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(loginStateDidChangeNotification), name: XSLoginManager.loginStateDidChangeNotification, object: nil)
|
||||
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
xs_setNavigationStyle()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
Task {
|
||||
await XSLoginManager.manager.updateUserInfo()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func loginStateDidChangeNotification() {
|
||||
headerView.userInfo = XSLoginManager.manager.userInfo
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSWalletViewController {
|
||||
|
||||
private func xs_setupUI() {
|
||||
view.addSubview(bgImageView)
|
||||
view.addSubview(headerView)
|
||||
view.addSubview(tableView)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
headerView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalTo(self.view.safeAreaLayoutGuide).offset(10)
|
||||
}
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(headerView.snp.bottom).offset(18)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate & UITableViewDataSource
|
||||
extension XSWalletViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let item = self.dataArr[indexPath.row]
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! XSWalletCell
|
||||
cell.item = item
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let item = self.dataArr[indexPath.row]
|
||||
|
||||
var vc: UIViewController?
|
||||
|
||||
switch item.type {
|
||||
case .consumptionRecords:
|
||||
vc = XSConsumptionRecordsViewController()
|
||||
|
||||
case .purchaseRecords:
|
||||
vc = XSOrderRecordsViewController()
|
||||
|
||||
case .rewardCoins:
|
||||
vc = XSRewardCoinsViewController()
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if let vc = vc {
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
21
XSeri/Class/Store/Model/XSBuyRecordsModel.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// XSBuyRecordsModel.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct XSBuyRecordsModel: SmartCodable {
|
||||
|
||||
var short_play_video_id: String?
|
||||
var created_at: String?
|
||||
var short_play_id: String?
|
||||
var coins: Int?
|
||||
var image_url: String?
|
||||
var name: String?
|
||||
var episode: String?
|
||||
var coin_type: Int?
|
||||
}
|
||||
46
XSeri/Class/Store/Model/XSPayDateModel.swift
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// XSPayDateModel.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class XSPayDateModel: NSObject, SmartCodable {
|
||||
|
||||
required override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
enum SortName: String, SmartCaseDefaultable {
|
||||
case coin = "list_coins"
|
||||
case vip = "list_sub_vip"
|
||||
}
|
||||
|
||||
var list_coins: [XSPayItem]?
|
||||
var list_sub_vip: [XSPayItem]?
|
||||
var list_sub_coins: [XSPayItem]?
|
||||
var sort: [SortName]?
|
||||
|
||||
///0: 老版支付 1:新版支付
|
||||
var pay_mode: Int?
|
||||
///0: 普通金币 1:金币包模式
|
||||
var show_type: Int?
|
||||
|
||||
var retrieve_lang: XSPayRetrieveLang?
|
||||
}
|
||||
|
||||
class XSPayRetrieveLang: NSObject, SmartCodable {
|
||||
required override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
var title: String?
|
||||
var remaining_time: String?
|
||||
var miss_out: String?
|
||||
var subtitle: String?
|
||||
var claim_reward: String?
|
||||
}
|
||||
|
||||
112
XSeri/Class/Store/Model/XSPayItem.swift
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// XSPayItem.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
import StoreKit
|
||||
|
||||
class XSPayItem: NSObject, SmartCodable {
|
||||
|
||||
required override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
enum VipTypeKey: String, SmartCaseDefaultable {
|
||||
case week = "week"
|
||||
case month = "month"
|
||||
case quarter = "quarter"
|
||||
case year = "year"
|
||||
}
|
||||
|
||||
enum SizeType: String, SmartCaseDefaultable {
|
||||
case big = "big"
|
||||
case small = "small"
|
||||
case spread = "spread"
|
||||
}
|
||||
|
||||
|
||||
var id: String?
|
||||
var backhaul_price: String?
|
||||
var coins: Int?
|
||||
var status: String?
|
||||
var price: String?
|
||||
var send_coins: Int?
|
||||
var buy_type: XSStoreAPI.BuyType?
|
||||
var origin_price: String?
|
||||
|
||||
var brief: String?
|
||||
var title: String?
|
||||
var auto_sub: String?
|
||||
var vip_type: String?
|
||||
var vip_type_key: VipTypeKey?
|
||||
var sort: String?
|
||||
var xs_description: String?
|
||||
|
||||
|
||||
var send_coin_ttl: Int?
|
||||
|
||||
var size: SizeType?
|
||||
|
||||
var ios_template_id: String?
|
||||
///角标
|
||||
var corner_marker: String?
|
||||
///平台
|
||||
var platform: String?
|
||||
///货币符号
|
||||
var currency: String?
|
||||
|
||||
var ext_info: XSPayExtInfo?
|
||||
|
||||
///0 无优惠 1 首次购买优惠 2 二次购买优惠
|
||||
var discount_type: Int?
|
||||
|
||||
@IgnoredKey
|
||||
var product: SKProduct?
|
||||
|
||||
|
||||
///首冲优惠数据
|
||||
var introductionaryOffer: SKProductDiscount? {
|
||||
return product?.introductoryPrice
|
||||
}
|
||||
|
||||
///促销优惠数据
|
||||
var promotionalOffers: [SKProductDiscount]? {
|
||||
return product?.discounts
|
||||
}
|
||||
|
||||
var discount_price: String? {
|
||||
var price: String? = nil
|
||||
if self.discount_type == 1, let introductoryPrice = self.introductionaryOffer {
|
||||
price = introductoryPrice.price.stringValue
|
||||
} else if self.discount_type == 2, let discount = self.promotionalOffers?.first {
|
||||
price = discount.price.stringValue
|
||||
}
|
||||
return price
|
||||
}
|
||||
|
||||
|
||||
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||
return [
|
||||
CodingKeys.xs_description <--- ["description"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class XSPayExtInfo: NSObject, SmartCodable {
|
||||
|
||||
required override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
var extra_day_coins: Int?
|
||||
var receive_coins_rate: String?
|
||||
var max_total_coins: Int?
|
||||
var max_total_coins_pop: Int?
|
||||
var sub_coins_txt_list: [String]?
|
||||
|
||||
}
|
||||
21
XSeri/Class/Store/Model/XSSendCoinRecordModel.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// XSSendCoinRecordModel.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct XSSendCoinRecordModel: SmartCodable {
|
||||
|
||||
var id: String?
|
||||
var diff_datetime: String?
|
||||
var expired_time: TimeInterval?
|
||||
var coins: Int?
|
||||
var type: String?
|
||||
var left_coins: String?
|
||||
var created_at: String?
|
||||
var is_effective: Int?
|
||||
}
|
||||
96
XSeri/Class/Store/View/XSConsumptionRecordsCell.swift
Normal file
@ -0,0 +1,96 @@
|
||||
//
|
||||
// XSConsumptionRecordsCell.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSConsumptionRecordsCell: XSTableViewCell {
|
||||
|
||||
var model: XSBuyRecordsModel? {
|
||||
didSet {
|
||||
subtitleLabel.text = "EP.##".localizedReplace(text: "\(model?.episode ?? "")") + " " + "\(model?.name ?? "")"
|
||||
dateLabel.text = model?.created_at
|
||||
coinsLabel.text = "-\(model?.coins ?? 0)" + "Coins".localized
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .FFDAA_4
|
||||
label.text = "Purchase Single Episode".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var subtitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = .white
|
||||
label.setContentHuggingPriority(.required, for: .horizontal)
|
||||
label.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var dateLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .FFDAA_4
|
||||
label.setContentHuggingPriority(.required, for: .horizontal)
|
||||
label.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSConsumptionRecordsCell {
|
||||
|
||||
private func xs_setupUI() {
|
||||
contentView.addSubview(titleLabel)
|
||||
contentView.addSubview(subtitleLabel)
|
||||
contentView.addSubview(dateLabel)
|
||||
contentView.addSubview(coinsLabel)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(32)
|
||||
make.top.equalToSuperview().offset(16)
|
||||
make.right.lessThanOrEqualTo(dateLabel.snp.left).offset(-10)
|
||||
}
|
||||
|
||||
subtitleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(titleLabel)
|
||||
make.bottom.equalToSuperview().offset(-16)
|
||||
make.right.lessThanOrEqualTo(coinsLabel.snp.left).offset(-20)
|
||||
}
|
||||
|
||||
dateLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(titleLabel)
|
||||
make.right.equalToSuperview().offset(-36)
|
||||
}
|
||||
|
||||
coinsLabel.snp.makeConstraints { make in
|
||||
make.right.equalTo(dateLabel)
|
||||
make.centerY.equalTo(subtitleLabel)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
142
XSeri/Class/Store/View/XSRewardCoinsCell.swift
Normal file
@ -0,0 +1,142 @@
|
||||
//
|
||||
// XSRewardCoinsCell.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSRewardCoinsCell: XSTableViewCell {
|
||||
|
||||
var model: XSSendCoinRecordModel? {
|
||||
didSet {
|
||||
nameLabel.text = model?.type
|
||||
dateLabel.text = model?.created_at
|
||||
countLabel.text = "+\(model?.coins ?? 0)"
|
||||
remainingLabel.text = model?.left_coins
|
||||
|
||||
if model?.is_effective == 1 {
|
||||
expiresIconImageView.isHidden = false
|
||||
expiresLabel.isHidden = false
|
||||
expiredLabel.isHidden = true
|
||||
expiresLabel.text = "Expires in ## days".localizedReplace(text: model?.diff_datetime ?? "")
|
||||
} else {
|
||||
expiresIconImageView.isHidden = true
|
||||
expiresLabel.isHidden = true
|
||||
expiredLabel.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var dateLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .medium)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var nameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 16, weight: .semibold)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var expiresIconImageView = UIImageView(image: UIImage(named: "expires_icon_01"))
|
||||
|
||||
private lazy var expiresLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = .FFDAA_4
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var expiredLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white
|
||||
label.text = "Expired".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var countLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 16, weight: .semibold)
|
||||
label.textColor = .FFDAA_4
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var remainingLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
self.dateLabel.text = "2024-6-10 23:41:18"
|
||||
self.nameLabel.text = "Check in"
|
||||
self.countLabel.text = "+50"
|
||||
self.remainingLabel.text = "Remaining:0"
|
||||
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSRewardCoinsCell {
|
||||
|
||||
private func xs_setupUI() {
|
||||
contentView.addSubview(dateLabel)
|
||||
contentView.addSubview(nameLabel)
|
||||
contentView.addSubview(expiresIconImageView)
|
||||
contentView.addSubview(expiresLabel)
|
||||
contentView.addSubview(expiredLabel)
|
||||
contentView.addSubview(countLabel)
|
||||
contentView.addSubview(remainingLabel)
|
||||
|
||||
dateLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(32)
|
||||
make.top.equalTo(17)
|
||||
}
|
||||
|
||||
nameLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(dateLabel)
|
||||
make.top.equalTo(dateLabel.snp.bottom).offset(6)
|
||||
}
|
||||
|
||||
expiresIconImageView.snp.makeConstraints { make in
|
||||
make.left.equalTo(dateLabel)
|
||||
make.bottom.equalToSuperview().offset(-17)
|
||||
}
|
||||
|
||||
expiresLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(expiresIconImageView)
|
||||
make.left.equalTo(expiresIconImageView.snp.right).offset(4)
|
||||
}
|
||||
|
||||
expiredLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(expiresIconImageView)
|
||||
make.centerY.equalTo(expiresIconImageView)
|
||||
}
|
||||
|
||||
countLabel.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-32)
|
||||
make.top.equalToSuperview().offset(28)
|
||||
}
|
||||
|
||||
remainingLabel.snp.makeConstraints { make in
|
||||
make.right.equalTo(countLabel)
|
||||
make.centerY.equalTo(expiresIconImageView)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
77
XSeri/Class/Store/View/XSStoreCoinsView.swift
Normal file
@ -0,0 +1,77 @@
|
||||
//
|
||||
// XSStoreCoinsView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSStoreCoinsView: UIView {
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 16, weight: .bold)
|
||||
label.textColor = .white
|
||||
label.text = "Coins Purchase".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
// private lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
||||
// let config = UICollectionViewCompositionalLayoutConfiguration()
|
||||
// config.interSectionSpacing = 10
|
||||
//
|
||||
// let layout = UICollectionViewCompositionalLayout { [weak self] section, _ in
|
||||
// guard let self = self else { return nil}
|
||||
// guard let model = dataArr[section].first else { return nil }
|
||||
//
|
||||
// if model.buy_type == .subCoins {
|
||||
// return self.coinsBigLayoutSection()
|
||||
// } else if model.size == .big {
|
||||
// return self.bigLayoutSection()
|
||||
// } else {
|
||||
// return self.smallLayoutSection()
|
||||
// }
|
||||
// }
|
||||
// layout.configuration = config
|
||||
//
|
||||
// return layout
|
||||
// }()
|
||||
//
|
||||
// private lazy var collectionView: FACollectionView = {
|
||||
// let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
// collectionView.delegate = self
|
||||
// collectionView.dataSource = self
|
||||
// collectionView.clipsToBounds = false
|
||||
// collectionView.isScrollEnabled = false
|
||||
// collectionView.register(FAStoreCoinsBigCell.self, forCellWithReuseIdentifier: "FAStoreCoinsBigCell")
|
||||
// collectionView.register(FAStoreCoinsSmallCell.self, forCellWithReuseIdentifier: "FAStoreCoinsSmallCell")
|
||||
// collectionView.register(FAStoreCoinsPackCell.self, forCellWithReuseIdentifier: "FAStoreCoinsPackCell")
|
||||
// collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
// return collectionView
|
||||
// }()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSStoreCoinsView {
|
||||
|
||||
private func xs_setupUI() {
|
||||
addSubview(titleLabel)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
14
XSeri/Class/Store/View/XSStoreVipView.swift
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// XSStoreVipView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class XSStoreVipView: UIView {
|
||||
|
||||
|
||||
|
||||
}
|
||||
69
XSeri/Class/Store/View/XSWalletCell.swift
Normal file
@ -0,0 +1,69 @@
|
||||
//
|
||||
// XSWalletCell.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSWalletCell: XSTableViewCell {
|
||||
|
||||
var item: XSMineItem? {
|
||||
didSet {
|
||||
iconImageView.image = item?.iconImage
|
||||
titleLabel.text = item?.title
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var iconImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 16, weight: .medium)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var indicatorImageView = UIImageView(image: UIImage(named: "arrow_right_icon_06"))
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSWalletCell {
|
||||
|
||||
private func xs_setupUI() {
|
||||
contentView.addSubview(iconImageView)
|
||||
contentView.addSubview(titleLabel)
|
||||
contentView.addSubview(indicatorImageView)
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(16)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(42)
|
||||
}
|
||||
|
||||
indicatorImageView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-14)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
204
XSeri/Class/Store/View/XSWalletHeaderView.swift
Normal file
@ -0,0 +1,204 @@
|
||||
//
|
||||
// XSWalletHeaderView.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
class XSWalletHeaderView: UIView {
|
||||
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return .init(width: XSScreen.width, height: 119)
|
||||
}
|
||||
|
||||
var userInfo: XSUserInfo? {
|
||||
didSet {
|
||||
coinsView.coins = userInfo?.coin_left_total
|
||||
sendCoinsView.coins = userInfo?.send_coin_left_total
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private lazy var bgView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white.withAlphaComponent(0.1)
|
||||
view.layer.cornerRadius = 8
|
||||
view.layer.masksToBounds = true
|
||||
view.layer.borderWidth = 1
|
||||
view.layer.borderColor = UIColor.white.withAlphaComponent(0.14).cgColor
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .semibold)
|
||||
label.textColor = .white
|
||||
label.text = "My Wallet".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var lineView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white.withAlphaComponent(0.12)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var storeButton: UIButton = {
|
||||
var configuration = UIButton.Configuration.plain()
|
||||
configuration.background.image = UIImage(named: "store_button_bg_image")
|
||||
configuration.attributedTitle = AttributedString("Store".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 16, weight: .bold),
|
||||
.foregroundColor : UIColor._482_B_00
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = XSStoreViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var coinsView: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "Coins".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var sendCoinsView: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "Bonus".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
xs_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSWalletHeaderView {
|
||||
|
||||
private func xs_setupUI() {
|
||||
addSubview(bgView)
|
||||
bgView.addSubview(titleLabel)
|
||||
bgView.addSubview(lineView)
|
||||
bgView.addSubview(storeButton)
|
||||
bgView.addSubview(coinsView)
|
||||
bgView.addSubview(sendCoinsView)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(10)
|
||||
make.height.equalTo(36)
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
lineView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(titleLabel.snp.bottom)
|
||||
make.height.equalTo(1)
|
||||
}
|
||||
|
||||
storeButton.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
make.bottom.equalToSuperview().offset(-22)
|
||||
make.width.equalTo(102)
|
||||
make.height.equalTo(36)
|
||||
}
|
||||
|
||||
coinsView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(8)
|
||||
make.bottom.equalToSuperview().offset(-18)
|
||||
}
|
||||
|
||||
sendCoinsView.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsView)
|
||||
make.left.equalToSuperview().offset(119)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension XSWalletHeaderView {
|
||||
|
||||
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: 14, weight: .semibold)
|
||||
label.textColor = .white.withAlphaComponent(0.52)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinsIconView = UIImageView(image: UIImage(named: "coins_icon_02"))
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 18, weight: .bold)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
addSubview(titleLabel)
|
||||
addSubview(coinsIconView)
|
||||
addSubview(coinsLabel)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(3)
|
||||
make.top.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
|
||||
coinsIconView.snp.makeConstraints { make in
|
||||
make.bottom.left.equalToSuperview()
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(11)
|
||||
}
|
||||
|
||||
coinsLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsIconView)
|
||||
make.left.equalTo(coinsIconView.snp.right).offset(2)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
297
XSeri/Libs/IapManager/XSIapManager.swift
Normal file
@ -0,0 +1,297 @@
|
||||
//
|
||||
// XSIapManager.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
import JXIAPManager
|
||||
|
||||
class XSIapManager {
|
||||
|
||||
typealias CompletionHandler = ((_ finish: Bool) -> Void)
|
||||
///内购模版前缀
|
||||
static let IAPPrefix = "xseri"
|
||||
|
||||
static let manager = XSIapManager()
|
||||
|
||||
private lazy var iapManager: JXIAPManager = {
|
||||
let manager = JXIAPManager.manager
|
||||
manager.delegate = self
|
||||
return manager
|
||||
}()
|
||||
|
||||
///成功回调
|
||||
private var completionHandler: CompletionHandler?
|
||||
|
||||
private var shortPlayId: String?
|
||||
private var videoId: String?
|
||||
|
||||
private var orderCode: String?
|
||||
private var payId: String?
|
||||
|
||||
///恢复购买使用
|
||||
///等待恢复的数据
|
||||
private var waitRestoreModel: XSWaitRestoreModel? = UserDefaults.xs_object(forKey: kXSWaitRestoreIAPDefaultsKey, as: XSWaitRestoreModel.self)
|
||||
|
||||
///预加载数据
|
||||
private var payRequest: XSPayDataRequest?
|
||||
var payDateModel: XSPayDateModel?
|
||||
|
||||
|
||||
///开始内购
|
||||
@MainActor
|
||||
func start(model: XSPayItem, shortPlayId: String? = nil, videoId: String? = nil, hudShowView: UIView? = nil, handler: CompletionHandler? = nil) {
|
||||
|
||||
if let _ = self.waitRestoreModel {
|
||||
XSToast.show("pay_error_6".localized)
|
||||
handler?(false)
|
||||
return
|
||||
}
|
||||
|
||||
guard let payId = model.id else {
|
||||
handler?(false)
|
||||
return
|
||||
}
|
||||
self.shortPlayId = shortPlayId
|
||||
self.videoId = videoId
|
||||
self.completionHandler = handler
|
||||
self.waitRestoreModel = XSWaitRestoreModel()
|
||||
self.waitRestoreModel?.buyType = model.buy_type
|
||||
let productId = getProductId(templateId: model.ios_template_id) ?? ""
|
||||
var isDiscount = false
|
||||
var identifierDiscount: String? = nil
|
||||
if model.discount_type == 1, let _ = model.introductionaryOffer {
|
||||
isDiscount = true
|
||||
} else if model.discount_type == 2, let discount = model.promotionalOffers?.first {
|
||||
isDiscount = true
|
||||
identifierDiscount = discount.identifier
|
||||
}
|
||||
|
||||
XSHud.show(containerView: hudShowView)
|
||||
|
||||
Task {
|
||||
guard let orderModel = await XSStoreAPI.requestCreateOrder(payId: payId, shortPlayId: shortPlayId ?? "0", videoId: videoId ?? "0", isDiscount: isDiscount, identifierDiscount: identifierDiscount) else {
|
||||
XSHud.dismiss()
|
||||
self.waitRestoreModel = nil
|
||||
self.completionHandler?(false)
|
||||
self.clean()
|
||||
return
|
||||
}
|
||||
|
||||
self.orderCode = orderModel.order_code
|
||||
self.payId = payId
|
||||
self.waitRestoreModel?.payId = payId
|
||||
self.waitRestoreModel?.orderCode = orderModel.order_code
|
||||
|
||||
var discount: SKPaymentDiscount? = nil
|
||||
|
||||
if let identifierDiscount = identifierDiscount,
|
||||
let signData = orderModel.discount?.sign_data,
|
||||
let keyIdentifier = signData.keyIdentifier,
|
||||
let nonce = UUID(uuidString: signData.nonce ?? ""),
|
||||
let signature = signData.signature,
|
||||
let timestamp = signData.timestamp
|
||||
{
|
||||
discount = SKPaymentDiscount(identifier: identifierDiscount,
|
||||
keyIdentifier: keyIdentifier,
|
||||
nonce: nonce,
|
||||
signature: signature,
|
||||
timestamp: NSNumber(value: timestamp))
|
||||
}
|
||||
|
||||
self.iapManager.start(productId: productId, orderId: self.orderCode ?? "", applicationUsername: orderModel.discount?.sign_data?.applicationUsername, discount: discount)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func restore(isLoding: Bool = true, shortPlayId: String? = nil, videoId: String? = nil, completer: ((_ isFinish: Bool, _ buyType: XSStoreAPI.BuyType?) -> Void)?) {
|
||||
let buyType = self.waitRestoreModel?.buyType
|
||||
|
||||
guard let waitRestoreModel = self.waitRestoreModel,
|
||||
let orderCode = waitRestoreModel.orderCode,
|
||||
let payId = waitRestoreModel.payId,
|
||||
let receipt = waitRestoreModel.receipt,
|
||||
let transactionId = waitRestoreModel.transactionId
|
||||
else {
|
||||
if isLoding {
|
||||
XSToast.show("pay_error_5".localized)
|
||||
}
|
||||
completer?(false, buyType)
|
||||
return
|
||||
}
|
||||
|
||||
if isLoding {
|
||||
XSHud.show()
|
||||
}
|
||||
|
||||
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionId, purchaseToken: receipt)
|
||||
|
||||
let statParamenters: [String : Any] = [
|
||||
"type" : isLoding ? "manual" : "auto",
|
||||
"pay_data" : verifyData.toJsonString() ?? ""
|
||||
]
|
||||
// FAStatAPI.requestEventStat(orderCode: orderCode, shortPlayId: shortPlayId, videoId: videoId, eventKey: .payRestore, errorMsg: "restore", otherParamenters: statParamenters)
|
||||
|
||||
Task {
|
||||
let response = await XSStoreAPI.requestVerifyOrder(verifyData)
|
||||
if isLoding {
|
||||
XSHud.dismiss()
|
||||
}
|
||||
guard let model = response.data else {
|
||||
completer?(false, buyType)
|
||||
return
|
||||
}
|
||||
|
||||
self.waitRestoreModel = nil
|
||||
UserDefaults.xs_setObject(nil, forKey: kXSWaitRestoreIAPDefaultsKey)
|
||||
|
||||
if model.status == "success" {
|
||||
if buyType == .subVip {
|
||||
XSLoginManager.manager.userInfo?.is_vip = true
|
||||
}
|
||||
|
||||
if isLoding {
|
||||
XSToast.show("Success".localized)
|
||||
}
|
||||
completer?(true, buyType)
|
||||
if buyType == .subVip {
|
||||
NotificationCenter.default.post(name: XSIapManager.buyVipFinishNotification, object: nil)
|
||||
}
|
||||
} else {
|
||||
completer?(false, buyType)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
func getProductId(templateId: String?) -> String? {
|
||||
guard let templateId = templateId else { return nil }
|
||||
return XSIapManager.IAPPrefix + "." + templateId
|
||||
}
|
||||
|
||||
func clean() {
|
||||
self.orderCode = nil
|
||||
self.payId = nil
|
||||
self.shortPlayId = nil
|
||||
self.videoId = nil
|
||||
self.completionHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: JXIAPManagerDelegate
|
||||
extension XSIapManager: JXIAPManagerDelegate {
|
||||
|
||||
func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String) {
|
||||
guard let orderCode = self.orderCode, let payId = self.payId else {
|
||||
self.waitRestoreModel = nil
|
||||
self.completionHandler?(false)
|
||||
self.clean()
|
||||
XSHud.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
self.waitRestoreModel?.productId = productId
|
||||
self.waitRestoreModel?.receipt = receipt
|
||||
self.waitRestoreModel?.transactionId = transactionIdentifier
|
||||
|
||||
UserDefaults.xs_setObject(self.waitRestoreModel, forKey: kXSWaitRestoreIAPDefaultsKey)
|
||||
|
||||
#if DEBUG
|
||||
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionIdentifier, purchaseToken: receipt)
|
||||
#else
|
||||
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionIdentifier, purchaseToken: receipt)
|
||||
#endif
|
||||
Task {
|
||||
let response = await XSStoreAPI.requestVerifyOrder(verifyData)
|
||||
XSHud.dismiss()
|
||||
|
||||
guard let model = response.data else {
|
||||
// FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: verifyData.toJsonString())
|
||||
self.completionHandler?(false)
|
||||
self.clean()
|
||||
return
|
||||
}
|
||||
|
||||
let buyType = self.waitRestoreModel?.buyType
|
||||
self.waitRestoreModel = nil
|
||||
UserDefaults.xs_setObject(nil, forKey: kXSWaitRestoreIAPDefaultsKey)
|
||||
|
||||
if model.status == "success" {
|
||||
if buyType == .subVip {
|
||||
XSLoginManager.manager.userInfo?.is_vip = true
|
||||
}
|
||||
|
||||
XSToast.show("Success".localized)
|
||||
self.completionHandler?(true)
|
||||
if buyType == .subVip {
|
||||
NotificationCenter.default.post(name: XSIapManager.buyVipFinishNotification, object: nil)
|
||||
}
|
||||
} else {
|
||||
XSToast.show("pay_error_4".localized)
|
||||
// FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: verifyData.toJsonString())
|
||||
self.completionHandler?(false)
|
||||
}
|
||||
self.clean()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func jx_iapPayFailed(productId: String, code: JXIAPManager.ErrorCode, msg: String?) {
|
||||
XSHud.dismiss()
|
||||
|
||||
if code == .noProduct {
|
||||
XSToast.show("pay_error_2".localized)
|
||||
} else if code == .cancelled {
|
||||
XSToast.show("pay_error_3".localized)
|
||||
}
|
||||
|
||||
// if code == .cancelled {
|
||||
// FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCancel, errorMsg: "user cancel")
|
||||
// } else {
|
||||
// FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payError, errorMsg: msg)
|
||||
// }
|
||||
|
||||
self.completionHandler?(false)
|
||||
|
||||
self.waitRestoreModel = nil
|
||||
self.clean()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSIapManager {
|
||||
|
||||
func getVerifyOrderParameters(orderCode: String, payId: String, transactionId: String, purchaseToken: String) -> [String : Any] {
|
||||
let parameters: [String : Any] = [
|
||||
"order_code" : orderCode,
|
||||
"pay_setting_id" : payId,
|
||||
"pkg_name" : kXSBundleIdentifier,
|
||||
"transaction_id": transactionId,
|
||||
"purchases_token" : purchaseToken
|
||||
]
|
||||
return parameters
|
||||
}
|
||||
|
||||
///预加载支付项
|
||||
func preloadingProducts() {
|
||||
JXIAPManager.manager.fetchReceipt { _ in
|
||||
self.payRequest = XSPayDataRequest()
|
||||
self.payRequest?.requestProducts(isToast: false) { model in
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension XSIapManager {
|
||||
///成功购买会员
|
||||
@objc static let buyVipFinishNotification = Notification.Name(rawValue: "XSIapManager.buyVipFinishNotification")
|
||||
|
||||
}
|
||||
37
XSeri/Libs/IapManager/XSIapOrderModel.swift
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// XSIapOrderModel.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct XSIapOrderModel: SmartCodable {
|
||||
|
||||
var code: Int?
|
||||
var message: String?
|
||||
var order_code: String?
|
||||
var is_backhaul: String?
|
||||
var money: String?
|
||||
var discount: XSIapOrderDiscountModel?
|
||||
|
||||
}
|
||||
|
||||
struct XSIapOrderDiscountModel: SmartCodable {
|
||||
|
||||
var discount_code: String?
|
||||
var is_discount: Bool?
|
||||
var sign_data: XSIapOrderDiscountSign?
|
||||
}
|
||||
|
||||
struct XSIapOrderDiscountSign: SmartCodable {
|
||||
|
||||
var keyIdentifier: String?
|
||||
var nonce: String?
|
||||
var timestamp: TimeInterval?
|
||||
var applicationUsername: String?
|
||||
var signature: String?
|
||||
}
|
||||
|
||||
16
XSeri/Libs/IapManager/XSIapVerifyModel.swift
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// XSIapVerifyModel.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct XSIapVerifyModel: SmartCodable {
|
||||
var money: String?
|
||||
var status: String?
|
||||
var is_backhaul: String?
|
||||
var code: String?
|
||||
}
|
||||
165
XSeri/Libs/IapManager/XSPayDataRequest.swift
Normal file
@ -0,0 +1,165 @@
|
||||
//
|
||||
// XSPayDataRequest.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class XSPayDataRequest: NSObject {
|
||||
|
||||
private var oldTemplateModel: XSPayDateModel?
|
||||
|
||||
private var completerBlock: ((_ model: XSPayDateModel?) -> Void)?
|
||||
private var payRetainBlock: ((_ model: XSPayDateModel?) -> Void)?
|
||||
|
||||
private var isLoding = false
|
||||
private var isToast = false
|
||||
|
||||
func requestProducts(isLoding: Bool = false, isToast: Bool = true, completer: @escaping ((_ model: XSPayDateModel?) -> Void)) {
|
||||
self.completerBlock = completer
|
||||
self.isLoding = isLoding
|
||||
self.isToast = isToast
|
||||
|
||||
if isLoding {
|
||||
XSHud.show()
|
||||
}
|
||||
|
||||
Task {
|
||||
guard let model = await XSStoreAPI.requestPayTemplate(isLoding: false, isToast: isToast) else {
|
||||
if isLoding {
|
||||
XSHud.dismiss()
|
||||
}
|
||||
return
|
||||
}
|
||||
self.oldTemplateModel = model
|
||||
|
||||
var productIdArr: [String] = []
|
||||
model.list_sub_vip?.forEach { item in
|
||||
productIdArr.append(XSIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
model.list_coins?.forEach { item in
|
||||
productIdArr.append(XSIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
|
||||
let set = Set(productIdArr)
|
||||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
productsRequest.delegate = self
|
||||
productsRequest.start()
|
||||
}
|
||||
}
|
||||
|
||||
func requestPayRetainInfo(completer: ((_ model: XSPayDateModel?) -> Void)?) {
|
||||
self.payRetainBlock = completer
|
||||
self.isLoding = true
|
||||
XSHud.show()
|
||||
|
||||
Task {
|
||||
guard let model = await XSStoreAPI.requestPayRetainInfo() else {
|
||||
XSHud.dismiss()
|
||||
self.payRetainBlock?(nil)
|
||||
return
|
||||
}
|
||||
|
||||
self.oldTemplateModel = model
|
||||
|
||||
var productIdArr: [String] = []
|
||||
model.list_coins?.forEach { item in
|
||||
productIdArr.append(XSIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
model.list_sub_vip?.forEach { item in
|
||||
productIdArr.append(XSIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
|
||||
let set = Set(productIdArr)
|
||||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
productsRequest.delegate = self
|
||||
productsRequest.start()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: SKProductsRequestDelegate
|
||||
extension XSPayDataRequest: SKProductsRequestDelegate {
|
||||
|
||||
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||
if isLoding {
|
||||
XSHud.dismiss()
|
||||
}
|
||||
let products = response.products
|
||||
|
||||
if self.completerBlock != nil || self.payRetainBlock != nil {
|
||||
guard let templateModel = self.oldTemplateModel else { return }
|
||||
|
||||
var newCoinList: [XSPayItem] = []
|
||||
var newVipList: [XSPayItem] = []
|
||||
|
||||
templateModel.list_coins?.forEach { item in
|
||||
let productId = XSIapManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||
for product in products {
|
||||
if productId == product.productIdentifier {
|
||||
item.price = product.price.stringValue
|
||||
item.currency = product.priceLocale.currencySymbol
|
||||
item.product = product
|
||||
newCoinList.append(item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templateModel.list_sub_vip?.forEach { item in
|
||||
let productId = XSIapManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||
for product in products {
|
||||
if productId == product.productIdentifier {
|
||||
item.price = product.price.stringValue
|
||||
item.currency = product.priceLocale.currencySymbol
|
||||
item.product = product
|
||||
newVipList.append(item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
templateModel.list_coins = newCoinList
|
||||
templateModel.list_sub_vip = newVipList
|
||||
|
||||
|
||||
if let block = self.completerBlock {
|
||||
XSIapManager.manager.payDateModel = templateModel
|
||||
DispatchQueue.main.async {
|
||||
block(templateModel)
|
||||
}
|
||||
} else if let block = self.payRetainBlock {
|
||||
DispatchQueue.main.async {
|
||||
block(templateModel)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// 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)
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
48
XSeri/Libs/IapManager/XSWaitRestoreModel.swift
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// XSWaitRestoreModel.swift
|
||||
// XSeri
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2026/3/17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class XSWaitRestoreModel: NSObject, NSSecureCoding {
|
||||
|
||||
var orderCode: String?
|
||||
var payId: String?
|
||||
var productId: String?
|
||||
var receipt: String?
|
||||
var buyType: XSStoreAPI.BuyType?
|
||||
var transactionId: String?
|
||||
|
||||
|
||||
required override init() { }
|
||||
|
||||
static var supportsSecureCoding: Bool {
|
||||
get {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func encode(with coder: NSCoder) {
|
||||
coder.encode(orderCode, forKey: "orderCode")
|
||||
coder.encode(payId, forKey: "payId")
|
||||
coder.encode(productId, forKey: "productId")
|
||||
coder.encode(receipt, forKey: "receipt")
|
||||
coder.encode(buyType?.rawValue, forKey: "buyType")
|
||||
coder.encode(transactionId, forKey: "transactionId")
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init()
|
||||
orderCode = coder.decodeObject(of: NSString.self, forKey: "orderCode") as? String
|
||||
payId = coder.decodeObject(of: NSString.self, forKey: "payId") as? String
|
||||
productId = coder.decodeObject(of: NSString.self, forKey: "productId") as? String
|
||||
receipt = coder.decodeObject(of: NSString.self, forKey: "receipt") as? String
|
||||
transactionId = coder.decodeObject(of: NSString.self, forKey: "transactionId") as? String
|
||||
if let type = coder.decodeObject(of: NSString.self, forKey: "buyType") as? String {
|
||||
buyType = XSStoreAPI.BuyType(rawValue: type)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x00",
|
||||
"green" : "0x2B",
|
||||
"red" : "0x48"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x27",
|
||||
"green" : "0x39",
|
||||
"red" : "0x52"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x03",
|
||||
"green" : "0x2A",
|
||||
"red" : "0x71"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x4A",
|
||||
"green" : "0x56",
|
||||
"red" : "0xF6"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x36",
|
||||
"green" : "0x8C",
|
||||
"red" : "0xF9"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_04.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "arrow@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "arrow@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_04.imageset/arrow@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 422 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_04.imageset/arrow@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 499 B |
22
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_05.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "arrow@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "arrow@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_05.imageset/arrow@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 450 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_05.imageset/arrow@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 567 B |
22
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_06.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_06.imageset/Frame@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 265 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/arrow_right_icon_06.imageset/Frame@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 350 B |
22
XSeri/Source/Assets.xcassets/Image/icon/button_bg_image_01.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
XSeri/Source/Assets.xcassets/Image/icon/button_bg_image_01.imageset/渐变@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/button_bg_image_01.imageset/渐变@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 130 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/coins_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "查看图片 24@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "查看图片 24@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/coins_icon_01.imageset/查看图片 24@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/coins_icon_01.imageset/查看图片 24@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/coins_icon_02.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
XSeri/Source/Assets.xcassets/Image/icon/coins_icon_02.imageset/金币@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/coins_icon_02.imageset/金币@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/coins_pack_bg_image_01.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
XSeri/Source/Assets.xcassets/Image/icon/coins_pack_bg_image_01.imageset/内容@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/coins_pack_bg_image_01.imageset/内容@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 151 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/expires_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "time icon@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "time icon@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/expires_icon_01.imageset/time icon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 788 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/expires_icon_01.imageset/time icon@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/feedback_icon_03.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/feedback_icon_03.imageset/Frame@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 424 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/feedback_icon_03.imageset/Frame@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 535 B |
22
XSeri/Source/Assets.xcassets/Image/icon/gifts_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "礼物盒-icon@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "礼物盒-icon@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/gifts_icon_01.imageset/礼物盒-icon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/gifts_icon_01.imageset/礼物盒-icon@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 19 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 2108@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 2108@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_01.imageset/Group 2108@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_01.imageset/Group 2108@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Lock@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Lock@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_02.imageset/Lock@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 638 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_02.imageset/Lock@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 828 B |
22
XSeri/Source/Assets.xcassets/Image/icon/lock_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
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_03.imageset/锁-@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/lock_icon_03.imageset/锁-@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/order_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 315@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 315@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/order_icon_01.imageset/Group 315@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 516 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/order_icon_01.imageset/Group 315@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 677 B |
22
XSeri/Source/Assets.xcassets/Image/icon/order_icon_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Purchase records@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Purchase records@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/order_icon_02.imageset/Purchase records@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/order_icon_02.imageset/Purchase records@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 788 B |
22
XSeri/Source/Assets.xcassets/Image/icon/order_icon_03.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 614@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 614@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/order_icon_03.imageset/Group 614@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 809 B |
BIN
XSeri/Source/Assets.xcassets/Image/icon/order_icon_03.imageset/Group 614@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/store_button_bg_image.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2085662672@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2085662672@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/store_button_bg_image.imageset/Frame 2085662672@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
XSeri/Source/Assets.xcassets/Image/icon/store_button_bg_image.imageset/Frame 2085662672@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 28 KiB |
22
XSeri/Source/Assets.xcassets/Image/icon/time_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2085663363@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2085663363@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
XSeri/Source/Assets.xcassets/Image/icon/time_icon_01.imageset/Frame 2085663363@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 501 B |