Compare commits
2 Commits
36b6cf95a0
...
54742c4a67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54742c4a67 | ||
|
|
c97bd5b30a |
@ -7,6 +7,37 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
031FDEAC2EAF05FB00F4CAC7 /* FAStoreVipCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEAB2EAF05FB00F4CAC7 /* FAStoreVipCell.swift */; };
|
||||||
|
031FDEAE2EB093B100F4CAC7 /* FABuyRecordsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEAD2EB093B100F4CAC7 /* FABuyRecordsModel.swift */; };
|
||||||
|
031FDEB02EB09AB300F4CAC7 /* FARechargeRecordModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEAF2EB09AB300F4CAC7 /* FARechargeRecordModel.swift */; };
|
||||||
|
031FDEB22EB0A5AF00F4CAC7 /* FASendCoinRecordModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEB12EB0A5AF00F4CAC7 /* FASendCoinRecordModel.swift */; };
|
||||||
|
031FDEB42EB0AD7D00F4CAC7 /* FACoinPackConfirmView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEB32EB0AD7D00F4CAC7 /* FACoinPackConfirmView.swift */; };
|
||||||
|
031FDEB62EB0B77F00F4CAC7 /* FACoinPackConfirmItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEB52EB0B77F00F4CAC7 /* FACoinPackConfirmItemView.swift */; };
|
||||||
|
031FDEB82EB0B80400F4CAC7 /* FACoinPackConfirmItem1View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEB72EB0B80400F4CAC7 /* FACoinPackConfirmItem1View.swift */; };
|
||||||
|
031FDEBA2EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEB92EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift */; };
|
||||||
|
031FDEBC2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEBB2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift */; };
|
||||||
|
031FDEBE2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEBD2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift */; };
|
||||||
|
039CE6042EAA2621007B5EED /* AppDelegate+FAAdjust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */; };
|
||||||
|
039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */; };
|
||||||
|
039CE60B2EAA31CB007B5EED /* FAStatAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */; };
|
||||||
|
039CE60E2EAA32A8007B5EED /* FAOpenAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE60D2EAA32A8007B5EED /* FAOpenAppModel.swift */; };
|
||||||
|
039CE6112EAB0D49007B5EED /* JXIAPManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6102EAB0D47007B5EED /* JXIAPManager.swift */; };
|
||||||
|
039CE6142EAB0E0D007B5EED /* FAIapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6132EAB0E0D007B5EED /* FAIapManager.swift */; };
|
||||||
|
039CE6162EAB0E30007B5EED /* FAWaitRestoreModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6152EAB0E30007B5EED /* FAWaitRestoreModel.swift */; };
|
||||||
|
039CE6182EAB0E7E007B5EED /* FAStoreAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6172EAB0E7E007B5EED /* FAStoreAPI.swift */; };
|
||||||
|
039CE61A2EAB0EE0007B5EED /* FAIapVerifyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6192EAB0EE0007B5EED /* FAIapVerifyModel.swift */; };
|
||||||
|
039CE61C2EAB0F29007B5EED /* FAIapOrderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE61B2EAB0F29007B5EED /* FAIapOrderModel.swift */; };
|
||||||
|
039CE6202EAB114B007B5EED /* FAPayDateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE61F2EAB114B007B5EED /* FAPayDateModel.swift */; };
|
||||||
|
039CE6222EAB1340007B5EED /* FAUserDefaultsKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6212EAB1335007B5EED /* FAUserDefaultsKey.swift */; };
|
||||||
|
039CE6242EAB29D1007B5EED /* FAPayDataRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6232EAB29D1007B5EED /* FAPayDataRequest.swift */; };
|
||||||
|
039CE6262EAB2A72007B5EED /* FAPayAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6252EAB2A72007B5EED /* FAPayAlertModel.swift */; };
|
||||||
|
039CE6282EAB50A9007B5EED /* FAStoreCoinsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6272EAB50A9007B5EED /* FAStoreCoinsView.swift */; };
|
||||||
|
039CE62A2EAB5A8C007B5EED /* FAStoreCoinsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6292EAB5A8C007B5EED /* FAStoreCoinsCell.swift */; };
|
||||||
|
039CE62C2EAB5B07007B5EED /* FAStoreCoinsBigCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE62B2EAB5B07007B5EED /* FAStoreCoinsBigCell.swift */; };
|
||||||
|
039CE62E2EAB5B18007B5EED /* FAStoreCoinsSmallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE62D2EAB5B18007B5EED /* FAStoreCoinsSmallCell.swift */; };
|
||||||
|
039CE6302EAB5B26007B5EED /* FAStoreCoinsPackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE62F2EAB5B26007B5EED /* FAStoreCoinsPackCell.swift */; };
|
||||||
|
039CE6322EAB796F007B5EED /* FALabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6312EAB796F007B5EED /* FALabel.swift */; };
|
||||||
|
03DBD8512EAEFF5F00DD04B8 /* FAStoreVipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DBD8502EAEFF5F00DD04B8 /* FAStoreVipView.swift */; };
|
||||||
03E239632EAA1945004A8CEC /* AppDelegate+FAConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E239612EAA1945004A8CEC /* AppDelegate+FAConfig.swift */; };
|
03E239632EAA1945004A8CEC /* AppDelegate+FAConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E239612EAA1945004A8CEC /* AppDelegate+FAConfig.swift */; };
|
||||||
03E239642EAA1945004A8CEC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E239602EAA1945004A8CEC /* AppDelegate.swift */; };
|
03E239642EAA1945004A8CEC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E239602EAA1945004A8CEC /* AppDelegate.swift */; };
|
||||||
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E239622EAA1945004A8CEC /* SceneDelegate.swift */; };
|
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E239622EAA1945004A8CEC /* SceneDelegate.swift */; };
|
||||||
@ -265,6 +296,38 @@
|
|||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
031FDEAB2EAF05FB00F4CAC7 /* FAStoreVipCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreVipCell.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEAD2EB093B100F4CAC7 /* FABuyRecordsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FABuyRecordsModel.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEAF2EB09AB300F4CAC7 /* FARechargeRecordModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARechargeRecordModel.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEB12EB0A5AF00F4CAC7 /* FASendCoinRecordModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FASendCoinRecordModel.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEB32EB0AD7D00F4CAC7 /* FACoinPackConfirmView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackConfirmView.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEB52EB0B77F00F4CAC7 /* FACoinPackConfirmItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackConfirmItemView.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEB72EB0B80400F4CAC7 /* FACoinPackConfirmItem1View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackConfirmItem1View.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEB92EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackConfirmItem2View.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEBB2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOldVideoRechargeView.swift; sourceTree = "<group>"; };
|
||||||
|
031FDEBD2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FANewVideoRechargeView.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+FAAdjust.swift"; sourceTree = "<group>"; };
|
||||||
|
039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAdjustStateManager.swift; sourceTree = "<group>"; };
|
||||||
|
039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStatAPI.swift; sourceTree = "<group>"; };
|
||||||
|
039CE60D2EAA32A8007B5EED /* FAOpenAppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOpenAppModel.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6102EAB0D47007B5EED /* JXIAPManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXIAPManager.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6132EAB0E0D007B5EED /* FAIapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAIapManager.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6152EAB0E30007B5EED /* FAWaitRestoreModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWaitRestoreModel.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6172EAB0E7E007B5EED /* FAStoreAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreAPI.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6192EAB0EE0007B5EED /* FAIapVerifyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAIapVerifyModel.swift; sourceTree = "<group>"; };
|
||||||
|
039CE61B2EAB0F29007B5EED /* FAIapOrderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAIapOrderModel.swift; sourceTree = "<group>"; };
|
||||||
|
039CE61D2EAB0FE4007B5EED /* Fableon.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Fableon.entitlements; sourceTree = "<group>"; };
|
||||||
|
039CE61F2EAB114B007B5EED /* FAPayDateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAPayDateModel.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6212EAB1335007B5EED /* FAUserDefaultsKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAUserDefaultsKey.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6232EAB29D1007B5EED /* FAPayDataRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAPayDataRequest.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6252EAB2A72007B5EED /* FAPayAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAPayAlertModel.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6272EAB50A9007B5EED /* FAStoreCoinsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreCoinsView.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6292EAB5A8C007B5EED /* FAStoreCoinsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreCoinsCell.swift; sourceTree = "<group>"; };
|
||||||
|
039CE62B2EAB5B07007B5EED /* FAStoreCoinsBigCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreCoinsBigCell.swift; sourceTree = "<group>"; };
|
||||||
|
039CE62D2EAB5B18007B5EED /* FAStoreCoinsSmallCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreCoinsSmallCell.swift; sourceTree = "<group>"; };
|
||||||
|
039CE62F2EAB5B26007B5EED /* FAStoreCoinsPackCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreCoinsPackCell.swift; sourceTree = "<group>"; };
|
||||||
|
039CE6312EAB796F007B5EED /* FALabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FALabel.swift; sourceTree = "<group>"; };
|
||||||
|
03DBD8502EAEFF5F00DD04B8 /* FAStoreVipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreVipView.swift; sourceTree = "<group>"; };
|
||||||
03E239602EAA1945004A8CEC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
03E239602EAA1945004A8CEC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
03E239612EAA1945004A8CEC /* AppDelegate+FAConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+FAConfig.swift"; sourceTree = "<group>"; };
|
03E239612EAA1945004A8CEC /* AppDelegate+FAConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+FAConfig.swift"; sourceTree = "<group>"; };
|
||||||
03E239622EAA1945004A8CEC /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
03E239622EAA1945004A8CEC /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
@ -538,6 +601,54 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
039CE6072EAA2F37007B5EED /* AdjustStateManager */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */,
|
||||||
|
);
|
||||||
|
path = AdjustStateManager;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
039CE60C2EAA328A007B5EED /* Model */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
039CE60D2EAA32A8007B5EED /* FAOpenAppModel.swift */,
|
||||||
|
);
|
||||||
|
path = Model;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
039CE60F2EAB0D2D007B5EED /* JXIAPManager */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
039CE6102EAB0D47007B5EED /* JXIAPManager.swift */,
|
||||||
|
);
|
||||||
|
path = JXIAPManager;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
039CE6122EAB0DE1007B5EED /* FAIap */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
039CE6132EAB0E0D007B5EED /* FAIapManager.swift */,
|
||||||
|
039CE6232EAB29D1007B5EED /* FAPayDataRequest.swift */,
|
||||||
|
039CE6192EAB0EE0007B5EED /* FAIapVerifyModel.swift */,
|
||||||
|
039CE61B2EAB0F29007B5EED /* FAIapOrderModel.swift */,
|
||||||
|
039CE6152EAB0E30007B5EED /* FAWaitRestoreModel.swift */,
|
||||||
|
);
|
||||||
|
path = FAIap;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
039CE61E2EAB10EC007B5EED /* M */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
039CE61F2EAB114B007B5EED /* FAPayDateModel.swift */,
|
||||||
|
039CE6252EAB2A72007B5EED /* FAPayAlertModel.swift */,
|
||||||
|
031FDEAD2EB093B100F4CAC7 /* FABuyRecordsModel.swift */,
|
||||||
|
031FDEAF2EB09AB300F4CAC7 /* FARechargeRecordModel.swift */,
|
||||||
|
031FDEB12EB0A5AF00F4CAC7 /* FASendCoinRecordModel.swift */,
|
||||||
|
);
|
||||||
|
path = M;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
03E2395F2EAA1900004A8CEC /* Object */ = {
|
03E2395F2EAA1900004A8CEC /* Object */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -552,6 +663,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
03E2396A2EAA1A29004A8CEC /* Controller */,
|
03E2396A2EAA1A29004A8CEC /* Controller */,
|
||||||
|
039CE60C2EAA328A007B5EED /* Model */,
|
||||||
03E2396C2EAA1A29004A8CEC /* Define */,
|
03E2396C2EAA1A29004A8CEC /* Define */,
|
||||||
03E2397A2EAA1A29004A8CEC /* Extension */,
|
03E2397A2EAA1A29004A8CEC /* Extension */,
|
||||||
03E239812EAA1A29004A8CEC /* Request */,
|
03E239812EAA1A29004A8CEC /* Request */,
|
||||||
@ -575,6 +687,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
03E2396B2EAA1A29004A8CEC /* FADefine.swift */,
|
03E2396B2EAA1A29004A8CEC /* FADefine.swift */,
|
||||||
|
039CE6212EAB1335007B5EED /* FAUserDefaultsKey.swift */,
|
||||||
);
|
);
|
||||||
path = Define;
|
path = Define;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -610,6 +723,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
03E2397B2EAA1A29004A8CEC /* FAAPI.swift */,
|
03E2397B2EAA1A29004A8CEC /* FAAPI.swift */,
|
||||||
|
039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */,
|
||||||
|
039CE6172EAB0E7E007B5EED /* FAStoreAPI.swift */,
|
||||||
);
|
);
|
||||||
path = FAAPI;
|
path = FAAPI;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -637,6 +752,7 @@
|
|||||||
03E239872EAA1A29004A8CEC /* FAScrollView.swift */,
|
03E239872EAA1A29004A8CEC /* FAScrollView.swift */,
|
||||||
03E239882EAA1A29004A8CEC /* FATableView.swift */,
|
03E239882EAA1A29004A8CEC /* FATableView.swift */,
|
||||||
03E239892EAA1A29004A8CEC /* FATableViewCell.swift */,
|
03E239892EAA1A29004A8CEC /* FATableViewCell.swift */,
|
||||||
|
039CE6312EAB796F007B5EED /* FALabel.swift */,
|
||||||
);
|
);
|
||||||
path = View;
|
path = View;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -862,6 +978,8 @@
|
|||||||
03E23A0E2EAA1A4E004A8CEC /* FAPlayerDetailControlView.swift */,
|
03E23A0E2EAA1A4E004A8CEC /* FAPlayerDetailControlView.swift */,
|
||||||
03E23A0F2EAA1A4E004A8CEC /* FAPlayerProgressView.swift */,
|
03E23A0F2EAA1A4E004A8CEC /* FAPlayerProgressView.swift */,
|
||||||
03E23A102EAA1A4E004A8CEC /* FAVideoLockView.swift */,
|
03E23A102EAA1A4E004A8CEC /* FAVideoLockView.swift */,
|
||||||
|
031FDEBB2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift */,
|
||||||
|
031FDEBD2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift */,
|
||||||
);
|
);
|
||||||
path = V;
|
path = V;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -885,10 +1003,10 @@
|
|||||||
03E23A162EAA1A4E004A8CEC /* Player */ = {
|
03E23A162EAA1A4E004A8CEC /* Player */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
03E23A062EAA1A4E004A8CEC /* M */,
|
|
||||||
03E23A082EAA1A4E004A8CEC /* UI */,
|
03E23A082EAA1A4E004A8CEC /* UI */,
|
||||||
03E23A112EAA1A4E004A8CEC /* V */,
|
|
||||||
03E23A132EAA1A4E004A8CEC /* VC */,
|
03E23A132EAA1A4E004A8CEC /* VC */,
|
||||||
|
03E23A062EAA1A4E004A8CEC /* M */,
|
||||||
|
03E23A112EAA1A4E004A8CEC /* V */,
|
||||||
03E23A152EAA1A4E004A8CEC /* VM */,
|
03E23A152EAA1A4E004A8CEC /* VM */,
|
||||||
);
|
);
|
||||||
path = Player;
|
path = Player;
|
||||||
@ -932,13 +1050,13 @@
|
|||||||
03E23A262EAA1A4E004A8CEC /* C */ = {
|
03E23A262EAA1A4E004A8CEC /* C */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
03E23A232EAA1A4E004A8CEC /* FAStoreViewController.swift */,
|
||||||
|
03E23A252EAA1A4E004A8CEC /* FAWalletViewController.swift */,
|
||||||
03E23A1F2EAA1A4E004A8CEC /* FACoinRecordViewController.swift */,
|
03E23A1F2EAA1A4E004A8CEC /* FACoinRecordViewController.swift */,
|
||||||
03E23A202EAA1A4E004A8CEC /* FAConsumptionRecordsViewController.swift */,
|
03E23A202EAA1A4E004A8CEC /* FAConsumptionRecordsViewController.swift */,
|
||||||
03E23A212EAA1A4E004A8CEC /* FAOrderRecordsViewController.swift */,
|
03E23A212EAA1A4E004A8CEC /* FAOrderRecordsViewController.swift */,
|
||||||
03E23A222EAA1A4E004A8CEC /* FARewardCoinsViewController.swift */,
|
03E23A222EAA1A4E004A8CEC /* FARewardCoinsViewController.swift */,
|
||||||
03E23A232EAA1A4E004A8CEC /* FAStoreViewController.swift */,
|
|
||||||
03E23A242EAA1A4E004A8CEC /* FAVipRecordViewController.swift */,
|
03E23A242EAA1A4E004A8CEC /* FAVipRecordViewController.swift */,
|
||||||
03E23A252EAA1A4E004A8CEC /* FAWalletViewController.swift */,
|
|
||||||
);
|
);
|
||||||
path = C;
|
path = C;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -955,6 +1073,17 @@
|
|||||||
03E23A2D2EAA1A4E004A8CEC /* FAWalletCell.swift */,
|
03E23A2D2EAA1A4E004A8CEC /* FAWalletCell.swift */,
|
||||||
03E23A2E2EAA1A4E004A8CEC /* FAWalletCell.xib */,
|
03E23A2E2EAA1A4E004A8CEC /* FAWalletCell.xib */,
|
||||||
03E23A2F2EAA1A4E004A8CEC /* FAWalletHeaderView.swift */,
|
03E23A2F2EAA1A4E004A8CEC /* FAWalletHeaderView.swift */,
|
||||||
|
039CE6272EAB50A9007B5EED /* FAStoreCoinsView.swift */,
|
||||||
|
03DBD8502EAEFF5F00DD04B8 /* FAStoreVipView.swift */,
|
||||||
|
039CE6292EAB5A8C007B5EED /* FAStoreCoinsCell.swift */,
|
||||||
|
039CE62B2EAB5B07007B5EED /* FAStoreCoinsBigCell.swift */,
|
||||||
|
039CE62D2EAB5B18007B5EED /* FAStoreCoinsSmallCell.swift */,
|
||||||
|
039CE62F2EAB5B26007B5EED /* FAStoreCoinsPackCell.swift */,
|
||||||
|
031FDEAB2EAF05FB00F4CAC7 /* FAStoreVipCell.swift */,
|
||||||
|
031FDEB32EB0AD7D00F4CAC7 /* FACoinPackConfirmView.swift */,
|
||||||
|
031FDEB52EB0B77F00F4CAC7 /* FACoinPackConfirmItemView.swift */,
|
||||||
|
031FDEB72EB0B80400F4CAC7 /* FACoinPackConfirmItem1View.swift */,
|
||||||
|
031FDEB92EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift */,
|
||||||
);
|
);
|
||||||
path = V;
|
path = V;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -964,6 +1093,7 @@
|
|||||||
children = (
|
children = (
|
||||||
03E23A262EAA1A4E004A8CEC /* C */,
|
03E23A262EAA1A4E004A8CEC /* C */,
|
||||||
03E23A302EAA1A4E004A8CEC /* V */,
|
03E23A302EAA1A4E004A8CEC /* V */,
|
||||||
|
039CE61E2EAB10EC007B5EED /* M */,
|
||||||
);
|
);
|
||||||
path = Store;
|
path = Store;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -971,6 +1101,9 @@
|
|||||||
03E23A962EAA1A65004A8CEC /* Libs */ = {
|
03E23A962EAA1A65004A8CEC /* Libs */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
039CE6122EAB0DE1007B5EED /* FAIap */,
|
||||||
|
039CE60F2EAB0D2D007B5EED /* JXIAPManager */,
|
||||||
|
039CE6072EAA2F37007B5EED /* AdjustStateManager */,
|
||||||
03E23A982EAA1A7F004A8CEC /* Empty */,
|
03E23A982EAA1A7F004A8CEC /* Empty */,
|
||||||
03E23A9B2EAA1A7F004A8CEC /* FADeviceId */,
|
03E23A9B2EAA1A7F004A8CEC /* FADeviceId */,
|
||||||
03E23A9D2EAA1A7F004A8CEC /* FALocalized */,
|
03E23A9D2EAA1A7F004A8CEC /* FALocalized */,
|
||||||
@ -1468,6 +1601,7 @@
|
|||||||
children = (
|
children = (
|
||||||
03E239602EAA1945004A8CEC /* AppDelegate.swift */,
|
03E239602EAA1945004A8CEC /* AppDelegate.swift */,
|
||||||
03E239612EAA1945004A8CEC /* AppDelegate+FAConfig.swift */,
|
03E239612EAA1945004A8CEC /* AppDelegate+FAConfig.swift */,
|
||||||
|
039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */,
|
||||||
03E239622EAA1945004A8CEC /* SceneDelegate.swift */,
|
03E239622EAA1945004A8CEC /* SceneDelegate.swift */,
|
||||||
);
|
);
|
||||||
path = App;
|
path = App;
|
||||||
@ -1505,6 +1639,7 @@
|
|||||||
F3YR32SS1P8731297KD665X5 /* Fableon */ = {
|
F3YR32SS1P8731297KD665X5 /* Fableon */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
039CE61D2EAB0FE4007B5EED /* Fableon.entitlements */,
|
||||||
F3U31ND27BB4R9G072AN9BM3 /* App */,
|
F3U31ND27BB4R9G072AN9BM3 /* App */,
|
||||||
03E2395F2EAA1900004A8CEC /* Object */,
|
03E2395F2EAA1900004A8CEC /* Object */,
|
||||||
F3IF9S30I6U4301G5521663T /* Source */,
|
F3IF9S30I6U4301G5521663T /* Source */,
|
||||||
@ -1687,11 +1822,16 @@
|
|||||||
F3Q1B8O8164TYQ9724T34V29 /* OACAbleView.swift in Sources */,
|
F3Q1B8O8164TYQ9724T34V29 /* OACAbleView.swift in Sources */,
|
||||||
F36MZ39RQ295569BV1915908 /* FOMptyView.swift in Sources */,
|
F36MZ39RQ295569BV1915908 /* FOMptyView.swift in Sources */,
|
||||||
F323CZU4466303487TY7K12U /* YHRegister.swift in Sources */,
|
F323CZU4466303487TY7K12U /* YHRegister.swift in Sources */,
|
||||||
|
031FDEB02EB09AB300F4CAC7 /* FARechargeRecordModel.swift in Sources */,
|
||||||
F35T0LSS4O974ZP1IJ27TB30 /* BEedbackCenterController.swift in Sources */,
|
F35T0LSS4O974ZP1IJ27TB30 /* BEedbackCenterController.swift in Sources */,
|
||||||
F39356S815VILHH18O4HK577 /* BHSSwiftRefresh.swift in Sources */,
|
F39356S815VILHH18O4HK577 /* BHSSwiftRefresh.swift in Sources */,
|
||||||
F33O83184592105998E35JY1 /* VRServiceCenterItem.swift in Sources */,
|
F33O83184592105998E35JY1 /* VRServiceCenterItem.swift in Sources */,
|
||||||
F347N086226Y53261B0285I3 /* QLoginRoundedView.swift in Sources */,
|
F347N086226Y53261B0285I3 /* QLoginRoundedView.swift in Sources */,
|
||||||
|
031FDEB22EB0A5AF00F4CAC7 /* FASendCoinRecordModel.swift in Sources */,
|
||||||
|
03DBD8512EAEFF5F00DD04B8 /* FAStoreVipView.swift in Sources */,
|
||||||
|
031FDEB62EB0B77F00F4CAC7 /* FACoinPackConfirmItemView.swift in Sources */,
|
||||||
F35S8138Z362EG3435ME1455 /* CSGleeView.swift in Sources */,
|
F35S8138Z362EG3435ME1455 /* CSGleeView.swift in Sources */,
|
||||||
|
031FDEB42EB0AD7D00F4CAC7 /* FACoinPackConfirmView.swift in Sources */,
|
||||||
F31451S3X15B941342J922Q3 /* TConfigCell.swift in Sources */,
|
F31451S3X15B941342J922Q3 /* TConfigCell.swift in Sources */,
|
||||||
F3670DZ2KI89TBO3L9L36P57 /* XLoginView.swift in Sources */,
|
F3670DZ2KI89TBO3L9L36P57 /* XLoginView.swift in Sources */,
|
||||||
F3V24670CK2EGR4595CDQ261 /* AWUModalMageCell.swift in Sources */,
|
F3V24670CK2EGR4595CDQ261 /* AWUModalMageCell.swift in Sources */,
|
||||||
@ -1702,6 +1842,7 @@
|
|||||||
F381909BQ5JWXYI119A49469 /* DREychainCell.swift in Sources */,
|
F381909BQ5JWXYI119A49469 /* DREychainCell.swift in Sources */,
|
||||||
F39R66F983517825QO331145 /* QCenterEfineView.swift in Sources */,
|
F39R66F983517825QO331145 /* QCenterEfineView.swift in Sources */,
|
||||||
F3II3AF834346F516W51V693 /* GAMainRecommendedView.swift in Sources */,
|
F3II3AF834346F516W51V693 /* GAMainRecommendedView.swift in Sources */,
|
||||||
|
031FDEAE2EB093B100F4CAC7 /* FABuyRecordsModel.swift in Sources */,
|
||||||
F377Y22Z3J44H22J23963544 /* CDNewsController.swift in Sources */,
|
F377Y22Z3J44H22J23963544 /* CDNewsController.swift in Sources */,
|
||||||
F358686093028548K00WQIO1 /* NGleeVionView.swift in Sources */,
|
F358686093028548K00WQIO1 /* NGleeVionView.swift in Sources */,
|
||||||
F3019606DA7P36H41G408X13 /* ZStreamCell.swift in Sources */,
|
F3019606DA7P36H41G408X13 /* ZStreamCell.swift in Sources */,
|
||||||
@ -1716,11 +1857,13 @@
|
|||||||
03E239632EAA1945004A8CEC /* AppDelegate+FAConfig.swift in Sources */,
|
03E239632EAA1945004A8CEC /* AppDelegate+FAConfig.swift in Sources */,
|
||||||
03E239642EAA1945004A8CEC /* AppDelegate.swift in Sources */,
|
03E239642EAA1945004A8CEC /* AppDelegate.swift in Sources */,
|
||||||
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */,
|
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */,
|
||||||
|
039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */,
|
||||||
F333U95746V7VK13QI9275B3 /* UMenuTransformerCell.swift in Sources */,
|
F333U95746V7VK13QI9275B3 /* UMenuTransformerCell.swift in Sources */,
|
||||||
F3Q234J5M18F1Q5G2948P056 /* NPVBoutModalController.swift in Sources */,
|
F3Q234J5M18F1Q5G2948P056 /* NPVBoutModalController.swift in Sources */,
|
||||||
F38Y7NBX3M0RE4O142264411 /* EZEFlow.swift in Sources */,
|
F38Y7NBX3M0RE4O142264411 /* EZEFlow.swift in Sources */,
|
||||||
F363P024H4W1T8LN2546W883 /* YBanner.swift in Sources */,
|
F363P024H4W1T8LN2546W883 /* YBanner.swift in Sources */,
|
||||||
F3P4D170962A2JAF14W0520R /* ADCheckMageView.swift in Sources */,
|
F3P4D170962A2JAF14W0520R /* ADCheckMageView.swift in Sources */,
|
||||||
|
031FDEBA2EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift in Sources */,
|
||||||
F3206101P0DVK224N85S1W62 /* XIPathEviceController.swift in Sources */,
|
F3206101P0DVK224N85S1W62 /* XIPathEviceController.swift in Sources */,
|
||||||
F31N0S2575E3YC5AOG80WE90 /* TYElyon.swift in Sources */,
|
F31N0S2575E3YC5AOG80WE90 /* TYElyon.swift in Sources */,
|
||||||
F3JX29E3JQ40V23245TS8Z36 /* YRegisterController.swift in Sources */,
|
F3JX29E3JQ40V23245TS8Z36 /* YRegisterController.swift in Sources */,
|
||||||
@ -1729,6 +1872,7 @@
|
|||||||
F39EH05VP4YX3F00P5162031 /* YFddebcdbeeffcebdfCenterView.swift in Sources */,
|
F39EH05VP4YX3F00P5162031 /* YFddebcdbeeffcebdfCenterView.swift in Sources */,
|
||||||
F32T95836171611R26I33D4D /* AJMEychainView.swift in Sources */,
|
F32T95836171611R26I33D4D /* AJMEychainView.swift in Sources */,
|
||||||
F3242J387RV5714007E92OH3 /* BEOConfigController.swift in Sources */,
|
F3242J387RV5714007E92OH3 /* BEOConfigController.swift in Sources */,
|
||||||
|
031FDEAC2EAF05FB00F4CAC7 /* FAStoreVipCell.swift in Sources */,
|
||||||
F3N346893L1U6DP8228XK227 /* UOLaunch.swift in Sources */,
|
F3N346893L1U6DP8228XK227 /* UOLaunch.swift in Sources */,
|
||||||
F39S0H806843N21RM0O95488 /* VARResultController.swift in Sources */,
|
F39S0H806843N21RM0O95488 /* VARResultController.swift in Sources */,
|
||||||
F3D03219Y8NV50N2S66014LX /* GPOOllectionFableon.swift in Sources */,
|
F3D03219Y8NV50N2S66014LX /* GPOOllectionFableon.swift in Sources */,
|
||||||
@ -1738,20 +1882,25 @@
|
|||||||
03E23AAC2EAA1A7F004A8CEC /* FALogin.swift in Sources */,
|
03E23AAC2EAA1A7F004A8CEC /* FALogin.swift in Sources */,
|
||||||
03E23AAD2EAA1A7F004A8CEC /* FAKeychainHelper.swift in Sources */,
|
03E23AAD2EAA1A7F004A8CEC /* FAKeychainHelper.swift in Sources */,
|
||||||
03E23AAE2EAA1A7F004A8CEC /* FATool.swift in Sources */,
|
03E23AAE2EAA1A7F004A8CEC /* FATool.swift in Sources */,
|
||||||
|
039CE6262EAB2A72007B5EED /* FAPayAlertModel.swift in Sources */,
|
||||||
03E23AAF2EAA1A7F004A8CEC /* FSPagerSwiftUIView.swift in Sources */,
|
03E23AAF2EAA1A7F004A8CEC /* FSPagerSwiftUIView.swift in Sources */,
|
||||||
03E23AB02EAA1A7F004A8CEC /* FADeviceIDManager.swift in Sources */,
|
03E23AB02EAA1A7F004A8CEC /* FADeviceIDManager.swift in Sources */,
|
||||||
03E23AB12EAA1A7F004A8CEC /* FATokenModel.swift in Sources */,
|
03E23AB12EAA1A7F004A8CEC /* FATokenModel.swift in Sources */,
|
||||||
03E23AB22EAA1A7F004A8CEC /* FAEmpty.swift in Sources */,
|
03E23AB22EAA1A7F004A8CEC /* FAEmpty.swift in Sources */,
|
||||||
03E23AB32EAA1A7F004A8CEC /* FAHUD.swift in Sources */,
|
03E23AB32EAA1A7F004A8CEC /* FAHUD.swift in Sources */,
|
||||||
03E23AB42EAA1A7F004A8CEC /* FAPagerViewTransformer.swift in Sources */,
|
03E23AB42EAA1A7F004A8CEC /* FAPagerViewTransformer.swift in Sources */,
|
||||||
|
039CE62A2EAB5A8C007B5EED /* FAStoreCoinsCell.swift in Sources */,
|
||||||
|
039CE6242EAB29D1007B5EED /* FAPayDataRequest.swift in Sources */,
|
||||||
03E23AB52EAA1A7F004A8CEC /* FAToast.swift in Sources */,
|
03E23AB52EAA1A7F004A8CEC /* FAToast.swift in Sources */,
|
||||||
03E23AB62EAA1A7F004A8CEC /* FAUserInfo.swift in Sources */,
|
03E23AB62EAA1A7F004A8CEC /* FAUserInfo.swift in Sources */,
|
||||||
03E23AB72EAA1A7F004A8CEC /* FALocalized.swift in Sources */,
|
03E23AB72EAA1A7F004A8CEC /* FALocalized.swift in Sources */,
|
||||||
|
039CE6222EAB1340007B5EED /* FAUserDefaultsKey.swift in Sources */,
|
||||||
03E23AB82EAA1A7F004A8CEC /* FAWaterfallFlowLayout.swift in Sources */,
|
03E23AB82EAA1A7F004A8CEC /* FAWaterfallFlowLayout.swift in Sources */,
|
||||||
F3K238643L913I6RK4G7S006 /* CSceneRegister.swift in Sources */,
|
F3K238643L913I6RK4G7S006 /* CSceneRegister.swift in Sources */,
|
||||||
F3ZT3I4VAGB5405FWL36UW12 /* ZFGEtworkCell.swift in Sources */,
|
F3ZT3I4VAGB5405FWL36UW12 /* ZFGEtworkCell.swift in Sources */,
|
||||||
F35O71332554S53191121042 /* UOModalCell.swift in Sources */,
|
F35O71332554S53191121042 /* UOModalCell.swift in Sources */,
|
||||||
F3L30772U87770116598U282 /* NLaunchDelegate.swift in Sources */,
|
F3L30772U87770116598U282 /* NLaunchDelegate.swift in Sources */,
|
||||||
|
039CE62C2EAB5B07007B5EED /* FAStoreCoinsBigCell.swift in Sources */,
|
||||||
F38L64O0092TC8W47P271967 /* COcalizedController.swift in Sources */,
|
F38L64O0092TC8W47P271967 /* COcalizedController.swift in Sources */,
|
||||||
03E23A322EAA1A4E004A8CEC /* FAFeedbackViewController.swift in Sources */,
|
03E23A322EAA1A4E004A8CEC /* FAFeedbackViewController.swift in Sources */,
|
||||||
03E23A332EAA1A4E004A8CEC /* FAHomeRecommendedItemView.swift in Sources */,
|
03E23A332EAA1A4E004A8CEC /* FAHomeRecommendedItemView.swift in Sources */,
|
||||||
@ -1777,6 +1926,7 @@
|
|||||||
03E23A472EAA1A4E004A8CEC /* FAPlayerDetailControlView.swift in Sources */,
|
03E23A472EAA1A4E004A8CEC /* FAPlayerDetailControlView.swift in Sources */,
|
||||||
03E23A482EAA1A4E004A8CEC /* FARewardCoinsCell.swift in Sources */,
|
03E23A482EAA1A4E004A8CEC /* FARewardCoinsCell.swift in Sources */,
|
||||||
03E23A492EAA1A4E004A8CEC /* FAVideoInfoModel.swift in Sources */,
|
03E23A492EAA1A4E004A8CEC /* FAVideoInfoModel.swift in Sources */,
|
||||||
|
039CE6202EAB114B007B5EED /* FAPayDateModel.swift in Sources */,
|
||||||
03E23A4A2EAA1A4E004A8CEC /* FAConsumptionRecordsViewController.swift in Sources */,
|
03E23A4A2EAA1A4E004A8CEC /* FAConsumptionRecordsViewController.swift in Sources */,
|
||||||
03E23A4B2EAA1A4E004A8CEC /* FAMeCoinsView.swift in Sources */,
|
03E23A4B2EAA1A4E004A8CEC /* FAMeCoinsView.swift in Sources */,
|
||||||
03E23A4C2EAA1A4E004A8CEC /* FAHomeViewModel.swift in Sources */,
|
03E23A4C2EAA1A4E004A8CEC /* FAHomeViewModel.swift in Sources */,
|
||||||
@ -1789,6 +1939,7 @@
|
|||||||
03E23A532EAA1A4E004A8CEC /* FAVideoLockView.swift in Sources */,
|
03E23A532EAA1A4E004A8CEC /* FAVideoLockView.swift in Sources */,
|
||||||
03E23A542EAA1A4E004A8CEC /* FAHomeViewController.swift in Sources */,
|
03E23A542EAA1A4E004A8CEC /* FAHomeViewController.swift in Sources */,
|
||||||
03E23A552EAA1A4E004A8CEC /* FAPopularListViewController.swift in Sources */,
|
03E23A552EAA1A4E004A8CEC /* FAPopularListViewController.swift in Sources */,
|
||||||
|
039CE6042EAA2621007B5EED /* AppDelegate+FAAdjust.swift in Sources */,
|
||||||
03E23A562EAA1A4E004A8CEC /* FAPlayerEpUIButton.swift in Sources */,
|
03E23A562EAA1A4E004A8CEC /* FAPlayerEpUIButton.swift in Sources */,
|
||||||
03E23A572EAA1A4E004A8CEC /* FAHistoryCell.swift in Sources */,
|
03E23A572EAA1A4E004A8CEC /* FAHistoryCell.swift in Sources */,
|
||||||
03E23A582EAA1A4E004A8CEC /* FASearchViewController.swift in Sources */,
|
03E23A582EAA1A4E004A8CEC /* FASearchViewController.swift in Sources */,
|
||||||
@ -1821,6 +1972,8 @@
|
|||||||
03E23A732EAA1A4E004A8CEC /* FASearchRecordCell.swift in Sources */,
|
03E23A732EAA1A4E004A8CEC /* FASearchRecordCell.swift in Sources */,
|
||||||
03E23A742EAA1A4E004A8CEC /* FAShortPlayModel.swift in Sources */,
|
03E23A742EAA1A4E004A8CEC /* FAShortPlayModel.swift in Sources */,
|
||||||
03E23A752EAA1A4E004A8CEC /* FASearchRecommendCell.swift in Sources */,
|
03E23A752EAA1A4E004A8CEC /* FASearchRecommendCell.swift in Sources */,
|
||||||
|
039CE6162EAB0E30007B5EED /* FAWaitRestoreModel.swift in Sources */,
|
||||||
|
039CE6302EAB5B26007B5EED /* FAStoreCoinsPackCell.swift in Sources */,
|
||||||
03E23A762EAA1A4E004A8CEC /* FASearchHomeView.swift in Sources */,
|
03E23A762EAA1A4E004A8CEC /* FASearchHomeView.swift in Sources */,
|
||||||
03E23A772EAA1A4E004A8CEC /* FAHomeNewContentCell.swift in Sources */,
|
03E23A772EAA1A4E004A8CEC /* FAHomeNewContentCell.swift in Sources */,
|
||||||
03E23A782EAA1A4E004A8CEC /* FAOrderRecordsViewController.swift in Sources */,
|
03E23A782EAA1A4E004A8CEC /* FAOrderRecordsViewController.swift in Sources */,
|
||||||
@ -1830,11 +1983,13 @@
|
|||||||
03E23A7C2EAA1A4E004A8CEC /* FAMeCell.swift in Sources */,
|
03E23A7C2EAA1A4E004A8CEC /* FAMeCell.swift in Sources */,
|
||||||
03E23A7D2EAA1A4E004A8CEC /* FAWalletHeaderView.swift in Sources */,
|
03E23A7D2EAA1A4E004A8CEC /* FAWalletHeaderView.swift in Sources */,
|
||||||
03E23A7E2EAA1A4E004A8CEC /* FAPlayerProgressView.swift in Sources */,
|
03E23A7E2EAA1A4E004A8CEC /* FAPlayerProgressView.swift in Sources */,
|
||||||
|
031FDEB82EB0B80400F4CAC7 /* FACoinPackConfirmItem1View.swift in Sources */,
|
||||||
03E23A7F2EAA1A4E004A8CEC /* FAMeItemModel.swift in Sources */,
|
03E23A7F2EAA1A4E004A8CEC /* FAMeItemModel.swift in Sources */,
|
||||||
03E23A802EAA1A4E004A8CEC /* FAGenresListCell.swift in Sources */,
|
03E23A802EAA1A4E004A8CEC /* FAGenresListCell.swift in Sources */,
|
||||||
03E23A812EAA1A4E004A8CEC /* FACollectCell.swift in Sources */,
|
03E23A812EAA1A4E004A8CEC /* FACollectCell.swift in Sources */,
|
||||||
03E23A822EAA1A4E004A8CEC /* FASearchRecommendView.swift in Sources */,
|
03E23A822EAA1A4E004A8CEC /* FASearchRecommendView.swift in Sources */,
|
||||||
03E23A832EAA1A4E004A8CEC /* FAHomeMustSeeShortView.swift in Sources */,
|
03E23A832EAA1A4E004A8CEC /* FAHomeMustSeeShortView.swift in Sources */,
|
||||||
|
039CE60B2EAA31CB007B5EED /* FAStatAPI.swift in Sources */,
|
||||||
03E23A842EAA1A4E004A8CEC /* FACoinRecordViewController.swift in Sources */,
|
03E23A842EAA1A4E004A8CEC /* FACoinRecordViewController.swift in Sources */,
|
||||||
F3511I08934IV2C80B9Z6X2T /* QDVBoutLayout.swift in Sources */,
|
F3511I08934IV2C80B9Z6X2T /* QDVBoutLayout.swift in Sources */,
|
||||||
F311250SJ7I3DZ74X009990N /* XJSelectorCell.swift in Sources */,
|
F311250SJ7I3DZ74X009990N /* XJSelectorCell.swift in Sources */,
|
||||||
@ -1842,22 +1997,27 @@
|
|||||||
F3O215L13X5155316V412904 /* AOkenView.swift in Sources */,
|
F3O215L13X5155316V412904 /* AOkenView.swift in Sources */,
|
||||||
F3G0PR235Z2X602JE530X692 /* EQThimraPathController.swift in Sources */,
|
F3G0PR235Z2X602JE530X692 /* EQThimraPathController.swift in Sources */,
|
||||||
F3563UZ4T03I36J2R93Y31N6 /* IMRefreshManagerController.swift in Sources */,
|
F3563UZ4T03I36J2R93Y31N6 /* IMRefreshManagerController.swift in Sources */,
|
||||||
|
039CE6112EAB0D49007B5EED /* JXIAPManager.swift in Sources */,
|
||||||
F3981047B9214665100286YG /* BZOEarchView.swift in Sources */,
|
F3981047B9214665100286YG /* BZOEarchView.swift in Sources */,
|
||||||
03E23ABA2EAA1D85004A8CEC /* MNNItemController.swift in Sources */,
|
03E23ABA2EAA1D85004A8CEC /* MNNItemController.swift in Sources */,
|
||||||
F3817W6E02182D9A62U02849 /* WHAOastMainCell.swift in Sources */,
|
F3817W6E02182D9A62U02849 /* WHAOastMainCell.swift in Sources */,
|
||||||
F32C0941C670UO0IU4114086 /* XHDelegate.swift in Sources */,
|
F32C0941C670UO0IU4114086 /* XHDelegate.swift in Sources */,
|
||||||
|
039CE61A2EAB0EE0007B5EED /* FAIapVerifyModel.swift in Sources */,
|
||||||
F3XWY0D08020883935X46FG7 /* FHeaderController.swift in Sources */,
|
F3XWY0D08020883935X46FG7 /* FHeaderController.swift in Sources */,
|
||||||
F3223B1O80A345NB22134220 /* LAgerShortController.swift in Sources */,
|
F3223B1O80A345NB22134220 /* LAgerShortController.swift in Sources */,
|
||||||
F3Q51496018LRJ1691985D08 /* PYMOastCell.swift in Sources */,
|
F3Q51496018LRJ1691985D08 /* PYMOastCell.swift in Sources */,
|
||||||
F33Q5651983154V88746Y001 /* ODPlayerCell.swift in Sources */,
|
F33Q5651983154V88746Y001 /* ODPlayerCell.swift in Sources */,
|
||||||
F3774560U03XA8151BTQ2Z61 /* HYLLayoutView.swift in Sources */,
|
F3774560U03XA8151BTQ2Z61 /* HYLLayoutView.swift in Sources */,
|
||||||
F3N85463XSRG9VFK665G9028 /* XKRefreshCell.swift in Sources */,
|
F3N85463XSRG9VFK665G9028 /* XKRefreshCell.swift in Sources */,
|
||||||
|
039CE6282EAB50A9007B5EED /* FAStoreCoinsView.swift in Sources */,
|
||||||
F35K41930D96476I83FHZ0D9 /* YLZFableonAlignmentCell.swift in Sources */,
|
F35K41930D96476I83FHZ0D9 /* YLZFableonAlignmentCell.swift in Sources */,
|
||||||
F3M8439X72Q55JY9G8U502D9 /* DXYFire.swift in Sources */,
|
F3M8439X72Q55JY9G8U502D9 /* DXYFire.swift in Sources */,
|
||||||
03E239912EAA1A29004A8CEC /* Dictionary+FAAdd.swift in Sources */,
|
03E239912EAA1A29004A8CEC /* Dictionary+FAAdd.swift in Sources */,
|
||||||
03E239922EAA1A29004A8CEC /* FAImageView.swift in Sources */,
|
03E239922EAA1A29004A8CEC /* FAImageView.swift in Sources */,
|
||||||
|
031FDEBE2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift in Sources */,
|
||||||
03E239932EAA1A29004A8CEC /* Date+FAAdd.swift in Sources */,
|
03E239932EAA1A29004A8CEC /* Date+FAAdd.swift in Sources */,
|
||||||
03E239942EAA1A29004A8CEC /* UserDefaults+FAAdd.swift in Sources */,
|
03E239942EAA1A29004A8CEC /* UserDefaults+FAAdd.swift in Sources */,
|
||||||
|
039CE6322EAB796F007B5EED /* FALabel.swift in Sources */,
|
||||||
03E239952EAA1A29004A8CEC /* Font+FAAdd.swift in Sources */,
|
03E239952EAA1A29004A8CEC /* Font+FAAdd.swift in Sources */,
|
||||||
03E239962EAA1A29004A8CEC /* FACryptorService.swift in Sources */,
|
03E239962EAA1A29004A8CEC /* FACryptorService.swift in Sources */,
|
||||||
03E239972EAA1A29004A8CEC /* FANetworkManager.swift in Sources */,
|
03E239972EAA1A29004A8CEC /* FANetworkManager.swift in Sources */,
|
||||||
@ -1866,6 +2026,7 @@
|
|||||||
03E2399A2EAA1A29004A8CEC /* FAViewController.swift in Sources */,
|
03E2399A2EAA1A29004A8CEC /* FAViewController.swift in Sources */,
|
||||||
03E2399B2EAA1A29004A8CEC /* FAWebMessageModel.swift in Sources */,
|
03E2399B2EAA1A29004A8CEC /* FAWebMessageModel.swift in Sources */,
|
||||||
03E2399C2EAA1A29004A8CEC /* FAGradientButton.swift in Sources */,
|
03E2399C2EAA1A29004A8CEC /* FAGradientButton.swift in Sources */,
|
||||||
|
039CE6142EAB0E0D007B5EED /* FAIapManager.swift in Sources */,
|
||||||
03E2399D2EAA1A29004A8CEC /* FAGradientView.swift in Sources */,
|
03E2399D2EAA1A29004A8CEC /* FAGradientView.swift in Sources */,
|
||||||
03E2399E2EAA1A29004A8CEC /* FADefine.swift in Sources */,
|
03E2399E2EAA1A29004A8CEC /* FADefine.swift in Sources */,
|
||||||
03E2399F2EAA1A29004A8CEC /* FABaseWebViewController.swift in Sources */,
|
03E2399F2EAA1A29004A8CEC /* FABaseWebViewController.swift in Sources */,
|
||||||
@ -1874,18 +2035,22 @@
|
|||||||
03E239A22EAA1A29004A8CEC /* FATabBarController.swift in Sources */,
|
03E239A22EAA1A29004A8CEC /* FATabBarController.swift in Sources */,
|
||||||
03E239A32EAA1A29004A8CEC /* UIStackView+FAAdd.swift in Sources */,
|
03E239A32EAA1A29004A8CEC /* UIStackView+FAAdd.swift in Sources */,
|
||||||
03E239A42EAA1A29004A8CEC /* UIScreen+FAAdd.swift in Sources */,
|
03E239A42EAA1A29004A8CEC /* UIScreen+FAAdd.swift in Sources */,
|
||||||
|
039CE6182EAB0E7E007B5EED /* FAStoreAPI.swift in Sources */,
|
||||||
03E239A52EAA1A29004A8CEC /* FACollectionView.swift in Sources */,
|
03E239A52EAA1A29004A8CEC /* FACollectionView.swift in Sources */,
|
||||||
03E239A62EAA1A29004A8CEC /* UIView+FAAdd.swift in Sources */,
|
03E239A62EAA1A29004A8CEC /* UIView+FAAdd.swift in Sources */,
|
||||||
03E239A72EAA1A29004A8CEC /* FAScrollView.swift in Sources */,
|
03E239A72EAA1A29004A8CEC /* FAScrollView.swift in Sources */,
|
||||||
03E239A82EAA1A29004A8CEC /* FATableView.swift in Sources */,
|
03E239A82EAA1A29004A8CEC /* FATableView.swift in Sources */,
|
||||||
03E239A92EAA1A29004A8CEC /* CGMutablePath+FARoundedCorner.swift in Sources */,
|
03E239A92EAA1A29004A8CEC /* CGMutablePath+FARoundedCorner.swift in Sources */,
|
||||||
|
031FDEBC2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift in Sources */,
|
||||||
03E239AA2EAA1A29004A8CEC /* FAPanModalContentView.swift in Sources */,
|
03E239AA2EAA1A29004A8CEC /* FAPanModalContentView.swift in Sources */,
|
||||||
03E239AB2EAA1A29004A8CEC /* FATableViewCell.swift in Sources */,
|
03E239AB2EAA1A29004A8CEC /* FATableViewCell.swift in Sources */,
|
||||||
03E239AC2EAA1A29004A8CEC /* FABaseWebViewController+Script.swift in Sources */,
|
03E239AC2EAA1A29004A8CEC /* FABaseWebViewController+Script.swift in Sources */,
|
||||||
03E239AD2EAA1A29004A8CEC /* FAAppWebViewController.swift in Sources */,
|
03E239AD2EAA1A29004A8CEC /* FAAppWebViewController.swift in Sources */,
|
||||||
03E239AE2EAA1A29004A8CEC /* SwiftUIExtension.swift in Sources */,
|
03E239AE2EAA1A29004A8CEC /* SwiftUIExtension.swift in Sources */,
|
||||||
|
039CE60E2EAA32A8007B5EED /* FAOpenAppModel.swift in Sources */,
|
||||||
03E239AF2EAA1A29004A8CEC /* FAAPI.swift in Sources */,
|
03E239AF2EAA1A29004A8CEC /* FAAPI.swift in Sources */,
|
||||||
03E239B02EAA1A29004A8CEC /* FAWebView.swift in Sources */,
|
03E239B02EAA1A29004A8CEC /* FAWebView.swift in Sources */,
|
||||||
|
039CE61C2EAB0F29007B5EED /* FAIapOrderModel.swift in Sources */,
|
||||||
03E239B12EAA1A29004A8CEC /* FANetworkMonitor.swift in Sources */,
|
03E239B12EAA1A29004A8CEC /* FANetworkMonitor.swift in Sources */,
|
||||||
03E239B22EAA1A29004A8CEC /* UINavigationBar+FAAdd.swift in Sources */,
|
03E239B22EAA1A29004A8CEC /* UINavigationBar+FAAdd.swift in Sources */,
|
||||||
F3EKB04Y9O2888900KQEO504 /* NHCornerController.swift in Sources */,
|
F3EKB04Y9O2888900KQEO504 /* NHCornerController.swift in Sources */,
|
||||||
@ -1903,6 +2068,7 @@
|
|||||||
F32G5ID338260A2W78SS4618 /* TCFableonCell.swift in Sources */,
|
F32G5ID338260A2W78SS4618 /* TCFableonCell.swift in Sources */,
|
||||||
F31E84U5Y6YW6430Z54X1K40 /* UCHVion.swift in Sources */,
|
F31E84U5Y6YW6430Z54X1K40 /* UCHVion.swift in Sources */,
|
||||||
F3554P018N62D11QM20Y695Q /* BCMonitorEcommendController.swift in Sources */,
|
F3554P018N62D11QM20Y695Q /* BCMonitorEcommendController.swift in Sources */,
|
||||||
|
039CE62E2EAB5B18007B5EED /* FAStoreCoinsSmallCell.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -2056,6 +2222,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Fableon/Fableon.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
||||||
@ -2076,7 +2243,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
@ -2096,6 +2263,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Fableon/Fableon.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
||||||
@ -2115,7 +2283,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
|
|||||||
144
Fableon/App/AppDelegate+FAAdjust.swift
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
//
|
||||||
|
// AppDelegate+FAAdjust.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/23.
|
||||||
|
//
|
||||||
|
import UIKit
|
||||||
|
import AdjustSdk
|
||||||
|
import SmartCodable
|
||||||
|
#if canImport(FacebookCore)
|
||||||
|
import FacebookCore
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extension AppDelegate {
|
||||||
|
|
||||||
|
func registerAdjust() {
|
||||||
|
#if DEBUG
|
||||||
|
let config = ADJConfig(appToken: "zyp26mbr3yf4", environment: ADJEnvironmentSandbox)
|
||||||
|
config?.logLevel = .verbose
|
||||||
|
#else
|
||||||
|
let config = ADJConfig(appToken: "zyp26mbr3yf4", environment: ADJEnvironmentProduction)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
config?.delegate = self
|
||||||
|
Adjust.initSdk(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: AdjustDelegate
|
||||||
|
extension AppDelegate: AdjustDelegate {
|
||||||
|
func adjustDeferredDeeplinkReceived(_ deeplink: URL?) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension SceneDelegate {
|
||||||
|
func handleOpenAppMessage(webpageURL: URL?) {
|
||||||
|
let manager = FAAdjustStateManager.manager
|
||||||
|
guard manager.allowOpenMessage else { return }
|
||||||
|
|
||||||
|
guard FANetworkMonitor.manager.isReachable == true,
|
||||||
|
manager.isOpenApp,
|
||||||
|
manager.idfaAuthorizationFinish //idfa授权完成
|
||||||
|
else {
|
||||||
|
if let webpageURL = webpageURL {
|
||||||
|
manager.webpageURL = webpageURL
|
||||||
|
}
|
||||||
|
manager.isNeedRetry = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
manager.isNeedRetry = false
|
||||||
|
manager.webpageURL = nil
|
||||||
|
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
|
self._handleOpenAppMessage(webpageURL: webpageURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private func _handleOpenAppMessage(webpageURL: URL?) {
|
||||||
|
|
||||||
|
guard FAAdjustStateManager.manager.allowOpenMessage else { return }
|
||||||
|
FAAdjustStateManager.manager.allowOpenMessage = false
|
||||||
|
|
||||||
|
//统计用URL
|
||||||
|
var statUrlStr: String? = webpageURL?.absoluteString
|
||||||
|
var data: [String : Any]? = webpageURL?.query?.urlQuryToDictionary()
|
||||||
|
|
||||||
|
if statUrlStr == nil, let pasteStr = UIPasteboard.general.string, pasteStr.contains("movia") {
|
||||||
|
let tempArr = pasteStr.components(separatedBy: "?")
|
||||||
|
let query = tempArr.last
|
||||||
|
|
||||||
|
let tempData = query?.urlQuryToDictionary()
|
||||||
|
if tempData?["short_play_id"] != nil {
|
||||||
|
data = tempData
|
||||||
|
statUrlStr = pasteStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UIPasteboard.general.string = nil
|
||||||
|
|
||||||
|
if let urlStr = statUrlStr {//上报结果
|
||||||
|
FAStatAPI.requestStatW2a(data: urlStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
guard let data = data else { return }
|
||||||
|
guard let model = FAOpenAppModel.deserialize(from: data) else { return }
|
||||||
|
guard let shortPlayId = model.short_play_id, shortPlayId.count > 0 else { return }
|
||||||
|
|
||||||
|
|
||||||
|
let vc = FAPlayerDetailViewController()
|
||||||
|
vc.shortPlayId = shortPlayId
|
||||||
|
FATool.topViewController?.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///重试
|
||||||
|
func retryHandleOpenAppMessage() {
|
||||||
|
guard FAAdjustStateManager.manager.isNeedRetry else { return }
|
||||||
|
handleOpenAppMessage(webpageURL: FAAdjustStateManager.manager.webpageURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension SceneDelegate {
|
||||||
|
|
||||||
|
///URL打开APP
|
||||||
|
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
|
||||||
|
guard let url = URLContexts.first?.url else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var result = false
|
||||||
|
|
||||||
|
#if canImport(FacebookCore)
|
||||||
|
result = ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation])
|
||||||
|
#endif
|
||||||
|
if !result {
|
||||||
|
if let link = ADJDeeplink(deeplink: url) {
|
||||||
|
Adjust.processDeeplink(link)
|
||||||
|
}
|
||||||
|
handleOpenAppMessage(webpageURL: url)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///UniversalLink 打开app
|
||||||
|
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
|
||||||
|
guard let webpageURL = userActivity.webpageURL else { return }
|
||||||
|
var result = false
|
||||||
|
|
||||||
|
#if canImport(FacebookCore)
|
||||||
|
let result = ApplicationDelegate.shared.application(UIApplication.shared, continue: userActivity)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if !result {
|
||||||
|
handleOpenAppMessage(webpageURL: webpageURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -28,6 +28,8 @@ extension AppDelegate {
|
|||||||
let appearance = UINavigationBarAppearance.defaultAppearance()
|
let appearance = UINavigationBarAppearance.defaultAppearance()
|
||||||
UINavigationBar.appearance().scrollEdgeAppearance = appearance
|
UINavigationBar.appearance().scrollEdgeAppearance = appearance
|
||||||
UINavigationBar.appearance().standardAppearance = appearance
|
UINavigationBar.appearance().standardAppearance = appearance
|
||||||
|
|
||||||
|
registerAdjust()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
window = UIWindow(windowScene: windowScene)
|
window = UIWindow(windowScene: windowScene)
|
||||||
window?.rootViewController = FATabBarController()
|
window?.rootViewController = FATabBarController()
|
||||||
window?.makeKeyAndVisible()
|
window?.makeKeyAndVisible()
|
||||||
|
FAAdjustStateManager.manager.isOpenApp = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func sceneDidDisconnect(_ scene: UIScene) {
|
func sceneDidDisconnect(_ scene: UIScene) {
|
||||||
@ -39,14 +40,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sceneWillEnterForeground(_ scene: UIScene) {
|
func sceneWillEnterForeground(_ scene: UIScene) {
|
||||||
// Called as the scene transitions from the background to the foreground.
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
// Use this method to undo the changes made on entering the background.
|
self.handleOpenAppMessage(webpageURL: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sceneDidEnterBackground(_ scene: UIScene) {
|
func sceneDidEnterBackground(_ scene: UIScene) {
|
||||||
// Called as the scene transitions from the foreground to the background.
|
FAAdjustStateManager.manager.allowOpenMessage = true
|
||||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
|
||||||
// to restore the scene back to its current state.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
11
Fableon/Fableon.entitlements
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.developer.associated-domains</key>
|
||||||
|
<array>
|
||||||
|
<string>applinks:fableon.go.link</string>
|
||||||
|
<string>applinks:kuzt.adj.st</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -39,6 +39,14 @@ class FATabBarController: UITabBarController {
|
|||||||
self.tabBar.standardAppearance = appearance
|
self.tabBar.standardAppearance = appearance
|
||||||
self.tabBar.isTranslucent = false
|
self.tabBar.isTranslucent = false
|
||||||
|
|
||||||
|
///预加载支付数据
|
||||||
|
FAIapManager.manager.preloadingProducts()
|
||||||
|
|
||||||
|
FAIapManager.manager.restore(isLoding: false) { isFinish, buyType in
|
||||||
|
if isFinish {
|
||||||
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override var childForStatusBarStyle: UIViewController? {
|
override var childForStatusBarStyle: UIViewController? {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import UIKit
|
|||||||
|
|
||||||
///当前系统版本号
|
///当前系统版本号
|
||||||
let kFAOsVersion: String = UIDevice.current.systemVersion
|
let kFAOsVersion: String = UIDevice.current.systemVersion
|
||||||
let kBRAPPBundleIdentifier: String = (Bundle.main.infoDictionary!["CFBundleIdentifier"] as? String) ?? "0"
|
let kFAAPPBundleIdentifier: String = (Bundle.main.infoDictionary!["CFBundleIdentifier"] as? String) ?? "0"
|
||||||
|
|
||||||
///app版本号
|
///app版本号
|
||||||
let kFAAPPVersion: String = (Bundle.main.infoDictionary!["CFBundleShortVersionString"] as? String) ?? "0"
|
let kFAAPPVersion: String = (Bundle.main.infoDictionary!["CFBundleShortVersionString"] as? String) ?? "0"
|
||||||
|
|||||||
9
Fableon/Object/Base/Define/FAUserDefaultsKey.swift
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// FAUserDefaultsKey.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
let kFAWaitRestoreIAPDefaultsKey = "kFAWaitRestoreIAPDefaultsKey"
|
||||||
@ -9,6 +9,7 @@ import Foundation
|
|||||||
import SmartCodable
|
import SmartCodable
|
||||||
import YYCategories
|
import YYCategories
|
||||||
|
|
||||||
|
|
||||||
extension String: SmartCodable {
|
extension String: SmartCodable {
|
||||||
|
|
||||||
static func timeZone() -> String {
|
static func timeZone() -> String {
|
||||||
@ -39,3 +40,22 @@ extension String {
|
|||||||
static let color_333333 = "#333333"
|
static let color_333333 = "#333333"
|
||||||
static let color_D9D9D9 = "#D9D9D9"
|
static let color_D9D9D9 = "#D9D9D9"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
///将url中的参数转换成字典
|
||||||
|
func urlQuryToDictionary() -> [String : Any] {
|
||||||
|
let array = self.components(separatedBy: "&")
|
||||||
|
var tempDic: [String : Any] = [:]
|
||||||
|
|
||||||
|
array.forEach {
|
||||||
|
if let strRange = $0.range(of: "=") {
|
||||||
|
var key: String = String($0.prefix(upTo: strRange.upperBound))
|
||||||
|
key.removeLast()
|
||||||
|
var value: String = String($0.suffix(from: strRange.upperBound))
|
||||||
|
value = value.removingPercentEncoding ?? value
|
||||||
|
tempDic[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tempDic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
25
Fableon/Object/Base/Model/FAOpenAppModel.swift
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// FAOpenAppModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct FAOpenAppModel: SmartCodable {
|
||||||
|
|
||||||
|
enum Path: String, SmartCaseDefaultable {
|
||||||
|
case videoDetail = "detail"
|
||||||
|
///反馈列表
|
||||||
|
case feedback = "feedback"
|
||||||
|
///活动
|
||||||
|
case promotion = "promotion"
|
||||||
|
}
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
var message_id: String?
|
||||||
|
var short_play_id: String?
|
||||||
|
var path: Path?
|
||||||
|
}
|
||||||
87
Fableon/Object/Base/Request/FAAPI/FAStatAPI.swift
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// FAStatAPI.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAStatAPI: NSObject {
|
||||||
|
enum EventKey: String {
|
||||||
|
case payError = "pay_error" //支付过程中的其它错误
|
||||||
|
case payCallback = "pay_callback" //支付成功,但是后台接口失败
|
||||||
|
case payRestore = "pay_restore" //restore 失败
|
||||||
|
case forceUpdate = "force_update"//更新弹窗
|
||||||
|
case payCancel = "pay_cancel" //用户取消支付
|
||||||
|
case payTemplateDialog = "pay_template_dialog"//详情页面弹出支付模版事件
|
||||||
|
}
|
||||||
|
|
||||||
|
///统计w2a点击
|
||||||
|
static func requestStatW2a(data: String) {
|
||||||
|
|
||||||
|
let parameters = [
|
||||||
|
"data" : data
|
||||||
|
]
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/w2aSelfAttribution",
|
||||||
|
method: .post,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: false,
|
||||||
|
) { (response: FANetworkManager.Response<String>) in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///事件统计
|
||||||
|
static func requestEventStat(orderCode: String?, shortPlayId: String?, videoId: String?, eventKey: EventKey, errorMsg: String?, otherParamenters: [String : Any]? = nil) {
|
||||||
|
|
||||||
|
var eventName = ""
|
||||||
|
switch eventKey {
|
||||||
|
case .payRestore:
|
||||||
|
eventName = "pay restore"
|
||||||
|
|
||||||
|
case .payCallback:
|
||||||
|
eventName = "pay callback failed"
|
||||||
|
|
||||||
|
case .forceUpdate:
|
||||||
|
eventName = "force update"
|
||||||
|
|
||||||
|
case .payCancel:
|
||||||
|
eventName = "user pay canceled"
|
||||||
|
|
||||||
|
default:
|
||||||
|
eventName = "platform pay failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters: [String : Any] = [
|
||||||
|
"userId" : FALogin.manager.userInfo?.customer_id ?? "",
|
||||||
|
"short_play_video_id" : videoId ?? "0",
|
||||||
|
"short_play_id" : shortPlayId ?? "0",
|
||||||
|
"event_key" : eventKey.rawValue,
|
||||||
|
"order_code": orderCode ?? "",
|
||||||
|
"event_name" : eventName,
|
||||||
|
]
|
||||||
|
|
||||||
|
if let errorMsg = errorMsg {
|
||||||
|
parameters["error_msg"] = errorMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if let otherParamenters = otherParamenters {
|
||||||
|
otherParamenters.forEach {
|
||||||
|
parameters[$0] = $1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/event/add",
|
||||||
|
method: .post,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: false,
|
||||||
|
) { (response: FANetworkManager.Response<String>) in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
134
Fableon/Object/Base/Request/FAAPI/FAStoreAPI.swift
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
//
|
||||||
|
// FAStoreAPI.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class FAStoreAPI: NSObject {
|
||||||
|
enum BuyType: String, SmartCaseDefaultable {
|
||||||
|
case coins = "coins"
|
||||||
|
case subVip = "sub_vip"
|
||||||
|
case subCoins = "sub_coins"
|
||||||
|
case vip = "vip"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///创建内购订单
|
||||||
|
static func requestCreateOrder(payId: String, shortPlayId: String, videoId: String, isDiscount: Bool = false, identifierDiscount: String? = nil, completer: ((_ orderModel: FAIapOrderModel?) -> Void)?) {
|
||||||
|
|
||||||
|
let parameters: [String : Any] = [
|
||||||
|
"payment_channel" : "apple",
|
||||||
|
"short_play_id" : shortPlayId,
|
||||||
|
"video_id" : videoId,
|
||||||
|
"pay_setting_id" : payId,
|
||||||
|
"is_discount" : isDiscount ? 1 : 0,
|
||||||
|
"product_discount" : identifierDiscount ?? "",
|
||||||
|
]
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/createOrder",
|
||||||
|
method: .post,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: false,
|
||||||
|
) { (response: FANetworkManager.Response<FAIapOrderModel>) in
|
||||||
|
guard let data = response.data else {
|
||||||
|
FAToast.show(text: "network_error_01".localized)
|
||||||
|
completer?(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let message = data.message, message.count > 0 {
|
||||||
|
if response.data?.code == 30007 {
|
||||||
|
FAToast.show(text: "pay_error_1".localized)
|
||||||
|
} else {
|
||||||
|
FAToast.show(text: message)
|
||||||
|
}
|
||||||
|
completer?(nil)
|
||||||
|
} else {
|
||||||
|
completer?(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///校验内购
|
||||||
|
static func requestVerifyOrder(parameters: [String : Any], completer: ((_ response: FANetworkManager.Response<FAIapVerifyModel>) -> Void)?) {
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/applePaid",
|
||||||
|
method: .post,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: true,
|
||||||
|
) { (response: FANetworkManager.Response<FAIapVerifyModel>) in
|
||||||
|
completer?(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///获取支付模版
|
||||||
|
static func requestPayTemplate(isLoding: Bool = false, isToast: Bool = true, completer: ((_ model: FAPayDateModel?) -> Void)?) {
|
||||||
|
let parameters = [
|
||||||
|
"discount" : "1",
|
||||||
|
"purchases_token" : JXIAPManager.manager.getAppStoreReceipt() ?? "",
|
||||||
|
]
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/paySettingsV4",
|
||||||
|
method: .post,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: isLoding,
|
||||||
|
isToast: isToast,
|
||||||
|
) { (response: FANetworkManager.Response<FAPayDateModel>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestBuyRecords(page: Int, completer: ((_ listModel: FANetworkManager.List<FABuyRecordsModel>?) -> Void)?) {
|
||||||
|
let parameters = [
|
||||||
|
"page_size" : 20,
|
||||||
|
"current_page" : page,
|
||||||
|
]
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/getCustomerBuyRecords",
|
||||||
|
method: .get,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: true,
|
||||||
|
) { (response: FANetworkManager.Response<FANetworkManager.List<FABuyRecordsModel>>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestRechargeRecord(page: Int, buyType: BuyType, completer: ((_ listModel: FANetworkManager.List<FARechargeRecordModel>?) -> Void)?) {
|
||||||
|
let parameters: [String : Any] = [
|
||||||
|
"page_size" : 20,
|
||||||
|
"current_page" : page,
|
||||||
|
"buy_type" : buyType.rawValue
|
||||||
|
]
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/getCustomerOrder",
|
||||||
|
method: .get,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: true,
|
||||||
|
) { (response: FANetworkManager.Response<FANetworkManager.List<FARechargeRecordModel>>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func reuqestSendCoinRecord(page: Int, completer: ((_ listModel: FANetworkManager.List<FASendCoinRecordModel>?) -> Void)?) {
|
||||||
|
let parameters: [String : Any] = [
|
||||||
|
"page_size" : 20,
|
||||||
|
"current_page" : page,
|
||||||
|
]
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/sendCoinList",
|
||||||
|
method: .post,
|
||||||
|
parameters: parameters,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: true,
|
||||||
|
) { (response: FANetworkManager.Response<FANetworkManager.List<FASendCoinRecordModel>>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
Fableon/Object/Base/View/FALabel.swift
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
//
|
||||||
|
// FALabel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FALabel: UILabel {
|
||||||
|
|
||||||
|
var textColorImage: UIImage?
|
||||||
|
var fa_textColor: UIColor?
|
||||||
|
var textColors: [CGColor]?
|
||||||
|
var textStartPoint: CGPoint?
|
||||||
|
var textEndPoint: CGPoint?
|
||||||
|
|
||||||
|
var borderLineWidth: CGFloat = 0
|
||||||
|
var borderImage: UIImage?
|
||||||
|
var borderColor: UIColor?
|
||||||
|
var borderColors: [CGColor]?
|
||||||
|
var borderStartPoint: CGPoint?
|
||||||
|
var borderEndPoint: CGPoint?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override var intrinsicContentSize: CGSize {
|
||||||
|
let size = super.intrinsicContentSize
|
||||||
|
return .init(width: size.width + borderLineWidth / 2, height: size.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func drawText(in rect: CGRect) {
|
||||||
|
guard let context = UIGraphicsGetCurrentContext(),
|
||||||
|
let text = self.text else {
|
||||||
|
super.drawText(in: rect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// var attributes: [NSAttributedString.Key: Any] = [:]
|
||||||
|
//
|
||||||
|
// if let att = self.attributedText?.yy_attributes {
|
||||||
|
// att.forEach {
|
||||||
|
// let key = NSAttributedString.Key.init($0)
|
||||||
|
// attributes[key] = $1
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// } else if let font = self.font {
|
||||||
|
// attributes = [
|
||||||
|
// .font: font
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let textSize = text.size(withAttributes: attributes)
|
||||||
|
// let x = (rect.width - textSize.width) / 2
|
||||||
|
// let y = (rect.height - textSize.height) / 2
|
||||||
|
|
||||||
|
let textSize = self.attributedText?.boundingRect(with: rect.size, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil).size ?? .zero
|
||||||
|
let x = 0.0
|
||||||
|
let y = 0.0
|
||||||
|
let textRect = CGRect(x: x, y: y, width: textSize.width, height: textSize.height)
|
||||||
|
|
||||||
|
|
||||||
|
context.setLineWidth(borderLineWidth)
|
||||||
|
context.setLineJoin(.round)
|
||||||
|
// 先描边
|
||||||
|
context.setTextDrawingMode(.stroke)
|
||||||
|
if let image = self.borderImage {
|
||||||
|
self.textColor = UIColor(patternImage: image.sp_resized(to: rect.size))
|
||||||
|
} else if let colors = self.borderColors, let startPoint = self.borderStartPoint, let endPoine = self.borderEndPoint {
|
||||||
|
self.textColor = UIColor(patternImage: UIImage.fa_getGradientImage(size: size, colors: colors, startPoint: startPoint, endPoint: endPoine))
|
||||||
|
} else {
|
||||||
|
self.textColor = self.borderColor ?? .clear
|
||||||
|
}
|
||||||
|
super.drawText(in: textRect)
|
||||||
|
|
||||||
|
// 再填充
|
||||||
|
context.setTextDrawingMode(.fill)
|
||||||
|
if let image = self.textColorImage {
|
||||||
|
self.textColor = UIColor(patternImage: image.sp_resized(to: rect.size))
|
||||||
|
} else if let colors = self.textColors, let startPoint = self.textStartPoint, let endPoine = self.textEndPoint {
|
||||||
|
self.textColor = UIColor(patternImage: UIImage.fa_getGradientImage(size: size, colors: colors, startPoint: startPoint, endPoint: endPoine))
|
||||||
|
} else {
|
||||||
|
self.textColor = fa_textColor // 填充色
|
||||||
|
}
|
||||||
|
super.drawText(in: textRect)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UIImage {
|
||||||
|
|
||||||
|
static func fa_getGradientImage(size: CGSize, colors: [CGColor], startPoint: CGPoint, endPoint: CGPoint) -> UIImage{
|
||||||
|
|
||||||
|
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
|
||||||
|
guard let context = UIGraphicsGetCurrentContext() else{return UIImage()}
|
||||||
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
|
///设置渐变颜色
|
||||||
|
let gradientRef = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: nil)!
|
||||||
|
let startPoint = CGPoint(x: size.width * startPoint.x, y: size.height * startPoint.y)
|
||||||
|
let endPoint = CGPoint(x: size.width * endPoint.x, y: size.height * endPoint.y)
|
||||||
|
context.drawLinearGradient(gradientRef, start: startPoint, end: endPoint, options: CGGradientDrawingOptions(arrayLiteral: .drawsBeforeStartLocation,.drawsAfterEndLocation))
|
||||||
|
let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return gradientImage ?? UIImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sp_resized(to size: CGSize) -> UIImage {
|
||||||
|
let renderer = UIGraphicsImageRenderer(size: size)
|
||||||
|
return renderer.image { _ in
|
||||||
|
self.draw(in: CGRect(origin: .zero, size: size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ class FAAppWebViewController: FABaseWebViewController {
|
|||||||
|
|
||||||
private var receiveDataCount = 0
|
private var receiveDataCount = 0
|
||||||
|
|
||||||
var theme: String? = "theme_2"
|
var theme: String? = "theme_1"
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|||||||
@ -95,7 +95,7 @@ extension FAMeViewController: JXPagingViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func tableHeaderViewHeight(in pagingView: JXPagingView) -> Int {
|
func tableHeaderViewHeight(in pagingView: JXPagingView) -> Int {
|
||||||
return Int(ceill(headerView.contentHeight))
|
return Int(ceil(headerView.contentHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableHeaderView(in pagingView: JXPagingView) -> UIView {
|
func tableHeaderView(in pagingView: JXPagingView) -> UIView {
|
||||||
|
|||||||
36
Fableon/Object/Class/Player/V/FANewVideoRechargeView.swift
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// FANewVideoRechargeView.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FANewVideoRechargeView: FAPanModalContentView {
|
||||||
|
|
||||||
|
var model: FAPayDateModel? {
|
||||||
|
didSet {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var videoInfo: FAVideoInfoModel? {
|
||||||
|
didSet {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func allowsTapBackgroundToDismiss() -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
290
Fableon/Object/Class/Player/V/FAOldVideoRechargeView.swift
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
//
|
||||||
|
// FAOldVideoRechargeView.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import HWPanModal
|
||||||
|
|
||||||
|
class FAOldVideoRechargeView: FAPanModalContentView {
|
||||||
|
|
||||||
|
var buyFinishHandle: (() -> Void)?
|
||||||
|
|
||||||
|
var model: FAPayDateModel? {
|
||||||
|
didSet {
|
||||||
|
self.stackView.fa_removeAllArrangedSubview()
|
||||||
|
self.vipView.dataArr = model?.list_sub_vip ?? []
|
||||||
|
self.coinsView.setDataArr(model?.list_coins ?? [])
|
||||||
|
|
||||||
|
if let sort = model?.sort, sort.count > 0 {
|
||||||
|
sort.forEach {
|
||||||
|
if $0 == .vip, model?.list_sub_vip?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.vipView)
|
||||||
|
} else if $0 == .coin, model?.list_coins?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.coinsView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if model?.list_sub_vip?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.vipView)
|
||||||
|
}
|
||||||
|
if model?.list_coins?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.coinsView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// self.stackView.addArrangedSubview(self.tipView)
|
||||||
|
|
||||||
|
self.setNeedsLayoutUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var videoInfo: FAVideoInfoModel? {
|
||||||
|
didSet {
|
||||||
|
self.coinsView.videoId = videoInfo?.short_play_video_id
|
||||||
|
self.coinsView.shortPlayId = videoInfo?.short_play_id
|
||||||
|
self.vipView.videoId = videoInfo?.short_play_video_id
|
||||||
|
self.vipView.shortPlayId = videoInfo?.short_play_id
|
||||||
|
videoCoinsView.coins = videoInfo?.coins ?? 0
|
||||||
|
|
||||||
|
self.requestRestore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var closeButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
FAStatAPI.requestEventStat(orderCode: nil, shortPlayId: self.videoInfo?.short_play_id, videoId: self.videoInfo?.short_play_video_id, eventKey: .payTemplateDialog, errorMsg: nil, otherParamenters: [
|
||||||
|
"event_name" : "pay cancel"
|
||||||
|
])
|
||||||
|
Task {
|
||||||
|
await self.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
button.setImage(UIImage(named: "close_icon_02"), for: .normal)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var scrollView: FAScrollView = {
|
||||||
|
let scrollView = FAScrollView()
|
||||||
|
scrollView.clipsToBounds = false
|
||||||
|
return scrollView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var stackView: UIStackView = {
|
||||||
|
let view = UIStackView()
|
||||||
|
view.axis = .vertical
|
||||||
|
view.spacing = 18
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsView: FAStoreCoinsView = {
|
||||||
|
let view = FAStoreCoinsView()
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
self?.buyFinishHandle?()
|
||||||
|
Task {
|
||||||
|
await self?.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var vipView: FAStoreVipView = {
|
||||||
|
let view = FAStoreVipView()
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
self?.buyFinishHandle?()
|
||||||
|
Task {
|
||||||
|
await self?.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var videoCoinsView: FAOldVideoRechargeView.CoinsView = {
|
||||||
|
let view = FAOldVideoRechargeView.CoinsView()
|
||||||
|
view.title = "Price".localized + ":"
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var totalCoinsView: FAOldVideoRechargeView.CoinsView = {
|
||||||
|
let view = FAOldVideoRechargeView.CoinsView()
|
||||||
|
view.title = "Balance".localized + ":"
|
||||||
|
view.coins = FALogin.manager.userInfo?.totalCoins ?? 0
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
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
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: FALogin.userInfoUpdateNotification, object: nil)
|
||||||
|
self.contentHeight = UIScreen.height - UIScreen.safeTop
|
||||||
|
// self.backgroundColor = ._000000.withAlphaComponent(0.6)
|
||||||
|
self.backgroundColor = .clear
|
||||||
|
self.mainScrollView = self.scrollView
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func userInfoUpdateNotification() {
|
||||||
|
totalCoinsView.coins = FALogin.manager.userInfo?.totalCoins ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override func present(in view: UIView?) {
|
||||||
|
super.present(in: view)
|
||||||
|
self.hw_contentView.fa_addEffectView(style: .dark)
|
||||||
|
self.hw_contentView.fa_setRoundedCorner(topLeft: 24, topRight: 24, bottomLeft: 0, bottomRight: 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func allowsTapBackgroundToDismiss() -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAOldVideoRechargeView {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(closeButton)
|
||||||
|
addSubview(videoCoinsView)
|
||||||
|
addSubview(totalCoinsView)
|
||||||
|
addSubview(titleLabel)
|
||||||
|
addSubview(scrollView)
|
||||||
|
scrollView.addSubview(stackView)
|
||||||
|
|
||||||
|
closeButton.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview().offset(-16)
|
||||||
|
make.top.equalToSuperview().offset(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
videoCoinsView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(closeButton)
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCoinsView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(closeButton)
|
||||||
|
make.left.equalTo(videoCoinsView.snp.right).offset(15)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.top.equalToSuperview().offset(39)
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollView.snp.makeConstraints { make in
|
||||||
|
make.left.right.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(74)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
stackView.snp.makeConstraints { make in
|
||||||
|
make.left.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAOldVideoRechargeView {
|
||||||
|
|
||||||
|
@objc private func requestRestore() {
|
||||||
|
guard let shortPlayId = self.videoInfo?.short_play_id, let videoId = self.videoInfo?.short_play_video_id else { return }
|
||||||
|
|
||||||
|
FAIapManager.manager.restore(isLoding: false, shortPlayId: shortPlayId, videoId: videoId) { [weak self] isFinish, buyType in
|
||||||
|
if isFinish {
|
||||||
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
|
self?.buyFinishHandle?()
|
||||||
|
Task {
|
||||||
|
await self?.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension FAOldVideoRechargeView {
|
||||||
|
|
||||||
|
class CoinsView: UIView {
|
||||||
|
var title: String? {
|
||||||
|
didSet {
|
||||||
|
titleLabel.text = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var coins: Int = 0 {
|
||||||
|
didSet {
|
||||||
|
coinsLabel.text = "\(coins)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .regular)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var iconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_08"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .bold)
|
||||||
|
label.textColor = .F_9_F_494
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
addSubview(titleLabel)
|
||||||
|
addSubview(iconImageView)
|
||||||
|
addSubview(coinsLabel)
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.bottom.lessThanOrEqualToSuperview()
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
iconImageView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.bottom.lessThanOrEqualToSuperview()
|
||||||
|
make.left.equalTo(titleLabel.snp.right).offset(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.bottom.lessThanOrEqualToSuperview()
|
||||||
|
make.left.equalTo(iconImageView.snp.right).offset(4)
|
||||||
|
make.right.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -87,7 +87,19 @@ class FAPlayerDetailViewController: JXPlayerListViewController {
|
|||||||
}
|
}
|
||||||
self.pause()
|
self.pause()
|
||||||
|
|
||||||
|
let myCoins = FALogin.manager.userInfo?.totalCoins ?? 0
|
||||||
|
let lockCoins = videoInfo?.coins ?? 0
|
||||||
|
|
||||||
|
if myCoins < lockCoins, (self.fa_viewModel.currentCell as? FAPlayerDetailCell)?.hasLastEpisodeUnlocked != true {
|
||||||
|
self.fa_viewModel.openRechargeView()
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if (self.fa_viewModel.currentCell as? FAPlayerDetailCell)?.hasLastEpisodeUnlocked != true {
|
||||||
|
self.fa_viewModel.handleUnlockVideo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,8 +37,10 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
|
|||||||
|
|
||||||
weak var popView: UIView?
|
weak var popView: UIView?
|
||||||
|
|
||||||
|
private var payDataRequest: FAPayDataRequest?
|
||||||
|
|
||||||
func requestDetailData(completer: ((_ code: Int) -> Void)?) {
|
|
||||||
|
func requestDetailData(indexPath: IndexPath? = nil, completer: ((_ code: Int) -> Void)?) {
|
||||||
FAAPI.requestShortDetailData(shortPlayId: shortPlayId) { [weak self] model, code, msg in
|
FAAPI.requestShortDetailData(shortPlayId: shortPlayId) { [weak self] model, code, msg in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if let model = model {
|
if let model = model {
|
||||||
@ -48,7 +50,9 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
var targetIndexPath = IndexPath(row: 0, section: 0)
|
var targetIndexPath = IndexPath(row: 0, section: 0)
|
||||||
|
|
||||||
if let videoInfo = model.video_info {
|
if let indexPath = indexPath, indexPath.row < (model.episodeList?.count ?? 0) {
|
||||||
|
targetIndexPath = indexPath
|
||||||
|
} else if let videoInfo = model.video_info {
|
||||||
var row: Int?
|
var row: Int?
|
||||||
model.episodeList?.enumerated().forEach {
|
model.episodeList?.enumerated().forEach {
|
||||||
if $1.short_play_video_id == videoInfo.short_play_video_id {
|
if $1.short_play_video_id == videoInfo.short_play_video_id {
|
||||||
@ -125,11 +129,59 @@ extension FAShortDetailViewModel {
|
|||||||
guard let videoInfo = self.currentCell?.model as? FAVideoInfoModel else { return }
|
guard let videoInfo = self.currentCell?.model as? FAVideoInfoModel else { return }
|
||||||
guard self.popView == nil else { return }
|
guard self.popView == nil else { return }
|
||||||
|
|
||||||
|
self.payDataRequest = FAPayDataRequest()
|
||||||
|
if let model = FAIapManager.manager.payDateModel {
|
||||||
|
self._openRechargeView(model, videoInfo)
|
||||||
|
self.payDataRequest?.requestProducts(isLoding: false) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
if let view = self.popView as? FAOldVideoRechargeView {
|
||||||
|
view.model = model
|
||||||
|
} else if let view = self.popView as? FANewVideoRechargeView {
|
||||||
|
view.model = model
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.payDataRequest?.requestProducts(isLoding: true) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
self._openRechargeView(model, videoInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func _openRechargeView(_ model: FAPayDateModel, _ videoInfo: FAVideoInfoModel) {
|
||||||
|
guard self.popView == nil else { return }
|
||||||
|
FAStatAPI.requestEventStat(orderCode: nil, shortPlayId: videoInfo.short_play_id, videoId: videoInfo.short_play_video_id, eventKey: .payTemplateDialog, errorMsg: nil, otherParamenters: [
|
||||||
|
"event_name" : "pay open"
|
||||||
|
])
|
||||||
|
|
||||||
|
// if model.pay_mode == 1 {
|
||||||
|
// _openNewRechargeView(model, videoInfo)
|
||||||
|
// } else {
|
||||||
|
_openOldRechargeView(model, videoInfo)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func _openOldRechargeView(_ model: FAPayDateModel, _ videoInfo: FAVideoInfoModel) {
|
||||||
|
let view = FAOldVideoRechargeView()
|
||||||
|
view.model = model
|
||||||
|
view.videoInfo = videoInfo
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.requestDetailData(indexPath: self.currentIndexPath, completer: nil)
|
||||||
|
}
|
||||||
|
view.present(in: nil)
|
||||||
|
self.popView = view
|
||||||
|
}
|
||||||
|
|
||||||
|
private func _openNewRechargeView(_ model: FAPayDateModel, _ videoInfo: FAVideoInfoModel) {
|
||||||
|
let view = FANewVideoRechargeView()
|
||||||
|
view.model = model
|
||||||
|
view.videoInfo = videoInfo
|
||||||
|
view.present(in: nil)
|
||||||
|
self.popView = view
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FAShortDetailViewModel {
|
extension FAShortDetailViewModel {
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import UIKit
|
|||||||
|
|
||||||
class FACoinRecordViewController: FAViewController {
|
class FACoinRecordViewController: FAViewController {
|
||||||
|
|
||||||
|
private lazy var dataArr: [FARechargeRecordModel] = []
|
||||||
|
private lazy var page = 1
|
||||||
|
|
||||||
private lazy var tableView: FATableView = {
|
private lazy var tableView: FATableView = {
|
||||||
let tableView = FATableView(frame: .zero, style: .plain)
|
let tableView = FATableView(frame: .zero, style: .plain)
|
||||||
@ -19,6 +21,13 @@ class FACoinRecordViewController: FAViewController {
|
|||||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
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.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
tableView.register(UINib(nibName: "FAOrderRecordCell", bundle: nil), forCellReuseIdentifier: "cell")
|
tableView.register(UINib(nibName: "FAOrderRecordCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||||
|
tableView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
|
self?.handleHeaderRefresh(nil)
|
||||||
|
}
|
||||||
|
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
||||||
|
self?.handleFooterRefresh(nil)
|
||||||
|
}
|
||||||
return tableView
|
return tableView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -32,8 +41,21 @@ class FACoinRecordViewController: FAViewController {
|
|||||||
make.left.right.bottom.equalToSuperview()
|
make.left.right.bottom.equalToSuperview()
|
||||||
make.top.equalToSuperview()
|
make.top.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestDataArr(page: 1, completer: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endHeaderRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: self.page + 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endFooterRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +63,47 @@ class FACoinRecordViewController: FAViewController {
|
|||||||
extension FACoinRecordViewController: UITableViewDelegate, UITableViewDataSource {
|
extension FACoinRecordViewController: UITableViewDelegate, UITableViewDataSource {
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let model = self.dataArr[indexPath.row]
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
||||||
|
if model.type == "send" {
|
||||||
|
cell.titleLabel.text = "Bonus Coins".localized
|
||||||
|
} else {
|
||||||
|
cell.titleLabel.text = "Recharge Coins".localized
|
||||||
|
}
|
||||||
|
cell.dateLabel.text = model.created_at
|
||||||
|
cell.countLabel.text = "+\(model.value ?? "0")"
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return 20
|
return self.dataArr.count
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FACoinRecordViewController {
|
||||||
|
|
||||||
|
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||||
|
FAStoreAPI.requestRechargeRecord(page: page, buyType: .coins) { [weak self] listModel in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let listModel = listModel, let list = listModel.list else {
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel?.hasNextPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if page == 1 {
|
||||||
|
self.dataArr.removeAll()
|
||||||
|
}
|
||||||
|
self.dataArr += list
|
||||||
|
|
||||||
|
self.page = page
|
||||||
|
self.tableView.reloadData()
|
||||||
|
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel.hasNextPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import UIKit
|
|||||||
|
|
||||||
class FAConsumptionRecordsViewController: FAViewController {
|
class FAConsumptionRecordsViewController: FAViewController {
|
||||||
|
|
||||||
|
private lazy var dataArr: [FABuyRecordsModel] = []
|
||||||
|
private lazy var page = 1
|
||||||
|
|
||||||
private lazy var tableView: FATableView = {
|
private lazy var tableView: FATableView = {
|
||||||
let tableView = FATableView(frame: .zero, style: .plain)
|
let tableView = FATableView(frame: .zero, style: .plain)
|
||||||
@ -19,6 +21,13 @@ class FAConsumptionRecordsViewController: FAViewController {
|
|||||||
tableView.separatorInset = .init(top: 0, left: 34, bottom: 0, right: 34)
|
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.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
tableView.register(UINib(nibName: "FAConsumptionRecordsCell", bundle: nil), forCellReuseIdentifier: "cell")
|
tableView.register(UINib(nibName: "FAConsumptionRecordsCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||||
|
tableView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
|
self?.handleHeaderRefresh(nil)
|
||||||
|
}
|
||||||
|
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
||||||
|
self?.handleFooterRefresh(nil)
|
||||||
|
}
|
||||||
return tableView
|
return tableView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -27,6 +36,8 @@ class FAConsumptionRecordsViewController: FAViewController {
|
|||||||
self.title = "Consumption Records".localized
|
self.title = "Consumption Records".localized
|
||||||
|
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
|
|
||||||
|
requestDataArr(page: 1, completer: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -35,6 +46,18 @@ class FAConsumptionRecordsViewController: FAViewController {
|
|||||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||||
fa_setNavigationStyle()
|
fa_setNavigationStyle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endHeaderRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: self.page + 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endFooterRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,10 +80,37 @@ extension FAConsumptionRecordsViewController: UITableViewDelegate, UITableViewDa
|
|||||||
|
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAConsumptionRecordsCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAConsumptionRecordsCell
|
||||||
|
cell.model = dataArr[indexPath.row]
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return 20
|
return dataArr.count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FAConsumptionRecordsViewController {
|
||||||
|
|
||||||
|
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||||
|
FAStoreAPI.requestBuyRecords(page: page) { [weak self] listModel in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let listModel = listModel, let list = listModel.list else {
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel?.hasNextPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if page == 1 {
|
||||||
|
self.dataArr.removeAll()
|
||||||
|
}
|
||||||
|
self.dataArr += list
|
||||||
|
|
||||||
|
self.page = page
|
||||||
|
self.tableView.reloadData()
|
||||||
|
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel.hasNextPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,9 @@ import UIKit
|
|||||||
|
|
||||||
class FARewardCoinsViewController: FAViewController {
|
class FARewardCoinsViewController: FAViewController {
|
||||||
|
|
||||||
|
private lazy var dataArr: [FASendCoinRecordModel] = []
|
||||||
|
private lazy var page = 1
|
||||||
|
|
||||||
private lazy var tableView: FATableView = {
|
private lazy var tableView: FATableView = {
|
||||||
let tableView = FATableView(frame: .zero, style: .plain)
|
let tableView = FATableView(frame: .zero, style: .plain)
|
||||||
tableView.delegate = self
|
tableView.delegate = self
|
||||||
@ -18,6 +21,13 @@ class FARewardCoinsViewController: FAViewController {
|
|||||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
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.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
tableView.register(UINib(nibName: "FARewardCoinsCell", bundle: nil), forCellReuseIdentifier: "cell")
|
tableView.register(UINib(nibName: "FARewardCoinsCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||||
|
tableView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
|
self?.handleHeaderRefresh(nil)
|
||||||
|
}
|
||||||
|
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
||||||
|
self?.handleFooterRefresh(nil)
|
||||||
|
}
|
||||||
return tableView
|
return tableView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -31,6 +41,8 @@ class FARewardCoinsViewController: FAViewController {
|
|||||||
make.left.right.bottom.equalToSuperview()
|
make.left.right.bottom.equalToSuperview()
|
||||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight + 10)
|
make.top.equalToSuperview().offset(UIScreen.navBarHeight + 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestDataArr(page: 1, completer: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -39,6 +51,18 @@ class FARewardCoinsViewController: FAViewController {
|
|||||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||||
fa_setNavigationStyle()
|
fa_setNavigationStyle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endHeaderRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: self.page + 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endFooterRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,10 +70,37 @@ class FARewardCoinsViewController: FAViewController {
|
|||||||
extension FARewardCoinsViewController: UITableViewDelegate, UITableViewDataSource {
|
extension FARewardCoinsViewController: UITableViewDelegate, UITableViewDataSource {
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FARewardCoinsCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FARewardCoinsCell
|
||||||
|
cell.model = self.dataArr[indexPath.row]
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return 20
|
return self.dataArr.count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FARewardCoinsViewController {
|
||||||
|
|
||||||
|
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||||
|
FAStoreAPI.reuqestSendCoinRecord(page: page) { [weak self] listModel in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let listModel = listModel, let list = listModel.list else {
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel?.hasNextPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if page == 1 {
|
||||||
|
self.dataArr.removeAll()
|
||||||
|
}
|
||||||
|
self.dataArr += list
|
||||||
|
|
||||||
|
self.page = page
|
||||||
|
self.tableView.reloadData()
|
||||||
|
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel.hasNextPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,11 @@ import UIKit
|
|||||||
|
|
||||||
class FAStoreViewController: FAViewController {
|
class FAStoreViewController: FAViewController {
|
||||||
|
|
||||||
|
private var payRequest: FAPayDataRequest?
|
||||||
|
|
||||||
|
///支付数据
|
||||||
|
private var payDataModel = FAIapManager.manager.payDateModel
|
||||||
|
|
||||||
private lazy var scrollView: FAScrollView = {
|
private lazy var scrollView: FAScrollView = {
|
||||||
let scrollView = FAScrollView()
|
let scrollView = FAScrollView()
|
||||||
return scrollView
|
return scrollView
|
||||||
@ -22,11 +27,84 @@ class FAStoreViewController: FAViewController {
|
|||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var stackView: UIStackView = {
|
||||||
|
let view = UIStackView()
|
||||||
|
view.axis = .vertical
|
||||||
|
view.spacing = 18
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsView: FAStoreCoinsView = {
|
||||||
|
let view = FAStoreCoinsView()
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
self?.buyFinish()
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var vipView: FAStoreVipView = {
|
||||||
|
let view = FAStoreVipView()
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
self?.buyFinish()
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var tipView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.addSubview(tipTitleLabel)
|
||||||
|
view.addSubview(tipTextLabel)
|
||||||
|
|
||||||
|
tipTitleLabel.snp.makeConstraints { make in
|
||||||
|
make.top.equalToSuperview().offset(7)
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
tipTextLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||||
|
make.top.equalTo(tipTitleLabel.snp.bottom).offset(4)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var tipTitleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
label.text = "store_tips_title".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var tipTextLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 10, weight: .regular)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
label.text = "store_tips".localized
|
||||||
|
label.numberOfLines = 0
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.title = "Store".localized
|
self.title = "Store".localized
|
||||||
|
let barButtonItem = UIBarButtonItem(title: "Restore".localized, style: .plain, target: self, action: #selector(handleRestore))
|
||||||
|
barButtonItem.tintColor = .FFFFFF
|
||||||
|
self.navigationItem.rightBarButtonItem = barButtonItem
|
||||||
|
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
|
|
||||||
|
updateLayout()
|
||||||
|
|
||||||
|
requestPayData()
|
||||||
|
|
||||||
|
FAIapManager.manager.restore(isLoding: false) { [weak self] isFinish, buyType in
|
||||||
|
if isFinish {
|
||||||
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
|
self?.buyFinish()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
@ -35,7 +113,74 @@ class FAStoreViewController: FAViewController {
|
|||||||
fa_setNavigationStyle()
|
fa_setNavigationStyle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func buyFinish() {
|
||||||
|
self.requestPayData()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func handleRestore() {
|
||||||
|
FAIapManager.manager.restore { [weak self] isFinish, buyType in
|
||||||
|
if isFinish {
|
||||||
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
|
self?.buyFinish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLayout() {
|
||||||
|
self.stackView.fa_removeAllArrangedSubview()
|
||||||
|
guard let model = self.payDataModel else { return }
|
||||||
|
|
||||||
|
if model.pay_mode == 1 {
|
||||||
|
self.addCoinsView()
|
||||||
|
} else {
|
||||||
|
if let sort = model.sort, sort.count > 0 {
|
||||||
|
sort.forEach {
|
||||||
|
if $0 == .vip {
|
||||||
|
self.addVipView()
|
||||||
|
} else if $0 == .coin {
|
||||||
|
self.addCoinsView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.addVipView()
|
||||||
|
self.addCoinsView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.stackView.addArrangedSubview(tipView)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func addCoinsView() {
|
||||||
|
guard let model = self.payDataModel else { return }
|
||||||
|
|
||||||
|
var newList: [FAPayItem] = []
|
||||||
|
|
||||||
|
if model.show_type == 1, model.pay_mode == 1 {
|
||||||
|
if let list = model.list_coins, list.count > 0 {
|
||||||
|
list.forEach {
|
||||||
|
if $0.buy_type == .subCoins {
|
||||||
|
newList.append($0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let list = model.list_coins, list.count > 0 {
|
||||||
|
newList = list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if newList.count > 0 {
|
||||||
|
coinsView.setDataArr(newList)
|
||||||
|
self.stackView.addArrangedSubview(coinsView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func addVipView() {
|
||||||
|
guard let list = payDataModel?.list_sub_vip else { return }
|
||||||
|
guard list.count > 0 else { return }
|
||||||
|
|
||||||
|
self.vipView.dataArr = list
|
||||||
|
self.stackView.addArrangedSubview(self.vipView)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FAStoreViewController {
|
extension FAStoreViewController {
|
||||||
@ -43,6 +188,7 @@ extension FAStoreViewController {
|
|||||||
private func fa_setupLayout() {
|
private func fa_setupLayout() {
|
||||||
view.addSubview(scrollView)
|
view.addSubview(scrollView)
|
||||||
scrollView.addSubview(titleLabel)
|
scrollView.addSubview(titleLabel)
|
||||||
|
scrollView.addSubview(stackView)
|
||||||
|
|
||||||
scrollView.snp.makeConstraints { make in
|
scrollView.snp.makeConstraints { make in
|
||||||
make.left.right.bottom.equalToSuperview()
|
make.left.right.bottom.equalToSuperview()
|
||||||
@ -53,6 +199,29 @@ extension FAStoreViewController {
|
|||||||
make.top.equalToSuperview().offset(0)
|
make.top.equalToSuperview().offset(0)
|
||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stackView.snp.makeConstraints { make in
|
||||||
|
make.left.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(29)
|
||||||
|
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FAStoreViewController {
|
||||||
|
|
||||||
|
private func requestPayData() {
|
||||||
|
payRequest = FAPayDataRequest()
|
||||||
|
|
||||||
|
payRequest?.requestProducts { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
self.payDataModel = model
|
||||||
|
|
||||||
|
self.updateLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,9 @@ import UIKit
|
|||||||
|
|
||||||
class FAVipRecordViewController: FAViewController {
|
class FAVipRecordViewController: FAViewController {
|
||||||
|
|
||||||
|
private lazy var dataArr: [FARechargeRecordModel] = []
|
||||||
|
private lazy var page = 1
|
||||||
|
|
||||||
private lazy var tableView: FATableView = {
|
private lazy var tableView: FATableView = {
|
||||||
let tableView = FATableView(frame: .zero, style: .plain)
|
let tableView = FATableView(frame: .zero, style: .plain)
|
||||||
tableView.delegate = self
|
tableView.delegate = self
|
||||||
@ -18,6 +21,13 @@ class FAVipRecordViewController: FAViewController {
|
|||||||
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
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.contentInset = .init(top: 10, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
tableView.register(UINib(nibName: "FAOrderRecordCell", bundle: nil), forCellReuseIdentifier: "cell")
|
tableView.register(UINib(nibName: "FAOrderRecordCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||||
|
tableView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
|
self?.handleHeaderRefresh(nil)
|
||||||
|
}
|
||||||
|
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
||||||
|
self?.handleFooterRefresh(nil)
|
||||||
|
}
|
||||||
return tableView
|
return tableView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -31,9 +41,21 @@ class FAVipRecordViewController: FAViewController {
|
|||||||
make.left.right.bottom.equalToSuperview()
|
make.left.right.bottom.equalToSuperview()
|
||||||
make.top.equalToSuperview()
|
make.top.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestDataArr(page: 1, completer: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endHeaderRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func handleFooterRefresh(_ completer: (() -> Void)?) {
|
||||||
|
requestDataArr(page: self.page + 1) { [weak self] in
|
||||||
|
self?.tableView.fa_endFooterRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,13 +63,43 @@ class FAVipRecordViewController: FAViewController {
|
|||||||
extension FAVipRecordViewController: UITableViewDelegate, UITableViewDataSource {
|
extension FAVipRecordViewController: UITableViewDelegate, UITableViewDataSource {
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let model = self.dataArr[indexPath.row]
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
||||||
cell.iconImageView.isHidden = true
|
cell.iconImageView.isHidden = true
|
||||||
|
cell.titleLabel.text = model.type
|
||||||
|
cell.dateLabel.text = model.created_at
|
||||||
|
cell.countLabel.text = "+\(model.value ?? "")"
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return 20
|
return self.dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAVipRecordViewController {
|
||||||
|
|
||||||
|
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||||
|
FAStoreAPI.requestRechargeRecord(page: page, buyType: .vip) { [weak self] listModel in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let listModel = listModel, let list = listModel.list else {
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel?.hasNextPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if page == 1 {
|
||||||
|
self.dataArr.removeAll()
|
||||||
|
}
|
||||||
|
self.dataArr += list
|
||||||
|
|
||||||
|
self.page = page
|
||||||
|
self.tableView.reloadData()
|
||||||
|
|
||||||
|
completer?()
|
||||||
|
self.tableView.fa_updateNoMoreDataState(listModel.hasNextPage)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
21
Fableon/Object/Class/Store/M/FABuyRecordsModel.swift
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// FABuyRecordsModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct FABuyRecordsModel: SmartCodable {
|
||||||
|
|
||||||
|
var created_at: String?
|
||||||
|
var short_play_id: String?
|
||||||
|
var coins: Int?
|
||||||
|
var short_play_video_id: String?
|
||||||
|
var coin_type: Int?
|
||||||
|
var image_url: String?
|
||||||
|
var name: String?
|
||||||
|
var episode: String?
|
||||||
|
}
|
||||||
24
Fableon/Object/Class/Store/M/FAPayAlertModel.swift
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// FAPayAlertModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class FAPayAlertModel: NSObject, SmartCodable {
|
||||||
|
|
||||||
|
required override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
var coins_modal_easy_close: Bool?
|
||||||
|
|
||||||
|
var info: FAPayItem?
|
||||||
|
|
||||||
|
var forced_recharge: Bool?
|
||||||
|
|
||||||
|
var close_label: String?
|
||||||
|
}
|
||||||
167
Fableon/Object/Class/Store/M/FAPayDateModel.swift
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
//
|
||||||
|
// FAPayDateModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
import StoreKit
|
||||||
|
|
||||||
|
class FAPayDateModel: NSObject, SmartCodable {
|
||||||
|
|
||||||
|
|
||||||
|
required override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortName: String, SmartCaseDefaultable {
|
||||||
|
case coin = "list_coins"
|
||||||
|
case vip = "list_sub_vip"
|
||||||
|
}
|
||||||
|
|
||||||
|
var list_coins: [FAPayItem]?
|
||||||
|
var list_sub_vip: [FAPayItem]?
|
||||||
|
var list_sub_coins: [FAPayItem]?
|
||||||
|
var sort: [SortName]?
|
||||||
|
|
||||||
|
///0: 老版支付 1:新版支付
|
||||||
|
var pay_mode: Int?
|
||||||
|
///0: 普通金币 1:金币包模式
|
||||||
|
var show_type: Int?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FAPayItem: NSObject, SmartCodable {
|
||||||
|
|
||||||
|
required override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum VipTypeKey: String, SmartCaseDefaultable {
|
||||||
|
case week = "week"
|
||||||
|
case month = "month"
|
||||||
|
case quarter = "quarter"
|
||||||
|
case year = "year"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SizeType: String, SmartCaseDefaultable {
|
||||||
|
case big = "big"
|
||||||
|
case small = "small"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
var backhaul_price: String?
|
||||||
|
var coins: Int?
|
||||||
|
var status: String?
|
||||||
|
var price: String?
|
||||||
|
var send_coins: Int?
|
||||||
|
var buy_type: FAStoreAPI.BuyType?
|
||||||
|
var origin_price: String?
|
||||||
|
|
||||||
|
var vip_type: String?
|
||||||
|
var vip_type_key: VipTypeKey?
|
||||||
|
var sort: String?
|
||||||
|
var fa_description: String?
|
||||||
|
var brief: String?
|
||||||
|
var title: String?
|
||||||
|
var auto_sub: String?
|
||||||
|
|
||||||
|
|
||||||
|
var send_coin_ttl: Int?
|
||||||
|
|
||||||
|
var size: SizeType?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var ios_template_id: String?
|
||||||
|
///角标
|
||||||
|
var corner_marker: String?
|
||||||
|
///平台
|
||||||
|
var platform: String?
|
||||||
|
///货币符号
|
||||||
|
var currency: String?
|
||||||
|
|
||||||
|
var ext_info: FAPayExtInfo?
|
||||||
|
|
||||||
|
///0 无优惠 1 首次购买优惠 2 二次购买优惠
|
||||||
|
var discount_type: Int?
|
||||||
|
|
||||||
|
@SmartIgnored
|
||||||
|
var product: SKProduct?
|
||||||
|
|
||||||
|
///首冲优惠数据
|
||||||
|
var introductionaryOffer: SKProductDiscount? {
|
||||||
|
return product?.introductoryPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
///促销优惠数据
|
||||||
|
var promotionalOffers: [SKProductDiscount]? {
|
||||||
|
return product?.discounts
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||||
|
return [
|
||||||
|
CodingKeys.fa_description <--- ["description"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func getTimeString() -> String? {
|
||||||
|
switch self.vip_type_key {
|
||||||
|
case .week:
|
||||||
|
return "week".localized
|
||||||
|
|
||||||
|
case .month:
|
||||||
|
return "month".localized
|
||||||
|
|
||||||
|
case .quarter:
|
||||||
|
return "quarter".localized
|
||||||
|
|
||||||
|
case .year:
|
||||||
|
return "year".localized
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVipTitle() -> String? {
|
||||||
|
switch self.vip_type_key {
|
||||||
|
case .week:
|
||||||
|
return "Weekly VIP".localized
|
||||||
|
|
||||||
|
case .month:
|
||||||
|
return "Monthly VIP".localized
|
||||||
|
|
||||||
|
case .quarter:
|
||||||
|
return "Quarterly VIP".localized
|
||||||
|
|
||||||
|
case .year:
|
||||||
|
return "Yearly VIP".localized
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class FAPayExtInfo: NSObject, SmartCodable {
|
||||||
|
|
||||||
|
required override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
var extra_day_coins: Int?
|
||||||
|
var receive_coins_rate: String?
|
||||||
|
var max_total_coins: Int?
|
||||||
|
var sub_coins_txt_list: [String]?
|
||||||
|
|
||||||
|
}
|
||||||
17
Fableon/Object/Class/Store/M/FARechargeRecordModel.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// FARechargeRecordModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct FARechargeRecordModel: SmartCodable {
|
||||||
|
|
||||||
|
var type: String?
|
||||||
|
var value: String?
|
||||||
|
var created_at: String?
|
||||||
|
|
||||||
|
}
|
||||||
21
Fableon/Object/Class/Store/M/FASendCoinRecordModel.swift
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// FASendCoinRecordModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct FASendCoinRecordModel: SmartCodable {
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
var left_coins: String?
|
||||||
|
var created_at: String?
|
||||||
|
var type: String?
|
||||||
|
var diff_datetime: String?
|
||||||
|
var expired_time: TimeInterval?
|
||||||
|
var coins: Int?
|
||||||
|
var is_effective: Int?
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// FACoinPackConfirmItem1View.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FACoinPackConfirmItem1View: FACoinPackConfirmItemView {
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
titleLabel.text = "Bonus You Get".localized
|
||||||
|
|
||||||
|
let view1 = getItemView(image: UIImage(named: "Group 2072750450"), text: "Weekly Refill Package".localized)
|
||||||
|
let view2 = getItemView(image: UIImage(named: "Group 2072750451"), text: "Dailu Bonuses".localized)
|
||||||
|
|
||||||
|
addSubview(view1)
|
||||||
|
addSubview(view2)
|
||||||
|
|
||||||
|
view1.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||||
|
make.height.equalTo(83)
|
||||||
|
make.bottom.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
|
||||||
|
view2.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(view1.snp.right).offset(12)
|
||||||
|
make.right.equalToSuperview().offset(-12)
|
||||||
|
make.width.height.top.equalTo(view1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getItemView(image: UIImage?, text: String) -> UIView {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = ._40395_D.withAlphaComponent(0.75)
|
||||||
|
view.layer.cornerRadius = 8
|
||||||
|
view.layer.masksToBounds = true
|
||||||
|
|
||||||
|
let imageView = UIImageView(image: image)
|
||||||
|
imageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
|
|
||||||
|
let label = UILabel()
|
||||||
|
label.numberOfLines = 0
|
||||||
|
label.font = .font(ofSize: 12, weight: .init(800))
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
label.text = text
|
||||||
|
|
||||||
|
|
||||||
|
view.addSubview(imageView)
|
||||||
|
view.addSubview(label)
|
||||||
|
|
||||||
|
imageView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
label.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalTo(imageView.snp.right).offset(8)
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-8)
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
123
Fableon/Object/Class/Store/V/FACoinPackConfirmItem2View.swift
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
//
|
||||||
|
// FACoinPackConfirmItem2View.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FACoinPackConfirmItem2View: FACoinPackConfirmItemView {
|
||||||
|
|
||||||
|
var list: [String]? {
|
||||||
|
didSet {
|
||||||
|
|
||||||
|
self.stackView.fa_removeAllArrangedSubview()
|
||||||
|
|
||||||
|
list?.forEach {
|
||||||
|
let view = FACoinPackConfirmItem2View.ItemView()
|
||||||
|
view.text = $0
|
||||||
|
self.stackView.addArrangedSubview(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var lineView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .FFFFFF.withAlphaComponent(0.1)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var stackView: UIStackView = {
|
||||||
|
let view = UIStackView()
|
||||||
|
view.axis = .vertical
|
||||||
|
view.spacing = 24
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
self.titleLabel.text = "How Do I Receive Coins?"
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FACoinPackConfirmItem2View {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(lineView)
|
||||||
|
addSubview(stackView)
|
||||||
|
|
||||||
|
lineView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(titleLabel.snp.bottom).offset(16)
|
||||||
|
make.height.equalTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
stackView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(lineView.snp.bottom).offset(16)
|
||||||
|
make.bottom.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FACoinPackConfirmItem2View {
|
||||||
|
|
||||||
|
class ItemView: UIView {
|
||||||
|
var text: String? {
|
||||||
|
didSet {
|
||||||
|
textLabel.text = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var iconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_06"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var textLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .regular)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
label.numberOfLines = 0
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
addSubview(iconImageView)
|
||||||
|
addSubview(textLabel)
|
||||||
|
|
||||||
|
iconImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
textLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(iconImageView.snp.right).offset(12)
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
39
Fableon/Object/Class/Store/V/FACoinPackConfirmItemView.swift
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// FACoinPackConfirmItemView.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FACoinPackConfirmItemView: UIView {
|
||||||
|
|
||||||
|
lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 18, weight: .bold)
|
||||||
|
label.textColor = ._20_A_1_FF
|
||||||
|
label.textAlignment = .center
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
backgroundColor = ._29223_C
|
||||||
|
layer.cornerRadius = 8
|
||||||
|
layer.masksToBounds = true
|
||||||
|
|
||||||
|
addSubview(titleLabel)
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||||
|
make.top.equalToSuperview().offset(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
209
Fableon/Object/Class/Store/V/FACoinPackConfirmView.swift
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
//
|
||||||
|
// FACoinPackConfirmView.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import HWPanModal
|
||||||
|
|
||||||
|
class FACoinPackConfirmView: FAPanModalContentView {
|
||||||
|
|
||||||
|
var buyFinishHandle: (() -> Void)?
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
|
var model: FAPayItem? {
|
||||||
|
didSet {
|
||||||
|
item2View.list = model?.ext_info?.sub_coins_txt_list
|
||||||
|
|
||||||
|
var price = model?.price ?? ""
|
||||||
|
if model?.discount_type == 1, let introductoryPrice = model?.introductionaryOffer {
|
||||||
|
price = introductoryPrice.price.stringValue
|
||||||
|
} else if model?.discount_type == 2, let discount = model?.promotionalOffers?.first {
|
||||||
|
price = discount.price.stringValue
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.text = "\(model?.currency ?? "")\(price)/\(model?.getTimeString() ?? "")"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var bgImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "弹窗背景色"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bgIconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "Ellipse 873"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var titleLabel: FALabel = {
|
||||||
|
let label = FALabel()
|
||||||
|
label.font = .font(ofSize: 24, weight: .init(700))
|
||||||
|
label.textColors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor]
|
||||||
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
label.text = "What You Get".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var closeButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
Task {
|
||||||
|
await self.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
button.setImage(UIImage(named: "close_icon_01"), for: .normal)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var scrollView: FAScrollView = {
|
||||||
|
let scrollView = FAScrollView()
|
||||||
|
scrollView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
|
return scrollView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var item1View: FACoinPackConfirmItem1View = {
|
||||||
|
let view = FACoinPackConfirmItem1View()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var item2View: FACoinPackConfirmItem2View = {
|
||||||
|
let view = FACoinPackConfirmItem2View()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 18, weight: .bold)
|
||||||
|
label.textColor = ._20_A_1_FF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var continueButton: UIButton = {
|
||||||
|
let button = FAGradientButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = self.model else { return }
|
||||||
|
FAIapManager.manager.start(model: model, shortPlayId: self.shortPlayId, videoId: self.videoId) { [weak self] finish in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if finish {
|
||||||
|
self.buyFinishHandle?()
|
||||||
|
Task {
|
||||||
|
await self.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
button.layer.cornerRadius = 24
|
||||||
|
button.layer.masksToBounds = true
|
||||||
|
button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.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("Continue".localized, for: .normal)
|
||||||
|
button.setTitleColor(.FFFFFF, for: .normal)
|
||||||
|
button.titleLabel?.font = .font(ofSize: 14, weight: .bold)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
self.backgroundColor = .clear
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
self.panModalSetNeedsLayoutUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func allowsTapBackgroundToDismiss() -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override func cornerRadius() -> CGFloat {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override func longFormHeight() -> PanModalHeight {
|
||||||
|
let height = 96 + scrollView.contentSize.height + 92 + 10
|
||||||
|
return PanModalHeightMake(.content, height + UIScreen.safeBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FACoinPackConfirmView {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(bgImageView)
|
||||||
|
bgImageView.addSubview(bgIconImageView)
|
||||||
|
addSubview(titleLabel)
|
||||||
|
addSubview(closeButton)
|
||||||
|
addSubview(scrollView)
|
||||||
|
scrollView.addSubview(item1View)
|
||||||
|
scrollView.addSubview(item2View)
|
||||||
|
addSubview(priceLabel)
|
||||||
|
addSubview(continueButton)
|
||||||
|
|
||||||
|
bgImageView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
bgIconImageView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(55)
|
||||||
|
}
|
||||||
|
|
||||||
|
closeButton.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview().offset(-16)
|
||||||
|
make.top.equalToSuperview().offset(24)
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollView.snp.makeConstraints { make in
|
||||||
|
make.left.right.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(96)
|
||||||
|
make.bottom.equalToSuperview().offset(-(92 + UIScreen.safeBottom + 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
item1View.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
item2View.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(item1View.snp.bottom).offset(12)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.centerY.equalTo(scrollView.snp.bottom).offset(22)
|
||||||
|
}
|
||||||
|
|
||||||
|
continueButton.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.top.equalTo(scrollView.snp.bottom).offset(44)
|
||||||
|
make.height.equalTo(48)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,6 +9,15 @@ import UIKit
|
|||||||
|
|
||||||
class FAConsumptionRecordsCell: FATableViewCell {
|
class FAConsumptionRecordsCell: FATableViewCell {
|
||||||
|
|
||||||
|
var model: FABuyRecordsModel? {
|
||||||
|
didSet {
|
||||||
|
titleLabel.text = "Purchase Single Episode".localized
|
||||||
|
subtitleLabel.text = "Ep.##".localizedReplace(text: "\(model?.episode ?? "")") + " " + "\(model?.name ?? "")"
|
||||||
|
dateLabel.text = model?.created_at
|
||||||
|
coinsLabel.text = "-\(model?.coins ?? 0)" + "Coins".localized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@IBOutlet weak var titleLabel: UILabel!
|
@IBOutlet weak var titleLabel: UILabel!
|
||||||
|
|
||||||
@ -22,7 +31,7 @@ class FAConsumptionRecordsCell: FATableViewCell {
|
|||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
|
||||||
titleLabel.text = "Purchase Single Episode dafdaaafafaafdasfadfsafdafadsadfas";
|
titleLabel.text = "Purchase Single Episode";
|
||||||
subtitleLabel.text = "Ep.8 Romantic Flash Marriage In Progress"
|
subtitleLabel.text = "Ep.8 Romantic Flash Marriage In Progress"
|
||||||
dateLabel.text = "2024-6-10 23:41:18"
|
dateLabel.text = "2024-6-10 23:41:18"
|
||||||
coinsLabel.text = "-10 Coins"
|
coinsLabel.text = "-10 Coins"
|
||||||
|
|||||||
@ -9,6 +9,27 @@ import UIKit
|
|||||||
|
|
||||||
class FARewardCoinsCell: FATableViewCell {
|
class FARewardCoinsCell: FATableViewCell {
|
||||||
|
|
||||||
|
var model: FASendCoinRecordModel? {
|
||||||
|
didSet {
|
||||||
|
nameLabel.text = model?.type
|
||||||
|
dateLabel.text = model?.created_at
|
||||||
|
countLabel.text = "+\(model?.coins ?? 0)"
|
||||||
|
remainingLabel.text = model?.left_coins
|
||||||
|
|
||||||
|
if model?.is_effective == 1 {
|
||||||
|
expiresIconImageView.isHidden = false
|
||||||
|
expiresLabel.isHidden = false
|
||||||
|
expiredLabel.isHidden = true
|
||||||
|
expiresLabel.text = "Expires in ## days".localizedReplace(text: model?.diff_datetime ?? "")
|
||||||
|
} else {
|
||||||
|
expiresIconImageView.isHidden = true
|
||||||
|
expiresLabel.isHidden = true
|
||||||
|
expiredLabel.isHidden = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@IBOutlet weak var dateLabel: UILabel!
|
@IBOutlet weak var dateLabel: UILabel!
|
||||||
|
|
||||||
|
|||||||
173
Fableon/Object/Class/Store/V/FAStoreCoinsBigCell.swift
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
//
|
||||||
|
// FAStoreCoinsBigCell.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAStoreCoinsBigCell: FAStoreCoinsCell {
|
||||||
|
|
||||||
|
override var fa_isSelected: Bool {
|
||||||
|
didSet {
|
||||||
|
if fa_isSelected {
|
||||||
|
bgImageView.image = UIImage(named: "Rectangle 6216")
|
||||||
|
} else {
|
||||||
|
bgImageView.image = UIImage(named: "Rectangle 6217")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override var model: FAPayItem? {
|
||||||
|
didSet {
|
||||||
|
let coins = model?.coins ?? 0
|
||||||
|
let sendCoins = model?.send_coins ?? 0
|
||||||
|
|
||||||
|
coinCountLabel.text = "\(coins)"
|
||||||
|
|
||||||
|
priceLabel.text = (model?.currency ?? "") + " " + (model?.price ?? "")
|
||||||
|
|
||||||
|
if sendCoins > 0 {
|
||||||
|
sendCoinsLabel.isHidden = false
|
||||||
|
sendCoinsRatioImageView.isHidden = false
|
||||||
|
sendCoinsLabel.text = "+\(sendCoins) " + "Coins".localized
|
||||||
|
|
||||||
|
let ratio = String(format: "%.0f", CGFloat(sendCoins) / CGFloat(coins) * 100)
|
||||||
|
sendCoinsRatioLabel.text = "+\(ratio)%"
|
||||||
|
} else {
|
||||||
|
sendCoinsLabel.isHidden = true
|
||||||
|
sendCoinsRatioImageView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if let mark = model?.corner_marker, !mark.isEmpty {
|
||||||
|
self.hotImageView.isHidden = false
|
||||||
|
} else {
|
||||||
|
self.hotImageView.isHidden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var bgImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "Rectangle 6217"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_04"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinCountLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 16, weight: .medium)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var sendCoinsLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 10, weight: .medium)
|
||||||
|
label.textColor = ._000000
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var sendCoinsRatioImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "Rectangle 36"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var sendCoinsRatioLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceBgView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "Frame 3030"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .heavy)
|
||||||
|
label.textColor = ._000000
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var hotImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "hot_icon_01"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAStoreCoinsBigCell {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
contentView.addSubview(bgImageView)
|
||||||
|
bgImageView.addSubview(coinImageView)
|
||||||
|
bgImageView.addSubview(coinCountLabel)
|
||||||
|
bgImageView.addSubview(sendCoinsLabel)
|
||||||
|
bgImageView.addSubview(sendCoinsRatioImageView)
|
||||||
|
sendCoinsRatioImageView.addSubview(sendCoinsRatioLabel)
|
||||||
|
contentView.addSubview(priceBgView)
|
||||||
|
priceBgView.addSubview(priceLabel)
|
||||||
|
contentView.addSubview(hotImageView)
|
||||||
|
|
||||||
|
bgImageView.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
coinImageView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(7)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinCountLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(coinImageView.snp.bottom).offset(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCoinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(coinCountLabel.snp.bottom).offset(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCoinsRatioImageView.snp.makeConstraints { make in
|
||||||
|
make.top.right.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCoinsRatioLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(7)
|
||||||
|
make.right.equalToSuperview().offset(-10)
|
||||||
|
}
|
||||||
|
|
||||||
|
priceBgView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
hotImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(17)
|
||||||
|
make.top.equalToSuperview().offset(-9)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
Fableon/Object/Class/Store/V/FAStoreCoinsCell.swift
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// FAStoreCoinsCell.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAStoreCoinsCell: UICollectionViewCell {
|
||||||
|
|
||||||
|
var model: FAPayItem?
|
||||||
|
|
||||||
|
var fa_isSelected = false
|
||||||
|
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
230
Fableon/Object/Class/Store/V/FAStoreCoinsPackCell.swift
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
//
|
||||||
|
// FAStoreCoinsPackCell.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAStoreCoinsPackCell: FAStoreCoinsCell {
|
||||||
|
|
||||||
|
|
||||||
|
override var model: FAPayItem? {
|
||||||
|
didSet {
|
||||||
|
coinsLabel.text = "\(model?.ext_info?.max_total_coins ?? 0)"
|
||||||
|
ratioLabel.text = "\(model?.ext_info?.receive_coins_rate ?? "0%")"
|
||||||
|
|
||||||
|
priceView.setNeedsUpdateConfiguration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var bgView: FAGradientView = {
|
||||||
|
let view = FAGradientView()
|
||||||
|
view.fa_colors = [UIColor._524_B_8_E.cgColor, UIColor._303265.cgColor]
|
||||||
|
view.fa_locations = [0, 1]
|
||||||
|
view.fa_startPoint = .init(x: 0, y: 0.5)
|
||||||
|
view.fa_endPoint = .init(x: 1, y: 0.5)
|
||||||
|
view.layer.cornerRadius = 12
|
||||||
|
view.layer.masksToBounds = true
|
||||||
|
view.layer.borderWidth = 1
|
||||||
|
view.layer.borderColor = UIColor.E_5_E_5_E_5.cgColor
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bgAttachmentView1: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coin_attachment_01"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bgAttachmentView2: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coin_attachment_02"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinPileImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_05"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .init(700))
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
label.text = "Weekly Refill".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_06"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsLabel: UILabel = {
|
||||||
|
let label = FALabel()
|
||||||
|
label.font = .font(ofSize: 18, weight: .init(900))
|
||||||
|
label.textColors = [UIColor.FFCE_63.cgColor, UIColor.FFE_1_AA.cgColor]
|
||||||
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var ratioBgView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .FFFFFF.withAlphaComponent(0.15)
|
||||||
|
view.layer.cornerRadius = 4
|
||||||
|
view.layer.masksToBounds = true
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var ratioLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .regular)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceView: UIButton = {
|
||||||
|
var config = UIButton.Configuration.plain()
|
||||||
|
config.titleAlignment = .center
|
||||||
|
config.titlePadding = 0
|
||||||
|
config.contentInsets = .init(top: 0, leading: 10, bottom: 0, trailing: 10)
|
||||||
|
|
||||||
|
let button = FAGradientButton(configuration: config)
|
||||||
|
button.isUserInteractionEnabled = false
|
||||||
|
button.layer.masksToBounds = true
|
||||||
|
button.layer.cornerRadius = 24
|
||||||
|
button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor]
|
||||||
|
button.fa_startPoint = .init(x: 0, y: 0.5)
|
||||||
|
button.fa_endPoint = .init(x: 0.5, y: 0.5)
|
||||||
|
button.fa_locations = [0, 1]
|
||||||
|
button.configurationUpdateHandler = { [weak self] button in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
let currency = self.model?.currency ?? ""
|
||||||
|
let timeText = model?.getTimeString() ?? ""
|
||||||
|
let oldPrice = self.model?.price ?? ""
|
||||||
|
var discountPrice: String? = nil
|
||||||
|
|
||||||
|
if self.model?.discount_type == 1, let introductoryPrice = self.model?.introductionaryOffer {
|
||||||
|
discountPrice = introductoryPrice.price.stringValue
|
||||||
|
} else if self.model?.discount_type == 2, let discount = self.model?.promotionalOffers?.first {
|
||||||
|
discountPrice = discount.price.stringValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if let discountPrice = discountPrice {
|
||||||
|
|
||||||
|
let priceString = AttributedString("\(currency)\(discountPrice)", attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 18, weight: .bold),
|
||||||
|
.foregroundColor : UIColor._114_CEE
|
||||||
|
]))
|
||||||
|
|
||||||
|
|
||||||
|
button.configuration?.attributedTitle = priceString
|
||||||
|
|
||||||
|
var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||||
|
.foregroundColor : UIColor._636_F_7_B.withAlphaComponent(0.2),
|
||||||
|
.strikethroughStyle: NSUnderlineStyle.single.rawValue,
|
||||||
|
.strikethroughColor: UIColor._636_F_7_B.withAlphaComponent(0.2)
|
||||||
|
]))
|
||||||
|
|
||||||
|
button.configuration?.attributedSubtitle = subtitle
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
button.configuration?.attributedTitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 18, weight: .bold),
|
||||||
|
.foregroundColor : UIColor._114_CEE
|
||||||
|
]))
|
||||||
|
|
||||||
|
button.configuration?.attributedSubtitle = AttributedString("/\(timeText)", attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||||
|
.foregroundColor : UIColor._000000.withAlphaComponent(0.5)
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAStoreCoinsPackCell {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
contentView.addSubview(bgView)
|
||||||
|
bgView.addSubview(bgAttachmentView1)
|
||||||
|
bgView.addSubview(bgAttachmentView2)
|
||||||
|
bgView.addSubview(coinPileImageView)
|
||||||
|
bgView.addSubview(titleLabel)
|
||||||
|
bgView.addSubview(coinsImageView)
|
||||||
|
bgView.addSubview(coinsLabel)
|
||||||
|
bgView.addSubview(ratioBgView)
|
||||||
|
ratioBgView.addSubview(ratioLabel)
|
||||||
|
bgView.addSubview(priceView)
|
||||||
|
|
||||||
|
bgView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
bgAttachmentView1.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(0)
|
||||||
|
make.top.equalToSuperview().offset(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
bgAttachmentView2.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview().offset(-26)
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
coinPileImageView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.top.equalToSuperview().offset(19)
|
||||||
|
make.left.equalTo(coinPileImageView.snp.right).offset(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(titleLabel)
|
||||||
|
make.bottom.equalToSuperview().offset(-21)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(coinsImageView)
|
||||||
|
make.left.equalTo(coinsImageView.snp.right).offset(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
ratioBgView.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(coinsLabel.snp.right).offset(4)
|
||||||
|
make.height.equalTo(18)
|
||||||
|
make.centerY.equalTo(coinsImageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
ratioLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
priceView.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview().offset(-12)
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.height.equalTo(48)
|
||||||
|
make.width.greaterThanOrEqualTo(88)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
161
Fableon/Object/Class/Store/V/FAStoreCoinsSmallCell.swift
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
//
|
||||||
|
// FAStoreCoinsSmallCell.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAStoreCoinsSmallCell: FAStoreCoinsCell {
|
||||||
|
|
||||||
|
override var model: FAPayItem? {
|
||||||
|
didSet {
|
||||||
|
let coins = model?.coins ?? 0
|
||||||
|
let sendCoins = model?.send_coins ?? 0
|
||||||
|
|
||||||
|
coinsLabel.text = "\(coins)"
|
||||||
|
|
||||||
|
priceLabel.text = "\(model?.currency ?? "") \(model?.price ?? "")"
|
||||||
|
|
||||||
|
if let mark = model?.corner_marker, !mark.isEmpty {
|
||||||
|
self.hotImageView.isHidden = false
|
||||||
|
} else {
|
||||||
|
self.hotImageView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if sendCoins > 0 {
|
||||||
|
sendCoinsLabel.isHidden = false
|
||||||
|
sendCoinsRatioView.isHidden = false
|
||||||
|
sendCoinsLabel.text = "+\(sendCoins) " + "Coins".localized
|
||||||
|
|
||||||
|
let ratio = String(format: "%.0f", CGFloat(sendCoins) / CGFloat(coins) * 100)
|
||||||
|
sendCoinsRatioLabel.text = "+\(ratio)%"
|
||||||
|
} else {
|
||||||
|
sendCoinsLabel.isHidden = true
|
||||||
|
sendCoinsRatioView.isHidden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var coinImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_07"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 16, weight: .medium)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var sendCoinsLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 10, weight: .medium)
|
||||||
|
label.textColor = ._000000
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceBgView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .B_8_EFFD
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 13, weight: .bold)
|
||||||
|
label.textColor = ._000000
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var sendCoinsRatioView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = ._2_D_75_FF
|
||||||
|
view.fa_setRoundedCorner(topLeft: 0, topRight: 0, bottomLeft: 8, bottomRight: 0)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var sendCoinsRatioLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var hotImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "hot_icon_01"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
contentView.backgroundColor = ._84_C_0_FF.withAlphaComponent(0.77)
|
||||||
|
contentView.layer.cornerRadius = 9
|
||||||
|
contentView.layer.masksToBounds = true
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAStoreCoinsSmallCell {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
contentView.addSubview(coinImageView)
|
||||||
|
contentView.addSubview(coinsLabel)
|
||||||
|
contentView.addSubview(sendCoinsLabel)
|
||||||
|
contentView.addSubview(priceBgView)
|
||||||
|
priceBgView.addSubview(priceLabel)
|
||||||
|
addSubview(hotImageView)
|
||||||
|
contentView.addSubview(sendCoinsRatioView)
|
||||||
|
sendCoinsRatioView.addSubview(sendCoinsRatioLabel)
|
||||||
|
|
||||||
|
coinImageView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(coinImageView.snp.bottom).offset(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCoinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(coinsLabel.snp.bottom).offset(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
priceBgView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.height.equalTo(28)
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
hotImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(-8)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCoinsRatioView.snp.makeConstraints { make in
|
||||||
|
make.right.top.equalToSuperview()
|
||||||
|
make.height.equalTo(17)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCoinsRatioLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
212
Fableon/Object/Class/Store/V/FAStoreCoinsView.swift
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
//
|
||||||
|
// FAStoreCoinsView.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAStoreCoinsView: UIView {
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
|
var buyFinishHandle: (() -> Void)?
|
||||||
|
|
||||||
|
private lazy var dataArr: [[FAPayItem]] = []
|
||||||
|
|
||||||
|
private var selectedIndexPath: IndexPath?
|
||||||
|
|
||||||
|
private lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
||||||
|
let config = UICollectionViewCompositionalLayoutConfiguration()
|
||||||
|
config.interSectionSpacing = 10
|
||||||
|
|
||||||
|
let layout = UICollectionViewCompositionalLayout { [weak self] section, _ in
|
||||||
|
guard let self = self else { return nil}
|
||||||
|
guard let model = dataArr[section].first else { return nil }
|
||||||
|
|
||||||
|
if model.buy_type == .subCoins {
|
||||||
|
return self.coinsBigLayoutSection()
|
||||||
|
} else if model.size == .big {
|
||||||
|
return self.bigLayoutSection()
|
||||||
|
} else {
|
||||||
|
return self.smallLayoutSection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layout.configuration = config
|
||||||
|
|
||||||
|
return layout
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionView: FACollectionView = {
|
||||||
|
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
|
collectionView.delegate = self
|
||||||
|
collectionView.dataSource = self
|
||||||
|
collectionView.clipsToBounds = false
|
||||||
|
collectionView.isScrollEnabled = false
|
||||||
|
collectionView.register(FAStoreCoinsBigCell.self, forCellWithReuseIdentifier: "FAStoreCoinsBigCell")
|
||||||
|
collectionView.register(FAStoreCoinsSmallCell.self, forCellWithReuseIdentifier: "FAStoreCoinsSmallCell")
|
||||||
|
collectionView.register(FAStoreCoinsPackCell.self, forCellWithReuseIdentifier: "FAStoreCoinsPackCell")
|
||||||
|
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
|
return collectionView
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
collectionView.removeObserver(self, forKeyPath: "contentSize")
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
let height = self.collectionView.contentSize.height + 1
|
||||||
|
self.collectionView.snp.updateConstraints { make in
|
||||||
|
make.height.equalTo(height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDataArr(_ arr: [FAPayItem]) {
|
||||||
|
self.dataArr.removeAll()
|
||||||
|
var bigArr: [FAPayItem] = []
|
||||||
|
var smallArr: [FAPayItem] = []
|
||||||
|
var coinPackArr: [FAPayItem] = []
|
||||||
|
|
||||||
|
arr.forEach {
|
||||||
|
if $0.buy_type == .subCoins {
|
||||||
|
coinPackArr.append($0)
|
||||||
|
} else if $0.size == .big {
|
||||||
|
bigArr.append($0)
|
||||||
|
} else {
|
||||||
|
smallArr.append($0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bigArr.count > 0 {
|
||||||
|
self.dataArr.append(bigArr)
|
||||||
|
}
|
||||||
|
if coinPackArr.count > 0 {
|
||||||
|
self.dataArr.append(coinPackArr)
|
||||||
|
}
|
||||||
|
if smallArr.count > 0 {
|
||||||
|
self.dataArr.append(smallArr)
|
||||||
|
}
|
||||||
|
self.collectionView.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAStoreCoinsView {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(collectionView)
|
||||||
|
|
||||||
|
collectionView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
make.height.equalTo(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAStoreCoinsView {
|
||||||
|
|
||||||
|
private func bigLayoutSection() -> NSCollectionLayoutSection {
|
||||||
|
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1)))
|
||||||
|
|
||||||
|
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(100)), subitems: [item])
|
||||||
|
group.interItemSpacing = .fixed(1)
|
||||||
|
|
||||||
|
let layoutSection = NSCollectionLayoutSection(group: group)
|
||||||
|
layoutSection.interGroupSpacing = 10
|
||||||
|
layoutSection.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
|
||||||
|
return layoutSection
|
||||||
|
}
|
||||||
|
|
||||||
|
private func smallLayoutSection() -> NSCollectionLayoutSection {
|
||||||
|
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(1 / 3), heightDimension: .fractionalHeight(1)))
|
||||||
|
|
||||||
|
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(121)), subitems: [item])
|
||||||
|
group.interItemSpacing = .fixed(8)
|
||||||
|
|
||||||
|
let layoutSection = NSCollectionLayoutSection(group: group)
|
||||||
|
layoutSection.interGroupSpacing = 10
|
||||||
|
layoutSection.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
|
||||||
|
return layoutSection
|
||||||
|
}
|
||||||
|
|
||||||
|
private func coinsBigLayoutSection() -> NSCollectionLayoutSection {
|
||||||
|
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)))
|
||||||
|
|
||||||
|
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(84)), subitems: [item])
|
||||||
|
|
||||||
|
|
||||||
|
let layoutSection = NSCollectionLayoutSection(group: group)
|
||||||
|
layoutSection.interGroupSpacing = 10
|
||||||
|
layoutSection.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
|
||||||
|
return layoutSection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||||
|
extension FAStoreCoinsView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
let model = dataArr[indexPath.section][indexPath.row]
|
||||||
|
|
||||||
|
var identifier = "FAStoreCoinsBigCell"
|
||||||
|
if model.buy_type == .subCoins {
|
||||||
|
identifier = "FAStoreCoinsPackCell"
|
||||||
|
} else if model.size == .small {
|
||||||
|
identifier = "FAStoreCoinsSmallCell"
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! FAStoreCoinsCell
|
||||||
|
cell.model = model
|
||||||
|
cell.fa_isSelected = selectedIndexPath == indexPath
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return dataArr[section].count
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||||
|
return dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
|
let model = dataArr[indexPath.section][indexPath.row]
|
||||||
|
self.selectedIndexPath = indexPath
|
||||||
|
collectionView.reloadData()
|
||||||
|
|
||||||
|
if model.buy_type == .subCoins {
|
||||||
|
let view = FACoinPackConfirmView()
|
||||||
|
view.model = model
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
|
self.buyFinishHandle?()
|
||||||
|
}
|
||||||
|
view.present(in: nil)
|
||||||
|
} else {
|
||||||
|
FAIapManager.manager.start(model: model, shortPlayId: self.shortPlayId, videoId: self.videoId) { [weak self] finish in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if finish {
|
||||||
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
|
self.buyFinishHandle?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
278
Fableon/Object/Class/Store/V/FAStoreVipCell.swift
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
//
|
||||||
|
// FAStoreVipCell.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/27.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import YYText
|
||||||
|
|
||||||
|
class FAStoreVipCell: UICollectionViewCell {
|
||||||
|
|
||||||
|
var item: FAPayItem? {
|
||||||
|
didSet {
|
||||||
|
nameLabel.text = item?.title
|
||||||
|
desLabel.text = item?.fa_description
|
||||||
|
// coinTimeLabel.text = item?.auto_sub
|
||||||
|
|
||||||
|
if let coins = item?.send_coins, coins > 0 {
|
||||||
|
sendCoinLabel.text = "+\("extra".localized) \(coins)"
|
||||||
|
sendCoinLabel.isHidden = false
|
||||||
|
coinImageView.isHidden = false
|
||||||
|
} else {
|
||||||
|
sendCoinLabel.isHidden = true
|
||||||
|
coinImageView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let currency = item?.currency ?? ""
|
||||||
|
let oldPrice = item?.price ?? ""
|
||||||
|
let time = "/\(item?.getTimeString() ?? "")"
|
||||||
|
var offerPrice: String?
|
||||||
|
|
||||||
|
if item?.discount_type == 1, let offer = item?.introductionaryOffer {
|
||||||
|
offerPrice = offer.price.stringValue
|
||||||
|
} else if item?.discount_type == 2, let offer = item?.promotionalOffers?.first {
|
||||||
|
offerPrice = offer.price.stringValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if let price = offerPrice {
|
||||||
|
let priceString = NSMutableAttributedString(string: currency + price)
|
||||||
|
priceString.yy_font = .font(ofSize: 28, weight: .init(800))
|
||||||
|
priceLabel.attributedText = priceString
|
||||||
|
|
||||||
|
let oldPriceStr = NSMutableAttributedString(string: oldPrice)
|
||||||
|
oldPriceStr.yy_strikethroughColor = discountLabel.textColor
|
||||||
|
oldPriceStr.yy_strikethroughStyle = .single
|
||||||
|
discountLabel.attributedText = oldPriceStr
|
||||||
|
|
||||||
|
discountLabel.isHidden = false
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let priceString = NSMutableAttributedString(string: currency + oldPrice)
|
||||||
|
priceString.yy_font = .font(ofSize: 28, weight: .init(800))
|
||||||
|
let timeString = NSMutableAttributedString(string: time)
|
||||||
|
timeString.yy_font = .font(ofSize: 14, weight: .medium)
|
||||||
|
timeString.yy_baselineOffset = 1
|
||||||
|
priceString.append(timeString)
|
||||||
|
|
||||||
|
priceLabel.attributedText = priceString
|
||||||
|
discountLabel.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
switch item?.vip_type_key {
|
||||||
|
case .week:
|
||||||
|
bgView.image = UIImage(named: "vip_bg_image_week")
|
||||||
|
bgIconView.image = UIImage(named: "vip_bg_icon_week")
|
||||||
|
vipImageView.image = UIImage(named: "vip_image_week")
|
||||||
|
subBgView.backgroundColor = .E_9_F_0_FE
|
||||||
|
nameBgView.backgroundColor = ._6398_FF
|
||||||
|
priceLabel.textColors = [UIColor.FFFFFF.cgColor, UIColor.FFFFFF.cgColor]
|
||||||
|
desLabel.textColor = .FFFFFF
|
||||||
|
sendCoinLabel.textColor = ._679_AFF
|
||||||
|
|
||||||
|
case .month:
|
||||||
|
bgView.image = UIImage(named: "vip_bg_image_month")
|
||||||
|
bgIconView.image = UIImage(named: "vip_bg_icon_month")
|
||||||
|
vipImageView.image = UIImage(named: "vip_image_month")
|
||||||
|
subBgView.backgroundColor = .E_2_F_9_FF
|
||||||
|
nameBgView.backgroundColor = ._58_D_4_F_1
|
||||||
|
priceLabel.textColors = [UIColor.FFFFFF.cgColor, UIColor.FFFFFF.cgColor]
|
||||||
|
desLabel.textColor = .FFFFFF
|
||||||
|
sendCoinLabel.textColor = ._2_DD_7_FF
|
||||||
|
|
||||||
|
case .quarter:
|
||||||
|
bgView.image = UIImage(named: "vip_bg_image_quarter")
|
||||||
|
bgIconView.image = UIImage(named: "vip_bg_icon_quarter")
|
||||||
|
vipImageView.image = UIImage(named: "vip_image_quarter")
|
||||||
|
subBgView.backgroundColor = .EFE_8_FF
|
||||||
|
nameBgView.backgroundColor = ._8_D_5_BF_6
|
||||||
|
priceLabel.textColors = [UIColor.FFFFFF.cgColor, UIColor.FFFFFF.cgColor]
|
||||||
|
desLabel.textColor = .FFFFFF
|
||||||
|
sendCoinLabel.textColor = ._8853_FF
|
||||||
|
|
||||||
|
case .year:
|
||||||
|
bgView.image = UIImage(named: "vip_bg_image_year")
|
||||||
|
bgIconView.image = UIImage(named: "vip_bg_icon_year")
|
||||||
|
vipImageView.image = UIImage(named: "vip_image_year")
|
||||||
|
subBgView.backgroundColor = .FFF_8_D_0
|
||||||
|
nameBgView.backgroundColor = .F_4_A_93_E
|
||||||
|
priceLabel.textColors = [UIColor.DB_9_E_42.cgColor, UIColor._56280_F.cgColor]
|
||||||
|
desLabel.textColor = ._814_E_20
|
||||||
|
sendCoinLabel.textColor = .C_78_C_3_B
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
coinTimeLabel.textColor = sendCoinLabel.textColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var bgView: UIImageView = {
|
||||||
|
let view = UIImageView()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bgIconView: UIImageView = {
|
||||||
|
let view = UIImageView()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var subBgView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.fa_setRoundedCorner(topLeft: 0, topRight: 0, bottomLeft: 15, bottomRight: 15)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var nameBgView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.layer.cornerRadius = 4
|
||||||
|
view.layer.masksToBounds = true
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var nameLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .init(800))
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var vipImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView()
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceLabel: FALabel = {
|
||||||
|
let label = FALabel()
|
||||||
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var discountLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 16, weight: .medium)
|
||||||
|
label.textColor = .FFFFFF.withAlphaComponent(0.4)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var desLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .regular)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var sendCoinLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_08"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinTimeLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 10, weight: .regular)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAStoreVipCell {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
contentView.addSubview(bgView)
|
||||||
|
contentView.addSubview(subBgView)
|
||||||
|
bgView.addSubview(bgIconView)
|
||||||
|
bgView.addSubview(nameBgView)
|
||||||
|
nameBgView.addSubview(nameLabel)
|
||||||
|
bgView.addSubview(vipImageView)
|
||||||
|
bgView.addSubview(priceLabel)
|
||||||
|
bgView.addSubview(desLabel)
|
||||||
|
bgView.addSubview(discountLabel)
|
||||||
|
subBgView.addSubview(sendCoinLabel)
|
||||||
|
subBgView.addSubview(coinImageView)
|
||||||
|
subBgView.addSubview(coinTimeLabel)
|
||||||
|
|
||||||
|
bgView.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
subBgView.snp.makeConstraints { make in
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
make.top.equalTo(bgView.snp.bottom)
|
||||||
|
make.left.equalToSuperview().offset(30)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
bgIconView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
nameBgView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.top.equalToSuperview().offset(13)
|
||||||
|
make.height.equalTo(18)
|
||||||
|
}
|
||||||
|
|
||||||
|
nameLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
vipImageView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.right.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.top.equalToSuperview().offset(36)
|
||||||
|
}
|
||||||
|
|
||||||
|
desLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.bottom.equalToSuperview().offset(-10)
|
||||||
|
}
|
||||||
|
|
||||||
|
discountLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(priceLabel.snp.right).offset(4)
|
||||||
|
make.centerY.equalTo(priceLabel).offset(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCoinLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinImageView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalTo(sendCoinLabel.snp.right).offset(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinTimeLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.right.equalToSuperview().offset(-11)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
113
Fableon/Object/Class/Store/V/FAStoreVipView.swift
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
//
|
||||||
|
// FAStoreVipView.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/27.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAStoreVipView: UIView {
|
||||||
|
|
||||||
|
var dataArr: [FAPayItem] = [] {
|
||||||
|
didSet {
|
||||||
|
collectionView.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
|
var buyFinishHandle: (() -> Void)?
|
||||||
|
|
||||||
|
private lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
||||||
|
|
||||||
|
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)))
|
||||||
|
|
||||||
|
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(110)), subitems: [item])
|
||||||
|
group.interItemSpacing = .fixed(14)
|
||||||
|
|
||||||
|
let layoutSection = NSCollectionLayoutSection(group: group)
|
||||||
|
layoutSection.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
|
||||||
|
|
||||||
|
let config = UICollectionViewCompositionalLayoutConfiguration()
|
||||||
|
|
||||||
|
let layout = UICollectionViewCompositionalLayout(section: layoutSection)
|
||||||
|
layout.configuration = config
|
||||||
|
|
||||||
|
return layout
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionView: FACollectionView = {
|
||||||
|
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
|
collectionView.delegate = self
|
||||||
|
collectionView.dataSource = self
|
||||||
|
collectionView.isScrollEnabled = false
|
||||||
|
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
|
collectionView.register(FAStoreVipCell.self, forCellWithReuseIdentifier: "cell")
|
||||||
|
return collectionView
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
collectionView.removeObserver(self, forKeyPath: "contentSize")
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
let height = self.collectionView.contentSize.height + 1
|
||||||
|
self.collectionView.snp.updateConstraints { make in
|
||||||
|
make.height.equalTo(height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAStoreVipView {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(collectionView)
|
||||||
|
|
||||||
|
collectionView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
make.height.equalTo(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||||
|
extension FAStoreVipView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FAStoreVipCell
|
||||||
|
cell.item = self.dataArr[indexPath.row]
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
|
let model = self.dataArr[indexPath.row]
|
||||||
|
|
||||||
|
FAIapManager.manager.start(model: model, shortPlayId: self.shortPlayId, videoId: self.videoId) { [weak self] finish in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if finish {
|
||||||
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
|
self.buyFinishHandle?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// FAAdjustStateManager.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAAdjustStateManager {
|
||||||
|
static let manager = FAAdjustStateManager()
|
||||||
|
|
||||||
|
var webpageURL: URL?
|
||||||
|
///是否需要重试
|
||||||
|
var isNeedRetry = false
|
||||||
|
|
||||||
|
var allowOpenMessage = true
|
||||||
|
|
||||||
|
var isOpenApp = false
|
||||||
|
|
||||||
|
var idfaAuthorizationFinish = false
|
||||||
|
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@ import LYEmptyView
|
|||||||
|
|
||||||
struct FAEmpty {
|
struct FAEmpty {
|
||||||
|
|
||||||
static func fa_emptyView(image: UIImage?, title: String?) -> LYEmptyView {
|
static func fa_emptyView(image: UIImage? = UIImage(named: "__shop-72"), title: String? = "empty_title_02".localized) -> LYEmptyView {
|
||||||
|
|
||||||
let view = LYEmptyView.emptyActionView(with: image, titleStr: title, detailStr: nil, btnTitleStr: nil) {
|
let view = LYEmptyView.emptyActionView(with: image, titleStr: title, detailStr: nil, btnTitleStr: nil) {
|
||||||
// btnClickBlock?()
|
// btnClickBlock?()
|
||||||
|
|||||||
292
Fableon/Object/Libs/FAIap/FAIapManager.swift
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
//
|
||||||
|
// FAIapManager.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import StoreKit
|
||||||
|
|
||||||
|
class FAIapManager {
|
||||||
|
typealias CompletionHandler = ((_ finish: Bool) -> Void)
|
||||||
|
///内购模版前缀
|
||||||
|
static let IAPPrefix = "fableon"
|
||||||
|
|
||||||
|
|
||||||
|
static let manager = FAIapManager()
|
||||||
|
|
||||||
|
///成功回调
|
||||||
|
private var completionHandler: CompletionHandler?
|
||||||
|
|
||||||
|
private var shortPlayId: String?
|
||||||
|
private var videoId: String?
|
||||||
|
|
||||||
|
private lazy var iapManager: JXIAPManager = {
|
||||||
|
let manager = JXIAPManager()
|
||||||
|
manager.delegate = self
|
||||||
|
return manager
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var orderCode: String?
|
||||||
|
private var payId: String?
|
||||||
|
|
||||||
|
///预加载数据
|
||||||
|
private var payRequest: FAPayDataRequest?
|
||||||
|
var payDateModel: FAPayDateModel?
|
||||||
|
|
||||||
|
|
||||||
|
///恢复购买使用
|
||||||
|
///等待恢复的数据
|
||||||
|
private var waitRestoreModel: FAWaitRestoreModel? = UserDefaults.fa_object(forKey: kFAWaitRestoreIAPDefaultsKey, as: FAWaitRestoreModel.self)
|
||||||
|
|
||||||
|
|
||||||
|
///开始内购
|
||||||
|
func start(model: FAPayItem, shortPlayId: String? = nil, videoId: String? = nil, hudShowView: UIView? = nil, handler: CompletionHandler? = nil) {
|
||||||
|
|
||||||
|
if let _ = self.waitRestoreModel {
|
||||||
|
FAToast.show(text: "pay_error_6".localized)
|
||||||
|
handler?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let payId = model.id else {
|
||||||
|
handler?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.shortPlayId = shortPlayId
|
||||||
|
self.videoId = videoId
|
||||||
|
self.completionHandler = handler
|
||||||
|
self.waitRestoreModel = FAWaitRestoreModel()
|
||||||
|
self.waitRestoreModel?.buyType = model.buy_type
|
||||||
|
let productId = getProductId(templateId: model.ios_template_id) ?? ""
|
||||||
|
var isDiscount = false
|
||||||
|
var identifierDiscount: String? = nil
|
||||||
|
if model.discount_type == 1, let _ = model.introductionaryOffer {
|
||||||
|
isDiscount = true
|
||||||
|
} else if model.discount_type == 2, let discount = model.promotionalOffers?.first {
|
||||||
|
isDiscount = true
|
||||||
|
identifierDiscount = discount.identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
FAHUD.show(containerView: hudShowView)
|
||||||
|
|
||||||
|
FAStoreAPI.requestCreateOrder(payId: payId, shortPlayId: shortPlayId ?? "0", videoId: videoId ?? "0", isDiscount: isDiscount, identifierDiscount: identifierDiscount) { orderModel in
|
||||||
|
guard let orderModel = orderModel else {
|
||||||
|
FAHUD.dismiss()
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
self.completionHandler?(false)
|
||||||
|
self.clean()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.orderCode = orderModel.order_code
|
||||||
|
self.payId = payId
|
||||||
|
self.waitRestoreModel?.payId = payId
|
||||||
|
self.waitRestoreModel?.orderCode = orderModel.order_code
|
||||||
|
|
||||||
|
var discount: SKPaymentDiscount? = nil
|
||||||
|
|
||||||
|
if let identifierDiscount = identifierDiscount,
|
||||||
|
let signData = orderModel.discount?.sign_data,
|
||||||
|
let keyIdentifier = signData.keyIdentifier,
|
||||||
|
let nonce = UUID(uuidString: signData.nonce ?? ""),
|
||||||
|
let signature = signData.signature,
|
||||||
|
let timestamp = signData.timestamp
|
||||||
|
{
|
||||||
|
discount = SKPaymentDiscount(identifier: identifierDiscount,
|
||||||
|
keyIdentifier: keyIdentifier,
|
||||||
|
nonce: nonce,
|
||||||
|
signature: signature,
|
||||||
|
timestamp: NSNumber(value: timestamp))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iapManager.start(productId: productId, orderId: self.orderCode ?? "", applicationUsername: orderModel.discount?.sign_data?.applicationUsername, discount: discount)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func restore(isLoding: Bool = true, shortPlayId: String? = nil, videoId: String? = nil, completer: ((_ isFinish: Bool, _ buyType: FAStoreAPI.BuyType?) -> Void)?) {
|
||||||
|
let buyType = self.waitRestoreModel?.buyType
|
||||||
|
|
||||||
|
guard let waitRestoreModel = self.waitRestoreModel,
|
||||||
|
let orderCode = waitRestoreModel.orderCode,
|
||||||
|
let payId = waitRestoreModel.payId,
|
||||||
|
let receipt = waitRestoreModel.receipt,
|
||||||
|
let transactionId = waitRestoreModel.transactionId
|
||||||
|
else {
|
||||||
|
if isLoding {
|
||||||
|
FAToast.show(text: "pay_error_5".localized)
|
||||||
|
}
|
||||||
|
completer?(false, buyType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLoding {
|
||||||
|
FAHUD.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionId, purchaseToken: receipt)
|
||||||
|
|
||||||
|
let statParamenters: [String : Any] = [
|
||||||
|
"type" : isLoding ? "manual" : "auto",
|
||||||
|
"pay_data" : verifyData.toJsonString() ?? ""
|
||||||
|
]
|
||||||
|
FAStatAPI.requestEventStat(orderCode: orderCode, shortPlayId: shortPlayId, videoId: videoId, eventKey: .payRestore, errorMsg: "restore", otherParamenters: statParamenters)
|
||||||
|
|
||||||
|
FAStoreAPI.requestVerifyOrder(parameters: verifyData) { response in
|
||||||
|
if isLoding {
|
||||||
|
FAHUD.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let model = response.data else {
|
||||||
|
completer?(false, buyType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
UserDefaults.fa_setObject(nil, forKey: kFAWaitRestoreIAPDefaultsKey)
|
||||||
|
|
||||||
|
if model.status == "success" {
|
||||||
|
if buyType == .subVip {
|
||||||
|
FALogin.manager.userInfo?.is_vip = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLoding {
|
||||||
|
FAToast.show(text: "success".localized)
|
||||||
|
}
|
||||||
|
completer?(true, buyType)
|
||||||
|
if buyType == .subVip {
|
||||||
|
NotificationCenter.default.post(name: FAIapManager.buyVipFinishNotification, object: nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completer?(false, buyType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func getProductId(templateId: String?) -> String? {
|
||||||
|
guard let templateId = templateId else { return nil }
|
||||||
|
return FAIapManager.IAPPrefix + "." + templateId
|
||||||
|
}
|
||||||
|
|
||||||
|
func clean() {
|
||||||
|
self.orderCode = nil
|
||||||
|
self.payId = nil
|
||||||
|
self.shortPlayId = nil
|
||||||
|
self.videoId = nil
|
||||||
|
self.completionHandler = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: JXIAPManagerDelegate
|
||||||
|
extension FAIapManager: JXIAPManagerDelegate {
|
||||||
|
|
||||||
|
func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String) {
|
||||||
|
guard let orderCode = self.orderCode, let payId = self.payId else {
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
self.completionHandler?(false)
|
||||||
|
self.clean()
|
||||||
|
FAHUD.dismiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.waitRestoreModel?.productId = productId
|
||||||
|
self.waitRestoreModel?.receipt = receipt
|
||||||
|
self.waitRestoreModel?.transactionId = transactionIdentifier
|
||||||
|
|
||||||
|
UserDefaults.fa_setObject(self.waitRestoreModel, forKey: kFAWaitRestoreIAPDefaultsKey)
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionIdentifier, purchaseToken: receipt)
|
||||||
|
#else
|
||||||
|
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionIdentifier, purchaseToken: receipt)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FAStoreAPI.requestVerifyOrder(parameters: verifyData) { response in
|
||||||
|
FAHUD.dismiss()
|
||||||
|
|
||||||
|
guard let model = response.data else {
|
||||||
|
FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: verifyData.toJsonString())
|
||||||
|
self.completionHandler?(false)
|
||||||
|
self.clean()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let buyType = self.waitRestoreModel?.buyType
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
UserDefaults.fa_setObject(nil, forKey: kFAWaitRestoreIAPDefaultsKey)
|
||||||
|
|
||||||
|
if model.status == "success" {
|
||||||
|
if buyType == .subVip {
|
||||||
|
FALogin.manager.userInfo?.is_vip = true
|
||||||
|
}
|
||||||
|
|
||||||
|
FAToast.show(text: "success".localized)
|
||||||
|
self.completionHandler?(true)
|
||||||
|
if buyType == .subVip {
|
||||||
|
NotificationCenter.default.post(name: FAIapManager.buyVipFinishNotification, object: nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FAToast.show(text: "pay_error_4".localized)
|
||||||
|
FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: verifyData.toJsonString())
|
||||||
|
self.completionHandler?(false)
|
||||||
|
}
|
||||||
|
self.clean()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func jx_iapPayFailed(productId: String, code: JXIAPManagerCode, msg: String?) {
|
||||||
|
FAHUD.dismiss()
|
||||||
|
|
||||||
|
if code == .noProduct {
|
||||||
|
FAToast.show(text: "pay_error_2".localized)
|
||||||
|
} else if code == .cancelled {
|
||||||
|
FAToast.show(text: "pay_error_3".localized)
|
||||||
|
}
|
||||||
|
|
||||||
|
if code == .cancelled {
|
||||||
|
FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCancel, errorMsg: "user cancel")
|
||||||
|
} else {
|
||||||
|
FAStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payError, errorMsg: msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.completionHandler?(false)
|
||||||
|
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
self.clean()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAIapManager {
|
||||||
|
|
||||||
|
func getVerifyOrderParameters(orderCode: String, payId: String, transactionId: String, purchaseToken: String) -> [String : Any] {
|
||||||
|
let parameters: [String : Any] = [
|
||||||
|
"order_code" : orderCode,
|
||||||
|
"pay_setting_id" : payId,
|
||||||
|
"pkg_name" : kFAAPPBundleIdentifier,
|
||||||
|
"transaction_id": transactionId,
|
||||||
|
"purchases_token" : purchaseToken
|
||||||
|
]
|
||||||
|
return parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
///预加载支付项
|
||||||
|
func preloadingProducts() {
|
||||||
|
JXIAPManager.manager.fetchReceipt { _ in
|
||||||
|
self.payRequest = FAPayDataRequest()
|
||||||
|
self.payRequest?.requestProducts(isLoding: false, isToast: false) { model in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAIapManager {
|
||||||
|
///成功购买会员
|
||||||
|
@objc static let buyVipFinishNotification = NSNotification.Name(rawValue: "FAIapManager.buyVipFinishNotification")
|
||||||
|
|
||||||
|
}
|
||||||
37
Fableon/Object/Libs/FAIap/FAIapOrderModel.swift
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// FAIapOrderModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct FAIapOrderModel: SmartCodable {
|
||||||
|
|
||||||
|
var code: Int?
|
||||||
|
var message: String?
|
||||||
|
var order_code: String?
|
||||||
|
var is_backhaul: String?
|
||||||
|
var money: String?
|
||||||
|
var discount: FAIapOrderDiscountModel?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FAIapOrderDiscountModel: SmartCodable {
|
||||||
|
|
||||||
|
var discount_code: String?
|
||||||
|
var is_discount: Bool?
|
||||||
|
var sign_data: FAIapOrderDiscountSign?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FAIapOrderDiscountSign: SmartCodable {
|
||||||
|
|
||||||
|
var keyIdentifier: String?
|
||||||
|
var nonce: String?
|
||||||
|
var timestamp: TimeInterval?
|
||||||
|
var applicationUsername: String?
|
||||||
|
var signature: String?
|
||||||
|
}
|
||||||
|
|
||||||
17
Fableon/Object/Libs/FAIap/FAIapVerifyModel.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// FAIapVerifyModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct FAIapVerifyModel: SmartCodable {
|
||||||
|
|
||||||
|
var money: String?
|
||||||
|
var status: String?
|
||||||
|
var is_backhaul: String?
|
||||||
|
var code: String?
|
||||||
|
}
|
||||||
181
Fableon/Object/Libs/FAIap/FAPayDataRequest.swift
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
//
|
||||||
|
// FAPayDataRequest.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import StoreKit
|
||||||
|
|
||||||
|
class FAPayDataRequest: NSObject {
|
||||||
|
|
||||||
|
private var oldTemplateModel: FAPayDateModel?
|
||||||
|
private(set) var newTemplateModel: FAPayDateModel?
|
||||||
|
|
||||||
|
private var payAlertModel: FAPayAlertModel?
|
||||||
|
|
||||||
|
private var completerBlock: ((_ model: FAPayDateModel?) -> Void)?
|
||||||
|
private var payAlertBlock: ((_ model: FAPayAlertModel?) -> Void)?
|
||||||
|
|
||||||
|
private var isLoding = false
|
||||||
|
private var isToast = false
|
||||||
|
|
||||||
|
|
||||||
|
func requestProducts(isLoding: Bool = false, isToast: Bool = true, completer: @escaping ((_ model: FAPayDateModel?) -> Void)) {
|
||||||
|
self.payAlertBlock = nil
|
||||||
|
self.completerBlock = completer
|
||||||
|
self.isLoding = isLoding
|
||||||
|
self.isToast = isToast
|
||||||
|
|
||||||
|
if isLoding {
|
||||||
|
FAHUD.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
FAStoreAPI.requestPayTemplate(isToast: isToast) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else {
|
||||||
|
if isLoding {
|
||||||
|
FAHUD.dismiss()
|
||||||
|
}
|
||||||
|
self.completerBlock?(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.oldTemplateModel = model
|
||||||
|
|
||||||
|
var productIdArr: [String] = []
|
||||||
|
model.list_sub_vip?.forEach { item in
|
||||||
|
productIdArr.append(FAIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||||
|
}
|
||||||
|
model.list_coins?.forEach { item in
|
||||||
|
productIdArr.append(FAIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||||
|
}
|
||||||
|
|
||||||
|
let set = Set(productIdArr)
|
||||||
|
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||||
|
productsRequest.delegate = self
|
||||||
|
productsRequest.start()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestCoinAlertData(completer: @escaping ((_ model: FAPayAlertModel?) -> Void)) {
|
||||||
|
self.completerBlock = nil
|
||||||
|
self.payAlertBlock = completer
|
||||||
|
|
||||||
|
// BRStoreAPI.requestCoinAlertInfo { [weak self] model in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
//
|
||||||
|
// guard let model = model else {
|
||||||
|
// self.payAlertBlock?(nil)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// self.payAlertModel = model
|
||||||
|
//
|
||||||
|
// let productId = BRIAP.manager.getProductId(templateId: model.info?.ios_template_id) ?? ""
|
||||||
|
//
|
||||||
|
// let set = Set([productId])
|
||||||
|
// let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||||
|
// productsRequest.delegate = self
|
||||||
|
// productsRequest.start()
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///挽留信息
|
||||||
|
func requestRetainVipPayInfo(completer: ((_ model: FAPayAlertModel?) -> Void)?) {
|
||||||
|
self.completerBlock = nil
|
||||||
|
self.payAlertBlock = completer
|
||||||
|
|
||||||
|
// FAStoreAPI.requestRetainVipPayInfo { [weak self] model in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// guard let model = model else {
|
||||||
|
// self.payAlertBlock?(nil)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// self.payAlertModel = model
|
||||||
|
//
|
||||||
|
// let productId = BRIAP.manager.getProductId(templateId: model.info?.ios_template_id) ?? ""
|
||||||
|
//
|
||||||
|
// let set = Set([productId])
|
||||||
|
// let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||||
|
// productsRequest.delegate = self
|
||||||
|
// productsRequest.start()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: SKProductsRequestDelegate
|
||||||
|
extension FAPayDataRequest: SKProductsRequestDelegate {
|
||||||
|
|
||||||
|
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||||
|
if isLoding {
|
||||||
|
FAHUD.dismiss()
|
||||||
|
}
|
||||||
|
let products = response.products
|
||||||
|
|
||||||
|
if let block = self.completerBlock {
|
||||||
|
guard let templateModel = self.oldTemplateModel else { return }
|
||||||
|
|
||||||
|
var newCoinList: [FAPayItem] = []
|
||||||
|
var newVipList: [FAPayItem] = []
|
||||||
|
|
||||||
|
templateModel.list_coins?.forEach { item in
|
||||||
|
let productId = FAIapManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||||
|
for product in products {
|
||||||
|
if productId == product.productIdentifier {
|
||||||
|
item.price = product.price.stringValue
|
||||||
|
item.currency = product.priceLocale.currencySymbol
|
||||||
|
item.product = product
|
||||||
|
newCoinList.append(item)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templateModel.list_sub_vip?.forEach { item in
|
||||||
|
let productId = FAIapManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||||
|
for product in products {
|
||||||
|
if productId == product.productIdentifier {
|
||||||
|
item.price = product.price.stringValue
|
||||||
|
item.currency = product.priceLocale.currencySymbol
|
||||||
|
item.product = product
|
||||||
|
newVipList.append(item)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
templateModel.list_coins = newCoinList
|
||||||
|
templateModel.list_sub_vip = newVipList
|
||||||
|
|
||||||
|
self.newTemplateModel = templateModel
|
||||||
|
FAIapManager.manager.payDateModel = templateModel
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
block(templateModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if let block = self.payAlertBlock {
|
||||||
|
guard let coinalertModel = self.payAlertModel else { return }
|
||||||
|
let productId = FAIapManager.manager.getProductId(templateId: coinalertModel.info?.ios_template_id) ?? ""
|
||||||
|
|
||||||
|
for product in products {
|
||||||
|
if productId == product.productIdentifier {
|
||||||
|
coinalertModel.info?.price = product.price.stringValue
|
||||||
|
coinalertModel.info?.currency = product.priceLocale.currencySymbol
|
||||||
|
coinalertModel.info?.product = product
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
block(coinalertModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
49
Fableon/Object/Libs/FAIap/FAWaitRestoreModel.swift
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// FAWaitRestoreModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class FAWaitRestoreModel: NSObject, NSSecureCoding {
|
||||||
|
|
||||||
|
|
||||||
|
var orderCode: String?
|
||||||
|
var payId: String?
|
||||||
|
var productId: String?
|
||||||
|
var receipt: String?
|
||||||
|
var buyType: FAStoreAPI.BuyType?
|
||||||
|
var transactionId: String?
|
||||||
|
|
||||||
|
|
||||||
|
required override init() { }
|
||||||
|
|
||||||
|
static var supportsSecureCoding: Bool {
|
||||||
|
get {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(with coder: NSCoder) {
|
||||||
|
coder.encode(orderCode, forKey: "orderCode")
|
||||||
|
coder.encode(payId, forKey: "payId")
|
||||||
|
coder.encode(productId, forKey: "productId")
|
||||||
|
coder.encode(receipt, forKey: "receipt")
|
||||||
|
coder.encode(buyType?.rawValue, forKey: "buyType")
|
||||||
|
coder.encode(transactionId, forKey: "transactionId")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init()
|
||||||
|
orderCode = coder.decodeObject(of: NSString.self, forKey: "orderCode") as? String
|
||||||
|
payId = coder.decodeObject(of: NSString.self, forKey: "payId") as? String
|
||||||
|
productId = coder.decodeObject(of: NSString.self, forKey: "productId") as? String
|
||||||
|
receipt = coder.decodeObject(of: NSString.self, forKey: "receipt") as? String
|
||||||
|
transactionId = coder.decodeObject(of: NSString.self, forKey: "transactionId") as? String
|
||||||
|
if let type = coder.decodeObject(of: NSString.self, forKey: "buyType") as? String {
|
||||||
|
buyType = FAStoreAPI.BuyType(rawValue: type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
215
Fableon/Object/Libs/JXIAPManager/JXIAPManager.swift
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
//
|
||||||
|
// JXIAPManager.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/10/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import StoreKit
|
||||||
|
|
||||||
|
@objc protocol JXIAPManagerDelegate {
|
||||||
|
/// 购买成功
|
||||||
|
@objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String)
|
||||||
|
/// 购买失败
|
||||||
|
@objc optional func jx_iapPayFailed(productId: String, code: JXIAPManagerCode, msg: String?)
|
||||||
|
/// 恢复商品(仅限永久有效商品)
|
||||||
|
@objc optional func iapPayRestore(productIds: [String], transactionIds: [String])
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc enum JXIAPManagerCode: Int {
|
||||||
|
///未知错误
|
||||||
|
case unknown
|
||||||
|
///取消交易
|
||||||
|
case cancelled
|
||||||
|
///没有商品
|
||||||
|
case noProduct
|
||||||
|
}
|
||||||
|
|
||||||
|
class JXIAPManager: NSObject {
|
||||||
|
|
||||||
|
|
||||||
|
static let manager: JXIAPManager = JXIAPManager()
|
||||||
|
|
||||||
|
weak var delegate: JXIAPManagerDelegate?
|
||||||
|
|
||||||
|
private var payment: SKPayment?
|
||||||
|
|
||||||
|
private var product: SKProduct?
|
||||||
|
private var productId: String?
|
||||||
|
|
||||||
|
private var discount: SKPaymentDiscount?
|
||||||
|
private var orderId: String?
|
||||||
|
private var applicationUsername: String?
|
||||||
|
|
||||||
|
var receiptCompletion: ((URL?) -> Void)?
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
SKPaymentQueue.default().add(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func start(productId: String, orderId: String, applicationUsername: String?, discount: SKPaymentDiscount? = nil) {
|
||||||
|
self.product = nil
|
||||||
|
self.productId = productId
|
||||||
|
self.orderId = orderId
|
||||||
|
self.discount = discount
|
||||||
|
self.applicationUsername = applicationUsername
|
||||||
|
|
||||||
|
let set = Set([productId])
|
||||||
|
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||||
|
productsRequest.delegate = self
|
||||||
|
productsRequest.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 购买商品
|
||||||
|
private func buyProduct() {
|
||||||
|
guard let product = self.product else { return }
|
||||||
|
|
||||||
|
// 要购买商品,开个小票
|
||||||
|
let payment = SKMutablePayment(product: product)
|
||||||
|
payment.applicationUsername = self.applicationUsername
|
||||||
|
if let discount = self.discount {
|
||||||
|
payment.paymentDiscount = discount
|
||||||
|
self.discount = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.payment = payment
|
||||||
|
|
||||||
|
// 去收银台排队,准备购买
|
||||||
|
SKPaymentQueue.default().add(payment)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- SKProductsRequestDelegate --------------
|
||||||
|
extension JXIAPManager: SKProductsRequestDelegate {
|
||||||
|
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||||
|
guard let product = response.products.first else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let productId = self.productId {
|
||||||
|
self.productId = nil
|
||||||
|
self.delegate?.jx_iapPayFailed?(productId: productId, code: .noProduct, msg: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.product = product
|
||||||
|
|
||||||
|
self.buyProduct()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- SKPaymentTransactionObserver --------------
|
||||||
|
extension JXIAPManager: SKPaymentTransactionObserver {
|
||||||
|
///购买回调
|
||||||
|
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
||||||
|
|
||||||
|
for transaction in transactions {
|
||||||
|
switch transaction.transactionState {
|
||||||
|
case .purchased:
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.completeTransaction(transaction: transaction)
|
||||||
|
}
|
||||||
|
SKPaymentQueue.default().finishTransaction(transaction)
|
||||||
|
|
||||||
|
case .failed:
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.failedTransaction(transaction: transaction)
|
||||||
|
}
|
||||||
|
SKPaymentQueue.default().finishTransaction(transaction)
|
||||||
|
// case .restored:
|
||||||
|
// self.restoreTransaction(transaction: transaction)
|
||||||
|
|
||||||
|
case .purchasing:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
SKPaymentQueue.default().finishTransaction(transaction)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// 恢复购买回调
|
||||||
|
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension JXIAPManager {
|
||||||
|
|
||||||
|
|
||||||
|
private func completeTransaction(transaction: SKPaymentTransaction) {
|
||||||
|
guard let encodeStr = getAppStoreReceipt() else { return }
|
||||||
|
guard let transactionIdentifier = transaction.transactionIdentifier else { return }
|
||||||
|
|
||||||
|
guard let productId = self.productId, productId == transaction.payment.productIdentifier else { return }
|
||||||
|
self.productId = nil
|
||||||
|
self.delegate?.jx_iapPaySuccess?(productId: productId, receipt: encodeStr, transactionIdentifier: transactionIdentifier)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func failedTransaction(transaction: SKPaymentTransaction) {
|
||||||
|
let error = transaction.error as? SKError
|
||||||
|
guard let productId = self.productId else { return }
|
||||||
|
self.productId = nil
|
||||||
|
|
||||||
|
switch error?.code {
|
||||||
|
case SKError.paymentCancelled:
|
||||||
|
self.delegate?.jx_iapPayFailed?(productId: productId, code: .cancelled, msg: error?.localizedDescription)
|
||||||
|
default:
|
||||||
|
self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown, msg: error?.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension JXIAPManager: SKRequestDelegate {
|
||||||
|
|
||||||
|
func getAppStoreReceipt() -> String? {
|
||||||
|
guard let receiptURL = Bundle.main.appStoreReceiptURL else { return nil }
|
||||||
|
let receiptData = NSData(contentsOf: receiptURL)
|
||||||
|
return receiptData?.base64EncodedString(options: .endLineWithLineFeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
///获取凭证
|
||||||
|
func fetchReceipt(completion: @escaping (URL?) -> Void) {
|
||||||
|
let receiptURL = Bundle.main.appStoreReceiptURL
|
||||||
|
if let url = receiptURL, FileManager.default.fileExists(atPath: url.path) {
|
||||||
|
completion(url)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = SKReceiptRefreshRequest()
|
||||||
|
request.delegate = self
|
||||||
|
request.start()
|
||||||
|
// 在 delegate 回调里处理
|
||||||
|
self.receiptCompletion = completion
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestDidFinish(_ request: SKRequest) {
|
||||||
|
let receiptURL = Bundle.main.appStoreReceiptURL
|
||||||
|
if let url = receiptURL, FileManager.default.fileExists(atPath: url.path) {
|
||||||
|
receiptCompletion?(url)
|
||||||
|
} else {
|
||||||
|
receiptCompletion?(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func request(_ request: SKRequest, didFailWithError error: Error) {
|
||||||
|
print("Receipt request failed: \(error)")
|
||||||
|
receiptCompletion?(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xEE",
|
||||||
|
"green" : "0x4C",
|
||||||
|
"red" : "0x11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0xA1",
|
||||||
|
"red" : "0x20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x3C",
|
||||||
|
"green" : "0x22",
|
||||||
|
"red" : "0x29"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0x75",
|
||||||
|
"red" : "0x2D"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0xD7",
|
||||||
|
"red" : "0x2D"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x65",
|
||||||
|
"green" : "0x32",
|
||||||
|
"red" : "0x30"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x5D",
|
||||||
|
"green" : "0x39",
|
||||||
|
"red" : "0x40"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x8E",
|
||||||
|
"green" : "0x4B",
|
||||||
|
"red" : "0x52"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xF1",
|
||||||
|
"green" : "0xA2",
|
||||||
|
"red" : "0x53"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x0F",
|
||||||
|
"green" : "0x28",
|
||||||
|
"red" : "0x56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xF1",
|
||||||
|
"green" : "0xD4",
|
||||||
|
"red" : "0x58"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x7B",
|
||||||
|
"green" : "0x6F",
|
||||||
|
"red" : "0x63"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0x98",
|
||||||
|
"red" : "0x63"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0x9A",
|
||||||
|
"red" : "0x67"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x20",
|
||||||
|
"green" : "0x4E",
|
||||||
|
"red" : "0x81"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0xC0",
|
||||||
|
"red" : "0x84"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0x53",
|
||||||
|
"red" : "0x88"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xF6",
|
||||||
|
"green" : "0x5B",
|
||||||
|
"red" : "0x8D"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFD",
|
||||||
|
"green" : "0xEF",
|
||||||
|
"red" : "0xB8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xF5",
|
||||||
|
"green" : "0xDD",
|
||||||
|
"red" : "0xC5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x3B",
|
||||||
|
"green" : "0x8C",
|
||||||
|
"red" : "0xC7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x42",
|
||||||
|
"green" : "0x9E",
|
||||||
|
"red" : "0xDB"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0xF9",
|
||||||
|
"red" : "0xE2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xE5",
|
||||||
|
"green" : "0xE5",
|
||||||
|
"red" : "0xE5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFE",
|
||||||
|
"green" : "0xF0",
|
||||||
|
"red" : "0xE9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xFF",
|
||||||
|
"green" : "0xE8",
|
||||||
|
"red" : "0xEF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x3E",
|
||||||
|
"green" : "0xA9",
|
||||||
|
"red" : "0xF4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x94",
|
||||||
|
"green" : "0xF4",
|
||||||
|
"red" : "0xF9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x63",
|
||||||
|
"green" : "0xCE",
|
||||||
|
"red" : "0xFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xAA",
|
||||||
|
"green" : "0xE1",
|
||||||
|
"red" : "0xFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xD0",
|
||||||
|
"green" : "0xF8",
|
||||||
|
"red" : "0xFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
22
Fableon/Source/Assets.xcassets/image/Ellipse 873.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Ellipse 873@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Ellipse 873@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Fableon/Source/Assets.xcassets/image/Ellipse 873.imageset/Ellipse 873@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
Fableon/Source/Assets.xcassets/image/Ellipse 873.imageset/Ellipse 873@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 358 KiB |
22
Fableon/Source/Assets.xcassets/image/Frame 3030.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Frame 3030@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Frame 3030@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Fableon/Source/Assets.xcassets/image/Frame 3030.imageset/Frame 3030@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
Fableon/Source/Assets.xcassets/image/Frame 3030.imageset/Frame 3030@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
22
Fableon/Source/Assets.xcassets/image/Group 2072750450.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group 2072750450@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group 2072750450@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Fableon/Source/Assets.xcassets/image/Group 2072750450.imageset/Group 2072750450@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
Fableon/Source/Assets.xcassets/image/Group 2072750450.imageset/Group 2072750450@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 19 KiB |
22
Fableon/Source/Assets.xcassets/image/Group 2072750451.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group 2072750451@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group 2072750451@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Fableon/Source/Assets.xcassets/image/Group 2072750451.imageset/Group 2072750451@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
Fableon/Source/Assets.xcassets/image/Group 2072750451.imageset/Group 2072750451@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
44
Fableon/Source/Assets.xcassets/image/Rectangle 36.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Rectangle 36@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"resizing" : {
|
||||||
|
"cap-insets" : {
|
||||||
|
"left" : 27,
|
||||||
|
"right" : 24
|
||||||
|
},
|
||||||
|
"center" : {
|
||||||
|
"mode" : "tile",
|
||||||
|
"width" : 1
|
||||||
|
},
|
||||||
|
"mode" : "3-part-horizontal"
|
||||||
|
},
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Rectangle 36@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"resizing" : {
|
||||||
|
"cap-insets" : {
|
||||||
|
"left" : 31,
|
||||||
|
"right" : 35
|
||||||
|
},
|
||||||
|
"center" : {
|
||||||
|
"mode" : "tile",
|
||||||
|
"width" : 1
|
||||||
|
},
|
||||||
|
"mode" : "3-part-horizontal"
|
||||||
|
},
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Fableon/Source/Assets.xcassets/image/Rectangle 36.imageset/Rectangle 36@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 602 B |
BIN
Fableon/Source/Assets.xcassets/image/Rectangle 36.imageset/Rectangle 36@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 818 B |
22
Fableon/Source/Assets.xcassets/image/Rectangle 6216.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Rectangle 6216@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Rectangle 6216@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Fableon/Source/Assets.xcassets/image/Rectangle 6216.imageset/Rectangle 6216@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
Fableon/Source/Assets.xcassets/image/Rectangle 6216.imageset/Rectangle 6216@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 67 KiB |
44
Fableon/Source/Assets.xcassets/image/Rectangle 6217.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Rectangle 6217@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"resizing" : {
|
||||||
|
"cap-insets" : {
|
||||||
|
"left" : 71,
|
||||||
|
"right" : 65
|
||||||
|
},
|
||||||
|
"center" : {
|
||||||
|
"mode" : "tile",
|
||||||
|
"width" : 1
|
||||||
|
},
|
||||||
|
"mode" : "3-part-horizontal"
|
||||||
|
},
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Rectangle 6217@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"resizing" : {
|
||||||
|
"cap-insets" : {
|
||||||
|
"left" : 89,
|
||||||
|
"right" : 103
|
||||||
|
},
|
||||||
|
"center" : {
|
||||||
|
"mode" : "tile",
|
||||||
|
"width" : 1
|
||||||
|
},
|
||||||
|
"mode" : "3-part-horizontal"
|
||||||
|
},
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||