Merge branch 'main' of https://git.qinjiu8.com/zengjx/Fableon
# Conflicts: # Podfile.lock
@ -16,6 +16,23 @@
|
||||
F342969A2EA0F8E700A58F99 /* FAGenresListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296992EA0F8E700A58F99 /* FAGenresListViewController.swift */; };
|
||||
F342969F2EA0FA2200A58F99 /* FAGenresListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F342969E2EA0FA2200A58F99 /* FAGenresListCell.xib */; };
|
||||
F34296A02EA0FA2200A58F99 /* FAGenresListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F342969D2EA0FA2200A58F99 /* FAGenresListCell.swift */; };
|
||||
F34296A82EA5D2C600A58F99 /* FACategoryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296A72EA5D2C600A58F99 /* FACategoryModel.swift */; };
|
||||
F34296AA2EA5DF1600A58F99 /* FAPopularListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296A92EA5DF1600A58F99 /* FAPopularListViewController.swift */; };
|
||||
F34296AC2EA5E11A00A58F99 /* FANewListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296AB2EA5E11A00A58F99 /* FANewListViewController.swift */; };
|
||||
F34296AE2EA5E4CE00A58F99 /* FAPopularModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296AD2EA5E4CE00A58F99 /* FAPopularModel.swift */; };
|
||||
F34296B22EA604D400A58F99 /* FARankingListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296B12EA604D400A58F99 /* FARankingListViewController.swift */; };
|
||||
F34296B42EA605E800A58F99 /* FARankingListHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296B32EA605E800A58F99 /* FARankingListHeaderView.swift */; };
|
||||
F34296B62EA60C8E00A58F99 /* FAGradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296B52EA60C8E00A58F99 /* FAGradientView.swift */; };
|
||||
F34296B92EA61C9100A58F99 /* FARankingListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F34296B82EA61C9100A58F99 /* FARankingListCell.xib */; };
|
||||
F34296BA2EA61C9100A58F99 /* FARankingListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296B72EA61C9100A58F99 /* FARankingListCell.swift */; };
|
||||
F34296BC2EA62C1A00A58F99 /* FAVideoLockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296BB2EA62C1A00A58F99 /* FAVideoLockView.swift */; };
|
||||
F34296BE2EA765CA00A58F99 /* FAGradientButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296BD2EA765CA00A58F99 /* FAGradientButton.swift */; };
|
||||
F34296C02EA7742900A58F99 /* FAVideoUnlockResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296BF2EA7742900A58F99 /* FAVideoUnlockResult.swift */; };
|
||||
F34296D52EA8B70100A58F99 /* FAMeCoinsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296D42EA8B70100A58F99 /* FAMeCoinsView.swift */; };
|
||||
F34296D92EA8BD0B00A58F99 /* FAMeTableViewHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296D82EA8BD0B00A58F99 /* FAMeTableViewHeaderView.swift */; };
|
||||
F34296DB2EA8CA2B00A58F99 /* Date+FAAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296DA2EA8CA2400A58F99 /* Date+FAAdd.swift */; };
|
||||
F34296DF2EA8D04800A58F99 /* FAStoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296DE2EA8D04800A58F99 /* FAStoreViewController.swift */; };
|
||||
F34296E12EA8D85D00A58F99 /* FABaseWebViewController+Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34296E02EA8D85400A58F99 /* FABaseWebViewController+Script.swift */; };
|
||||
F37103312E978F8C00E7F171 /* FACollectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37103302E978F8C00E7F171 /* FACollectViewController.swift */; };
|
||||
F37103352E97929F00E7F171 /* FACollectCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F37103342E97929F00E7F171 /* FACollectCell.xib */; };
|
||||
F37103362E97929F00E7F171 /* FACollectCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37103332E97929F00E7F171 /* FACollectCell.swift */; };
|
||||
@ -127,6 +144,23 @@
|
||||
F3DCC08B2E8BB16F00D58007 /* FARecommendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DCC08A2E8BB16F00D58007 /* FARecommendViewController.swift */; };
|
||||
F3DCC08E2E8BB1F100D58007 /* FARecommendViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DCC08D2E8BB1F100D58007 /* FARecommendViewModel.swift */; };
|
||||
F3DCC0912E8BBB7600D58007 /* FARecommendPlayerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DCC0902E8BBB7600D58007 /* FARecommendPlayerCell.swift */; };
|
||||
F3EE96562EA8DFBD00A9306D /* FAWebMessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96552EA8DFBD00A9306D /* FAWebMessageModel.swift */; };
|
||||
F3EE96582EA8E1A000A9306D /* FAWalletViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96572EA8E1A000A9306D /* FAWalletViewController.swift */; };
|
||||
F3EE96602EA8E39200A9306D /* FAWalletCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE965E2EA8E39200A9306D /* FAWalletCell.swift */; };
|
||||
F3EE96612EA8E39200A9306D /* FAWalletCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F3EE965F2EA8E39200A9306D /* FAWalletCell.xib */; };
|
||||
F3EE96632EA8E61200A9306D /* FAWalletHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96622EA8E61200A9306D /* FAWalletHeaderView.swift */; };
|
||||
F3EE96652EA9C63D00A9306D /* FAConsumptionRecordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96642EA9C63D00A9306D /* FAConsumptionRecordsViewController.swift */; };
|
||||
F3EE966A2EA9C72600A9306D /* FAConsumptionRecordsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96682EA9C72600A9306D /* FAConsumptionRecordsCell.swift */; };
|
||||
F3EE966B2EA9C72600A9306D /* FAConsumptionRecordsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F3EE96692EA9C72600A9306D /* FAConsumptionRecordsCell.xib */; };
|
||||
F3EE966D2EA9D29600A9306D /* FAOrderRecordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE966C2EA9D29600A9306D /* FAOrderRecordsViewController.swift */; };
|
||||
F3EE966F2EA9F94E00A9306D /* FACoinRecordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE966E2EA9F94E00A9306D /* FACoinRecordViewController.swift */; };
|
||||
F3EE96712EA9F96E00A9306D /* FAVipRecordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96702EA9F96D00A9306D /* FAVipRecordViewController.swift */; };
|
||||
F3EE96742EA9FA5D00A9306D /* FAOrderRecordCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F3EE96732EA9FA5C00A9306D /* FAOrderRecordCell.xib */; };
|
||||
F3EE96752EA9FA5D00A9306D /* FAOrderRecordCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96722EA9FA5C00A9306D /* FAOrderRecordCell.swift */; };
|
||||
F3EE96772EA9FD5F00A9306D /* FARewardCoinsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96762EA9FD5F00A9306D /* FARewardCoinsViewController.swift */; };
|
||||
F3EE967A2EA9FE0800A9306D /* FARewardCoinsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F3EE96792EA9FE0800A9306D /* FARewardCoinsCell.xib */; };
|
||||
F3EE967B2EA9FE0800A9306D /* FARewardCoinsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE96782EA9FE0800A9306D /* FARewardCoinsCell.swift */; };
|
||||
F3EE967D2EAA07F200A9306D /* FAMeListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EE967C2EAA07F200A9306D /* FAMeListViewController.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@ -141,6 +175,23 @@
|
||||
F34296992EA0F8E700A58F99 /* FAGenresListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAGenresListViewController.swift; sourceTree = "<group>"; };
|
||||
F342969D2EA0FA2200A58F99 /* FAGenresListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAGenresListCell.swift; sourceTree = "<group>"; };
|
||||
F342969E2EA0FA2200A58F99 /* FAGenresListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FAGenresListCell.xib; sourceTree = "<group>"; };
|
||||
F34296A72EA5D2C600A58F99 /* FACategoryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACategoryModel.swift; sourceTree = "<group>"; };
|
||||
F34296A92EA5DF1600A58F99 /* FAPopularListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAPopularListViewController.swift; sourceTree = "<group>"; };
|
||||
F34296AB2EA5E11A00A58F99 /* FANewListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FANewListViewController.swift; sourceTree = "<group>"; };
|
||||
F34296AD2EA5E4CE00A58F99 /* FAPopularModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAPopularModel.swift; sourceTree = "<group>"; };
|
||||
F34296B12EA604D400A58F99 /* FARankingListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARankingListViewController.swift; sourceTree = "<group>"; };
|
||||
F34296B32EA605E800A58F99 /* FARankingListHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARankingListHeaderView.swift; sourceTree = "<group>"; };
|
||||
F34296B52EA60C8E00A58F99 /* FAGradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAGradientView.swift; sourceTree = "<group>"; };
|
||||
F34296B72EA61C9100A58F99 /* FARankingListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARankingListCell.swift; sourceTree = "<group>"; };
|
||||
F34296B82EA61C9100A58F99 /* FARankingListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FARankingListCell.xib; sourceTree = "<group>"; };
|
||||
F34296BB2EA62C1A00A58F99 /* FAVideoLockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAVideoLockView.swift; sourceTree = "<group>"; };
|
||||
F34296BD2EA765CA00A58F99 /* FAGradientButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAGradientButton.swift; sourceTree = "<group>"; };
|
||||
F34296BF2EA7742900A58F99 /* FAVideoUnlockResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAVideoUnlockResult.swift; sourceTree = "<group>"; };
|
||||
F34296D42EA8B70100A58F99 /* FAMeCoinsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAMeCoinsView.swift; sourceTree = "<group>"; };
|
||||
F34296D82EA8BD0B00A58F99 /* FAMeTableViewHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAMeTableViewHeaderView.swift; sourceTree = "<group>"; };
|
||||
F34296DA2EA8CA2400A58F99 /* Date+FAAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+FAAdd.swift"; sourceTree = "<group>"; };
|
||||
F34296DE2EA8D04800A58F99 /* FAStoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreViewController.swift; sourceTree = "<group>"; };
|
||||
F34296E02EA8D85400A58F99 /* FABaseWebViewController+Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FABaseWebViewController+Script.swift"; sourceTree = "<group>"; };
|
||||
F37103302E978F8C00E7F171 /* FACollectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectViewController.swift; sourceTree = "<group>"; };
|
||||
F37103332E97929F00E7F171 /* FACollectCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACollectCell.swift; sourceTree = "<group>"; };
|
||||
F37103342E97929F00E7F171 /* FACollectCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FACollectCell.xib; sourceTree = "<group>"; };
|
||||
@ -255,6 +306,23 @@
|
||||
F3DCC08A2E8BB16F00D58007 /* FARecommendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARecommendViewController.swift; sourceTree = "<group>"; };
|
||||
F3DCC08D2E8BB1F100D58007 /* FARecommendViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARecommendViewModel.swift; sourceTree = "<group>"; };
|
||||
F3DCC0902E8BBB7600D58007 /* FARecommendPlayerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARecommendPlayerCell.swift; sourceTree = "<group>"; };
|
||||
F3EE96552EA8DFBD00A9306D /* FAWebMessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWebMessageModel.swift; sourceTree = "<group>"; };
|
||||
F3EE96572EA8E1A000A9306D /* FAWalletViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWalletViewController.swift; sourceTree = "<group>"; };
|
||||
F3EE965E2EA8E39200A9306D /* FAWalletCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWalletCell.swift; sourceTree = "<group>"; };
|
||||
F3EE965F2EA8E39200A9306D /* FAWalletCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FAWalletCell.xib; sourceTree = "<group>"; };
|
||||
F3EE96622EA8E61200A9306D /* FAWalletHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWalletHeaderView.swift; sourceTree = "<group>"; };
|
||||
F3EE96642EA9C63D00A9306D /* FAConsumptionRecordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAConsumptionRecordsViewController.swift; sourceTree = "<group>"; };
|
||||
F3EE96682EA9C72600A9306D /* FAConsumptionRecordsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAConsumptionRecordsCell.swift; sourceTree = "<group>"; };
|
||||
F3EE96692EA9C72600A9306D /* FAConsumptionRecordsCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FAConsumptionRecordsCell.xib; sourceTree = "<group>"; };
|
||||
F3EE966C2EA9D29600A9306D /* FAOrderRecordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOrderRecordsViewController.swift; sourceTree = "<group>"; };
|
||||
F3EE966E2EA9F94E00A9306D /* FACoinRecordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinRecordViewController.swift; sourceTree = "<group>"; };
|
||||
F3EE96702EA9F96D00A9306D /* FAVipRecordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAVipRecordViewController.swift; sourceTree = "<group>"; };
|
||||
F3EE96722EA9FA5C00A9306D /* FAOrderRecordCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOrderRecordCell.swift; sourceTree = "<group>"; };
|
||||
F3EE96732EA9FA5C00A9306D /* FAOrderRecordCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FAOrderRecordCell.xib; sourceTree = "<group>"; };
|
||||
F3EE96762EA9FD5F00A9306D /* FARewardCoinsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARewardCoinsViewController.swift; sourceTree = "<group>"; };
|
||||
F3EE96782EA9FE0800A9306D /* FARewardCoinsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARewardCoinsCell.swift; sourceTree = "<group>"; };
|
||||
F3EE96792EA9FE0800A9306D /* FARewardCoinsCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FARewardCoinsCell.xib; sourceTree = "<group>"; };
|
||||
F3EE967C2EAA07F200A9306D /* FAMeListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAMeListViewController.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -286,6 +354,29 @@
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F34296DC2EA8D02500A58F99 /* Store */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F34296DD2EA8D03200A58F99 /* C */,
|
||||
F3EE965D2EA8E35A00A9306D /* V */,
|
||||
);
|
||||
path = Store;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F34296DD2EA8D03200A58F99 /* C */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F34296DE2EA8D04800A58F99 /* FAStoreViewController.swift */,
|
||||
F3EE96572EA8E1A000A9306D /* FAWalletViewController.swift */,
|
||||
F3EE96642EA9C63D00A9306D /* FAConsumptionRecordsViewController.swift */,
|
||||
F3EE966C2EA9D29600A9306D /* FAOrderRecordsViewController.swift */,
|
||||
F3EE966E2EA9F94E00A9306D /* FACoinRecordViewController.swift */,
|
||||
F3EE96702EA9F96D00A9306D /* FAVipRecordViewController.swift */,
|
||||
F3EE96762EA9FD5F00A9306D /* FARewardCoinsViewController.swift */,
|
||||
);
|
||||
path = C;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F371032E2E978F4D00E7F171 /* MyShort */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -337,6 +428,8 @@
|
||||
F371037D2EA082C700E7F171 /* FAWebView.swift */,
|
||||
F371037F2EA0839500E7F171 /* FABaseWebViewController.swift */,
|
||||
F37103812EA0868100E7F171 /* FAAppWebViewController.swift */,
|
||||
F34296E02EA8D85400A58F99 /* FABaseWebViewController+Script.swift */,
|
||||
F3EE96552EA8DFBD00A9306D /* FAWebMessageModel.swift */,
|
||||
);
|
||||
path = WebView;
|
||||
sourceTree = "<group>";
|
||||
@ -428,6 +521,7 @@
|
||||
F37103482E9DD97200E7F171 /* UIScrollView+FARefresh.swift */,
|
||||
F371036A2E9E52FE00E7F171 /* UIStackView+FAAdd.swift */,
|
||||
F37103832EA0873400E7F171 /* Dictionary+FAAdd.swift */,
|
||||
F34296DA2EA8CA2400A58F99 /* Date+FAAdd.swift */,
|
||||
);
|
||||
path = Extension;
|
||||
sourceTree = "<group>";
|
||||
@ -456,6 +550,7 @@
|
||||
F3A792C92E77F70C0097E0BC /* FAShortDetailModel.swift */,
|
||||
F3A792CA2E77F70C0097E0BC /* FAShortPlayModel.swift */,
|
||||
F3A792CB2E77F70C0097E0BC /* FAVideoInfoModel.swift */,
|
||||
F34296BF2EA7742900A58F99 /* FAVideoUnlockResult.swift */,
|
||||
);
|
||||
path = M;
|
||||
sourceTree = "<group>";
|
||||
@ -478,6 +573,7 @@
|
||||
F3DCC0462E8A65B000D58007 /* FAEpSelectorCell.swift */,
|
||||
F3DCC0472E8A65B000D58007 /* FAEpSelectorCell.xib */,
|
||||
F3DCC04A2E8A6EAE00D58007 /* FAEpMenuView.swift */,
|
||||
F34296BB2EA62C1A00A58F99 /* FAVideoLockView.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -544,6 +640,8 @@
|
||||
children = (
|
||||
F3A792E72E77F8580097E0BC /* FAHomeModuleItem.swift */,
|
||||
F3A793112E78F8970097E0BC /* FAHomeItem.swift */,
|
||||
F34296A72EA5D2C600A58F99 /* FACategoryModel.swift */,
|
||||
F34296AD2EA5E4CE00A58F99 /* FAPopularModel.swift */,
|
||||
);
|
||||
path = M;
|
||||
sourceTree = "<group>";
|
||||
@ -575,6 +673,9 @@
|
||||
F34296962EA0EAAA00A58F99 /* FAGenresCell.xib */,
|
||||
F342969D2EA0FA2200A58F99 /* FAGenresListCell.swift */,
|
||||
F342969E2EA0FA2200A58F99 /* FAGenresListCell.xib */,
|
||||
F34296B32EA605E800A58F99 /* FARankingListHeaderView.swift */,
|
||||
F34296B72EA61C9100A58F99 /* FARankingListCell.swift */,
|
||||
F34296B82EA61C9100A58F99 /* FARankingListCell.xib */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -586,6 +687,9 @@
|
||||
F371034C2E9DF9FB00E7F171 /* FASearchViewController.swift */,
|
||||
F34296932EA0E8CB00A58F99 /* FAGenresViewController.swift */,
|
||||
F34296992EA0F8E700A58F99 /* FAGenresListViewController.swift */,
|
||||
F34296A92EA5DF1600A58F99 /* FAPopularListViewController.swift */,
|
||||
F34296AB2EA5E11A00A58F99 /* FANewListViewController.swift */,
|
||||
F34296B12EA604D400A58F99 /* FARankingListViewController.swift */,
|
||||
);
|
||||
path = C;
|
||||
sourceTree = "<group>";
|
||||
@ -636,6 +740,8 @@
|
||||
F3A793172E790D440097E0BC /* FAImageView.swift */,
|
||||
F3A798BD2E82ACD10097E0BC /* FAPanModalContentView.swift */,
|
||||
F3DCC04C2E8A6F0D00D58007 /* FAScrollView.swift */,
|
||||
F34296B52EA60C8E00A58F99 /* FAGradientView.swift */,
|
||||
F34296BD2EA765CA00A58F99 /* FAGradientButton.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -670,6 +776,7 @@
|
||||
F3C9AE582E77DD8C00E25109 /* Class */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F34296DC2EA8D02500A58F99 /* Store */,
|
||||
F3A792E02E77F8040097E0BC /* Home */,
|
||||
F3DCC0532E8A8EB200D58007 /* Me */,
|
||||
F3A792D52E77F70C0097E0BC /* Player */,
|
||||
@ -721,6 +828,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3DCC0562E8A8EE800D58007 /* FAMeViewController.swift */,
|
||||
F3EE967C2EAA07F200A9306D /* FAMeListViewController.swift */,
|
||||
F37103722E9F9E0D00E7F171 /* FAAboutViewController.swift */,
|
||||
F371037A2EA0820C00E7F171 /* FASettingViewController.swift */,
|
||||
F37103852EA087FB00E7F171 /* FAFeedbackViewController.swift */,
|
||||
@ -732,6 +840,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3DCC0592E8A931900D58007 /* FAMeHeaderView.swift */,
|
||||
F34296D42EA8B70100A58F99 /* FAMeCoinsView.swift */,
|
||||
F34296D82EA8BD0B00A58F99 /* FAMeTableViewHeaderView.swift */,
|
||||
F3DCC0612E8A9E7600D58007 /* FAMeCell.swift */,
|
||||
F3DCC0622E8A9E7600D58007 /* FAMeCell.xib */,
|
||||
F37103742E9FA15B00E7F171 /* FAAboutCell.swift */,
|
||||
@ -784,6 +894,22 @@
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F3EE965D2EA8E35A00A9306D /* V */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3EE965E2EA8E39200A9306D /* FAWalletCell.swift */,
|
||||
F3EE965F2EA8E39200A9306D /* FAWalletCell.xib */,
|
||||
F3EE96622EA8E61200A9306D /* FAWalletHeaderView.swift */,
|
||||
F3EE96682EA9C72600A9306D /* FAConsumptionRecordsCell.swift */,
|
||||
F3EE96692EA9C72600A9306D /* FAConsumptionRecordsCell.xib */,
|
||||
F3EE96722EA9FA5C00A9306D /* FAOrderRecordCell.swift */,
|
||||
F3EE96732EA9FA5C00A9306D /* FAOrderRecordCell.xib */,
|
||||
F3EE96782EA9FE0800A9306D /* FARewardCoinsCell.swift */,
|
||||
F3EE96792EA9FE0800A9306D /* FARewardCoinsCell.xib */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -847,19 +973,24 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F34296982EA0EAAA00A58F99 /* FAGenresCell.xib in Resources */,
|
||||
F3EE966B2EA9C72600A9306D /* FAConsumptionRecordsCell.xib in Resources */,
|
||||
F3A798B72E828C180097E0BC /* Localizable.strings in Resources */,
|
||||
F37103572E9E1FA500E7F171 /* FASearchRecordCell.xib in Resources */,
|
||||
F34296B92EA61C9100A58F99 /* FARankingListCell.xib in Resources */,
|
||||
F342969F2EA0FA2200A58F99 /* FAGenresListCell.xib in Resources */,
|
||||
F39E663A2E77BAD0008AAAFA /* Assets.xcassets in Resources */,
|
||||
F3EE96612EA8E39200A9306D /* FAWalletCell.xib in Resources */,
|
||||
F37103772E9FA15B00E7F171 /* FAAboutCell.xib in Resources */,
|
||||
F371035E2E9E2E7400E7F171 /* FASearchRecommendCell.xib in Resources */,
|
||||
F37103462E9CF9EE00E7F171 /* FAHistoryCell.xib in Resources */,
|
||||
F3A793292E795B4C0097E0BC /* FAHomeSectionTitleView.xib in Resources */,
|
||||
F3A793232E7944FF0097E0BC /* FAHomeRecommendedCell.xib in Resources */,
|
||||
F37103662E9E3ABC00E7F171 /* FASearchResultCell.xib in Resources */,
|
||||
F3EE967A2EA9FE0800A9306D /* FARewardCoinsCell.xib in Resources */,
|
||||
F3DCC0482E8A65B000D58007 /* FAEpSelectorCell.xib in Resources */,
|
||||
F39E663C2E77BAD0008AAAFA /* LaunchScreen.storyboard in Resources */,
|
||||
F3DCC0642E8A9E7600D58007 /* FAMeCell.xib in Resources */,
|
||||
F3EE96742EA9FA5D00A9306D /* FAOrderRecordCell.xib in Resources */,
|
||||
F37103352E97929F00E7F171 /* FACollectCell.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -924,13 +1055,20 @@
|
||||
F38C25FD2E86A290008C22C3 /* FADefine.swift in Sources */,
|
||||
F3A793182E790D440097E0BC /* FAImageView.swift in Sources */,
|
||||
F3DCC05A2E8A931900D58007 /* FAMeHeaderView.swift in Sources */,
|
||||
F34296AC2EA5E11A00A58F99 /* FANewListViewController.swift in Sources */,
|
||||
F3A792B62E77E0CC0097E0BC /* FANetworkManager.swift in Sources */,
|
||||
F3EE966A2EA9C72600A9306D /* FAConsumptionRecordsCell.swift in Sources */,
|
||||
F3A792C62E77E93E0097E0BC /* FANavigationController.swift in Sources */,
|
||||
F3EE966D2EA9D29600A9306D /* FAOrderRecordsViewController.swift in Sources */,
|
||||
F34296BE2EA765CA00A58F99 /* FAGradientButton.swift in Sources */,
|
||||
F34296A82EA5D2C600A58F99 /* FACategoryModel.swift in Sources */,
|
||||
F37103692E9E44A000E7F171 /* FASearchViewModel.swift in Sources */,
|
||||
F3A793122E78F8970097E0BC /* FAHomeItem.swift in Sources */,
|
||||
F3A798BE2E82ACD10097E0BC /* FAPanModalContentView.swift in Sources */,
|
||||
F3A792F22E77F8A80097E0BC /* FAHomeMustSeeView.swift in Sources */,
|
||||
F3A793242E7944FF0097E0BC /* FAHomeRecommendedCell.swift in Sources */,
|
||||
F34296B22EA604D400A58F99 /* FARankingListViewController.swift in Sources */,
|
||||
F34296B42EA605E800A58F99 /* FARankingListHeaderView.swift in Sources */,
|
||||
F3A792F42E77F8A80097E0BC /* FAHomeMustSeeContentView.swift in Sources */,
|
||||
F3DCC05E2E8A9C5800D58007 /* FATableViewCell.swift in Sources */,
|
||||
F371037E2EA082CD00E7F171 /* FAWebView.swift in Sources */,
|
||||
@ -938,16 +1076,19 @@
|
||||
F37103612E9E379E00E7F171 /* FASearchResultView.swift in Sources */,
|
||||
F3A792F52E77F8A80097E0BC /* FAHomeRecommendedItemView.swift in Sources */,
|
||||
F34296972EA0EAAA00A58F99 /* FAGenresCell.swift in Sources */,
|
||||
F34296D92EA8BD0B00A58F99 /* FAMeTableViewHeaderView.swift in Sources */,
|
||||
F37103842EA0873B00E7F171 /* Dictionary+FAAdd.swift in Sources */,
|
||||
F3A792F72E77F8A80097E0BC /* FAHomeNewView.swift in Sources */,
|
||||
F3A792F82E77F8A80097E0BC /* FAHomeMustSeeShortView.swift in Sources */,
|
||||
F3A793042E77FB110097E0BC /* FAHomeViewController.swift in Sources */,
|
||||
F34296DF2EA8D04800A58F99 /* FAStoreViewController.swift in Sources */,
|
||||
F371034F2E9DFB2000E7F171 /* FASearchInputView.swift in Sources */,
|
||||
F37103562E9E1FA500E7F171 /* FASearchRecordCell.swift in Sources */,
|
||||
F37103792E9FA91C00E7F171 /* FAAboutHeaderView.swift in Sources */,
|
||||
F3A792B12E77DFEE0097E0BC /* FALogin.swift in Sources */,
|
||||
F3DCC0502E8A861300D58007 /* FAHUD.swift in Sources */,
|
||||
F3DCC04D2E8A6F0D00D58007 /* FAScrollView.swift in Sources */,
|
||||
F3EE967D2EAA07F200A9306D /* FAMeListViewController.swift in Sources */,
|
||||
F3DCC0572E8A8EE800D58007 /* FAMeViewController.swift in Sources */,
|
||||
F3A792E82E77F8590097E0BC /* FAHomeModuleItem.swift in Sources */,
|
||||
F3DCC0452E89530200D58007 /* CGMutablePath+FARoundedCorner.swift in Sources */,
|
||||
@ -962,12 +1103,14 @@
|
||||
F3C9AE5B2E77DDE100E25109 /* FAKeychainHelper.swift in Sources */,
|
||||
F371034D2E9DF9FB00E7F171 /* FASearchViewController.swift in Sources */,
|
||||
F3A792B82E77E0EF0097E0BC /* FACryptorService.swift in Sources */,
|
||||
F3EE967B2EA9FE0800A9306D /* FARewardCoinsCell.swift in Sources */,
|
||||
F3A7932C2E796EF80097E0BC /* FAPlayerDetailControlView.swift in Sources */,
|
||||
F3A798BC2E82AB6F0097E0BC /* FAEpSelectorView.swift in Sources */,
|
||||
F37103512E9E1D7800E7F171 /* FASearchHomeView.swift in Sources */,
|
||||
F34296942EA0E8CB00A58F99 /* FAGenresViewController.swift in Sources */,
|
||||
F3A792AF2E77DFB90097E0BC /* FATokenModel.swift in Sources */,
|
||||
F38C25FA2E86A217008C22C3 /* UIView+FAAdd.swift in Sources */,
|
||||
F3EE96652EA9C63D00A9306D /* FAConsumptionRecordsViewController.swift in Sources */,
|
||||
F342969A2EA0F8E700A58F99 /* FAGenresListViewController.swift in Sources */,
|
||||
F3A7931A2E7911420097E0BC /* FAPagerViewTransformer.swift in Sources */,
|
||||
F3DCC0672E8AA14A00D58007 /* FAMeItemModel.swift in Sources */,
|
||||
@ -978,26 +1121,38 @@
|
||||
F37103762E9FA15B00E7F171 /* FAAboutCell.swift in Sources */,
|
||||
F37103412E97C20C00E7F171 /* UINavigationBar+FAAdd.swift in Sources */,
|
||||
F3A792D82E77F70C0097E0BC /* FAShortDetailViewModel.swift in Sources */,
|
||||
F3EE96562EA8DFBD00A9306D /* FAWebMessageModel.swift in Sources */,
|
||||
F37103802EA0839500E7F171 /* FABaseWebViewController.swift in Sources */,
|
||||
F3A793002E77FA0C0097E0BC /* SwiftUIExtension.swift in Sources */,
|
||||
F3A792D92E77F70C0097E0BC /* FAShortDetailModel.swift in Sources */,
|
||||
F34296C02EA7742900A58F99 /* FAVideoUnlockResult.swift in Sources */,
|
||||
F3A792DA2E77F70C0097E0BC /* FAPlayerDetailCell.swift in Sources */,
|
||||
F3A792DB2E77F70C0097E0BC /* FAVideoInfoModel.swift in Sources */,
|
||||
F3A7930C2E7813FE0097E0BC /* FACollectionView.swift in Sources */,
|
||||
F37103822EA0868100E7F171 /* FAAppWebViewController.swift in Sources */,
|
||||
F37103712E9F964000E7F171 /* FALocalized.swift in Sources */,
|
||||
F34296DB2EA8CA2B00A58F99 /* Date+FAAdd.swift in Sources */,
|
||||
F3EE966F2EA9F94E00A9306D /* FACoinRecordViewController.swift in Sources */,
|
||||
F3EE96632EA8E61200A9306D /* FAWalletHeaderView.swift in Sources */,
|
||||
F34296E12EA8D85D00A58F99 /* FABaseWebViewController+Script.swift in Sources */,
|
||||
F3A792DC2E77F70C0097E0BC /* FAPlayerDetailViewController.swift in Sources */,
|
||||
F38C25FF2E86B663008C22C3 /* AppDelegate+FAConfig.swift in Sources */,
|
||||
F37103592E9E281C00E7F171 /* FASearchRecommendView.swift in Sources */,
|
||||
F34296D52EA8B70100A58F99 /* FAMeCoinsView.swift in Sources */,
|
||||
F34296A02EA0FA2200A58F99 /* FAGenresListCell.swift in Sources */,
|
||||
F3A792BF2E77E4B80097E0BC /* FATool.swift in Sources */,
|
||||
F371033F2E97BDF800E7F171 /* FAHistoryViewController.swift in Sources */,
|
||||
F3EE96752EA9FA5D00A9306D /* FAOrderRecordCell.swift in Sources */,
|
||||
F34296BA2EA61C9100A58F99 /* FARankingListCell.swift in Sources */,
|
||||
F3DCC08B2E8BB16F00D58007 /* FARecommendViewController.swift in Sources */,
|
||||
F3DCC0492E8A65B000D58007 /* FAEpSelectorCell.swift in Sources */,
|
||||
F3A793162E790CC90097E0BC /* FAHomeBannerCell.swift in Sources */,
|
||||
F3EE96602EA8E39200A9306D /* FAWalletCell.swift in Sources */,
|
||||
F3EE96772EA9FD5F00A9306D /* FARewardCoinsViewController.swift in Sources */,
|
||||
F3DCC04B2E8A6EAE00D58007 /* FAEpMenuView.swift in Sources */,
|
||||
F3DCC0632E8A9E7600D58007 /* FAMeCell.swift in Sources */,
|
||||
F3A793142E78FC4C0097E0BC /* FAHomeBannerContentCell.swift in Sources */,
|
||||
F3EE96712EA9F96E00A9306D /* FAVipRecordViewController.swift in Sources */,
|
||||
F39E66372E77BAD0008AAAFA /* AppDelegate.swift in Sources */,
|
||||
F3DCC08E2E8BB1F100D58007 /* FARecommendViewModel.swift in Sources */,
|
||||
F371036B2E9E530400E7F171 /* UIStackView+FAAdd.swift in Sources */,
|
||||
@ -1005,13 +1160,16 @@
|
||||
F3A792BC2E77E2EE0097E0BC /* String+FAAdd.swift in Sources */,
|
||||
F3A792AD2E77DF830097E0BC /* FAUserInfo.swift in Sources */,
|
||||
F3A792DF2E77F7EA0097E0BC /* FAAPI.swift in Sources */,
|
||||
F34296AA2EA5DF1600A58F99 /* FAPopularListViewController.swift in Sources */,
|
||||
F3A7932A2E795B4C0097E0BC /* FAHomeSectionTitleView.swift in Sources */,
|
||||
F3DCC05C2E8A9C1B00D58007 /* FATableView.swift in Sources */,
|
||||
F37103492E9DD98600E7F171 /* UIScrollView+FARefresh.swift in Sources */,
|
||||
F3A7931E2E793D000097E0BC /* FAHomeNewContentCell.swift in Sources */,
|
||||
F34296BC2EA62C1A00A58F99 /* FAVideoLockView.swift in Sources */,
|
||||
F39E66382E77BAD0008AAAFA /* SceneDelegate.swift in Sources */,
|
||||
F371036E2E9E6E7800E7F171 /* FAEmpty.swift in Sources */,
|
||||
F37103362E97929F00E7F171 /* FACollectCell.swift in Sources */,
|
||||
F3EE96582EA8E1A000A9306D /* FAWalletViewController.swift in Sources */,
|
||||
F3A793532E7BA54A0097E0BC /* FAPlayerEpUIButton.swift in Sources */,
|
||||
F3A792EA2E77F8820097E0BC /* FAHomeViewModel.swift in Sources */,
|
||||
F3A792C82E77EED10097E0BC /* Font+FAAdd.swift in Sources */,
|
||||
@ -1020,6 +1178,8 @@
|
||||
F3A798B92E828F5E0097E0BC /* FAPlayerProgressView.swift in Sources */,
|
||||
F371035F2E9E2E7400E7F171 /* FASearchRecommendCell.swift in Sources */,
|
||||
F3A793092E7812F60097E0BC /* FAWaterfallFlowLayout.swift in Sources */,
|
||||
F34296AE2EA5E4CE00A58F99 /* FAPopularModel.swift in Sources */,
|
||||
F34296B62EA60C8E00A58F99 /* FAGradientView.swift in Sources */,
|
||||
F37103732E9F9E0D00E7F171 /* FAAboutViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -1060,6 +1220,8 @@
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Fableon/Source/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Fableon;
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||
@ -1096,6 +1258,8 @@
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Fableon/Source/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Fableon;
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||
|
||||
@ -6,8 +6,9 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import JXSegmentedView
|
||||
|
||||
class FAViewController: UIViewController {
|
||||
class FAViewController: UIViewController, JXSegmentedListContainerViewListDelegate {
|
||||
|
||||
lazy var bgView: UIView = {
|
||||
let view = UIImageView(image: UIImage(named: "背景"))
|
||||
@ -45,8 +46,13 @@ class FAViewController: UIViewController {
|
||||
return .lightContent
|
||||
}
|
||||
|
||||
|
||||
func listView() -> UIView {
|
||||
return self.view
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension UIViewController {
|
||||
func configNavigationBack(_ imageName: String = "Frame 3011") {
|
||||
let image = UIImage(named: imageName)
|
||||
|
||||
31
Fableon/Base/Extension/Date+FAAdd.swift
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Date+FAAdd.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Date {
|
||||
|
||||
///相差天数
|
||||
func fa_differenceDay(_ date: Date) -> Int {
|
||||
let dateComponents = Calendar.current.dateComponents([.day], from: self, to: date)
|
||||
return dateComponents.day ?? 0
|
||||
}
|
||||
|
||||
func fa_formatString(_ dateFormat: String) -> String {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = dateFormat
|
||||
return formatter.string(from: self)
|
||||
}
|
||||
|
||||
///是否是今天
|
||||
var br_isToday: Bool {
|
||||
get {
|
||||
return Calendar.current.isDateInToday(self)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -37,4 +37,13 @@ extension UIScreen {
|
||||
static var tabBarHeight: CGFloat {
|
||||
return safeBottom + 49
|
||||
}
|
||||
|
||||
///屏幕宽比
|
||||
static var widthRatio: CGFloat {
|
||||
return UIScreen.width / 375
|
||||
}
|
||||
|
||||
static func getRatioWidth(size: CGFloat) -> CGFloat {
|
||||
return self.widthRatio * size
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,6 +168,87 @@ struct FAAPI {
|
||||
completer?(response.data?.list)
|
||||
}
|
||||
}
|
||||
|
||||
static func requestGenresData(completer: ((_ list: [FACategoryModel]?) -> Void)?) {
|
||||
|
||||
let parameters = [
|
||||
"short_play_num" : 5,
|
||||
]
|
||||
|
||||
FANetworkManager.manager.request(FABaseURL + "/categoryListAppendShortPlay",
|
||||
method: .get,
|
||||
parameters: parameters,
|
||||
isToast: true) { (response: FANetworkManager.Response<FANetworkManager.List<FACategoryModel>>) in
|
||||
completer?(response.data?.list)
|
||||
}
|
||||
}
|
||||
|
||||
static func requestCategoryVideoList(id: String, page: Int, completer: ((_ listModel: FANetworkManager.List<FAShortPlayModel>?) -> Void)?) {
|
||||
|
||||
let parameters: [String : Any] = [
|
||||
"category_id" : id,
|
||||
"current_page" : page,
|
||||
"page_size" : 20
|
||||
]
|
||||
|
||||
FANetworkManager.manager.request(FABaseURL + "/videoList",
|
||||
method: .get,
|
||||
parameters: parameters,
|
||||
isToast: true) { (response: FANetworkManager.Response<FANetworkManager.List<FAShortPlayModel>>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
static func requestPopularVideoList( completer: ((_ list: [FAShortPlayModel]?) -> Void)?) {
|
||||
|
||||
FANetworkManager.manager.request(FABaseURL + "/homeTop",
|
||||
method: .post,
|
||||
parameters: nil,
|
||||
isToast: true) { (response: FANetworkManager.Response<FAPopularModel>) in
|
||||
completer?(response.data?.hotData)
|
||||
}
|
||||
}
|
||||
|
||||
static func requestNewVideoList( completer: ((_ list: [FAShortPlayModel]?) -> Void)?) {
|
||||
|
||||
FANetworkManager.manager.request(FABaseURL + "/newShortPlayNoPaginate",
|
||||
method: .post,
|
||||
parameters: nil,
|
||||
isToast: true) { (response: FANetworkManager.Response<FANetworkManager.List<FAShortPlayModel>>) in
|
||||
completer?(response.data?.list)
|
||||
}
|
||||
}
|
||||
|
||||
static func requestRankingVideoList( completer: ((_ list: [FAShortPlayModel]?) -> Void)?) {
|
||||
|
||||
let parameters = [
|
||||
"type" : "most_trending"
|
||||
]
|
||||
|
||||
FANetworkManager.manager.request(FABaseURL + "/homeRanking",
|
||||
method: .post,
|
||||
parameters: parameters,
|
||||
isToast: true) { (response: FANetworkManager.Response<FANetworkManager.List<FAShortPlayModel>>) in
|
||||
completer?(response.data?.list)
|
||||
}
|
||||
}
|
||||
|
||||
///金币解锁视频
|
||||
static func requestCoinUnlockVideo(shortPlayId: String, videoId: String, completer: ((_ model: FAVideoUnlockResult?) -> Void)?) {
|
||||
|
||||
let parameters = [
|
||||
"short_play_id" : shortPlayId,
|
||||
"video_id" : videoId,
|
||||
]
|
||||
|
||||
FANetworkManager.manager.request(FABaseURL + "/buy_video",
|
||||
method: .post,
|
||||
parameters: parameters,
|
||||
isLoding: true,
|
||||
isToast: true) { (response: FANetworkManager.Response<FAVideoUnlockResult>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
44
Fableon/Base/View/FAGradientButton.swift
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// FAGradientButton.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/21.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAGradientButton: UIButton {
|
||||
|
||||
override class var layerClass: AnyClass {
|
||||
return CAGradientLayer.self
|
||||
}
|
||||
|
||||
var fa_gradientLayer: CAGradientLayer {
|
||||
return self.layer as! CAGradientLayer
|
||||
}
|
||||
|
||||
var fa_colors: [CGColor]? {
|
||||
didSet {
|
||||
fa_gradientLayer.colors = fa_colors
|
||||
}
|
||||
}
|
||||
|
||||
var fa_startPoint: CGPoint = .zero {
|
||||
didSet {
|
||||
fa_gradientLayer.startPoint = fa_startPoint
|
||||
}
|
||||
}
|
||||
|
||||
var fa_endPoint: CGPoint = .zero {
|
||||
didSet {
|
||||
fa_gradientLayer.endPoint = fa_endPoint
|
||||
}
|
||||
}
|
||||
|
||||
var fa_locations: [NSNumber] = [] {
|
||||
didSet {
|
||||
fa_gradientLayer.locations = fa_locations
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
44
Fableon/Base/View/FAGradientView.swift
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// FAGradientView.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAGradientView: UIView {
|
||||
|
||||
override class var layerClass: AnyClass {
|
||||
return CAGradientLayer.self
|
||||
}
|
||||
|
||||
var fa_gradientLayer: CAGradientLayer {
|
||||
return self.layer as! CAGradientLayer
|
||||
}
|
||||
|
||||
var fa_colors: [CGColor]? {
|
||||
didSet {
|
||||
fa_gradientLayer.colors = fa_colors
|
||||
}
|
||||
}
|
||||
|
||||
var fa_startPoint: CGPoint = .zero {
|
||||
didSet {
|
||||
fa_gradientLayer.startPoint = fa_startPoint
|
||||
}
|
||||
}
|
||||
|
||||
var fa_endPoint: CGPoint = .zero {
|
||||
didSet {
|
||||
fa_gradientLayer.endPoint = fa_endPoint
|
||||
}
|
||||
}
|
||||
|
||||
var fa_locations: [NSNumber] = [] {
|
||||
didSet {
|
||||
fa_gradientLayer.locations = fa_locations
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,7 +7,10 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAScrollView: UIScrollView {
|
||||
class FAScrollView: UIScrollView, UIGestureRecognizerDelegate {
|
||||
|
||||
///允许同时识别滑动手势
|
||||
var allowSimultaneousRecognition = false
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
@ -18,4 +21,9 @@ class FAScrollView: UIScrollView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return allowSimultaneousRecognition
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -18,8 +18,16 @@ class FAAppWebViewController: FABaseWebViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.autoTitle = false
|
||||
|
||||
if webUrl == kFAFeedBackListWebUrl {
|
||||
self.title = "Feedback History".localized
|
||||
} else if webUrl == kFAFeedBackHomeWebUrl {
|
||||
self.title = "Feedback".localized
|
||||
} else if webUrl == kFAFeedBackDetailWebUrl {
|
||||
self.title = "Feedback Details".localized
|
||||
}
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
override func fa_webViewDidFinishLoad(_ webView: FAWebView) {
|
||||
|
||||
104
Fableon/Base/WebView/FABaseWebViewController+Script.swift
Normal file
@ -0,0 +1,104 @@
|
||||
//
|
||||
// FABaseWebViewController+Script.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import WebKit
|
||||
import ZLPhotoBrowser
|
||||
import SmartCodable
|
||||
|
||||
///APP交互
|
||||
let kFAWebMessageAPP = "js2app"
|
||||
///打开反馈列表
|
||||
let kFAWebMessageOpenFeedbackList = "openFeedbackList"
|
||||
///打开反馈详情
|
||||
let kFAWebMessageOpenFeedbackDetail = "openFeedbackDetail"
|
||||
///打开相册
|
||||
let kFAWebMessageOpenPhotoPicker = "openPhotoPicker"
|
||||
|
||||
extension FABaseWebViewController {
|
||||
|
||||
func fa_webViewUserContentController(didReceive message: WKScriptMessage) {
|
||||
let name = message.name
|
||||
let body = message.body
|
||||
|
||||
switch name {
|
||||
case kFAWebMessageOpenFeedbackList:
|
||||
let vc = FAAppWebViewController()
|
||||
vc.webUrl = kFAFeedBackListWebUrl
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case kFAWebMessageOpenFeedbackDetail:
|
||||
guard let body = body as? [String : Any] else { return }
|
||||
guard let id = body["id"] as? Int else { return }
|
||||
|
||||
let vc = FAAppWebViewController()
|
||||
vc.id = "\(id)"
|
||||
vc.webUrl = kFAFeedBackDetailWebUrl
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case kFAWebMessageOpenPhotoPicker:
|
||||
openPhotoPicker()
|
||||
|
||||
case kFAWebMessageAPP:
|
||||
guard let body = message.body as? [String : Any] else { return }
|
||||
guard let model = FAWebMessageModel.deserialize(from: body) else { return }
|
||||
let type = model.type
|
||||
let data = model.data
|
||||
|
||||
if type == "login" {
|
||||
// VPLoginManager.manager.openLogin()
|
||||
|
||||
} else if type == "open_notify" {
|
||||
// openNotify()
|
||||
|
||||
} else if type == "watch_video" {
|
||||
let vc = FAPlayerDetailViewController()
|
||||
vc.shortPlayId = data?.short_play_id
|
||||
vc.activityId = data?.activity_id
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
} else {
|
||||
|
||||
guard let urlStr = data?.link else { return }
|
||||
guard let url = URL(string: urlStr) else { return }
|
||||
if UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
///打开相册
|
||||
private func openPhotoPicker() {
|
||||
|
||||
ZLPhotoConfiguration.default().allowSelectOriginal = false
|
||||
ZLPhotoConfiguration.default().maxSelectCount = 1
|
||||
ZLPhotoConfiguration.default().allowEditImage = false
|
||||
ZLPhotoConfiguration.default().allowSelectVideo = false
|
||||
ZLPhotoConfiguration.default().allowSelectGif = false
|
||||
ZLPhotoConfiguration.default().allowTakePhotoInLibrary = false
|
||||
|
||||
let picker = ZLPhotoPicker()
|
||||
picker.selectImageBlock = { [weak self] (results, _) in
|
||||
guard let self = self else { return }
|
||||
guard let image = results.first?.image else { return }
|
||||
guard let imageData = image.jpegData(compressionQuality: 0.8) else { return }
|
||||
let imageDataStr = imageData.base64EncodedString(options: .endLineWithCarriageReturn)
|
||||
|
||||
let js = "uploadConvertImage('\(imageDataStr)')"
|
||||
self.webView.evaluateJavaScript(js)
|
||||
}
|
||||
|
||||
picker.showPhotoLibrary(sender: self)
|
||||
}
|
||||
|
||||
}
|
||||
@ -107,6 +107,6 @@ extension FABaseWebViewController: FAWebViewDelegate {
|
||||
}
|
||||
|
||||
func fa_userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
|
||||
self.fa_webViewUserContentController(didReceive: message)
|
||||
}
|
||||
}
|
||||
|
||||
24
Fableon/Base/WebView/FAWebMessageModel.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// FAWebMessageModel.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct FAWebMessageModel: SmartCodable {
|
||||
var type: String?
|
||||
|
||||
var data: FAWebMessageData?
|
||||
|
||||
}
|
||||
|
||||
struct FAWebMessageData: SmartCodable {
|
||||
|
||||
var activity_id: String?
|
||||
var short_play_id: String?
|
||||
var link: String?
|
||||
|
||||
}
|
||||
@ -34,6 +34,10 @@ class FAWebView: WKWebView {
|
||||
weak var delegate: FAWebViewDelegate?
|
||||
|
||||
private(set) var scriptMessageHandlerArray: [String] = [
|
||||
kFAWebMessageAPP,
|
||||
kFAWebMessageOpenFeedbackList,
|
||||
kFAWebMessageOpenFeedbackDetail,
|
||||
kFAWebMessageOpenPhotoPicker,
|
||||
]
|
||||
|
||||
|
||||
|
||||
@ -9,6 +9,10 @@ import UIKit
|
||||
|
||||
class FAGenresListViewController: FAViewController {
|
||||
|
||||
var model: FACategoryModel?
|
||||
|
||||
private var dataArr: [FAShortPlayModel] = []
|
||||
private var page = 1
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let width = floor((UIScreen.width - 32 - 16) / 3)
|
||||
@ -28,13 +32,22 @@ class FAGenresListViewController: FAViewController {
|
||||
collectionView.dataSource = self
|
||||
collectionView.contentInset = .init(top: 20, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
collectionView.register(UINib(nibName: "FAGenresListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||
collectionView.fa_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
collectionView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
||||
self?.handleFooterRefresh(nil)
|
||||
}
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = model?.category_name
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@ -43,7 +56,17 @@ class FAGenresListViewController: FAViewController {
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: 1) { [weak self] in
|
||||
self?.collectionView.fa_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: page + 1) { [weak self] in
|
||||
self?.collectionView.fa_endFooterRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -64,11 +87,43 @@ extension FAGenresListViewController {
|
||||
extension FAGenresListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return 10
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FAGenresListCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = dataArr[indexPath.row]
|
||||
let vc = FAPlayerDetailViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension FAGenresListViewController {
|
||||
|
||||
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||
guard let id = self.model?.id else { return }
|
||||
|
||||
FAAPI.requestCategoryVideoList(id: id, page: page) { [weak self] listModel in
|
||||
guard let self = self else { return }
|
||||
if let list = listModel?.list {
|
||||
if page == 1 {
|
||||
self.dataArr.removeAll()
|
||||
}
|
||||
|
||||
self.dataArr += list
|
||||
self.collectionView.reloadData()
|
||||
|
||||
self.page = page
|
||||
}
|
||||
completer?()
|
||||
self.collectionView.fa_updateNoMoreDataState(listModel?.hasNextPage)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ class FAGenresViewController: FAViewController {
|
||||
.FCB_072_0_5
|
||||
]
|
||||
|
||||
private lazy var dataArr: [FACategoryModel] = []
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.minimumLineSpacing = 10
|
||||
@ -39,6 +41,8 @@ class FAGenresViewController: FAViewController {
|
||||
self.title = "Genres".localized
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
requestDataArr()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@ -68,16 +72,33 @@ extension FAGenresViewController: UICollectionViewDelegate, UICollectionViewData
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FAGenresCell
|
||||
cell.bgView.backgroundColor = bgColorArr[indexPath.row % 5]
|
||||
cell.model = self.dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return 10
|
||||
return self.dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let vc = FAGenresListViewController()
|
||||
vc.model = dataArr[indexPath.row]
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAGenresViewController {
|
||||
|
||||
private func requestDataArr() {
|
||||
|
||||
FAAPI.requestGenresData { [weak self] list in
|
||||
guard let self = self else { return }
|
||||
guard let list = list else { return }
|
||||
|
||||
self.dataArr = list
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
119
Fableon/Class/Home/C/FANewListViewController.swift
Normal file
@ -0,0 +1,119 @@
|
||||
//
|
||||
// FANewListViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FANewListViewController: FAViewController {
|
||||
|
||||
private var dataArr: [FAShortPlayModel] = []
|
||||
// private var page = 1
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let width = floor((UIScreen.width - 32 - 16) / 3)
|
||||
let height = 145 / 109 * width + 41
|
||||
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.minimumLineSpacing = 12
|
||||
layout.minimumInteritemSpacing = 8
|
||||
layout.itemSize = .init(width: width, height: height)
|
||||
layout.sectionInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: FACollectionView = {
|
||||
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.contentInset = .init(top: 20, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
collectionView.register(UINib(nibName: "FAGenresListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||
collectionView.fa_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
// collectionView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
||||
// self?.handleFooterRefresh(nil)
|
||||
// }
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "New".localized
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: 1) { [weak self] in
|
||||
self?.collectionView.fa_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
// override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||
// requestDataArr(page: page + 1) { [weak self] in
|
||||
// self?.collectionView.fa_endFooterRefreshing()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
extension FANewListViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(collectionView)
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension FANewListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FAGenresListCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = dataArr[indexPath.row]
|
||||
let vc = FAPlayerDetailViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension FANewListViewController {
|
||||
|
||||
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||
|
||||
FAAPI.requestNewVideoList { [weak self] list in
|
||||
guard let self = self else { return }
|
||||
if let list = list {
|
||||
self.dataArr = list
|
||||
self.collectionView.reloadData()
|
||||
|
||||
}
|
||||
completer?()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
121
Fableon/Class/Home/C/FAPopularListViewController.swift
Normal file
@ -0,0 +1,121 @@
|
||||
//
|
||||
// FAPopularListViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAPopularListViewController: FAViewController {
|
||||
|
||||
private var dataArr: [FAShortPlayModel] = []
|
||||
// private var page = 1
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let width = floor((UIScreen.width - 32 - 16) / 3)
|
||||
let height = 145 / 109 * width + 41
|
||||
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.minimumLineSpacing = 12
|
||||
layout.minimumInteritemSpacing = 8
|
||||
layout.itemSize = .init(width: width, height: height)
|
||||
layout.sectionInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: FACollectionView = {
|
||||
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.contentInset = .init(top: 20, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
collectionView.register(UINib(nibName: "FAGenresListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||
collectionView.fa_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
// collectionView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
||||
// self?.handleFooterRefresh(nil)
|
||||
// }
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Popular".localized
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: 1) { [weak self] in
|
||||
self?.collectionView.fa_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
// override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||
// requestDataArr(page: page + 1) { [weak self] in
|
||||
// self?.collectionView.fa_endFooterRefreshing()
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
extension FAPopularListViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(collectionView)
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension FAPopularListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FAGenresListCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = dataArr[indexPath.row]
|
||||
let vc = FAPlayerDetailViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension FAPopularListViewController {
|
||||
|
||||
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||
|
||||
FAAPI.requestPopularVideoList { [weak self] list in
|
||||
guard let self = self else { return }
|
||||
if let list = list {
|
||||
|
||||
self.dataArr = list
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
completer?()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
128
Fableon/Class/Home/C/FARankingListViewController.swift
Normal file
@ -0,0 +1,128 @@
|
||||
//
|
||||
// FARankingListViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FARankingListViewController: FAViewController {
|
||||
|
||||
private lazy var dataArr: [FAShortPlayModel] = []
|
||||
|
||||
private lazy var headerView: FARankingListHeaderView = {
|
||||
let view = FARankingListHeaderView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var contentView: UIView = {
|
||||
let view = UIView()
|
||||
view.fa_setRoundedCorner(topLeft: 27, topRight: 27, bottomLeft: 0, bottomRight: 0)
|
||||
view.backgroundColor = ._5_CA_8_FF_0_2
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: UIScreen.width - 32, height: 70)
|
||||
layout.minimumLineSpacing = 15
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: FACollectionView = {
|
||||
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.contentInset = .init(top: 15, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
collectionView.register(UINib(nibName: "FARankingListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Rankings".localized
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
requestDataArr(completer: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FARankingListViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(headerView)
|
||||
view.addSubview(contentView)
|
||||
contentView.addSubview(collectionView)
|
||||
|
||||
headerView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(headerView.snp.bottom)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension FARankingListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FARankingListCell
|
||||
cell.model = dataArr[indexPath.row + 3]
|
||||
cell.number = indexPath.row + 4
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
let count = self.dataArr.count - 3
|
||||
if count < 0 {
|
||||
return 0
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = dataArr[indexPath.row + 3]
|
||||
let vc = FAPlayerDetailViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension FARankingListViewController {
|
||||
|
||||
private func requestDataArr(completer: (() -> Void)?) {
|
||||
|
||||
FAAPI.requestRankingVideoList { [weak self] list in
|
||||
guard let self = self else { return }
|
||||
if let list = list {
|
||||
self.dataArr = list
|
||||
self.headerView.dataArr = list
|
||||
self.collectionView.reloadData()
|
||||
|
||||
}
|
||||
completer?()
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Fableon/Class/Home/M/FACategoryModel.swift
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// FACategoryModel.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct FACategoryModel: SmartCodable {
|
||||
|
||||
var id: String?
|
||||
var category_name: String?
|
||||
var short_play_list: [FAShortPlayModel]?
|
||||
}
|
||||
15
Fableon/Class/Home/M/FAPopularModel.swift
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// FAPopularModel.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct FAPopularModel: SmartCodable {
|
||||
|
||||
var hotData: [FAShortPlayModel]?
|
||||
|
||||
}
|
||||
@ -25,12 +25,12 @@ struct FAHomeMustSeeContentView: View {
|
||||
.padding(.leading, 10)
|
||||
.padding(.top, 12)
|
||||
Spacer()
|
||||
// Image("Frame 3013")
|
||||
// .padding(.top, 14)
|
||||
// .padding(.trailing, 10)
|
||||
// .onTapGesture {
|
||||
// self.viewModel.pushMustSee(moduleKey)
|
||||
// }
|
||||
Image("Frame 3013")
|
||||
.padding(.top, 14)
|
||||
.padding(.trailing, 10)
|
||||
.onTapGesture {
|
||||
self.viewModel.pushMustSee(moduleKey)
|
||||
}
|
||||
}
|
||||
|
||||
VStack(spacing: 11) {
|
||||
|
||||
@ -31,9 +31,9 @@ struct FAHomeMustSeeShortView: View {
|
||||
KFImage(URL(string: model.image_url ?? ""))
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 76, height: 102)
|
||||
.cornerRadius(5)
|
||||
.clipped()
|
||||
.frame(width: 76, height: 102)
|
||||
.padding(.leading, 9)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
@ -9,6 +9,23 @@ import UIKit
|
||||
|
||||
class FAGenresCell: UICollectionViewCell {
|
||||
|
||||
var model: FACategoryModel? {
|
||||
didSet {
|
||||
var list = model?.short_play_list
|
||||
let firstModel = list?.removeFirst()
|
||||
|
||||
hotCountLabel.text = "\(firstModel?.watch_total ?? 0)"
|
||||
nameLabel.text = model?.category_name
|
||||
coverImageView.fa_setImage(firstModel?.image_url)
|
||||
|
||||
|
||||
list?.enumerated().forEach {
|
||||
let i = $0
|
||||
let imageView = smallImageViewArr[i]
|
||||
imageView.fa_setImage($1.image_url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var bgView: UIView!
|
||||
|
||||
@ -18,7 +35,7 @@ class FAGenresCell: UICollectionViewCell {
|
||||
|
||||
@IBOutlet weak var hotCountLabel: UILabel!
|
||||
|
||||
private lazy var smallImageViewArr: [UIView] = []
|
||||
private lazy var smallImageViewArr: [UIImageView] = []
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
<constraint firstItem="LbS-0P-tAf" firstAttribute="leading" secondItem="T3X-Bw-MIB" secondAttribute="leading" constant="152" id="Nrm-d1-SY5"/>
|
||||
<constraint firstItem="dr5-yQ-gX9" firstAttribute="top" secondItem="LbS-0P-tAf" secondAttribute="bottom" constant="9" id="PFQ-Cy-rgv"/>
|
||||
<constraint firstItem="JZp-LI-PlL" firstAttribute="centerY" secondItem="dr5-yQ-gX9" secondAttribute="centerY" id="Rx2-sn-DTb"/>
|
||||
<constraint firstItem="hqB-yr-uhy" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="LbS-0P-tAf" secondAttribute="trailing" constant="10" id="fGa-4l-D8P"/>
|
||||
<constraint firstItem="dr5-yQ-gX9" firstAttribute="leading" secondItem="LbS-0P-tAf" secondAttribute="leading" id="i4k-zs-CdI"/>
|
||||
<constraint firstItem="JZp-LI-PlL" firstAttribute="leading" secondItem="dr5-yQ-gX9" secondAttribute="trailing" constant="1" id="jH5-jE-fIE"/>
|
||||
<constraint firstItem="hqB-yr-uhy" firstAttribute="centerY" secondItem="LbS-0P-tAf" secondAttribute="centerY" id="llL-b1-yDx"/>
|
||||
|
||||
@ -9,6 +9,17 @@ import UIKit
|
||||
|
||||
class FAGenresListCell: UICollectionViewCell {
|
||||
|
||||
var model: FAShortPlayModel? {
|
||||
didSet {
|
||||
coverImageView.fa_setImage(model?.image_url)
|
||||
nameLabel.text = model?.name
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var coverImageView: FAImageView!
|
||||
|
||||
@IBOutlet weak var nameLabel: UILabel!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
|
||||
@ -45,6 +45,10 @@
|
||||
<constraint firstItem="7Si-zr-lN5" firstAttribute="top" secondItem="utm-U3-G8N" secondAttribute="bottom" constant="7" id="z5d-BM-XIT"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="229" height="312"/>
|
||||
<connections>
|
||||
<outlet property="coverImageView" destination="utm-U3-G8N" id="0fD-cC-dSP"/>
|
||||
<outlet property="nameLabel" destination="7Si-zr-lN5" id="gk6-pC-F5O"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="275.57251908396944" y="133.80281690140845"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
|
||||
42
Fableon/Class/Home/V/FARankingListCell.swift
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// FARankingListCell.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FARankingListCell: UICollectionViewCell {
|
||||
|
||||
var model: FAShortPlayModel? {
|
||||
didSet {
|
||||
coverImageView.fa_setImage(model?.image_url)
|
||||
nameLabel.text = model?.name
|
||||
epLabel.text = "Ep.##".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
||||
countLabel.text = "\(model?.watch_total ?? 0)"
|
||||
}
|
||||
}
|
||||
|
||||
var number: Int = 0 {
|
||||
didSet {
|
||||
numberLabel.text = "\(number)"
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var numberLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var coverImageView: FAImageView!
|
||||
|
||||
@IBOutlet weak var nameLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var epLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var countLabel: UILabel!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
}
|
||||
|
||||
}
|
||||
119
Fableon/Class/Home/V/FARankingListCell.xib
Normal file
@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="FARankingListCell" customModule="Fableon" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="509" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="509" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="b90-Bd-F4g">
|
||||
<rect key="frame" x="12.333333333333336" y="37" width="11.666666666666664" height="26.333333333333329"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
|
||||
<color key="textColor" name="#FFFFFF_0.8"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="HfV-02-Jbt" customClass="FAImageView" customModule="Fableon" customModuleProvider="target">
|
||||
<rect key="frame" x="37" y="0.0" width="53" height="100"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="53" id="WTo-v1-t4m"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="6"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5za-xf-gcJ">
|
||||
<rect key="frame" x="98" y="7.0000000000000009" width="31.666666666666657" height="14.333333333333336"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<color key="textColor" name="#FFFFFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pzn-o5-BYh">
|
||||
<rect key="frame" x="464.33333333333331" y="43" width="31.666666666666686" height="14.333333333333336"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<color key="textColor" name="#FFFFFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" image="Frame 2915" translatesAutoresizingMaskIntoConstraints="NO" id="v0e-ss-7Lj">
|
||||
<rect key="frame" x="450.33333333333331" y="44" width="12" height="12"/>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jIu-B2-ciK">
|
||||
<rect key="frame" x="98" y="27.333333333333329" width="39.666666666666657" height="12"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Y10-wf-GlX">
|
||||
<rect key="frame" x="9.0000000000000018" y="1.3333333333333357" width="21.666666666666671" height="9.6666666666666661"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="8"/>
|
||||
<color key="textColor" name="#FFFFFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" name="#6D6D6D_0.4"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Y10-wf-GlX" firstAttribute="centerY" secondItem="jIu-B2-ciK" secondAttribute="centerY" id="Noe-0G-SoL"/>
|
||||
<constraint firstItem="Y10-wf-GlX" firstAttribute="centerX" secondItem="jIu-B2-ciK" secondAttribute="centerX" id="OKR-8b-RT4"/>
|
||||
<constraint firstAttribute="height" constant="12" id="rWB-mc-vsy"/>
|
||||
<constraint firstItem="Y10-wf-GlX" firstAttribute="leading" secondItem="jIu-B2-ciK" secondAttribute="leading" constant="9" id="uaB-MB-QSe"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="6"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
|
||||
<constraints>
|
||||
<constraint firstItem="jIu-B2-ciK" firstAttribute="leading" secondItem="5za-xf-gcJ" secondAttribute="leading" id="AYK-bK-VBE"/>
|
||||
<constraint firstItem="pzn-o5-BYh" firstAttribute="leading" secondItem="v0e-ss-7Lj" secondAttribute="trailing" constant="2" id="BW0-ml-TWj"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="5za-xf-gcJ" secondAttribute="trailing" constant="80" id="U8T-vE-4vW"/>
|
||||
<constraint firstAttribute="bottom" secondItem="HfV-02-Jbt" secondAttribute="bottom" id="VqO-XA-aRF"/>
|
||||
<constraint firstItem="b90-Bd-F4g" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="bUl-mD-lff"/>
|
||||
<constraint firstItem="HfV-02-Jbt" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="37" id="fOE-wQ-TM2"/>
|
||||
<constraint firstItem="b90-Bd-F4g" firstAttribute="centerX" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="18" id="fuA-UT-HIO"/>
|
||||
<constraint firstItem="5za-xf-gcJ" firstAttribute="leading" secondItem="HfV-02-Jbt" secondAttribute="trailing" constant="8" id="gx3-xg-AsW"/>
|
||||
<constraint firstAttribute="trailing" secondItem="pzn-o5-BYh" secondAttribute="trailing" constant="13" id="pyb-RR-iSG"/>
|
||||
<constraint firstItem="jIu-B2-ciK" firstAttribute="top" secondItem="5za-xf-gcJ" secondAttribute="bottom" constant="6" id="q6S-9v-82E"/>
|
||||
<constraint firstItem="HfV-02-Jbt" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="sia-ic-tox"/>
|
||||
<constraint firstItem="5za-xf-gcJ" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="7" id="tow-FC-CE1"/>
|
||||
<constraint firstItem="pzn-o5-BYh" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="z2P-bm-B0K"/>
|
||||
<constraint firstItem="v0e-ss-7Lj" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="zJs-uc-PRZ"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="509" height="100"/>
|
||||
<connections>
|
||||
<outlet property="countLabel" destination="pzn-o5-BYh" id="CEy-h1-Fnx"/>
|
||||
<outlet property="coverImageView" destination="HfV-02-Jbt" id="0mc-gM-SHd"/>
|
||||
<outlet property="epLabel" destination="Y10-wf-GlX" id="c5I-WJ-Opb"/>
|
||||
<outlet property="nameLabel" destination="5za-xf-gcJ" id="LCr-OO-vcb"/>
|
||||
<outlet property="numberLabel" destination="b90-Bd-F4g" id="3m4-as-KAS"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="489.3129770992366" y="58.450704225352112"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="Frame 2915" width="12" height="12"/>
|
||||
<namedColor name="#6D6D6D_0.4">
|
||||
<color red="0.42745098039215684" green="0.42745098039215684" blue="0.42745098039215684" alpha="0.40000000596046448" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#FFFFFF">
|
||||
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#FFFFFF_0.8">
|
||||
<color red="1" green="1" blue="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
</resources>
|
||||
</document>
|
||||
212
Fableon/Class/Home/V/FARankingListHeaderView.swift
Normal file
@ -0,0 +1,212 @@
|
||||
//
|
||||
// FARankingListHeaderView.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FARankingListHeaderView: UIView {
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return .init(width: UIScreen.width, height: 150 + coverSize)
|
||||
}
|
||||
|
||||
var dataArr: [FAShortPlayModel] = [] {
|
||||
didSet {
|
||||
oneView.isHidden = true
|
||||
twoView.isHidden = true
|
||||
threeView.isHidden = true
|
||||
if dataArr.count > 0 {
|
||||
oneView.isHidden = false
|
||||
oneView.model = dataArr[0]
|
||||
}
|
||||
if dataArr.count > 1 {
|
||||
twoView.isHidden = false
|
||||
twoView.model = dataArr[1]
|
||||
}
|
||||
if dataArr.count > 2 {
|
||||
threeView.isHidden = false
|
||||
threeView.model = dataArr[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var margin = UIScreen.getRatioWidth(size: 43)
|
||||
private lazy var spacing = 10.0
|
||||
private lazy var itemWidth = floor((UIScreen.width - margin * 2 - spacing * 2) / 3)
|
||||
private lazy var coverSize = itemWidth - UIScreen.getRatioWidth(size: 36)
|
||||
|
||||
|
||||
|
||||
private lazy var oneView: FARankingListHeaderItemView = {
|
||||
let view = FARankingListHeaderItemView()
|
||||
view.isHidden = true
|
||||
view.coverSize = coverSize
|
||||
view.numberImageView.image = UIImage(named: "皇冠1")
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var twoView: FARankingListHeaderItemView = {
|
||||
let view = FARankingListHeaderItemView()
|
||||
view.isHidden = true
|
||||
view.coverSize = coverSize
|
||||
view.numberImageView.image = UIImage(named: "皇冠2")
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var threeView: FARankingListHeaderItemView = {
|
||||
let view = FARankingListHeaderItemView()
|
||||
view.isHidden = true
|
||||
view.coverSize = coverSize
|
||||
view.numberImageView.image = UIImage(named: "皇冠3")
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
|
||||
addSubview(oneView)
|
||||
addSubview(twoView)
|
||||
addSubview(threeView)
|
||||
|
||||
oneView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.width.equalTo(itemWidth)
|
||||
make.top.equalToSuperview().offset(32)
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
}
|
||||
|
||||
twoView.snp.makeConstraints { make in
|
||||
make.right.equalTo(oneView.snp.left).offset(-10)
|
||||
make.top.equalTo(oneView).offset(25)
|
||||
make.width.equalTo(oneView)
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
}
|
||||
|
||||
threeView.snp.makeConstraints { make in
|
||||
make.left.equalTo(oneView.snp.right).offset(10)
|
||||
make.top.equalTo(twoView).offset(5)
|
||||
make.width.equalTo(oneView)
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class FARankingListHeaderItemView: UIView {
|
||||
|
||||
// override var intrinsicContentSize: CGSize {
|
||||
// return .init(width: 97, height: 140 + coverSize)
|
||||
// }
|
||||
|
||||
var model: FAShortPlayModel? {
|
||||
didSet {
|
||||
coverImageView.fa_setImage(model?.image_url)
|
||||
nameLabel.text = model?.name
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var coverSize: CGFloat = 60 {
|
||||
didSet {
|
||||
self.invalidateIntrinsicContentSize()
|
||||
|
||||
coverImageView.snp.updateConstraints { make in
|
||||
make.width.height.equalTo(coverSize)
|
||||
}
|
||||
|
||||
coverImageView.layer.cornerRadius = coverSize / 2
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgView: UIView = {
|
||||
let view = FAGradientView()
|
||||
view.fa_locations = [0, 1]
|
||||
view.fa_colors = [UIColor._1680_FB.cgColor, UIColor._79_A_7_DB.withAlphaComponent(0).cgColor]
|
||||
view.fa_startPoint = .init(x: 0.5, y: 0)
|
||||
view.fa_endPoint = .init(x: 0.5, y: 1)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coverImageView: FAImageView = {
|
||||
let imageView = FAImageView()
|
||||
imageView.layer.borderWidth = 2
|
||||
imageView.layer.borderColor = UIColor.FFFFFF.cgColor
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private(set) lazy var numberImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var nameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textAlignment = .center
|
||||
label.textColor = .FFFFFF
|
||||
label.font = .font(ofSize: 14, weight: .bold)
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
addSubview(bgView)
|
||||
addSubview(coverImageView)
|
||||
addSubview(numberImageView)
|
||||
addSubview(nameLabel)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(20)
|
||||
make.width.height.equalTo(60)
|
||||
}
|
||||
|
||||
numberImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(-5)
|
||||
make.top.equalToSuperview().offset(-8)
|
||||
}
|
||||
|
||||
nameLabel.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview().offset(-9)
|
||||
make.top.equalTo(coverImageView.snp.bottom).offset(10)
|
||||
}
|
||||
|
||||
|
||||
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
|
||||
addGestureRecognizer(tap)
|
||||
}
|
||||
@objc private func handleTap() {
|
||||
let vc = FAPlayerDetailViewController()
|
||||
vc.shortPlayId = self.model?.short_play_id
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
bgView.fa_setRoundedCorner(topLeft: self.width / 2, topRight: self.width / 2, bottomLeft: 0, bottomRight: 0)
|
||||
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
@ -126,9 +126,27 @@ extension FAHomeViewModel {
|
||||
}
|
||||
|
||||
func pushMustSee(_ key: FAHomeModuleItem.ModuleKey?) {
|
||||
debugLog("\(key?.rawValue)")
|
||||
var vc: FAViewController?
|
||||
|
||||
let vc = FAGenresViewController()
|
||||
FATool.topViewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
switch key {
|
||||
case .v3_recommand:
|
||||
vc = FAPopularListViewController()
|
||||
|
||||
case .cagetory_recommand:
|
||||
vc = FAGenresViewController()
|
||||
|
||||
case .new_recommand:
|
||||
vc = FANewListViewController()
|
||||
|
||||
case .week_ranking:
|
||||
vc = FARankingListViewController()
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if let vc = vc {
|
||||
FATool.topViewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,18 +13,17 @@ class FAFeedbackViewController: FAAppWebViewController {
|
||||
self.webUrl = kFAFeedBackHomeWebUrl
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Frame 2085663258"), style: .plain, target: self, action: #selector(handleRightBarButton))
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
@objc private func handleRightBarButton() {
|
||||
|
||||
let vc = FAAppWebViewController()
|
||||
vc.webUrl = kFAFeedBackListWebUrl
|
||||
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
// 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.
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
154
Fableon/Class/Me/C/FAMeListViewController.swift
Normal file
@ -0,0 +1,154 @@
|
||||
//
|
||||
// FAMeListViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import JXPagingView
|
||||
|
||||
class FAMeListViewController: FAViewController, JXPagingViewListViewDelegate {
|
||||
|
||||
var scrollCallback: ((_ : UIScrollView) -> Void)?
|
||||
|
||||
private lazy var dataArr: [FAMeItemModel] = {
|
||||
let arr = [
|
||||
FAMeItemModel(type: .feedback, name: "Feedback".localized, icon: UIImage(named: "icon_feedback")),
|
||||
FAMeItemModel(type: .about, name: "About".localized, icon: UIImage(named: "icon_about")),
|
||||
// FAMeItemModel(type: .setting, name: "Setting".localized, icon: UIImage(named: "icon_setting"))
|
||||
|
||||
FAMeItemModel(type: .privacyPolicy, name: "Privacy Policy".localized, icon: UIImage(named: "icon_privacy")),
|
||||
FAMeItemModel(type: .userAgreement, name: "User Agreement".localized, icon: UIImage(named: "icon_user")),
|
||||
FAMeItemModel(type: .visitWebsite, name: "Visit Website".localized, icon: UIImage(named: "icon_visit")),
|
||||
]
|
||||
return arr
|
||||
}()
|
||||
|
||||
|
||||
|
||||
private lazy var tableViewHeaderView: FAMeTableViewHeaderView = {
|
||||
let view = FAMeTableViewHeaderView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 124))
|
||||
view.userInfo = FALogin.manager.userInfo
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var contentView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = ._4_D_4_A_4_A.withAlphaComponent(0.5)
|
||||
view.fa_setRoundedCorner(topLeft: 28, topRight: 0, bottomLeft: 0, bottomRight: 0)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tableView: FATableView = {
|
||||
let tableView = FATableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 56
|
||||
tableView.separatorInset = .init(top: 0, left: 32, bottom: 0, right: 32)
|
||||
tableView.register(UINib(nibName: "FAMeCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||
// tableView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
return tableView
|
||||
}()
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: FALogin.userInfoUpdateNotification, object: nil)
|
||||
|
||||
self.bgView.isHidden = true
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
|
||||
@objc private func userInfoUpdateNotification() {
|
||||
tableViewHeaderView.userInfo = FALogin.manager.userInfo
|
||||
}
|
||||
|
||||
func listScrollView() -> UIScrollView {
|
||||
return self.tableView
|
||||
}
|
||||
|
||||
func listViewDidScrollCallback(callback: @escaping (UIScrollView) -> ()) {
|
||||
self.scrollCallback = callback
|
||||
}
|
||||
}
|
||||
|
||||
extension FAMeListViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
tableView.tableHeaderView = self.tableViewHeaderView
|
||||
|
||||
view.addSubview(contentView)
|
||||
contentView.addSubview(tableView)
|
||||
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.left.right.top.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(19)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate, UITableViewDataSource
|
||||
extension FAMeListViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAMeCell
|
||||
cell.item = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
self.scrollCallback?(scrollView)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let item = dataArr[indexPath.row]
|
||||
switch item.type {
|
||||
case .about:
|
||||
let vc = FAAboutViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case .setting:
|
||||
let vc = FASettingViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case .feedback:
|
||||
let vc = FAFeedbackViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case .privacyPolicy:
|
||||
let vc = FABaseWebViewController()
|
||||
vc.webUrl = FAWebBaseURL + "/private"
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case .userAgreement:
|
||||
let vc = FABaseWebViewController()
|
||||
vc.webUrl = FAWebBaseURL + "/user_policy"
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case .visitWebsite:
|
||||
if let url = URL(string: FAWebBaseURL) {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,53 +7,36 @@
|
||||
|
||||
import UIKit
|
||||
import YYText
|
||||
import JXSegmentedView
|
||||
import JXPagingView
|
||||
|
||||
class FAMeViewController: FAViewController {
|
||||
|
||||
|
||||
private lazy var dataArr: [FAMeItemModel] = {
|
||||
let arr = [
|
||||
// FAMeItemModel(type: .feedback, name: "Feedback".localized, icon: UIImage(named: "icon_feedback")),
|
||||
FAMeItemModel(type: .about, name: "About".localized, icon: UIImage(named: "icon_about")),
|
||||
// FAMeItemModel(type: .setting, name: "Setting".localized, icon: UIImage(named: "icon_setting"))
|
||||
|
||||
FAMeItemModel(type: .privacyPolicy, name: "Privacy Policy".localized, icon: UIImage(named: "icon_privacy")),
|
||||
FAMeItemModel(type: .userAgreement, name: "User Agreement".localized, icon: UIImage(named: "icon_user")),
|
||||
FAMeItemModel(type: .visitWebsite, name: "Visit Website".localized, icon: UIImage(named: "icon_visit")),
|
||||
]
|
||||
return arr
|
||||
}()
|
||||
|
||||
|
||||
private lazy var scrollView: FAScrollView = {
|
||||
let scrollView = FAScrollView()
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var headerView: FAMeHeaderView = {
|
||||
let view = FAMeHeaderView()
|
||||
view.userInfo = FALogin.manager.userInfo
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var contentView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = ._4_D_4_A_4_A.withAlphaComponent(0.5)
|
||||
view.fa_setRoundedCorner(topLeft: 30, topRight: 30, bottomLeft: 0, bottomRight: 0)
|
||||
private lazy var listView: FAMeListViewController = FAMeListViewController()
|
||||
|
||||
private lazy var segmentedView: JXSegmentedView = {
|
||||
let view = JXSegmentedView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tableView: FATableView = {
|
||||
let tableView = FATableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 56
|
||||
tableView.separatorInset = .init(top: 0, left: 32, bottom: 0, right: 32)
|
||||
tableView.register(UINib(nibName: "FAMeCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||
tableView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
return tableView
|
||||
private lazy var pagingView: JXPagingView = {
|
||||
let view = JXPagingView(delegate: self)
|
||||
view.mainTableView.backgroundColor = .clear
|
||||
view.listContainerView.backgroundColor = .clear
|
||||
view.listContainerView.listCellBackgroundColor = .clear
|
||||
view.mainTableView.fa_addRefreshHeader(insetTop: 0) { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
@ -62,6 +45,8 @@ class FAMeViewController: FAViewController {
|
||||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: FALogin.userInfoUpdateNotification, object: nil)
|
||||
|
||||
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
@ -75,13 +60,12 @@ class FAMeViewController: FAViewController {
|
||||
FALogin.manager.requestUserInfo(completer: nil)
|
||||
}
|
||||
|
||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
if keyPath == "contentSize" {
|
||||
self.updateLayout()
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
FALogin.manager.requestUserInfo { [weak self] in
|
||||
self?.pagingView.mainTableView.fa_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc private func userInfoUpdateNotification() {
|
||||
headerView.userInfo = FALogin.manager.userInfo
|
||||
}
|
||||
@ -91,98 +75,43 @@ class FAMeViewController: FAViewController {
|
||||
extension FAMeViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(scrollView)
|
||||
scrollView.addSubview(headerView)
|
||||
scrollView.addSubview(contentView)
|
||||
contentView.addSubview(tableView)
|
||||
view.addSubview(pagingView)
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
pagingView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.safeTop)
|
||||
}
|
||||
|
||||
headerView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(40)
|
||||
}
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalTo(headerView.snp.bottom).offset(24)
|
||||
make.bottom.equalToSuperview()
|
||||
make.height.equalTo(UIScreen.height - UIScreen.tabBarHeight - UIScreen.safeTop)
|
||||
}
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(19)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateLayout() {
|
||||
let maxHeight = UIScreen.height - UIScreen.tabBarHeight - UIScreen.safeTop
|
||||
let minHeight = UIScreen.height - UIScreen.tabBarHeight - UIScreen.safeTop - self.headerView.height - 40 - 24
|
||||
var height = self.tableView.contentSize.height
|
||||
if height > maxHeight {
|
||||
height = maxHeight
|
||||
}
|
||||
if height < minHeight {
|
||||
height = minHeight
|
||||
}
|
||||
|
||||
contentView.snp.updateConstraints { make in
|
||||
make.height.equalTo(height)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate, UITableViewDataSource
|
||||
extension FAMeViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
//MARK: JXPagingViewDelegate
|
||||
extension FAMeViewController: JXPagingViewDelegate {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAMeCell
|
||||
cell.item = dataArr[indexPath.row]
|
||||
return cell
|
||||
func pagingView(_ pagingView: JXPagingView, initListAtIndex index: Int) -> any JXPagingViewListViewDelegate {
|
||||
return listView
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
func tableHeaderViewHeight(in pagingView: JXPagingView) -> Int {
|
||||
return Int(ceill(headerView.contentHeight))
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let item = dataArr[indexPath.row]
|
||||
switch item.type {
|
||||
case .about:
|
||||
let vc = FAAboutViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
func tableHeaderView(in pagingView: JXPagingView) -> UIView {
|
||||
return headerView
|
||||
}
|
||||
|
||||
case .setting:
|
||||
let vc = FASettingViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
func heightForPinSectionHeader(in pagingView: JXPagingView) -> Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
case .feedback:
|
||||
let vc = FAFeedbackViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
func viewForPinSectionHeader(in pagingView: JXPagingView) -> UIView {
|
||||
return UIView()
|
||||
}
|
||||
|
||||
case .privacyPolicy:
|
||||
let vc = FABaseWebViewController()
|
||||
vc.webUrl = FAWebBaseURL + "/private"
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case .userAgreement:
|
||||
let vc = FABaseWebViewController()
|
||||
vc.webUrl = FAWebBaseURL + "/user_policy"
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case .visitWebsite:
|
||||
if let url = URL(string: FAWebBaseURL) {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
func numberOfLists(in pagingView: JXPagingView) -> Int {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,12 @@ struct FAMeItemModel {
|
||||
case privacyPolicy
|
||||
case userAgreement
|
||||
case visitWebsite
|
||||
///消费记录
|
||||
case consumptionRecords
|
||||
///购买记录
|
||||
case purchaseRecords
|
||||
///金币奖励
|
||||
case rewardCoins
|
||||
}
|
||||
|
||||
|
||||
|
||||
83
Fableon/Class/Me/V/FAMeCoinsView.swift
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// FAMeCoinsView.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAMeCoinsView: UIControl {
|
||||
|
||||
var title: String? {
|
||||
didSet {
|
||||
titleLabel.text = title
|
||||
}
|
||||
}
|
||||
|
||||
var count: Int = 0 {
|
||||
didSet {
|
||||
coinLabel.text = "\(count)"
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var coinImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "coins_icon_01"))
|
||||
imageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 10, weight: .bold)
|
||||
label.textColor = .F_7_F_497
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .bold)
|
||||
label.textColor = .FFFFFF
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAMeCoinsView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(coinImageView)
|
||||
addSubview(titleLabel)
|
||||
addSubview(coinLabel)
|
||||
|
||||
coinImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.centerY.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(-2)
|
||||
make.left.equalTo(coinImageView.snp.right).offset(10)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
|
||||
coinLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(titleLabel)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.bottom.equalToSuperview().offset(0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -9,6 +9,8 @@ import UIKit
|
||||
|
||||
class FAMeHeaderView: UIView {
|
||||
|
||||
var contentHeight: CGFloat = 40 + 66 + 40 + 28 + 24
|
||||
|
||||
var userInfo: FAUserInfo? {
|
||||
didSet {
|
||||
avatarImageView.fa_setImage(userInfo?.avator)
|
||||
@ -16,6 +18,10 @@ class FAMeHeaderView: UIView {
|
||||
userNameLabel.text = userInfo?.getNickName()
|
||||
|
||||
idLabel.text = "ID:\(userInfo?.customer_id ?? "")"
|
||||
|
||||
coinsView.count = userInfo?.coin_left_total ?? 0
|
||||
|
||||
bonusCoinsView.count = userInfo?.send_coin_left_total ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +45,31 @@ class FAMeHeaderView: UIView {
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinsView: FAMeCoinsView = {
|
||||
let view = FAMeCoinsView()
|
||||
view.title = "Coins".localized
|
||||
view.count = 0
|
||||
view.addAction(UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = FAWalletViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}), for: .touchUpInside)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var bonusCoinsView: FAMeCoinsView = {
|
||||
let view = FAMeCoinsView()
|
||||
view.title = "Bonus"
|
||||
view.count = 0
|
||||
view.addAction(UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = FAWalletViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}), for: .touchUpInside)
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
fa_setupLayout()
|
||||
@ -55,12 +86,13 @@ extension FAMeHeaderView {
|
||||
addSubview(avatarImageView)
|
||||
addSubview(userNameLabel)
|
||||
addSubview(idLabel)
|
||||
addSubview(coinsView)
|
||||
addSubview(bonusCoinsView)
|
||||
|
||||
avatarImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(40)
|
||||
make.width.height.equalTo(66)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
userNameLabel.snp.makeConstraints { make in
|
||||
@ -73,6 +105,16 @@ extension FAMeHeaderView {
|
||||
make.left.equalTo(userNameLabel)
|
||||
make.top.equalTo(userNameLabel.snp.bottom).offset(2)
|
||||
}
|
||||
|
||||
coinsView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.equalTo(avatarImageView.snp.bottom).offset(40)
|
||||
}
|
||||
|
||||
bonusCoinsView.snp.makeConstraints { make in
|
||||
make.top.equalTo(coinsView)
|
||||
make.left.equalTo(coinsView.snp.right).offset(40)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
165
Fableon/Class/Me/V/FAMeTableViewHeaderView.swift
Normal file
@ -0,0 +1,165 @@
|
||||
//
|
||||
// FAMeTableViewHeaderView.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAMeTableViewHeaderView: UIView {
|
||||
|
||||
var userInfo: FAUserInfo? {
|
||||
didSet {
|
||||
if userInfo?.is_vip == true {
|
||||
subscribeView.isHidden = true
|
||||
expirationView.isHidden = false
|
||||
vipImageView.image = UIImage(named: "vip_image_02")
|
||||
titleLabel.text = "Activated".localized
|
||||
subtitleLabel.text = "vip_tip_01".localized
|
||||
} else {
|
||||
subscribeView.isHidden = false
|
||||
expirationView.isHidden = true
|
||||
vipImageView.image = UIImage(named: "vip_image_01")
|
||||
titleLabel.text = "Not Activated".localized
|
||||
subtitleLabel.text = "vip_tip_02".localized
|
||||
}
|
||||
|
||||
|
||||
expirationView.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var contentView: FAGradientView = {
|
||||
let view = FAGradientView()
|
||||
view.fa_colors = [UIColor.C_3_FAFF.cgColor, UIColor._7_FDBF_5.cgColor, UIColor._105_C_91.cgColor]
|
||||
view.fa_locations = [0, 0.5, 1]
|
||||
view.fa_startPoint = .init(x: 0, y: 0.5)
|
||||
view.fa_endPoint = .init(x: 1, y: 0.5)
|
||||
view.fa_setRoundedCorner(topLeft: 28, topRight: 6, bottomLeft: 6, bottomRight: 6)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var vipImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "vip_image_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 18, weight: .bold)
|
||||
label.textColor = ._3_A_271_E
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var subtitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = ._000000.withAlphaComponent(0.5)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var subscribeView: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.attributedTitle = AttributedString("Subscribe".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor._333333
|
||||
]))
|
||||
|
||||
let button = FAGradientButton(configuration: config)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.layer.cornerRadius = 18
|
||||
button.layer.masksToBounds = true
|
||||
button.fa_colors = [UIColor.BEDFFF.cgColor, UIColor._52_A_2_F_1.cgColor]
|
||||
button.fa_locations = [0, 1]
|
||||
button.fa_startPoint = .init(x: 0, y: 0.5)
|
||||
button.fa_endPoint = .init(x: 1, y: 0.5)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var expirationView: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.contentInsets = .zero
|
||||
config.image = UIImage(named: "Frame 3021")
|
||||
config.imagePadding = 4
|
||||
|
||||
let button = UIButton(configuration: config)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
|
||||
let date = Date(timeIntervalSince1970: userInfo?.vip_end_time ?? 0)
|
||||
let text = "vip_expires_date".localizedReplace(text: date.fa_formatString("yyyy-MM-dd"))
|
||||
button.configuration?.attributedTitle = AttributedString(text, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .medium),
|
||||
.foregroundColor : UIColor._3_A_271_E
|
||||
]))
|
||||
}
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
let tap = UITapGestureRecognizer { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = FAStoreViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
contentView.addGestureRecognizer(tap)
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAMeTableViewHeaderView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(contentView)
|
||||
contentView.addSubview(vipImageView)
|
||||
contentView.addSubview(titleLabel)
|
||||
contentView.addSubview(subtitleLabel)
|
||||
contentView.addSubview(subscribeView)
|
||||
contentView.addSubview(expirationView)
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
vipImageView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-4)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.equalToSuperview().offset(16)
|
||||
}
|
||||
|
||||
subtitleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(3)
|
||||
}
|
||||
|
||||
subscribeView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.bottom.equalToSuperview().offset(-16)
|
||||
make.height.equalTo(36)
|
||||
make.width.equalTo(130)
|
||||
}
|
||||
|
||||
expirationView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.bottom.equalToSuperview().offset(-16)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
26
Fableon/Class/Player/M/FAVideoUnlockResult.swift
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// FAVideoUnlockResult.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/21.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct FAVideoUnlockResult: SmartCodable {
|
||||
|
||||
enum Status: String, SmartCaseDefaultable {
|
||||
///前面还有没购买的剧
|
||||
case jump = "jump"
|
||||
///没找到视频
|
||||
case noPlay = "no_play"
|
||||
///金币不足跳充值
|
||||
case notEnough = "not_enough"
|
||||
///购买成功
|
||||
case success = "success"
|
||||
}
|
||||
|
||||
var status: Status?
|
||||
|
||||
}
|
||||
@ -12,6 +12,8 @@ class FAEpSelectorCell: UICollectionViewCell {
|
||||
var model: FAVideoInfoModel? {
|
||||
didSet {
|
||||
numberLabel.text = model?.episode
|
||||
|
||||
lockImageView.isHidden = !(model?.is_lock ?? true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +33,9 @@ class FAEpSelectorCell: UICollectionViewCell {
|
||||
|
||||
@IBOutlet weak var numberLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var lockImageView: UIImageView!
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
self.layer.masksToBounds = false
|
||||
|
||||
@ -23,18 +23,27 @@
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" image="lock_icon_01" translatesAutoresizingMaskIntoConstraints="NO" id="SWr-gt-V62">
|
||||
<rect key="frame" x="169" y="237" width="12" height="12"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</view>
|
||||
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
|
||||
<constraints>
|
||||
<constraint firstItem="yhy-MQ-hyT" firstAttribute="centerX" secondItem="gTV-IL-0wX" secondAttribute="centerX" id="CFQ-ov-ult"/>
|
||||
<constraint firstItem="yhy-MQ-hyT" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="Ov2-Ct-sBR"/>
|
||||
<constraint firstAttribute="bottom" secondItem="SWr-gt-V62" secondAttribute="bottom" constant="1" id="yP9-YB-f8b"/>
|
||||
<constraint firstAttribute="trailing" secondItem="SWr-gt-V62" secondAttribute="trailing" constant="4" id="zsC-gY-FUL"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="185" height="250"/>
|
||||
<connections>
|
||||
<outlet property="lockImageView" destination="SWr-gt-V62" id="Y64-xm-3BX"/>
|
||||
<outlet property="numberLabel" destination="yhy-MQ-hyT" id="SSw-lq-oFo"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="241.98473282442748" y="111.9718309859155"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="lock_icon_01" width="12" height="12"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@ -14,11 +14,17 @@ class FAPlayerDetailCell: JXPlayerListCell {
|
||||
return FAPlayerDetailControlView.self
|
||||
}
|
||||
|
||||
var fa_viewModel: FAShortDetailViewModel {
|
||||
return self.viewModel as! FAShortDetailViewModel
|
||||
}
|
||||
|
||||
override var model: Any? {
|
||||
didSet {
|
||||
let model = self.model as? FAVideoInfoModel
|
||||
self.player.setPlayUrl(url: model?.video_url ?? "")
|
||||
|
||||
self.lockView.isHidden = !(model?.is_lock ?? true)
|
||||
lockView.videoInfo = model
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,9 +35,26 @@ class FAPlayerDetailCell: JXPlayerListCell {
|
||||
}
|
||||
}
|
||||
|
||||
var hasLastEpisodeUnlocked: Bool = false {
|
||||
didSet {
|
||||
self.lockView.hasLastEpisodeUnlocked = hasLastEpisodeUnlocked
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private lazy var lockView: FAVideoLockView = {
|
||||
let view = FAVideoLockView()
|
||||
view.clickUnlockButton = { [weak self] in
|
||||
self?.fa_viewModel.handleUnlockVideo()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
@ -41,6 +64,18 @@ class FAPlayerDetailCell: JXPlayerListCell {
|
||||
|
||||
}
|
||||
|
||||
extension FAPlayerDetailCell {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(lockView)
|
||||
|
||||
lockView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAPlayerDetailCell {
|
||||
|
||||
override func jx_playerReadyToPlay(_ player: JXPlayer) {
|
||||
|
||||
@ -24,7 +24,7 @@ class FAPlayerDetailControlView: JXPlayerListControlView {
|
||||
|
||||
override var model: Any? {
|
||||
didSet {
|
||||
// let model = self.model as? FAVideoInfoModel
|
||||
let model = self.model as? FAVideoInfoModel
|
||||
|
||||
updateEp()
|
||||
}
|
||||
@ -133,6 +133,8 @@ class FAPlayerDetailControlView: JXPlayerListControlView {
|
||||
return button
|
||||
}()
|
||||
|
||||
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
@ -230,6 +232,8 @@ extension FAPlayerDetailControlView {
|
||||
make.height.equalTo(44)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
80
Fableon/Class/Player/V/FAVideoLockView.swift
Normal file
@ -0,0 +1,80 @@
|
||||
//
|
||||
// FAVideoLockView.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAVideoLockView: UIView {
|
||||
|
||||
var clickUnlockButton: (() -> Void)?
|
||||
|
||||
var videoInfo: FAVideoInfoModel? {
|
||||
didSet {
|
||||
unlockButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
var hasLastEpisodeUnlocked = false {
|
||||
didSet {
|
||||
unlockButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var unlockButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.image = UIImage(named: "lock_icon_02")
|
||||
config.imagePadding = 6
|
||||
|
||||
let button = FAGradientButton(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: 14, weight: .medium),
|
||||
.foregroundColor : UIColor._000000
|
||||
])
|
||||
if hasLastEpisodeUnlocked {
|
||||
button.configuration?.attributedTitle = .init("video_lock_tip_text".localized, attributes: attributeContainer)
|
||||
} else {
|
||||
button.configuration?.attributedTitle = .init("Unlocking costs ## coins".localizedReplace(text: "\(videoInfo?.coins ?? 0)"), attributes: attributeContainer)
|
||||
}
|
||||
}
|
||||
button.layer.cornerRadius = 26
|
||||
button.layer.masksToBounds = true
|
||||
button.fa_colors = [UIColor.BEDFFF.cgColor, UIColor._52_A_2_F_1.cgColor]
|
||||
button.fa_locations = [0, 1]
|
||||
button.fa_startPoint = .init(x: 0, y: 0.5)
|
||||
button.fa_endPoint = .init(x: 1, y: 0.5)
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = ._000000.withAlphaComponent(0.6)
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAVideoLockView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(unlockButton)
|
||||
|
||||
unlockButton.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(44)
|
||||
make.height.equalTo(52)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,6 +13,7 @@ import FDFullscreenPopGesture
|
||||
class FAPlayerDetailViewController: JXPlayerListViewController {
|
||||
|
||||
var shortPlayId: String?
|
||||
var activityId: String?
|
||||
|
||||
override var ViewModelClass: JXPlayerListViewModel.Type {
|
||||
return FAShortDetailViewModel.self
|
||||
@ -77,10 +78,16 @@ class FAPlayerDetailViewController: JXPlayerListViewController {
|
||||
}
|
||||
|
||||
override func play() {
|
||||
super.play()
|
||||
|
||||
let videoInfo = self.viewModel.currentCell?.model as? FAVideoInfoModel
|
||||
FAAPI.requestCreatePlayHistory(videoId: videoInfo?.short_play_video_id, shortPlayId: videoInfo?.short_play_id)
|
||||
|
||||
if videoInfo?.is_lock != true {
|
||||
super.play()
|
||||
FAAPI.requestCreatePlayHistory(videoId: videoInfo?.short_play_video_id, shortPlayId: videoInfo?.short_play_id)
|
||||
return
|
||||
}
|
||||
self.pause()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,6 +117,13 @@ extension FAPlayerDetailViewController: JXPlayerListViewControllerDelegate, JXPl
|
||||
let cell = self.dequeueReusableCell(withReuseIdentifier: "FAPlayerDetailCell", for: indexPath) as! FAPlayerDetailCell
|
||||
cell.model = self.fa_viewModel.dataArr[indexPath.section].episodeList?[indexPath.row]
|
||||
cell.shortModel = self.fa_viewModel.dataArr[indexPath.section].shortPlayInfo
|
||||
|
||||
let upRow = indexPath.row - 1
|
||||
if upRow >= 0, let videoInfo = self.fa_viewModel.dataArr[indexPath.section].episodeList?[upRow], videoInfo.is_lock == true {
|
||||
cell.hasLastEpisodeUnlocked = true
|
||||
} else {
|
||||
cell.hasLastEpisodeUnlocked = false
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
@ -110,5 +110,61 @@ extension FAShortDetailViewModel {
|
||||
self.popView = view
|
||||
}
|
||||
|
||||
func handleUnlockVideo() {
|
||||
unlockVideo { [weak self] finish in
|
||||
if finish {
|
||||
self?.playerListVC?.reloadData {
|
||||
self?.playerListVC?.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///打开充值页面
|
||||
func openRechargeView() {
|
||||
guard let videoInfo = self.currentCell?.model as? FAVideoInfoModel else { return }
|
||||
guard self.popView == nil else { return }
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAShortDetailViewModel {
|
||||
|
||||
private func unlockVideo(completer: ((_ finish: Bool) -> Void)?) {
|
||||
guard let videoInfo = self.currentCell?.model as? FAVideoInfoModel else { return }
|
||||
guard let shortPlayId = videoInfo.short_play_id else { return }
|
||||
guard let videoId = videoInfo.short_play_video_id else { return }
|
||||
|
||||
FAAPI.requestCoinUnlockVideo(shortPlayId: shortPlayId, videoId: videoId) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else {
|
||||
completer?(false)
|
||||
return
|
||||
}
|
||||
|
||||
switch model.status {
|
||||
case .jump:
|
||||
FAToast.show(text: "buy_fail_toast_02".localized)
|
||||
case .noPlay:
|
||||
FAToast.show(text: "buy_fail_toast_01".localized)
|
||||
case .notEnough:
|
||||
self.openRechargeView()
|
||||
default: break
|
||||
}
|
||||
|
||||
if model.status == .success {
|
||||
FALogin.manager.requestUserInfo {
|
||||
videoInfo.is_lock = false
|
||||
completer?(true)
|
||||
}
|
||||
} else {
|
||||
completer?(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
52
Fableon/Class/Store/C/FACoinRecordViewController.swift
Normal file
@ -0,0 +1,52 @@
|
||||
//
|
||||
// FACoinRecordViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FACoinRecordViewController: FAViewController {
|
||||
|
||||
|
||||
private lazy var tableView: FATableView = {
|
||||
let tableView = FATableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 72
|
||||
tableView.separatorColor = .FFFFFF.withAlphaComponent(0.1)
|
||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
tableView.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
tableView.register(UINib(nibName: "FAOrderRecordCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
bgView.isHidden = true
|
||||
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate UITableViewDataSource
|
||||
extension FACoinRecordViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 20
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
//
|
||||
// FAConsumptionRecordsViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAConsumptionRecordsViewController: FAViewController {
|
||||
|
||||
|
||||
private lazy var tableView: FATableView = {
|
||||
let tableView = FATableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 71
|
||||
tableView.separatorColor = .FFFFFF.withAlphaComponent(0.1)
|
||||
tableView.separatorInset = .init(top: 0, left: 34, bottom: 0, right: 34)
|
||||
tableView.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
tableView.register(UINib(nibName: "FAConsumptionRecordsCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Consumption Records".localized
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAConsumptionRecordsViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//MARK: UITableViewDelegate UITableViewDataSource
|
||||
extension FAConsumptionRecordsViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAConsumptionRecordsCell
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 20
|
||||
}
|
||||
}
|
||||
112
Fableon/Class/Store/C/FAOrderRecordsViewController.swift
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// FAOrderRecordsViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import JXSegmentedView
|
||||
|
||||
class FAOrderRecordsViewController: FAViewController {
|
||||
|
||||
private lazy var titles = ["Coin Record".localized, "VIP Record".localized]
|
||||
private lazy var viewControllers = [FACoinRecordViewController(), FAVipRecordViewController()]
|
||||
|
||||
private lazy var segmentedDataSource: JXSegmentedTitleDataSource = {
|
||||
let dataSource = JXSegmentedTitleDataSource()
|
||||
dataSource.itemWidth = (UIScreen.width - 32 - 24) / CGFloat(titles.count)
|
||||
dataSource.titles = titles
|
||||
dataSource.isTitleMaskEnabled = true
|
||||
dataSource.titleNormalColor = .FFFFFF.withAlphaComponent(0.5)
|
||||
dataSource.titleSelectedColor = ._333333
|
||||
dataSource.titleNormalFont = .font(ofSize: 14, weight: .bold)
|
||||
dataSource.titleSelectedFont = .font(ofSize: 14, weight: .bold)
|
||||
dataSource.itemSpacing = 0
|
||||
return dataSource
|
||||
}()
|
||||
|
||||
private lazy var segmentedIndicator: JXSegmentedIndicatorBackgroundView = {
|
||||
let indicator = JXSegmentedIndicatorBackgroundView()
|
||||
indicator.indicatorHeight = 36
|
||||
indicator.indicatorWidthIncrement = 0
|
||||
indicator.indicatorColor = ._74_BBFF
|
||||
return indicator
|
||||
}()
|
||||
|
||||
private lazy var segmentedView: JXSegmentedView = {
|
||||
let view = JXSegmentedView()
|
||||
view.backgroundColor = .FFFFFF.withAlphaComponent(0.15)
|
||||
view.layer.cornerRadius = 24
|
||||
view.layer.masksToBounds = true
|
||||
view.dataSource = segmentedDataSource
|
||||
view.delegate = self
|
||||
view.indicators = [segmentedIndicator]
|
||||
view.listContainer = listContainerView
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var listContainerView: JXSegmentedListContainerView = {
|
||||
let view = JXSegmentedListContainerView(dataSource: self)
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Order Records".localized
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension FAOrderRecordsViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(segmentedView)
|
||||
view.addSubview(listContainerView)
|
||||
|
||||
segmentedView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(20 + UIScreen.navBarHeight)
|
||||
make.height.equalTo(48)
|
||||
}
|
||||
|
||||
listContainerView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(segmentedView.snp.bottom)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MARK: JXSegmentedViewDelegate
|
||||
extension FAOrderRecordsViewController: JXSegmentedViewDelegate {
|
||||
func segmentedView(_ segmentedView: JXSegmentedView, didSelectedItemAt index: Int) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: JXSegmentedViewDelegate
|
||||
extension FAOrderRecordsViewController: JXSegmentedListContainerViewDataSource {
|
||||
func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> any JXSegmentedListContainerViewListDelegate {
|
||||
return viewControllers[index]
|
||||
}
|
||||
|
||||
func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int {
|
||||
return self.titles.count
|
||||
}
|
||||
|
||||
}
|
||||
55
Fableon/Class/Store/C/FARewardCoinsViewController.swift
Normal file
@ -0,0 +1,55 @@
|
||||
//
|
||||
// FARewardCoinsViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FARewardCoinsViewController: FAViewController {
|
||||
|
||||
private lazy var tableView: FATableView = {
|
||||
let tableView = FATableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 87
|
||||
tableView.separatorColor = .FFFFFF.withAlphaComponent(0.1)
|
||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
tableView.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
tableView.register(UINib(nibName: "FARewardCoinsCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Reward coins"
|
||||
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight + 10)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate UITableViewDataSource
|
||||
extension FARewardCoinsViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FARewardCoinsCell
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 20
|
||||
}
|
||||
}
|
||||
58
Fableon/Class/Store/C/FAStoreViewController.swift
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// FAStoreViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAStoreViewController: FAViewController {
|
||||
|
||||
private lazy var scrollView: FAScrollView = {
|
||||
let scrollView = FAScrollView()
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .FFFFFF
|
||||
label.text = "store_title_1".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Store".localized
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension FAStoreViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(scrollView)
|
||||
scrollView.addSubview(titleLabel)
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(0)
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
53
Fableon/Class/Store/C/FAVipRecordViewController.swift
Normal file
@ -0,0 +1,53 @@
|
||||
//
|
||||
// FAVipRecordViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAVipRecordViewController: FAViewController {
|
||||
|
||||
private lazy var tableView: FATableView = {
|
||||
let tableView = FATableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 72
|
||||
tableView.separatorColor = .FFFFFF.withAlphaComponent(0.1)
|
||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
||||
tableView.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||
tableView.register(UINib(nibName: "FAOrderRecordCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
bgView.isHidden = true
|
||||
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate UITableViewDataSource
|
||||
extension FAVipRecordViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
||||
cell.iconImageView.isHidden = true
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 20
|
||||
}
|
||||
|
||||
}
|
||||
115
Fableon/Class/Store/C/FAWalletViewController.swift
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// FAWalletViewController.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAWalletViewController: FAViewController {
|
||||
|
||||
private lazy var dataArr: [FAMeItemModel] = [
|
||||
FAMeItemModel(type: .consumptionRecords, name: "Consumption Records".localized),
|
||||
FAMeItemModel(type: .purchaseRecords, name: "Purchase Records".localized),
|
||||
FAMeItemModel(type: .rewardCoins, name: "Reward Coins".localized),
|
||||
]
|
||||
|
||||
private lazy var tableView: FATableView = {
|
||||
let tableView = FATableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 46
|
||||
tableView.separatorColor = .FFFFFF.withAlphaComponent(0.1)
|
||||
tableView.separatorInset = .init(top: 0, left: 32, bottom: 0, right: 32)
|
||||
tableView.register(UINib(nibName: "FAWalletCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
private lazy var headerView: FAWalletHeaderView = {
|
||||
let view = FAWalletHeaderView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 190))
|
||||
view.userInfo = FALogin.manager.userInfo
|
||||
return view
|
||||
}()
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "My Wallet".localized
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: FALogin.userInfoUpdateNotification, object: nil)
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
@objc private func userInfoUpdateNotification() {
|
||||
headerView.userInfo = FALogin.manager.userInfo
|
||||
}
|
||||
}
|
||||
|
||||
extension FAWalletViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
tableView.tableHeaderView = self.headerView
|
||||
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate UITableViewDataSource
|
||||
extension FAWalletViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAWalletCell
|
||||
cell.item = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let item = dataArr[indexPath.row]
|
||||
|
||||
var vc: FAViewController?
|
||||
|
||||
switch item.type {
|
||||
case .consumptionRecords:
|
||||
vc = FAConsumptionRecordsViewController()
|
||||
|
||||
case .purchaseRecords:
|
||||
vc = FAOrderRecordsViewController()
|
||||
|
||||
case .rewardCoins:
|
||||
vc = FARewardCoinsViewController()
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if let vc = vc {
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
37
Fableon/Class/Store/V/FAConsumptionRecordsCell.swift
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// FAConsumptionRecordsCell.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAConsumptionRecordsCell: FATableViewCell {
|
||||
|
||||
|
||||
@IBOutlet weak var titleLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var subtitleLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var dateLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var coinsLabel: UILabel!
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
titleLabel.text = "Purchase Single Episode dafdaaafafaafdasfadfsafdafadsadfas";
|
||||
subtitleLabel.text = "Ep.8 Romantic Flash Marriage In Progress"
|
||||
dateLabel.text = "2024-6-10 23:41:18"
|
||||
coinsLabel.text = "-10 Coins"
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
}
|
||||
80
Fableon/Class/Store/V/FAConsumptionRecordsCell.xib
Normal file
@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="78" id="KGk-i7-Jjw" customClass="FAConsumptionRecordsCell" customModule="Fableon" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="878" height="78"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="878" height="78"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Qg-wC-QCD">
|
||||
<rect key="frame" x="34" y="16" width="31.666666666666671" height="14"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<color key="textColor" name="#FFFFFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lf9-w0-dNJ">
|
||||
<rect key="frame" x="34" y="47" width="31" height="15"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" name="#999999"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="1000" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IuW-ER-ctV">
|
||||
<rect key="frame" x="813" y="16" width="31" height="14"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" name="#999999"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="1000" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xFu-h2-S6t">
|
||||
<rect key="frame" x="809" y="47.333333333333336" width="35" height="14.333333333333336"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="black" pointSize="12"/>
|
||||
<color key="textColor" name="#74BBFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="xFu-h2-S6t" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lf9-w0-dNJ" secondAttribute="trailing" constant="60" id="3pp-Hv-jjx"/>
|
||||
<constraint firstItem="0Qg-wC-QCD" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="34" id="7Sa-Zu-Jht"/>
|
||||
<constraint firstAttribute="trailing" secondItem="xFu-h2-S6t" secondAttribute="trailing" constant="34" id="A4h-wE-hHi"/>
|
||||
<constraint firstAttribute="trailing" secondItem="IuW-ER-ctV" secondAttribute="trailing" constant="34" id="EY7-Rl-2pK"/>
|
||||
<constraint firstItem="0Qg-wC-QCD" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="16" id="NZF-V8-Ahh"/>
|
||||
<constraint firstItem="IuW-ER-ctV" firstAttribute="centerY" secondItem="0Qg-wC-QCD" secondAttribute="centerY" id="TpD-Pr-GkC"/>
|
||||
<constraint firstAttribute="bottom" secondItem="lf9-w0-dNJ" secondAttribute="bottom" constant="16" id="aOU-nd-Yba"/>
|
||||
<constraint firstItem="IuW-ER-ctV" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="0Qg-wC-QCD" secondAttribute="trailing" constant="30" id="f03-XN-emY"/>
|
||||
<constraint firstItem="lf9-w0-dNJ" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="34" id="sL6-f0-Z2v"/>
|
||||
<constraint firstItem="xFu-h2-S6t" firstAttribute="centerY" secondItem="lf9-w0-dNJ" secondAttribute="centerY" id="yo1-GK-eyN"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
<connections>
|
||||
<outlet property="coinsLabel" destination="xFu-h2-S6t" id="WIS-W6-IhA"/>
|
||||
<outlet property="dateLabel" destination="IuW-ER-ctV" id="Oun-nw-9d5"/>
|
||||
<outlet property="subtitleLabel" destination="lf9-w0-dNJ" id="fAw-4D-Yxg"/>
|
||||
<outlet property="titleLabel" destination="0Qg-wC-QCD" id="6sV-aY-AF6"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="925.19083969465646" y="53.521126760563384"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<namedColor name="#74BBFF">
|
||||
<color red="0.45490196078431372" green="0.73333333333333328" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#999999">
|
||||
<color red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#FFFFFF">
|
||||
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
</resources>
|
||||
</document>
|
||||
33
Fableon/Class/Store/V/FAOrderRecordCell.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// FAOrderRecordCell.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAOrderRecordCell: FATableViewCell {
|
||||
|
||||
|
||||
@IBOutlet weak var titleLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var dateLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var countLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var iconImageView: UIImageView!
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
}
|
||||
76
Fableon/Class/Store/V/FAOrderRecordCell.xib
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="81" id="KGk-i7-Jjw" customClass="FAOrderRecordCell" customModule="Fableon" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="379" height="81"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="379" height="81"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1Q0-xP-S3w">
|
||||
<rect key="frame" x="31.999999999999996" y="17" width="36.666666666666657" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
|
||||
<color key="textColor" name="#FFFFFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OVF-ZK-B4x">
|
||||
<rect key="frame" x="32" y="49.666666666666664" width="31" height="14.333333333333336"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" name="#999999"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="L8z-xW-Sg5">
|
||||
<rect key="frame" x="307" y="32" width="40" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="black" pointSize="14"/>
|
||||
<color key="textColor" name="#74BBFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="coins_icon_03" translatesAutoresizingMaskIntoConstraints="NO" id="pco-tO-eSC">
|
||||
<rect key="frame" x="289" y="33.666666666666664" width="14" height="14"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="L8z-xW-Sg5" secondAttribute="trailing" constant="32" id="4C1-LR-UXd"/>
|
||||
<constraint firstAttribute="bottom" secondItem="OVF-ZK-B4x" secondAttribute="bottom" constant="17" id="BY7-of-buV"/>
|
||||
<constraint firstItem="OVF-ZK-B4x" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="32" id="EO3-Zf-zHi"/>
|
||||
<constraint firstItem="1Q0-xP-S3w" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="17" id="Ppz-xm-p7R"/>
|
||||
<constraint firstItem="pco-tO-eSC" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="SJG-aY-VPm"/>
|
||||
<constraint firstItem="L8z-xW-Sg5" firstAttribute="leading" secondItem="pco-tO-eSC" secondAttribute="trailing" constant="4" id="XWi-cM-bca"/>
|
||||
<constraint firstItem="1Q0-xP-S3w" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="32" id="bRm-qi-1Pd"/>
|
||||
<constraint firstItem="L8z-xW-Sg5" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="uCA-8Y-gx7"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
<connections>
|
||||
<outlet property="countLabel" destination="L8z-xW-Sg5" id="QGO-va-hKz"/>
|
||||
<outlet property="dateLabel" destination="OVF-ZK-B4x" id="0Cr-xn-8Bb"/>
|
||||
<outlet property="iconImageView" destination="pco-tO-eSC" id="UWj-Ao-NQn"/>
|
||||
<outlet property="titleLabel" destination="1Q0-xP-S3w" id="dWF-T9-buC"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="183.96946564885496" y="54.577464788732399"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="coins_icon_03" width="14" height="14"/>
|
||||
<namedColor name="#74BBFF">
|
||||
<color red="0.45490196078431372" green="0.73333333333333328" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#999999">
|
||||
<color red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#FFFFFF">
|
||||
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
</resources>
|
||||
</document>
|
||||
43
Fableon/Class/Store/V/FARewardCoinsCell.swift
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// FARewardCoinsCell.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FARewardCoinsCell: FATableViewCell {
|
||||
|
||||
|
||||
@IBOutlet weak var dateLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var nameLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var expiresIconImageView: UIImageView!
|
||||
|
||||
@IBOutlet weak var expiresLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var expiredLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var countLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var remainingLabel: UILabel!
|
||||
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
expiredLabel.text = "Expired".localized
|
||||
|
||||
expiredLabel.isHidden = true
|
||||
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
}
|
||||
106
Fableon/Class/Store/V/FARewardCoinsCell.xib
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="109" id="KGk-i7-Jjw" customClass="FARewardCoinsCell" customModule="Fableon" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="367" height="109"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="367" height="109"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QaO-WU-u9r">
|
||||
<rect key="frame" x="32" y="15" width="31" height="14.333333333333336"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" name="#999999"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="n33-4s-wzC">
|
||||
<rect key="frame" x="31.999999999999996" y="46" width="36.666666666666657" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
|
||||
<color key="textColor" name="#FFFFFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="time icon" translatesAutoresizingMaskIntoConstraints="NO" id="UAN-Fu-NVc">
|
||||
<rect key="frame" x="32" y="82" width="12" height="12"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="70n-hD-JF8">
|
||||
<rect key="frame" x="48" y="81" width="31" height="14.333333333333329"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" name="#74BBFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Oig-Ch-QGH">
|
||||
<rect key="frame" x="295" y="26" width="40" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="black" pointSize="14"/>
|
||||
<color key="textColor" name="#74BBFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jAC-rE-uKr">
|
||||
<rect key="frame" x="304" y="77.666666666666671" width="31" height="14.333333333333329"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" name="#8B8B8B"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Expired" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uKs-9u-8Of">
|
||||
<rect key="frame" x="31.999999999999996" y="81" width="42.666666666666643" height="14.333333333333329"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" name="#8B8B8B"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="Oig-Ch-QGH" secondAttribute="trailing" constant="32" id="3ez-Vh-RVN"/>
|
||||
<constraint firstItem="UAN-Fu-NVc" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="32" id="85i-RW-mTA"/>
|
||||
<constraint firstItem="Oig-Ch-QGH" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="26" id="8lJ-j7-0EM"/>
|
||||
<constraint firstItem="70n-hD-JF8" firstAttribute="centerY" secondItem="UAN-Fu-NVc" secondAttribute="centerY" id="CK6-ov-VSa"/>
|
||||
<constraint firstItem="70n-hD-JF8" firstAttribute="leading" secondItem="UAN-Fu-NVc" secondAttribute="trailing" constant="4" id="FLN-Sf-dOW"/>
|
||||
<constraint firstItem="n33-4s-wzC" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="32" id="OJi-3y-oKv"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jAC-rE-uKr" secondAttribute="trailing" constant="32" id="TVI-ld-6BY"/>
|
||||
<constraint firstItem="QaO-WU-u9r" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="15" id="dAY-I7-CyX"/>
|
||||
<constraint firstItem="QaO-WU-u9r" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="32" id="mRS-pB-qcP"/>
|
||||
<constraint firstAttribute="bottom" secondItem="jAC-rE-uKr" secondAttribute="bottom" constant="17" id="mtt-fe-fmp"/>
|
||||
<constraint firstItem="uKs-9u-8Of" firstAttribute="centerY" secondItem="UAN-Fu-NVc" secondAttribute="centerY" id="nLp-Xx-ouo"/>
|
||||
<constraint firstItem="uKs-9u-8Of" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="32" id="npS-od-aJU"/>
|
||||
<constraint firstAttribute="bottom" secondItem="UAN-Fu-NVc" secondAttribute="bottom" constant="15" id="sRE-Oe-n90"/>
|
||||
<constraint firstItem="n33-4s-wzC" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="xJm-u9-7Ra"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
<connections>
|
||||
<outlet property="countLabel" destination="Oig-Ch-QGH" id="jif-nc-jHk"/>
|
||||
<outlet property="dateLabel" destination="QaO-WU-u9r" id="fzy-pA-2hL"/>
|
||||
<outlet property="expiredLabel" destination="uKs-9u-8Of" id="zXO-tL-2TQ"/>
|
||||
<outlet property="expiresIconImageView" destination="UAN-Fu-NVc" id="co1-QO-DHe"/>
|
||||
<outlet property="expiresLabel" destination="70n-hD-JF8" id="tb7-to-JnU"/>
|
||||
<outlet property="nameLabel" destination="n33-4s-wzC" id="RoK-PM-5Jm"/>
|
||||
<outlet property="remainingLabel" destination="jAC-rE-uKr" id="tFc-78-oNw"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="174.80916030534351" y="64.436619718309856"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="time icon" width="12" height="12"/>
|
||||
<namedColor name="#74BBFF">
|
||||
<color red="0.45490196078431372" green="0.73333333333333328" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#8B8B8B">
|
||||
<color red="0.54509803921568623" green="0.54509803921568623" blue="0.54509803921568623" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#999999">
|
||||
<color red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="#FFFFFF">
|
||||
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
</resources>
|
||||
</document>
|
||||
33
Fableon/Class/Store/V/FAWalletCell.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// FAWalletCell.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAWalletCell: FATableViewCell {
|
||||
|
||||
var item: FAMeItemModel? {
|
||||
didSet {
|
||||
titleLabel.text = item?.name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IBOutlet weak var titleLabel: UILabel!
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
}
|
||||
52
Fableon/Class/Store/V/FAWalletCell.xib
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" customClass="FAWalletCell" customModule="Fableon" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dNW-KD-5Wv">
|
||||
<rect key="frame" x="32" y="15" width="33" height="14.333333333333336"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="12"/>
|
||||
<color key="textColor" name="#FFFFFF"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Frame 3015" translatesAutoresizingMaskIntoConstraints="NO" id="5vD-3A-9IP">
|
||||
<rect key="frame" x="278" y="17" width="10" height="10"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="5vD-3A-9IP" secondAttribute="trailing" constant="32" id="7YN-X5-1W8"/>
|
||||
<constraint firstItem="dNW-KD-5Wv" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="32" id="SRC-mm-4up"/>
|
||||
<constraint firstItem="dNW-KD-5Wv" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="fyz-P4-xJH"/>
|
||||
<constraint firstItem="5vD-3A-9IP" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="dNW-KD-5Wv" secondAttribute="trailing" constant="70" id="peE-kR-BX3"/>
|
||||
<constraint firstItem="5vD-3A-9IP" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="wP0-9k-9tW"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
<connections>
|
||||
<outlet property="titleLabel" destination="dNW-KD-5Wv" id="Mhc-0s-z9j"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="139" y="42"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="Frame 3015" width="10" height="10"/>
|
||||
<namedColor name="#FFFFFF">
|
||||
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
</resources>
|
||||
</document>
|
||||
158
Fableon/Class/Store/V/FAWalletHeaderView.swift
Normal file
@ -0,0 +1,158 @@
|
||||
//
|
||||
// FAWalletHeaderView.swift
|
||||
// Fableon
|
||||
//
|
||||
// Created by 长沙鸿瑶 on 2025/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FAWalletHeaderView: UIView {
|
||||
|
||||
var userInfo: FAUserInfo? {
|
||||
didSet {
|
||||
coinsView.setNeedsUpdateConfiguration()
|
||||
bonusView.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var contentView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = ._5_CA_8_FF_0_2
|
||||
view.layer.cornerRadius = 12
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var storeButton: UIButton = {
|
||||
let button = FAGradientButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let vc = FAStoreViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}))
|
||||
button.layer.cornerRadius = 24
|
||||
button.layer.masksToBounds = true
|
||||
button.fa_colors = [UIColor.BEDFFF.cgColor, UIColor._52_A_2_F_1.cgColor]
|
||||
button.fa_locations = [0, 1]
|
||||
button.fa_startPoint = .init(x: 0, y: 0.5)
|
||||
button.fa_endPoint = .init(x: 1, y: 0.5)
|
||||
button.setTitle("Store".localized, for: .normal)
|
||||
button.setTitleColor(._000000, for: .normal)
|
||||
button.titleLabel?.font = .font(ofSize: 18, weight: .bold)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var lineView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .FFFFFF.withAlphaComponent(0.1)
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.image = UIImage(named: "coins_icon_02")
|
||||
config.imagePadding = 11
|
||||
config.attributedTitle = AttributedString("Coins".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 10, weight: .bold),
|
||||
.foregroundColor : UIColor.F_7_F_497
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: config)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
|
||||
button.configuration?.attributedSubtitle = AttributedString("\(self.userInfo?.coin_left_total ?? 0)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.FFFFFF
|
||||
]))
|
||||
}
|
||||
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var bonusView: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.image = UIImage(named: "coins_icon_02")
|
||||
config.imagePadding = 11
|
||||
config.imagePlacement = .trailing
|
||||
config.titleAlignment = .leading
|
||||
config.attributedTitle = AttributedString("Bonus".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 10, weight: .bold),
|
||||
.foregroundColor : UIColor.F_7_F_497
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: config)
|
||||
button.isUserInteractionEnabled = false
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
|
||||
button.configuration?.attributedSubtitle = AttributedString("\(self.userInfo?.send_coin_left_total ?? 0)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.FFFFFF
|
||||
]))
|
||||
}
|
||||
|
||||
return button
|
||||
}()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FAWalletHeaderView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(contentView)
|
||||
contentView.addSubview(storeButton)
|
||||
contentView.addSubview(lineView)
|
||||
contentView.addSubview(coinsView)
|
||||
contentView.addSubview(bonusView)
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(25)
|
||||
make.height.equalTo(150)
|
||||
}
|
||||
|
||||
storeButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-14)
|
||||
make.height.equalTo(48)
|
||||
}
|
||||
|
||||
lineView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(33)
|
||||
make.width.equalTo(1)
|
||||
make.height.equalTo(30)
|
||||
}
|
||||
|
||||
coinsView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.right.equalTo(lineView.snp.left)
|
||||
make.centerY.equalTo(lineView)
|
||||
}
|
||||
|
||||
bonusView.snp.makeConstraints { make in
|
||||
make.left.equalTo(lineView.snp.right)
|
||||
make.right.equalToSuperview()
|
||||
make.centerY.equalTo(lineView)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,6 +15,10 @@ class FAUserInfo: NSObject, SmartCodable, NSSecureCoding {
|
||||
var is_tourist: Bool?
|
||||
var family_name: String?
|
||||
var avator: String?
|
||||
var coin_left_total: Int?
|
||||
var send_coin_left_total: Int?
|
||||
var is_vip: Bool?
|
||||
var vip_end_time: TimeInterval?
|
||||
|
||||
func getNickName() -> String {
|
||||
if let name = family_name, !name.isEmpty {
|
||||
@ -24,6 +28,10 @@ class FAUserInfo: NSObject, SmartCodable, NSSecureCoding {
|
||||
}
|
||||
}
|
||||
|
||||
var totalCoins: Int {
|
||||
return (coin_left_total ?? 0) + (send_coin_left_total ?? 0)
|
||||
}
|
||||
|
||||
required override init() { }
|
||||
|
||||
static var supportsSecureCoding: Bool {
|
||||
@ -36,6 +44,10 @@ class FAUserInfo: NSObject, SmartCodable, NSSecureCoding {
|
||||
coder.encode(is_tourist, forKey: "is_tourist")
|
||||
coder.encode(avator, forKey: "avator")
|
||||
coder.encode(family_name, forKey: "family_name")
|
||||
coder.encode(coin_left_total, forKey: "coin_left_total")
|
||||
coder.encode(send_coin_left_total, forKey: "send_coin_left_total")
|
||||
coder.encode(is_vip, forKey: "is_vip")
|
||||
coder.encode(vip_end_time, forKey: "vip_end_time")
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -45,5 +57,9 @@ class FAUserInfo: NSObject, SmartCodable, NSSecureCoding {
|
||||
is_tourist = coder.decodeObject(of: NSNumber.self, forKey: "is_tourist")?.boolValue
|
||||
avator = coder.decodeObject(of: NSString.self, forKey: "avator") as? String
|
||||
family_name = coder.decodeObject(of: NSString.self, forKey: "family_name") as? String
|
||||
coin_left_total = coder.decodeObject(of: NSNumber.self, forKey: "coin_left_total")?.intValue
|
||||
send_coin_left_total = coder.decodeObject(of: NSNumber.self, forKey: "send_coin_left_total")?.intValue
|
||||
is_vip = coder.decodeObject(of: NSNumber.self, forKey: "is_vip")?.boolValue
|
||||
vip_end_time = coder.decodeObject(of: NSNumber.self, forKey: "vip_end_time")?.doubleValue
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x91",
|
||||
"green" : "0x5C",
|
||||
"red" : "0x10"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xFB",
|
||||
"green" : "0x80",
|
||||
"red" : "0x16"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x1E",
|
||||
"green" : "0x27",
|
||||
"red" : "0x3A"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xFF",
|
||||
"green" : "0xBB",
|
||||
"red" : "0x74"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xDB",
|
||||
"green" : "0xA7",
|
||||
"red" : "0x79"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xF5",
|
||||
"green" : "0xDB",
|
||||
"red" : "0x7F"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xFF",
|
||||
"green" : "0xFA",
|
||||
"red" : "0xC3"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x97",
|
||||
"green" : "0xF4",
|
||||
"red" : "0xF7"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.800",
|
||||
"blue" : "0xFF",
|
||||
"green" : "0xFF",
|
||||
"red" : "0xFF"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
25
Fableon/Source/Assets.xcassets/image/Frame 2085663258.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2085663258@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2085663258@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "original"
|
||||
}
|
||||
}
|
||||
BIN
Fableon/Source/Assets.xcassets/image/Frame 2085663258.imageset/Frame 2085663258@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 521 B |
BIN
Fableon/Source/Assets.xcassets/image/Frame 2085663258.imageset/Frame 2085663258@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 669 B |
22
Fableon/Source/Assets.xcassets/image/Frame 3021.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 3021@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 3021@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Fableon/Source/Assets.xcassets/image/Frame 3021.imageset/Frame 3021@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 564 B |
BIN
Fableon/Source/Assets.xcassets/image/Frame 3021.imageset/Frame 3021@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 798 B |
22
Fableon/Source/Assets.xcassets/image/coins_icon_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
Fableon/Source/Assets.xcassets/image/coins_icon_01.imageset/金币@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
Fableon/Source/Assets.xcassets/image/coins_icon_01.imageset/金币@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
22
Fableon/Source/Assets.xcassets/image/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
Fableon/Source/Assets.xcassets/image/coins_icon_02.imageset/金币@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
Fableon/Source/Assets.xcassets/image/coins_icon_02.imageset/金币@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
22
Fableon/Source/Assets.xcassets/image/coins_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
Fableon/Source/Assets.xcassets/image/coins_icon_03.imageset/金币@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Fableon/Source/Assets.xcassets/image/coins_icon_03.imageset/金币@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
22
Fableon/Source/Assets.xcassets/image/lock_icon_01.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
Fableon/Source/Assets.xcassets/image/lock_icon_01.imageset/Frame@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 325 B |
BIN
Fableon/Source/Assets.xcassets/image/lock_icon_01.imageset/Frame@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 473 B |
22
Fableon/Source/Assets.xcassets/image/lock_icon_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2958@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame 2958@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Fableon/Source/Assets.xcassets/image/lock_icon_02.imageset/Frame 2958@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1004 B |
BIN
Fableon/Source/Assets.xcassets/image/lock_icon_02.imageset/Frame 2958@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
22
Fableon/Source/Assets.xcassets/image/time icon.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
Fableon/Source/Assets.xcassets/image/time icon.imageset/time icon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 770 B |
BIN
Fableon/Source/Assets.xcassets/image/time icon.imageset/time icon@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
22
Fableon/Source/Assets.xcassets/image/vip_image_01.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
Fableon/Source/Assets.xcassets/image/vip_image_01.imageset/Frame@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
Fableon/Source/Assets.xcassets/image/vip_image_01.imageset/Frame@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 42 KiB |
22
Fableon/Source/Assets.xcassets/image/vip_image_02.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
Fableon/Source/Assets.xcassets/image/vip_image_02.imageset/Frame@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 44 KiB |