1.代码提交
@ -141,7 +141,6 @@
|
||||
3754ACF02ED94A4C009EBCAD /* SRFeedBackController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */; };
|
||||
3754ACF22ED975B9009EBCAD /* SRRewardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACF12ED975B9009EBCAD /* SRRewardController.swift */; };
|
||||
3754ACF42ED98609009EBCAD /* SRCoinPackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACF32ED98609009EBCAD /* SRCoinPackCell.swift */; };
|
||||
3754ACF62ED9A2D4009EBCAD /* SRCoinPackTitleview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACF52ED9A2D4009EBCAD /* SRCoinPackTitleview.swift */; };
|
||||
3754ACF82ED9A32C009EBCAD /* SRCoinPackHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACF72ED9A32C009EBCAD /* SRCoinPackHeaderView.swift */; };
|
||||
3754ACFC2ED9A36C009EBCAD /* SRCoinsPackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */; };
|
||||
3754ACFE2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */; };
|
||||
@ -164,6 +163,35 @@
|
||||
3754AD3C2EDD9C01009EBCAD /* SRThirdModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD3B2EDD9C01009EBCAD /* SRThirdModel.swift */; };
|
||||
3754AD3E2EDD9C88009EBCAD /* SRLogin+FB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD3D2EDD9C88009EBCAD /* SRLogin+FB.swift */; };
|
||||
3754AEF82EDE94CD009EBCAD /* SRUserRewardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AEF72EDE94CD009EBCAD /* SRUserRewardCell.swift */; };
|
||||
3754AEFA2EDEB4F4009EBCAD /* SRUserListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AEF92EDEB4F4009EBCAD /* SRUserListViewController.swift */; };
|
||||
3754AEFD2EDEB515009EBCAD /* SRUserHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AEFB2EDEB515009EBCAD /* SRUserHeaderView.swift */; };
|
||||
3754AEFE2EDEB515009EBCAD /* SRUserListHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AEFC2EDEB515009EBCAD /* SRUserListHeaderView.swift */; };
|
||||
3754AF012EDED6FD009EBCAD /* SRPayManger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF002EDED6FD009EBCAD /* SRPayManger.swift */; };
|
||||
3754AF042EDED773009EBCAD /* SRIapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF032EDED773009EBCAD /* SRIapManager.swift */; };
|
||||
3754AF082EDED91C009EBCAD /* SRPayDateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF072EDED91C009EBCAD /* SRPayDateModel.swift */; };
|
||||
3754AF0A2EDED9A8009EBCAD /* SRStoreAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF092EDED9A8009EBCAD /* SRStoreAPI.swift */; };
|
||||
3754AF0C2EDEDA49009EBCAD /* SRPayDataRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF0B2EDEDA49009EBCAD /* SRPayDataRequest.swift */; };
|
||||
3754AF0E2EDEDAA9009EBCAD /* SRPayAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF0D2EDEDAA9009EBCAD /* SRPayAlertModel.swift */; };
|
||||
3754AF102EDEDD21009EBCAD /* SRWaitRestoreModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF0F2EDEDD21009EBCAD /* SRWaitRestoreModel.swift */; };
|
||||
3754AF122EDEDEBF009EBCAD /* SRIapOrderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF112EDEDEBF009EBCAD /* SRIapOrderModel.swift */; };
|
||||
3754AF142EDEE1AC009EBCAD /* SRStatAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF132EDEE1AC009EBCAD /* SRStatAPI.swift */; };
|
||||
3754AF162EDEE43E009EBCAD /* SRIapVerifyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF152EDEE43E009EBCAD /* SRIapVerifyModel.swift */; };
|
||||
3754AF192EDEF0AF009EBCAD /* SRStoreController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF182EDEF0AF009EBCAD /* SRStoreController.swift */; };
|
||||
3754AF1C2EDEF112009EBCAD /* SRStoreCoinsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF1B2EDEF112009EBCAD /* SRStoreCoinsView.swift */; };
|
||||
3754AF202EDEF133009EBCAD /* SRStoreVipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF1F2EDEF133009EBCAD /* SRStoreVipView.swift */; };
|
||||
3754AF242EDEF38C009EBCAD /* SRBigCoinViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF232EDEF38C009EBCAD /* SRBigCoinViewCell.swift */; };
|
||||
3754AF262EDEF3A7009EBCAD /* SRSmallCoinViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF252EDEF3A7009EBCAD /* SRSmallCoinViewCell.swift */; };
|
||||
3754AF282EDEF3CC009EBCAD /* SRPackCoinViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF272EDEF3CC009EBCAD /* SRPackCoinViewCell.swift */; };
|
||||
3754AF2A2EDEF425009EBCAD /* SRStoreCoinsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF292EDEF425009EBCAD /* SRStoreCoinsCell.swift */; };
|
||||
3754AF2C2EDEF4D5009EBCAD /* SRStoreVipCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AF2B2EDEF4D5009EBCAD /* SRStoreVipCell.swift */; };
|
||||
3754B00B2EE12040009EBCAD /* SRCoinsPackClaimListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B00A2EE12040009EBCAD /* SRCoinsPackClaimListView.swift */; };
|
||||
3754B00F2EE120C5009EBCAD /* SRCoinsPackClaimListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B00E2EE120C5009EBCAD /* SRCoinsPackClaimListCell.swift */; };
|
||||
3754B0112EE1248D009EBCAD /* SRCoinsPackBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B0102EE1248D009EBCAD /* SRCoinsPackBuyView.swift */; };
|
||||
3754B0152EE12521009EBCAD /* SRCoinPackConfirmView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B0142EE12521009EBCAD /* SRCoinPackConfirmView.swift */; };
|
||||
3754B0172EE12633009EBCAD /* SRCoinPackConfirmItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B0162EE12633009EBCAD /* SRCoinPackConfirmItemView.swift */; };
|
||||
3754B0192EE1267B009EBCAD /* SRCoinPackConfirmItem1View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B0182EE1267B009EBCAD /* SRCoinPackConfirmItem1View.swift */; };
|
||||
3754B01B2EE12690009EBCAD /* SRCoinPackConfirmItem2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B01A2EE12690009EBCAD /* SRCoinPackConfirmItem2View.swift */; };
|
||||
3754B0312EE2C9D4009EBCAD /* SRVideoRechargeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754B0302EE2C9D4009EBCAD /* SRVideoRechargeView.swift */; };
|
||||
3779D0612ECF1CB8006B1698 /* SRShortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */; };
|
||||
47BB39E2DD30787FA591F8EB /* Pods_SynthReel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9255BF4D4B1CFDDB5CFFB43 /* Pods_SynthReel.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -304,7 +332,6 @@
|
||||
3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRFeedBackController.swift; sourceTree = "<group>"; };
|
||||
3754ACF12ED975B9009EBCAD /* SRRewardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRRewardController.swift; sourceTree = "<group>"; };
|
||||
3754ACF32ED98609009EBCAD /* SRCoinPackCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackCell.swift; sourceTree = "<group>"; };
|
||||
3754ACF52ED9A2D4009EBCAD /* SRCoinPackTitleview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackTitleview.swift; sourceTree = "<group>"; };
|
||||
3754ACF72ED9A32C009EBCAD /* SRCoinPackHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackHeaderView.swift; sourceTree = "<group>"; };
|
||||
3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackModel.swift; sourceTree = "<group>"; };
|
||||
3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackReceiveModel.swift; sourceTree = "<group>"; };
|
||||
@ -320,6 +347,35 @@
|
||||
3754AD3B2EDD9C01009EBCAD /* SRThirdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRThirdModel.swift; sourceTree = "<group>"; };
|
||||
3754AD3D2EDD9C88009EBCAD /* SRLogin+FB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRLogin+FB.swift"; sourceTree = "<group>"; };
|
||||
3754AEF72EDE94CD009EBCAD /* SRUserRewardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserRewardCell.swift; sourceTree = "<group>"; };
|
||||
3754AEF92EDEB4F4009EBCAD /* SRUserListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserListViewController.swift; sourceTree = "<group>"; };
|
||||
3754AEFB2EDEB515009EBCAD /* SRUserHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserHeaderView.swift; sourceTree = "<group>"; };
|
||||
3754AEFC2EDEB515009EBCAD /* SRUserListHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserListHeaderView.swift; sourceTree = "<group>"; };
|
||||
3754AF002EDED6FD009EBCAD /* SRPayManger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayManger.swift; sourceTree = "<group>"; };
|
||||
3754AF032EDED773009EBCAD /* SRIapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRIapManager.swift; sourceTree = "<group>"; };
|
||||
3754AF072EDED91C009EBCAD /* SRPayDateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayDateModel.swift; sourceTree = "<group>"; };
|
||||
3754AF092EDED9A8009EBCAD /* SRStoreAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreAPI.swift; sourceTree = "<group>"; };
|
||||
3754AF0B2EDEDA49009EBCAD /* SRPayDataRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayDataRequest.swift; sourceTree = "<group>"; };
|
||||
3754AF0D2EDEDAA9009EBCAD /* SRPayAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayAlertModel.swift; sourceTree = "<group>"; };
|
||||
3754AF0F2EDEDD21009EBCAD /* SRWaitRestoreModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRWaitRestoreModel.swift; sourceTree = "<group>"; };
|
||||
3754AF112EDEDEBF009EBCAD /* SRIapOrderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRIapOrderModel.swift; sourceTree = "<group>"; };
|
||||
3754AF132EDEE1AC009EBCAD /* SRStatAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStatAPI.swift; sourceTree = "<group>"; };
|
||||
3754AF152EDEE43E009EBCAD /* SRIapVerifyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRIapVerifyModel.swift; sourceTree = "<group>"; };
|
||||
3754AF182EDEF0AF009EBCAD /* SRStoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreController.swift; sourceTree = "<group>"; };
|
||||
3754AF1B2EDEF112009EBCAD /* SRStoreCoinsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreCoinsView.swift; sourceTree = "<group>"; };
|
||||
3754AF1F2EDEF133009EBCAD /* SRStoreVipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreVipView.swift; sourceTree = "<group>"; };
|
||||
3754AF232EDEF38C009EBCAD /* SRBigCoinViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRBigCoinViewCell.swift; sourceTree = "<group>"; };
|
||||
3754AF252EDEF3A7009EBCAD /* SRSmallCoinViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRSmallCoinViewCell.swift; sourceTree = "<group>"; };
|
||||
3754AF272EDEF3CC009EBCAD /* SRPackCoinViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPackCoinViewCell.swift; sourceTree = "<group>"; };
|
||||
3754AF292EDEF425009EBCAD /* SRStoreCoinsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreCoinsCell.swift; sourceTree = "<group>"; };
|
||||
3754AF2B2EDEF4D5009EBCAD /* SRStoreVipCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreVipCell.swift; sourceTree = "<group>"; };
|
||||
3754B00A2EE12040009EBCAD /* SRCoinsPackClaimListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackClaimListView.swift; sourceTree = "<group>"; };
|
||||
3754B00E2EE120C5009EBCAD /* SRCoinsPackClaimListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackClaimListCell.swift; sourceTree = "<group>"; };
|
||||
3754B0102EE1248D009EBCAD /* SRCoinsPackBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackBuyView.swift; sourceTree = "<group>"; };
|
||||
3754B0142EE12521009EBCAD /* SRCoinPackConfirmView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmView.swift; sourceTree = "<group>"; };
|
||||
3754B0162EE12633009EBCAD /* SRCoinPackConfirmItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmItemView.swift; sourceTree = "<group>"; };
|
||||
3754B0182EE1267B009EBCAD /* SRCoinPackConfirmItem1View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmItem1View.swift; sourceTree = "<group>"; };
|
||||
3754B01A2EE12690009EBCAD /* SRCoinPackConfirmItem2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmItem2View.swift; sourceTree = "<group>"; };
|
||||
3754B0302EE2C9D4009EBCAD /* SRVideoRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRVideoRechargeView.swift; sourceTree = "<group>"; };
|
||||
3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRShortHeaderView.swift; sourceTree = "<group>"; };
|
||||
59DC746604B26E9FF802D317 /* Pods-SynthReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.debug.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
AA88214030574193B51DE563 /* Pods-SynthReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.release.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.release.xcconfig"; sourceTree = "<group>"; };
|
||||
@ -550,6 +606,7 @@
|
||||
3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */,
|
||||
3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */,
|
||||
3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */,
|
||||
3754B0302EE2C9D4009EBCAD /* SRVideoRechargeView.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -639,6 +696,8 @@
|
||||
03E9A7D42EC4764A000D1067 /* Libs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AF022EDED751009EBCAD /* SRAppstore */,
|
||||
3754AEFF2EDED691009EBCAD /* payManger */,
|
||||
3754AD342EDD9A8F009EBCAD /* SRLogin */,
|
||||
3754ACD82ED83724009EBCAD /* FSPagerView */,
|
||||
3754ACCF2ED81F2F009EBCAD /* Alert */,
|
||||
@ -715,6 +774,8 @@
|
||||
03B1A9292ECC072C006C353F /* SRShortApi.swift */,
|
||||
03B1A8E42EC715DA006C353F /* SRHomeApi.swift */,
|
||||
03E9A7FC2EC5763B000D1067 /* SRUserApi.swift */,
|
||||
3754AF092EDED9A8009EBCAD /* SRStoreAPI.swift */,
|
||||
3754AF132EDEE1AC009EBCAD /* SRStatAPI.swift */,
|
||||
);
|
||||
path = API;
|
||||
sourceTree = "<group>";
|
||||
@ -740,6 +801,7 @@
|
||||
370D2F0E2ED4532A00571E77 /* VC */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AEF92EDEB4F4009EBCAD /* SRUserListViewController.swift */,
|
||||
370D2F0F2ED4534500571E77 /* SRUserViewController.swift */,
|
||||
370D2F1D2ED54C7F00571E77 /* SRHelpCenterController.swift */,
|
||||
370D2F1F2ED54C8F00571E77 /* SRAboutUsController.swift */,
|
||||
@ -753,6 +815,8 @@
|
||||
370D2F132ED457C900571E77 /* view */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AEFB2EDEB515009EBCAD /* SRUserHeaderView.swift */,
|
||||
3754AEFC2EDEB515009EBCAD /* SRUserListHeaderView.swift */,
|
||||
370D2F142ED457F000571E77 /* SRUserTopCell.swift */,
|
||||
370D2F192ED45CCA00571E77 /* SRUserSettingCell.swift */,
|
||||
370D2F242ED5807600571E77 /* SRAboutHeaderVIew.swift */,
|
||||
@ -801,6 +865,7 @@
|
||||
3754ACDD2ED93C14009EBCAD /* Coinpack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754B0092EE11F71009EBCAD /* M */,
|
||||
3754ACDF2ED93C36009EBCAD /* view */,
|
||||
3754ACDE2ED93C2A009EBCAD /* VC */,
|
||||
);
|
||||
@ -818,8 +883,14 @@
|
||||
3754ACDF2ED93C36009EBCAD /* view */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACF52ED9A2D4009EBCAD /* SRCoinPackTitleview.swift */,
|
||||
3754ACF72ED9A32C009EBCAD /* SRCoinPackHeaderView.swift */,
|
||||
3754B00A2EE12040009EBCAD /* SRCoinsPackClaimListView.swift */,
|
||||
3754B00E2EE120C5009EBCAD /* SRCoinsPackClaimListCell.swift */,
|
||||
3754B0102EE1248D009EBCAD /* SRCoinsPackBuyView.swift */,
|
||||
3754B0142EE12521009EBCAD /* SRCoinPackConfirmView.swift */,
|
||||
3754B0162EE12633009EBCAD /* SRCoinPackConfirmItemView.swift */,
|
||||
3754B0182EE1267B009EBCAD /* SRCoinPackConfirmItem1View.swift */,
|
||||
3754B01A2EE12690009EBCAD /* SRCoinPackConfirmItem2View.swift */,
|
||||
);
|
||||
path = view;
|
||||
sourceTree = "<group>";
|
||||
@ -839,6 +910,8 @@
|
||||
3754ACF92ED9A34E009EBCAD /* Store */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AF1A2EDEF105009EBCAD /* Views */,
|
||||
3754AF172EDEF09C009EBCAD /* VC */,
|
||||
3754ACFA2ED9A359009EBCAD /* Model */,
|
||||
);
|
||||
path = Store;
|
||||
@ -847,8 +920,9 @@
|
||||
3754ACFA2ED9A359009EBCAD /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */,
|
||||
3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */,
|
||||
3754AF072EDED91C009EBCAD /* SRPayDateModel.swift */,
|
||||
3754AF0D2EDEDAA9009EBCAD /* SRPayAlertModel.swift */,
|
||||
3754AF152EDEE43E009EBCAD /* SRIapVerifyModel.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@ -881,6 +955,56 @@
|
||||
path = SRLogin;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754AEFF2EDED691009EBCAD /* payManger */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AF002EDED6FD009EBCAD /* SRPayManger.swift */,
|
||||
);
|
||||
path = payManger;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754AF022EDED751009EBCAD /* SRAppstore */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AF032EDED773009EBCAD /* SRIapManager.swift */,
|
||||
3754AF0B2EDEDA49009EBCAD /* SRPayDataRequest.swift */,
|
||||
3754AF0F2EDEDD21009EBCAD /* SRWaitRestoreModel.swift */,
|
||||
3754AF112EDEDEBF009EBCAD /* SRIapOrderModel.swift */,
|
||||
);
|
||||
path = SRAppstore;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754AF172EDEF09C009EBCAD /* VC */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AF182EDEF0AF009EBCAD /* SRStoreController.swift */,
|
||||
);
|
||||
path = VC;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754AF1A2EDEF105009EBCAD /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AF1B2EDEF112009EBCAD /* SRStoreCoinsView.swift */,
|
||||
3754AF1F2EDEF133009EBCAD /* SRStoreVipView.swift */,
|
||||
3754AF232EDEF38C009EBCAD /* SRBigCoinViewCell.swift */,
|
||||
3754AF252EDEF3A7009EBCAD /* SRSmallCoinViewCell.swift */,
|
||||
3754AF272EDEF3CC009EBCAD /* SRPackCoinViewCell.swift */,
|
||||
3754AF292EDEF425009EBCAD /* SRStoreCoinsCell.swift */,
|
||||
3754AF2B2EDEF4D5009EBCAD /* SRStoreVipCell.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754B0092EE11F71009EBCAD /* M */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */,
|
||||
3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */,
|
||||
);
|
||||
path = M;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3779D05F2ECF1C8D006B1698 /* V */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1046,15 +1170,20 @@
|
||||
03B1A8FB2EC818BE006C353F /* UIStackView+SRAdd.swift in Sources */,
|
||||
03B1A8E12EC6D6D3006C353F /* SRHomeMenuDataSource.swift in Sources */,
|
||||
03E9A7F82EC4AA54000D1067 /* SRUserDefaultsKey.swift in Sources */,
|
||||
3754B0312EE2C9D4009EBCAD /* SRVideoRechargeView.swift in Sources */,
|
||||
3754AF1C2EDEF112009EBCAD /* SRStoreCoinsView.swift in Sources */,
|
||||
03B1A8452EC5CBBB006C353F /* SRNavigationController.swift in Sources */,
|
||||
03B1A9092ECAAF55006C353F /* SRHomeTopChartsView.swift in Sources */,
|
||||
03E9A7E42EC49593000D1067 /* SRUrlPath.swift in Sources */,
|
||||
3754AF122EDEDEBF009EBCAD /* SRIapOrderModel.swift in Sources */,
|
||||
370D2EF92ED000D200571E77 /* SRHistoryViewController.swift in Sources */,
|
||||
3754B0112EE1248D009EBCAD /* SRCoinsPackBuyView.swift in Sources */,
|
||||
03B1A9462ECC5679006C353F /* SRSearchResultCell.swift in Sources */,
|
||||
03B1A9502ECEB4E6006C353F /* SRRecommendPlayerViewController.swift in Sources */,
|
||||
03B1A83E2EC5C91E006C353F /* SRTool.swift in Sources */,
|
||||
03B1A9172ECAF14F006C353F /* SRHomeHotView.swift in Sources */,
|
||||
03B1A8FD2EC81C62006C353F /* SRHomeBannerCell.swift in Sources */,
|
||||
3754AF2A2EDEF425009EBCAD /* SRStoreCoinsCell.swift in Sources */,
|
||||
03E9A7DB2EC485BE000D1067 /* SRNetwork.swift in Sources */,
|
||||
370D2F152ED457F000571E77 /* SRUserTopCell.swift in Sources */,
|
||||
3754ACBD2ED5B6B6009EBCAD /* UINavigationBar+SRAdd.swift in Sources */,
|
||||
@ -1066,10 +1195,13 @@
|
||||
370D2F072ED3FEFA00571E77 /* SRFavoritesCell.swift in Sources */,
|
||||
3754ACE42ED93E3B009EBCAD /* SRBaseWebViewController.swift in Sources */,
|
||||
03B1A8E72EC7175D006C353F /* SRCategoryModel.swift in Sources */,
|
||||
3754B0152EE12521009EBCAD /* SRCoinPackConfirmView.swift in Sources */,
|
||||
370D2F2F2ED5AB2500571E77 /* SRViralHitController.swift in Sources */,
|
||||
3754ACDA2ED8374D009EBCAD /* SRPagerViewTransformer.swift in Sources */,
|
||||
3754AF282EDEF3CC009EBCAD /* SRPackCoinViewCell.swift in Sources */,
|
||||
3754ACFE2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift in Sources */,
|
||||
3754ACF22ED975B9009EBCAD /* SRRewardController.swift in Sources */,
|
||||
3754AEFA2EDEB4F4009EBCAD /* SRUserListViewController.swift in Sources */,
|
||||
03B1A94A2ECC79AB006C353F /* SREpSelectorView.swift in Sources */,
|
||||
03B1A94E2ECD604B006C353F /* SREpSelectorCell.swift in Sources */,
|
||||
03B1A9262ECBFF31006C353F /* SRShortPlayerViewModel.swift in Sources */,
|
||||
@ -1093,6 +1225,8 @@
|
||||
370D2F092ED44A6D00571E77 /* SRListMenuCell.swift in Sources */,
|
||||
03980F532ECEDEAB0006E317 /* SRRecommendPlayerControlView.swift in Sources */,
|
||||
03B1A90F2ECAC768006C353F /* SRHomeBingeWorthyView.swift in Sources */,
|
||||
3754B0192EE1267B009EBCAD /* SRCoinPackConfirmItem1View.swift in Sources */,
|
||||
3754AF162EDEE43E009EBCAD /* SRIapVerifyModel.swift in Sources */,
|
||||
3754ACFC2ED9A36C009EBCAD /* SRCoinsPackModel.swift in Sources */,
|
||||
03B1A9072EC86656006C353F /* SRGradientView.swift in Sources */,
|
||||
370D2F292ED58EC400571E77 /* SRTopChartsViewController.swift in Sources */,
|
||||
@ -1103,18 +1237,24 @@
|
||||
03B1A8402EC5CA37006C353F /* AppDelegate+Config.swift in Sources */,
|
||||
03B1A9152ECAEE63006C353F /* SRHomeViralHitsCell.swift in Sources */,
|
||||
03B1A8472EC5CBCF006C353F /* SRViewController.swift in Sources */,
|
||||
3754AF192EDEF0AF009EBCAD /* SRStoreController.swift in Sources */,
|
||||
370D2F052ED3FEE700571E77 /* SRHistoryCell.swift in Sources */,
|
||||
3754AF202EDEF133009EBCAD /* SRStoreVipView.swift in Sources */,
|
||||
3754ACEA2ED94065009EBCAD /* SRBaseWebViewController + Script.swift in Sources */,
|
||||
3754AD3A2EDD9BB1009EBCAD /* SRLogin+apple.swift in Sources */,
|
||||
03B1A9032EC8555B006C353F /* SRHomeYouLikeView.swift in Sources */,
|
||||
03B1A9362ECC1D1D006C353F /* SRSearchRecordView.swift in Sources */,
|
||||
3754AF262EDEF3A7009EBCAD /* SRSmallCoinViewCell.swift in Sources */,
|
||||
03B1A8D82EC6D051006C353F /* SRCollectionView.swift in Sources */,
|
||||
03B1A90D2ECAC51A006C353F /* NSNumber+SRAdd.swift in Sources */,
|
||||
3754AF082EDED91C009EBCAD /* SRPayDateModel.swift in Sources */,
|
||||
03E9A7DD2EC485E1000D1067 /* SRNetworkModel.swift in Sources */,
|
||||
3754ACEC2ED943AB009EBCAD /* SRAppWebViewController.swift in Sources */,
|
||||
03B1A9442ECC4ED9006C353F /* SRSearchResultView.swift in Sources */,
|
||||
3754ACBF2ED5B839009EBCAD /* SRNavgationTitleView.swift in Sources */,
|
||||
3754B00B2EE12040009EBCAD /* SRCoinsPackClaimListView.swift in Sources */,
|
||||
03B1A8FF2EC81C92006C353F /* SRImageView.swift in Sources */,
|
||||
3754B00F2EE120C5009EBCAD /* SRCoinsPackClaimListCell.swift in Sources */,
|
||||
03B1A83B2EC5C8E0006C353F /* SRToast.swift in Sources */,
|
||||
03B1A9302ECC10D1006C353F /* SRSearchViewController.swift in Sources */,
|
||||
03B1A8432EC5CB99006C353F /* SRTabBarController.swift in Sources */,
|
||||
@ -1123,26 +1263,31 @@
|
||||
03B1A8ED2EC72C1F006C353F /* SRHomeModuleItem.swift in Sources */,
|
||||
370D2F102ED4534500571E77 /* SRUserViewController.swift in Sources */,
|
||||
03B1A9112ECAC927006C353F /* SRHomeBingeWorthyCell.swift in Sources */,
|
||||
3754AF0C2EDEDA49009EBCAD /* SRPayDataRequest.swift in Sources */,
|
||||
03E9A7F22EC4A8F6000D1067 /* UserDefaults+SRAdd.swift in Sources */,
|
||||
370D2F2B2ED597F700571E77 /* SRTopChartsCell.swift in Sources */,
|
||||
3754AD3C2EDD9C01009EBCAD /* SRThirdModel.swift in Sources */,
|
||||
03B1A93A2ECC3F54006C353F /* SRSearchViewModel.swift in Sources */,
|
||||
03E9A7F62EC4A9B1000D1067 /* SRUserInfo.swift in Sources */,
|
||||
3754AF0A2EDED9A8009EBCAD /* SRStoreAPI.swift in Sources */,
|
||||
03B1A8F92EC813BC006C353F /* SRScrollView.swift in Sources */,
|
||||
03B1A8E92EC721CD006C353F /* SRLabel.swift in Sources */,
|
||||
3754AD1A2EDD745A009EBCAD /* SRVideoLockView.swift in Sources */,
|
||||
03B1A9282ECC05B1006C353F /* SRShortDetailModel.swift in Sources */,
|
||||
03980F592ECEED190006E317 /* SRMyShortViewController.swift in Sources */,
|
||||
3754AEFD2EDEB515009EBCAD /* SRUserHeaderView.swift in Sources */,
|
||||
3754AF012EDED6FD009EBCAD /* SRPayManger.swift in Sources */,
|
||||
3754AEFE2EDEB515009EBCAD /* SRUserListHeaderView.swift in Sources */,
|
||||
3754ACD32ED82113009EBCAD /* SRGradientbutton.swift in Sources */,
|
||||
03B1A92A2ECC0738006C353F /* SRShortApi.swift in Sources */,
|
||||
03B1A90B2ECAB2EA006C353F /* SRHomeTopChartsContentView.swift in Sources */,
|
||||
370D2F0C2ED44ACB00571E77 /* SRListMenuDataSource.swift in Sources */,
|
||||
03B1A94C2ECC7A2D006C353F /* SRPanModalContentView.swift in Sources */,
|
||||
03B1A9052EC857B3006C353F /* SRHomeYouLikeCell.swift in Sources */,
|
||||
3754AF042EDED773009EBCAD /* SRIapManager.swift in Sources */,
|
||||
03B1A92E2ECC0D7E006C353F /* SRShortDetailControlView.swift in Sources */,
|
||||
03B1A9382ECC210D006C353F /* SRSearchRecordCell.swift in Sources */,
|
||||
03E9A7D72EC47A23000D1067 /* SRResponseCryptor.swift in Sources */,
|
||||
3754ACF62ED9A2D4009EBCAD /* SRCoinPackTitleview.swift in Sources */,
|
||||
03B1A8502EC5DB2E006C353F /* SRHomeViewController.swift in Sources */,
|
||||
03B1A8E52EC715E1006C353F /* SRHomeApi.swift in Sources */,
|
||||
3754AD022EDA8AF7009EBCAD /* SRLoginController.swift in Sources */,
|
||||
@ -1150,8 +1295,10 @@
|
||||
03B1A8F12EC72DD7006C353F /* SRHomeViewModel.swift in Sources */,
|
||||
03E9A7FD2EC57658000D1067 /* SRUserApi.swift in Sources */,
|
||||
03E9A7E72EC49819000D1067 /* SRDefine.swift in Sources */,
|
||||
3754AF2C2EDEF4D5009EBCAD /* SRStoreVipCell.swift in Sources */,
|
||||
03B1A9012EC852B2006C353F /* SRHomeModuleView.swift in Sources */,
|
||||
03E9A7EF2EC4A8AF000D1067 /* SRAccountManager.swift in Sources */,
|
||||
3754AF102EDEDD21009EBCAD /* SRWaitRestoreModel.swift in Sources */,
|
||||
03B1A8F52EC81277006C353F /* SRHomeBannerView.swift in Sources */,
|
||||
3754AD312EDD939A009EBCAD /* SRUserLoginView.swift in Sources */,
|
||||
3754AD1C2EDD77BA009EBCAD /* SRVideoUnlockResult.swift in Sources */,
|
||||
@ -1163,11 +1310,14 @@
|
||||
03B1A8552EC5E434006C353F /* UIFont+SRAdd.swift in Sources */,
|
||||
3779D0612ECF1CB8006B1698 /* SRShortHeaderView.swift in Sources */,
|
||||
03980F512ECEBEE20006E317 /* SRRecommendPlayerCell.swift in Sources */,
|
||||
3754AF242EDEF38C009EBCAD /* SRBigCoinViewCell.swift in Sources */,
|
||||
03B1A91B2ECAFFD6006C353F /* UIView+SRAdd.swift in Sources */,
|
||||
03B1A9222ECB456C006C353F /* SRDetailPlayerViewController.swift in Sources */,
|
||||
3754B0172EE12633009EBCAD /* SRCoinPackConfirmItemView.swift in Sources */,
|
||||
03B1A91F2ECB2A0E006C353F /* SRHomeBannerMiniCell.swift in Sources */,
|
||||
3754ACC12ED69105009EBCAD /* SRTopChartsHeaderView.swift in Sources */,
|
||||
03B1A93E2ECC4568006C353F /* SRTableView.swift in Sources */,
|
||||
3754AF0E2EDEDAA9009EBCAD /* SRPayAlertModel.swift in Sources */,
|
||||
03980F4F2ECEB91C0006E317 /* SRRecommendPlayerViewModel.swift in Sources */,
|
||||
03B1A9422ECC4632006C353F /* SRHotSearchCell.swift in Sources */,
|
||||
03B1A9342ECC12D9006C353F /* SRSearchTextView.swift in Sources */,
|
||||
@ -1176,6 +1326,8 @@
|
||||
03B1A93C2ECC406E006C353F /* SRHotSearchView.swift in Sources */,
|
||||
03B1A8E32EC6F577006C353F /* SRHomeMenuCell.swift in Sources */,
|
||||
3754AD362EDD9AA7009EBCAD /* SRLogin.swift in Sources */,
|
||||
3754AF142EDEE1AC009EBCAD /* SRStatAPI.swift in Sources */,
|
||||
3754B01B2EE12690009EBCAD /* SRCoinPackConfirmItem2View.swift in Sources */,
|
||||
3754ACE12ED93C4D009EBCAD /* SRCoinPackController.swift in Sources */,
|
||||
3754ACD52ED82722009EBCAD /* SRDetailRecommendview.swift in Sources */,
|
||||
);
|
||||
@ -1229,7 +1381,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.drama.hive;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.SynthReel.Tv.lssj;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
@ -1271,7 +1423,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.drama.hive;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.SynthReel.Tv.lssj;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
|
||||
67
SynthReel/Base/API/SRStatAPI.swift
Normal file
@ -0,0 +1,67 @@
|
||||
//
|
||||
// SRStatAPI.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRStatAPI: 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"//详情页面弹出支付模版事件
|
||||
}
|
||||
|
||||
|
||||
static func requestEventStat(orderCode: String?, shortPlayId: String?, videoId: String?, eventKey: EventKey, errorMsg: String?, otherParamenters: [String : Any]? = nil) async {
|
||||
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"
|
||||
}
|
||||
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = SRNetwork.Parameters(path: "/createOrder")
|
||||
param.method = .post
|
||||
param.parameters = [
|
||||
"userId" : SRAccountManager.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 {
|
||||
param.parameters?["error_msg"] = errorMsg
|
||||
}
|
||||
|
||||
|
||||
if let otherParamenters = otherParamenters {
|
||||
otherParamenters.forEach {
|
||||
param.parameters?[$0] = $1
|
||||
}
|
||||
}
|
||||
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||
continuation.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
93
SynthReel/Base/API/SRStoreAPI.swift
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// SRStoreAPI.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
|
||||
class SRStoreAPI: NSObject {
|
||||
enum BuyType: String, SmartCaseDefaultable {
|
||||
case coins = "coins"
|
||||
case subVip = "sub_vip"
|
||||
case subCoins = "sub_coins"
|
||||
case vip = "vip"
|
||||
}
|
||||
|
||||
|
||||
static func requestPayTemplate() async -> SRPayDateModel? {
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = SRNetwork.Parameters(path: "/paySettingsV4")
|
||||
param.method = .post
|
||||
param.parameters = [
|
||||
"discount" : "1",
|
||||
"purchases_token" : SRPayManger.manager.getAppStoreReceipt() ?? "",
|
||||
]
|
||||
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRPayDateModel>) in
|
||||
continuation.resume(returning: response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func requestCreateOrder(payId: String, shortPlayId: String, videoId: String, isDiscount: Bool = false, identifierDiscount: String? = nil) async -> SRIapOrderModel? {
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = SRNetwork.Parameters(path: "/createOrder")
|
||||
param.method = .post
|
||||
param.parameters = [
|
||||
"payment_channel" : "apple",
|
||||
"short_play_id" : shortPlayId,
|
||||
"video_id" : videoId,
|
||||
"pay_setting_id" : payId,
|
||||
"is_discount" : isDiscount ? 1 : 0,
|
||||
"product_discount" : identifierDiscount ?? "",
|
||||
]
|
||||
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRIapOrderModel>) in
|
||||
continuation.resume(returning: response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func requestVerifyOrder(parameters: [String : Any]) async -> SRIapVerifyModel? {
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = SRNetwork.Parameters(path: "/applePaid")
|
||||
param.method = .post
|
||||
param.parameters = parameters
|
||||
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRIapVerifyModel>) in
|
||||
continuation.resume(returning: response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func requestCoinsPackData() async -> SRCoinsPackModel? {
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = SRNetwork.Parameters(path: "/getReceiveDayCoinInfo")
|
||||
param.method = .get
|
||||
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRCoinsPackModel>) in
|
||||
continuation.resume(returning: response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func requestReceiveCoinsPackCoins(id: String?) async -> Bool {
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = SRNetwork.Parameters(path: "/getReceiveDayCoinInfo")
|
||||
param.method = .post
|
||||
param.parameters = [
|
||||
"id" : id ?? ""
|
||||
]
|
||||
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<String>) in
|
||||
if response.isSuccess {
|
||||
continuation.resume(returning: true)
|
||||
}else{
|
||||
continuation.resume(returning: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -12,3 +12,12 @@ let kSRAccountTokenDefaultsKey = "kSRAccountTokenDefaultsKey"
|
||||
|
||||
///用户信息
|
||||
let kSRUserInfoDefaultsKey = "kSRUserInfoDefaultsKey"
|
||||
|
||||
|
||||
let kSRWaitRestoreIAPDefaultsKey = "kSRWaitRestoreIAPDefaultsKey"
|
||||
|
||||
let kSRApnsAlertDefaultsKey = "kSRApnsAlertDefaultsKey"
|
||||
|
||||
let kSRVersionUpdateAlertDefaultsKey = "kSRVersionUpdateAlertDefaultsKey"
|
||||
|
||||
let kSRHasBeenOpenedAPPDefaultsKey = "kSRHasBeenOpenedAPPDefaultsKey"
|
||||
|
||||
@ -13,7 +13,8 @@ import SmartCodable
|
||||
extension String {
|
||||
|
||||
var localized: String {
|
||||
return String(localized: LocalizationValue(self))
|
||||
let value = String(localized: LocalizationValue(self))
|
||||
return value.replacingOccurrences(of: "<br>", with: "\n")
|
||||
}
|
||||
|
||||
func localizedReplace(text: String) -> String {
|
||||
|
||||
@ -7,11 +7,13 @@
|
||||
//
|
||||
|
||||
let SRBaseURL = "https://api-synthreeltv.synthreeltv.com"
|
||||
//let SRBaseURL = "https://api-univicos.univicos.com"
|
||||
let SRUrlPathPrefix = "/th"
|
||||
//let SRUrlPathPrefix = "/uni"
|
||||
let SRWebBaseURL = "https://www.synthreeltv.com"
|
||||
let SRCampaignWebURL = "https://campaign.synthreeltv.com"
|
||||
|
||||
|
||||
//@"https://api-univicos.univicos.com/uni";
|
||||
|
||||
///反馈首页
|
||||
let kSRFeedBackHomeWebUrl = SRCampaignWebURL + "/pages/leave/index"
|
||||
|
||||
@ -12,6 +12,7 @@ import SnapKit
|
||||
|
||||
class SRPanModalContentView: HWPanModalContentView {
|
||||
|
||||
var mainScrollView: UIScrollView?
|
||||
|
||||
var contentHeight = UIScreen.height * (2 / 3)
|
||||
|
||||
@ -56,9 +57,10 @@ class SRPanModalContentView: HWPanModalContentView {
|
||||
|
||||
//MARK: HWPanModalPresentable
|
||||
override func panScrollable() -> UIScrollView? {
|
||||
return nil
|
||||
return mainScrollView
|
||||
}
|
||||
|
||||
|
||||
override func longFormHeight() -> PanModalHeight {
|
||||
return PanModalHeightMake(.content, contentHeight)
|
||||
}
|
||||
|
||||
@ -10,15 +10,144 @@ import UIKit
|
||||
|
||||
class SRCoinPackController: SRViewController {
|
||||
|
||||
private var model: SRCoinsPackModel? {
|
||||
didSet {
|
||||
headerView.model = model
|
||||
claimView.dataArr = model?.receive_list ?? []
|
||||
}
|
||||
}
|
||||
|
||||
private var payDataModel : SRPayDateModel? {
|
||||
didSet {
|
||||
var arr: [SRPayItem] = []
|
||||
|
||||
payDataModel?.list_coins?.forEach {
|
||||
if $0.buy_type == .subCoins {
|
||||
arr.append($0)
|
||||
}
|
||||
}
|
||||
self.buyView.dataArr = arr
|
||||
}
|
||||
}
|
||||
|
||||
private var payDataRequest: SRPayDataRequest?
|
||||
|
||||
lazy var topImageview = UIImageView.init(image: .topCoinPack)
|
||||
|
||||
private lazy var bgIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "查看图片 25"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var scrollView: SRScrollView = {
|
||||
let scrollView = SRScrollView()
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var headerView: SRCoinPackHeaderView = {
|
||||
let view = SRCoinPackHeaderView()
|
||||
view.clickClaimButton = { [weak self] in
|
||||
self?.requestReceiveCoins(nil)
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .vertical
|
||||
stackView.spacing = 19
|
||||
return stackView
|
||||
}()
|
||||
|
||||
private lazy var claimView: SRCoinsPackClaimListView = {
|
||||
let view = SRCoinsPackClaimListView()
|
||||
view.clickClaimButton = { [weak self] id in
|
||||
guard let self = self else { return }
|
||||
self.requestReceiveCoins(id)
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var buyView: SRCoinsPackBuyView = {
|
||||
let view = SRCoinsPackBuyView()
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
self?.requestCoinsPackData()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tipView: UIView = {
|
||||
let view = UIView()
|
||||
view.addSubview(tipTitleLabel)
|
||||
view.addSubview(tipTextLabel)
|
||||
|
||||
tipTitleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(16)
|
||||
}
|
||||
|
||||
tipTextLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||
make.top.equalTo(tipTitleLabel.snp.bottom).offset(4)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tipTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white.withAlphaComponent(0.5)
|
||||
label.text = "coins_pack_tips_title".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private weak var recommandView: UIView?
|
||||
|
||||
private lazy var tipTextLabel: UILabel = {
|
||||
let att = NSMutableAttributedString(string: "coins_pack_tips".localized)
|
||||
att.yy_lineSpacing = 3
|
||||
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 10, weight: .regular)
|
||||
label.textColor = .white.withAlphaComponent(0.5)
|
||||
label.attributedText = att
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
sr_setui()
|
||||
()
|
||||
self.navigationItem.title = "My Refills".localized
|
||||
|
||||
payDataModel = SRIapManager.manager.payDateModel
|
||||
|
||||
sr_setui()
|
||||
|
||||
requestCoinsPackData()
|
||||
|
||||
updateLayout()
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
}
|
||||
|
||||
private func updateLayout() {
|
||||
stackView.sr_removeAllArrangedSubview()
|
||||
|
||||
if self.claimView.dataArr.count > 0 {
|
||||
stackView.addArrangedSubview(self.claimView)
|
||||
} else if self.buyView.dataArr.count > 0 {
|
||||
stackView.addArrangedSubview(self.buyView)
|
||||
}
|
||||
|
||||
stackView.addArrangedSubview(tipView)
|
||||
}
|
||||
}
|
||||
|
||||
extension SRCoinPackController {
|
||||
@ -28,5 +157,90 @@ extension SRCoinPackController {
|
||||
topImageview.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
view.addSubview(bgIconImageView)
|
||||
view.addSubview(scrollView)
|
||||
scrollView.addSubview(headerView)
|
||||
scrollView.addSubview(stackView)
|
||||
|
||||
bgIconImageView.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
headerView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalTo(headerView.snp.bottom).offset(16)
|
||||
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SRCoinPackController {
|
||||
|
||||
private func requestCoinsPackData() {
|
||||
Task {
|
||||
let model = await SRStoreAPI.requestCoinsPackData()
|
||||
guard let model = model else { return }
|
||||
self.model = model
|
||||
if (model.receive_list?.count ?? 0) == 0 {
|
||||
self.requestPayData()
|
||||
}
|
||||
self.updateLayout()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func requestPayData() {
|
||||
self.payDataRequest = SRPayDataRequest()
|
||||
self.payDataRequest?.requestProducts { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else { return }
|
||||
self.payDataModel = model
|
||||
|
||||
self.updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private func requestReceiveCoins(_ id: String?) {
|
||||
Task {
|
||||
let sucess = await SRStoreAPI.requestReceiveCoinsPackCoins(id: id)
|
||||
self.requestCoinsPackData()
|
||||
if sucess {
|
||||
self.showVideoRecommand()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///展示视频推荐
|
||||
private func showVideoRecommand() {
|
||||
guard self.recommandView == nil else { return }
|
||||
Task {
|
||||
let (model, _, _) = await SRShortApi.requestRecommand()
|
||||
guard let model = model else { return }
|
||||
guard self.recommandView == nil else { return }
|
||||
let view = SRDetailRecommendview()
|
||||
view.dataArr = model
|
||||
view.didSelectedVideo = { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
let vc = SRDetailPlayerViewController()
|
||||
vc.shortId = model.short_play_id
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
view.show(in: SRTool.keyWindow)
|
||||
self.recommandView = view
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
//
|
||||
// SRCoinPackConfirmItem1View.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/4.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinPackConfirmItem1View: SRCoinPackConfirmItemView {
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
lazy var bgIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "getBg"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
titleLabel.text = "synthreel_bonus_you_get".localized
|
||||
|
||||
let view1 = getItemView(image: UIImage(named: "dailyIocn"), text: "synthreel_weekly_refill_package".localized)
|
||||
let view2 = getItemView(image: UIImage(named: "rewardicon"), text: "synthreel_dailu_bonuses".localized)
|
||||
|
||||
addSubview(bgIconImageView)
|
||||
addSubview(view1)
|
||||
addSubview(view2)
|
||||
|
||||
bgIconImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
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 = UIImageView()
|
||||
view.image = .itemBg
|
||||
|
||||
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 = .white
|
||||
label.text = text
|
||||
label.textAlignment = .center
|
||||
|
||||
|
||||
view.addSubview(imageView)
|
||||
view.addSubview(label)
|
||||
|
||||
imageView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(5)
|
||||
}
|
||||
|
||||
label.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview().inset(10)
|
||||
make.top.equalTo(imageView.snp.bottom).offset(10)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
||||
134
SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem2View.swift
Normal file
@ -0,0 +1,134 @@
|
||||
//
|
||||
// SRCoinPackConfirmItem2View.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/4.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinPackConfirmItem2View: SRCoinPackConfirmItemView {
|
||||
|
||||
var list: [String]? {
|
||||
didSet {
|
||||
|
||||
self.stackView.sr_removeAllArrangedSubview()
|
||||
|
||||
list?.forEach {
|
||||
let view = SRCoinPackConfirmItem2View.ItemView()
|
||||
view.text = $0
|
||||
self.stackView.addArrangedSubview(view)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "receiveBg"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var lineView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white.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 = "synthreel_coin_bag_buy_tip_title".localized
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRCoinPackConfirmItem2View {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(bgIconImageView)
|
||||
addSubview(lineView)
|
||||
addSubview(stackView)
|
||||
|
||||
bgIconImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
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 SRCoinPackConfirmItem2View {
|
||||
|
||||
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 = .white
|
||||
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")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
//
|
||||
// SRCoinPackConfirmItemView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/4.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinPackConfirmItemView: UIView {
|
||||
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 18, weight: .bold)
|
||||
label.textColor = .white
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = .black
|
||||
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")
|
||||
}
|
||||
|
||||
}
|
||||
207
SynthReel/Class/Coinpack/view/SRCoinPackConfirmView.swift
Normal file
@ -0,0 +1,207 @@
|
||||
//
|
||||
// SRCoinPackConfirmView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/4.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import HWPanModal
|
||||
|
||||
class SRCoinPackConfirmView: SRPanModalContentView {
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
|
||||
var shortPlayId: String?
|
||||
var videoId: String?
|
||||
|
||||
var model: SRPayItem? {
|
||||
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: ""))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: SRLabel = {
|
||||
let label = SRLabel()
|
||||
label.font = .font(ofSize: 24, weight: .init(700))
|
||||
label.textColors = [UIColor._4_CFFD_4.cgColor, UIColor._51_D_4_FF.cgColor]
|
||||
label.textStartPoint = .init(x: 0.5, y: 0)
|
||||
label.textEndPoint = .init(x: 0.5, y: 1)
|
||||
label.text = "synthreel_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"), for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var scrollView: SRScrollView = {
|
||||
let scrollView = SRScrollView()
|
||||
scrollView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var item1View: SRCoinPackConfirmItem1View = {
|
||||
let view = SRCoinPackConfirmItem1View()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var item2View: SRCoinPackConfirmItem2View = {
|
||||
let view = SRCoinPackConfirmItem2View()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var priceLabel: SRLabel = {
|
||||
let label = SRLabel()
|
||||
label.font = .font(ofSize: 18, weight: .bold)
|
||||
label.textColors = [UIColor.srBlue.cgColor, UIColor.srBlue.cgColor]
|
||||
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var continueButton: UIButton = {
|
||||
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
guard let model = self.model else { return }
|
||||
SRIapManager.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.setTitle("synthreel_continue".localized, for: .normal)
|
||||
button.setTitleColor(.black, for: .normal)
|
||||
button.titleLabel?.font = .font(ofSize: 14, weight: .bold)
|
||||
button.setBackgroundImage(.continueBG, for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.backgroundColor = .clear
|
||||
sr_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 SRCoinPackConfirmView {
|
||||
|
||||
private func sr_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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -29,25 +29,24 @@ class SRCoinPackHeaderView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleView: SRCoinPackTitleview = {
|
||||
let view = SRCoinPackTitleview()
|
||||
// view.dotColor = .C_5_DDF_5
|
||||
private lazy var titleView: UILabel = {
|
||||
let view = UILabel()
|
||||
view.font = .font(ofSize: 14, weight: .regular)
|
||||
// view.textColors = [UIColor.C_5_DDF_5.cgColor, UIColor.C_5_DDF_5.cgColor]
|
||||
view.text = "fableon_rewards_overview".localized.uppercased()
|
||||
view.textColor = .white
|
||||
view.text = "synthreel_rewards_overview".localized.uppercased()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView1: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "fableon_weekly_total".localized
|
||||
view.title = "synthreel_weekly_total".localized
|
||||
view.coins = 0
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView2: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "fableon_claimable_coins".localized
|
||||
view.title = "synthreel_claimable_coins".localized
|
||||
view.coins = 0
|
||||
return view
|
||||
}()
|
||||
@ -66,7 +65,7 @@ class SRCoinPackHeaderView: UIView {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = .white.withAlphaComponent(0.5)
|
||||
label.text = "fableon_active_refills".localized + ": "
|
||||
label.text = "synthreel_active_refills".localized + ": "
|
||||
return label
|
||||
}()
|
||||
|
||||
@ -81,52 +80,111 @@ class SRCoinPackHeaderView: UIView {
|
||||
}()
|
||||
|
||||
private lazy var claimButton: UIButton = {
|
||||
let config = UIButton.Configuration.plain()
|
||||
let button = SRGradientbutton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
self?.clickClaimButton?()
|
||||
}))
|
||||
button.isEnabled = false
|
||||
button.layer.cornerRadius = 24
|
||||
button.layer.masksToBounds = true
|
||||
button.fa_locations = [0, 1]
|
||||
button.fa_startPoint = .init(x: 0, y: 0.5)
|
||||
button.fa_endPoint = .init(x: 1, y: 0.5)
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
let button = UIButton(type: .custom)
|
||||
|
||||
// 使用闭包创建配置更新处理器
|
||||
let updateHandler: UIButton.ConfigurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
guard let button = button as? SRGradientbutton else { return }
|
||||
|
||||
var config = UIButton.Configuration.plain()
|
||||
|
||||
if button.isEnabled {
|
||||
// button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor]
|
||||
button.setBackgroundImage(.claimAllHiglit, for: .normal)
|
||||
let coinImage = UIImage(named: "coins_icon_03")!
|
||||
// 启用状态
|
||||
config.background.image = .claimAllHiglit
|
||||
config.background.imageContentMode = .scaleToFill
|
||||
|
||||
// 创建富文本标题
|
||||
let coinImage = UIImage(named: "smallCoins")!
|
||||
let coinText = NSTextAttachment(image: coinImage)
|
||||
coinText.bounds = .init(x: 0, y: -2.5, width: coinImage.size.width, height: coinImage.size.height)
|
||||
coinText.bounds = CGRect(x: 0, y: -2.5, width: coinImage.size.width, height: coinImage.size.height)
|
||||
let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||
|
||||
let textAtt = AttributedString("fableon_claim_all".localized + " ", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.white
|
||||
let textAtt = AttributedString("synthreel_claim_all".localized + " ", attributes: AttributeContainer([
|
||||
.font: UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor: UIColor.white
|
||||
]))
|
||||
|
||||
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.white
|
||||
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)", attributes: AttributeContainer([
|
||||
.font: UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor: UIColor.white
|
||||
]))
|
||||
|
||||
button.configuration?.attributedTitle = textAtt + coinAtt + countAtt
|
||||
|
||||
config.attributedTitle = textAtt + coinAtt + countAtt
|
||||
|
||||
} else {
|
||||
// button.fa_colors = [UIColor._6_D_6_D_6_D.cgColor, UIColor._6_D_6_D_6_D.cgColor]
|
||||
button.setBackgroundImage(.claimAllNomarl, for: .normal)
|
||||
button.configuration?.attributedTitle = AttributedString("fableon_get_refill_button_text".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.white.withAlphaComponent(0.5)
|
||||
// 禁用状态
|
||||
config.background.image = .claimAllNomarl
|
||||
config.background.imageContentMode = .scaleToFill
|
||||
|
||||
config.attributedTitle = AttributedString("synthreel_get_refill_button_text".localized, attributes: AttributeContainer([
|
||||
.font: UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor: UIColor.white.withAlphaComponent(0.5)
|
||||
]))
|
||||
}
|
||||
|
||||
// 设置内边距
|
||||
config.contentInsets = NSDirectionalEdgeInsets(top: 12, leading: 20, bottom: 12, trailing: 20)
|
||||
|
||||
// 应用配置
|
||||
button.configuration = config
|
||||
}
|
||||
|
||||
// 初始化配置
|
||||
button.configurationUpdateHandler = updateHandler
|
||||
|
||||
// 设置点击事件
|
||||
button.addAction(UIAction(handler: { [weak self] _ in
|
||||
self?.clickClaimButton?()
|
||||
}), for: .touchUpInside)
|
||||
|
||||
// 初始状态
|
||||
button.isEnabled = false
|
||||
button.configurationUpdateHandler?(button) // 手动触发一次更新
|
||||
|
||||
return button
|
||||
}()
|
||||
// private lazy var claimButton: UIButton = {
|
||||
// let config = UIButton.Configuration.plain()
|
||||
// let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
// self?.clickClaimButton?()
|
||||
// }))
|
||||
// button.isEnabled = false
|
||||
// button.configurationUpdateHandler = { [weak self] button in
|
||||
// guard let self = self else { return }
|
||||
// guard let button = button as? UIButton else { return }
|
||||
// if button.isEnabled {
|
||||
//// button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor]
|
||||
// button.setBackgroundImage(.claimAllHiglit, for: .normal)
|
||||
// let coinImage = UIImage(named: "smallCoins")!
|
||||
// let coinText = NSTextAttachment(image: coinImage)
|
||||
// coinText.bounds = .init(x: 0, y: -2.5, width: coinImage.size.width, height: coinImage.size.height)
|
||||
// let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||
//
|
||||
// let textAtt = AttributedString("synthreel_claim_all".localized + " ", attributes: AttributeContainer([
|
||||
// .font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
// .foregroundColor : UIColor.white
|
||||
// ]))
|
||||
//
|
||||
// let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)".localized, attributes: AttributeContainer([
|
||||
// .font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
// .foregroundColor : UIColor.white
|
||||
// ]))
|
||||
//
|
||||
// button.configuration?.attributedTitle = textAtt + coinAtt + countAtt
|
||||
//
|
||||
//
|
||||
// } else {
|
||||
//// button.fa_colors = [UIColor._6_D_6_D_6_D.cgColor, UIColor._6_D_6_D_6_D.cgColor]
|
||||
// button.setBackgroundImage(.claimAllNomarl, for: .normal)
|
||||
// button.configuration?.attributedTitle = AttributedString("synthreel_get_refill_button_text".localized, attributes: AttributeContainer([
|
||||
// .font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
// .foregroundColor : UIColor.white.withAlphaComponent(0.5)
|
||||
// ]))
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// return button
|
||||
// }()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
@ -222,7 +280,7 @@ extension SRCoinPackHeaderView {
|
||||
}()
|
||||
|
||||
private lazy var iconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "coins_icon_09"))
|
||||
let imageView = UIImageView(image: UIImage(named: "smallCoins"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
|
||||
@ -1,92 +0,0 @@
|
||||
//
|
||||
// SRCoinPackTitleview.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinPackTitleview: UIView {
|
||||
|
||||
var text: String? {
|
||||
didSet {
|
||||
label.text = text
|
||||
}
|
||||
}
|
||||
|
||||
var font: UIFont? {
|
||||
didSet {
|
||||
label.font = font
|
||||
}
|
||||
}
|
||||
|
||||
var textColors: [CGColor]? {
|
||||
didSet {
|
||||
label.textColors = textColors
|
||||
}
|
||||
}
|
||||
|
||||
var dotColor: UIColor? {
|
||||
didSet {
|
||||
dotView1.backgroundColor = dotColor
|
||||
dotView2.backgroundColor = dotColor
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var dotView1: UIView = {
|
||||
let view = UIView()
|
||||
view.layer.cornerRadius = 3
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var dotView2: UIView = {
|
||||
let view = UIView()
|
||||
view.layer.cornerRadius = 3
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var label: SRLabel = {
|
||||
let label = SRLabel()
|
||||
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
addSubview(dotView1)
|
||||
addSubview(dotView2)
|
||||
addSubview(label)
|
||||
|
||||
dotView1.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview()
|
||||
make.width.height.equalTo(6)
|
||||
make.bottom.lessThanOrEqualToSuperview()
|
||||
}
|
||||
|
||||
label.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.bottom.lessThanOrEqualToSuperview()
|
||||
make.left.equalTo(dotView1.snp.right).offset(6)
|
||||
}
|
||||
|
||||
dotView2.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.bottom.lessThanOrEqualToSuperview()
|
||||
make.right.equalToSuperview()
|
||||
make.width.height.equalTo(dotView1)
|
||||
make.left.equalTo(label.snp.right).offset(6)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
114
SynthReel/Class/Coinpack/view/SRCoinsPackBuyView.swift
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// SRCoinsPackBuyView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/4.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinsPackBuyView: UIView {
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
|
||||
var dataArr: [SRPayItem] = []
|
||||
|
||||
private lazy var titleView: UILabel = {
|
||||
let view = UILabel()
|
||||
view.textColor = .white
|
||||
view.font = .font(ofSize: 14, weight: .regular)
|
||||
view.text = "synthreel_weekly_refill".localized.uppercased()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: UIScreen.width - 32, height: 84)
|
||||
layout.minimumLineSpacing = 12
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: SRCollectionView = {
|
||||
let collectionView = SRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
collectionView.register(SRPackCoinViewCell.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
|
||||
collectionView.snp.updateConstraints { make in
|
||||
make.height.equalTo(height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SRCoinsPackBuyView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(titleView)
|
||||
addSubview(collectionView)
|
||||
|
||||
titleView.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(30)
|
||||
make.height.equalTo(1)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension SRCoinsPackBuyView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SRPackCoinViewCell
|
||||
cell.model = self.dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = self.dataArr[indexPath.row]
|
||||
|
||||
let view = SRCoinPackConfirmView()
|
||||
view.model = model
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self.buyFinishHandle?()
|
||||
}
|
||||
}
|
||||
view.present(in: nil)
|
||||
}
|
||||
|
||||
}
|
||||
266
SynthReel/Class/Coinpack/view/SRCoinsPackClaimListCell.swift
Normal file
@ -0,0 +1,266 @@
|
||||
//
|
||||
// SRCoinsPackClaimListCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/4.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinsPackClaimListCell: UICollectionViewCell {
|
||||
var clickClaimButton: ((_ id: String?) -> Void)?
|
||||
|
||||
var model: SRCoinsPackReceiveModel? {
|
||||
didSet {
|
||||
coinsView1.coins = model?.week_max_total
|
||||
coinsView2.coins = model?.week_remaining_total
|
||||
|
||||
claimButton.isEnabled = (model?.receive_coins ?? 0) > 0
|
||||
claimButton.setNeedsUpdateConfiguration()
|
||||
|
||||
let titleAtt = NSMutableAttributedString(string: "\(model?.title ?? "")")
|
||||
titleAtt.yy_color = .white
|
||||
titleAtt.yy_font = .font(ofSize: 14, weight: .bold)
|
||||
|
||||
let day = "synthreel_d".localized
|
||||
let dayAtt = NSMutableAttributedString(string: " (\(day) \(model?.day_text ?? ""))")
|
||||
dayAtt.yy_color = .white
|
||||
dayAtt.yy_font = .font(ofSize: 14, weight: .regular)
|
||||
titleAtt.append(dayAtt)
|
||||
|
||||
titleLabel.attributedText = titleAtt
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
view.image = .claimCellbg
|
||||
view.contentMode = .scaleToFill
|
||||
view.isUserInteractionEnabled = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var bgIconImageView1 = UIImageView(image: UIImage(named: "coin_attachment_01"))
|
||||
private lazy var bgIconImageView2 = UIImageView(image: UIImage(named: "coin_attachment_03"))
|
||||
private lazy var bgIconImageView4 = UIImageView(image: UIImage(named: "coin_attachment_04"))
|
||||
private lazy var bgIconImageView5 = UIImageView(image: UIImage(named: "coin_attachment_05"))
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var lineView1 = UIImageView(image: UIImage(named: "横间隔虚线"))
|
||||
private lazy var lineView2 = UIImageView(image: UIImage(named: "间隔线"))
|
||||
|
||||
private lazy var coinsView1: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "synthreel_total_reward".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView2: CoinsView = {
|
||||
let view = CoinsView()
|
||||
view.title = "synthreel_remaining".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var claimButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.titleAlignment = .center
|
||||
config.background.image = .coinStackBg
|
||||
let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.clickClaimButton?(self.model?.id)
|
||||
}))
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
if button.isEnabled {
|
||||
button.configuration?.background.image = UIImage(named: "coinStackBg")
|
||||
let coinImage = UIImage(named: "bigCoins")!
|
||||
let coinText = NSTextAttachment(image: coinImage)
|
||||
coinText.bounds = .init(x: 0, y: -2.5, width: coinImage.size.width, height: coinImage.size.height)
|
||||
let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .bold),
|
||||
.foregroundColor : UIColor._000000.withAlphaComponent(0.5)
|
||||
]))
|
||||
|
||||
|
||||
button.configuration?.attributedTitle = AttributedString("fableon_claim".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.white
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = coinAtt + countAtt
|
||||
|
||||
} else {
|
||||
|
||||
button.configuration?.background.image = UIImage(named: "claimd_button_bg")
|
||||
button.configuration?.attributedTitle = AttributedString("synthreel_claimd".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||
.foregroundColor : UIColor.FFFFFF_40
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = nil
|
||||
}
|
||||
}
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRCoinsPackClaimListCell {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
contentView.addSubview(bgView)
|
||||
bgView.addSubview(bgIconImageView5)
|
||||
bgView.addSubview(bgIconImageView4)
|
||||
bgView.addSubview(bgIconImageView1)
|
||||
bgView.addSubview(bgIconImageView2)
|
||||
bgView.addSubview(titleLabel)
|
||||
bgView.addSubview(lineView1)
|
||||
bgView.addSubview(lineView2)
|
||||
bgView.addSubview(coinsView1)
|
||||
bgView.addSubview(coinsView2)
|
||||
bgView.addSubview(claimButton)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
bgIconImageView1.snp.makeConstraints { make in
|
||||
make.left.top.equalToSuperview()
|
||||
}
|
||||
|
||||
bgIconImageView2.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-8)
|
||||
}
|
||||
|
||||
bgIconImageView4.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.centerX.equalTo(bgIconImageView2)
|
||||
}
|
||||
|
||||
bgIconImageView5.snp.makeConstraints { make in
|
||||
make.bottom.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(0)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerY.equalTo(self.bgView.snp.top).offset(25)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-12)
|
||||
}
|
||||
|
||||
lineView1.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(48)
|
||||
}
|
||||
|
||||
coinsView1.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(12)
|
||||
make.bottom.equalToSuperview().offset(-18)
|
||||
}
|
||||
|
||||
lineView2.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsView1)
|
||||
make.left.equalTo(coinsView1.snp.right).offset(12)
|
||||
}
|
||||
|
||||
coinsView2.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinsView1)
|
||||
make.left.equalTo(lineView2.snp.right).offset(12)
|
||||
}
|
||||
|
||||
claimButton.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
make.centerY.equalTo(coinsView1)
|
||||
make.height.equalTo(48)
|
||||
make.width.equalTo(120)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRCoinsPackClaimListCell {
|
||||
|
||||
class CoinsView: UIView {
|
||||
|
||||
var title: String? {
|
||||
didSet {
|
||||
titleLabel.text = title
|
||||
}
|
||||
}
|
||||
|
||||
var coins: Int? {
|
||||
didSet {
|
||||
coinsLabel.text = "\(coins ?? 0)"
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .bold)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var iconImageView = UIImageView(image: UIImage(named: "coins_icon_03"))
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = SRLabel()
|
||||
label.font = .font(ofSize: 14, weight: .bold)
|
||||
label.textColors = [UIColor._4_CFFD_4.cgColor, UIColor._51_D_4_FF.cgColor]
|
||||
label.textStartPoint = .init(x: 0.5, y: 0)
|
||||
label.textEndPoint = .init(x: 0.5, y: 1)
|
||||
label.text = "0"
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
addSubview(titleLabel)
|
||||
addSubview(iconImageView)
|
||||
addSubview(coinsLabel)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||
}
|
||||
|
||||
coinsLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(iconImageView)
|
||||
make.left.equalTo(iconImageView.snp.right).offset(4)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
106
SynthReel/Class/Coinpack/view/SRCoinsPackClaimListView.swift
Normal file
@ -0,0 +1,106 @@
|
||||
//
|
||||
// SRCoinsPackClaimListView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/4.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinsPackClaimListView: UIView {
|
||||
|
||||
var clickClaimButton: ((_ id: String?) -> Void)?
|
||||
|
||||
var dataArr: [SRCoinsPackReceiveModel] = [] {
|
||||
didSet {
|
||||
collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleView: UILabel = {
|
||||
let view = UILabel()
|
||||
view.textColor = .white
|
||||
view.font = .font(ofSize: 14, weight: .regular)
|
||||
view.text = "synthreel_refills".localized.uppercased()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: UIScreen.width - 32, height: 122)
|
||||
layout.minimumLineSpacing = 12
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: SRCollectionView = {
|
||||
let collectionView = SRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
collectionView.register(SRCoinsPackClaimListCell.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
|
||||
collectionView.snp.updateConstraints { make in
|
||||
make.height.equalTo(height)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRCoinsPackClaimListView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(titleView)
|
||||
addSubview(collectionView)
|
||||
|
||||
titleView.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(30)
|
||||
make.height.equalTo(1)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension SRCoinsPackClaimListView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SRCoinsPackClaimListCell
|
||||
cell.model = self.dataArr[indexPath.row]
|
||||
cell.clickClaimButton = { [weak self] id in
|
||||
self?.clickClaimButton?(id)
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
}
|
||||
@ -81,8 +81,6 @@ class SREpSelectorCell: UICollectionViewCell {
|
||||
make.right.top.equalToSuperview().inset(4)
|
||||
make.width.height.equalTo(12)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -36,6 +36,12 @@ class SRShortDetailPlayerCell: JXPlayerListCell {
|
||||
await self?.sr_viewModel?.handleUnlockVideo()
|
||||
}
|
||||
}
|
||||
|
||||
view.adUnlockButton = { [weak self] in
|
||||
Task {
|
||||
await self?.sr_viewModel?.handleAdUnlockVideo()
|
||||
}
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
320
SynthReel/Class/Player/V/SRVideoRechargeView.swift
Normal file
@ -0,0 +1,320 @@
|
||||
//
|
||||
// SRVideoRechargeView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/5.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRVideoRechargeView: SRPanModalContentView {
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
var didDismissHandle: (() -> Void)?
|
||||
|
||||
var model: SRPayDateModel? {
|
||||
didSet {
|
||||
self.stackView.sr_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: SRVideoInfoModel? {
|
||||
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)
|
||||
}
|
||||
self.didDismissHandle?()
|
||||
}))
|
||||
button.setImage(UIImage(named: "Close"), for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var scrollView: SRScrollView = {
|
||||
let scrollView = SRScrollView()
|
||||
// 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: SRStoreCoinsView = {
|
||||
let view = SRStoreCoinsView()
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
self?.buyFinishHandle?()
|
||||
Task {
|
||||
await self?.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var vipView: SRStoreVipView = {
|
||||
let view = SRStoreVipView()
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
self?.buyFinishHandle?()
|
||||
Task {
|
||||
await self?.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var videoCoinsView: SRVideoRechargeView.CoinsView = {
|
||||
let view = SRVideoRechargeView.CoinsView()
|
||||
view.title = "synthreel_price".localized + ":"
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var totalCoinsView: SRVideoRechargeView.CoinsView = {
|
||||
let view = SRVideoRechargeView.CoinsView()
|
||||
view.title = "synthreel_balance".localized + ":"
|
||||
view.coins = SRLogin.manager.userInfo?.totalCoins ?? 0
|
||||
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 = .white
|
||||
label.text = "synthreel_tips".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var tipTextLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 10, weight: .regular)
|
||||
label.textColor = .white
|
||||
label.text = "store_tips".localized
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: SRLogin.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 = SRLogin.manager.userInfo?.totalCoins ?? 0
|
||||
}
|
||||
|
||||
override func present(in view: UIView?) {
|
||||
super.present(in: view)
|
||||
// self.hw_contentView.sr_addEffectView(style: .dark)
|
||||
// self.hw_contentView.sr_setRoundedCorner(topLeft: 24, topRight: 24, bottomLeft: 0, bottomRight: 0)
|
||||
}
|
||||
|
||||
override func allowsTapBackgroundToDismiss() -> Bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension SRVideoRechargeView {
|
||||
|
||||
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 SRVideoRechargeView {
|
||||
|
||||
@objc private func requestRestore() {
|
||||
guard let shortPlayId = self.videoInfo?.short_play_id, let videoId = self.videoInfo?.short_play_video_id else { return }
|
||||
|
||||
SRIapManager.manager.restore(isLoding: false, shortPlayId: shortPlayId, videoId: videoId) { [weak self] isFinish, buyType in
|
||||
if isFinish {
|
||||
Task {
|
||||
await SRLogin.manager.requestUserInfo(completer: nil)
|
||||
self?.buyFinishHandle?()
|
||||
await self?.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension SRVideoRechargeView {
|
||||
|
||||
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 = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var iconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bigCoins"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .bold)
|
||||
label.textColor = .white
|
||||
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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,6 +19,8 @@ class SRShortPlayerViewModel: JXPlayerListViewModel {
|
||||
|
||||
var recommandList: [SRShortModel] = []
|
||||
|
||||
private var payDataRequest: SRPayDataRequest?
|
||||
|
||||
///是否展示推荐数据
|
||||
private(set) var isShowRecommand = false
|
||||
private var recommandTimer: Timer?
|
||||
@ -87,9 +89,9 @@ class SRShortPlayerViewModel: JXPlayerListViewModel {
|
||||
case .noPlay:
|
||||
SRToast.show(text: "buy_fail_toast_01".localized)
|
||||
case .notEnough:
|
||||
break
|
||||
//跳广告解锁
|
||||
// self.openRechargeView()
|
||||
self.openRechargeView()
|
||||
break
|
||||
default: break
|
||||
}
|
||||
|
||||
@ -139,7 +141,71 @@ extension SRShortPlayerViewModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func handleAdUnlockVideo() async {
|
||||
|
||||
|
||||
}
|
||||
|
||||
func openRechargeView() {
|
||||
guard let videoInfo = self.currentCell?.model as? SRVideoInfoModel else { return }
|
||||
guard self.popView == nil else { return }
|
||||
|
||||
self.payDataRequest = SRPayDataRequest()
|
||||
if let model = SRIapManager.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? SRVideoRechargeView {
|
||||
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: SRPayDateModel, _ videoInfo: SRVideoInfoModel) {
|
||||
guard self.popView == nil else { return }
|
||||
Task {
|
||||
await SRStatAPI.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: SRPayDateModel, _ videoInfo: SRVideoInfoModel) {
|
||||
Task {
|
||||
await SRStatAPI.requestEventStat(orderCode: nil, shortPlayId: videoInfo.short_play_id, videoId: videoInfo.short_play_video_id, eventKey: .payTemplateDialog, errorMsg: nil, otherParamenters: [
|
||||
"event_name" : "pay open"
|
||||
])
|
||||
}
|
||||
let view = SRVideoRechargeView()
|
||||
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.didDismissHandle = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
// self._showVipRetainAlert(videoInfo)
|
||||
}
|
||||
view.present(in: nil)
|
||||
self.popView = view
|
||||
}
|
||||
|
||||
|
||||
@objc private func handleRecommandTimer() {
|
||||
self.isShowRecommand = true
|
||||
|
||||
18
SynthReel/Class/Store/Model/SRIapVerifyModel.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// SRIapVerifyModel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct SRIapVerifyModel: SmartCodable {
|
||||
|
||||
var money: String?
|
||||
var status: String?
|
||||
var is_backhaul: String?
|
||||
var code: String?
|
||||
}
|
||||
25
SynthReel/Class/Store/Model/SRPayAlertModel.swift
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// SRPayAlertModel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class SRPayAlertModel: NSObject, SmartCodable {
|
||||
|
||||
required override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
var coins_modal_easy_close: Bool?
|
||||
|
||||
var info: SRPayItem?
|
||||
|
||||
var forced_recharge: Bool?
|
||||
|
||||
var close_label: String?
|
||||
}
|
||||
168
SynthReel/Class/Store/Model/SRPayDateModel.swift
Normal file
@ -0,0 +1,168 @@
|
||||
//
|
||||
// SRPayDateModel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
import StoreKit
|
||||
|
||||
class SRPayDateModel: NSObject, SmartCodable {
|
||||
|
||||
|
||||
required override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
enum SortName: String, SmartCaseDefaultable {
|
||||
case coin = "list_coins"
|
||||
case vip = "list_sub_vip"
|
||||
}
|
||||
|
||||
var list_coins: [SRPayItem]?
|
||||
var list_sub_vip: [SRPayItem]?
|
||||
var list_sub_coins: [SRPayItem]?
|
||||
var sort: [SortName]?
|
||||
|
||||
///0: 老版支付 1:新版支付
|
||||
var pay_mode: Int?
|
||||
///0: 普通金币 1:金币包模式
|
||||
var show_type: Int?
|
||||
|
||||
}
|
||||
|
||||
|
||||
class SRPayItem: 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: SRStoreAPI.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: SRPayExtInfo?
|
||||
|
||||
///0 无优惠 1 首次购买优惠 2 二次购买优惠
|
||||
var discount_type: Int?
|
||||
|
||||
@IgnoredKey
|
||||
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 "w_complex".localized
|
||||
|
||||
case .month:
|
||||
return "m_complex".localized
|
||||
|
||||
case .quarter:
|
||||
return "q_complex".localized
|
||||
|
||||
case .year:
|
||||
return "Y_complex".localized
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func getVipTitle() -> String? {
|
||||
switch self.vip_type_key {
|
||||
case .week:
|
||||
return "synthreel_weekly_vip".localized
|
||||
|
||||
case .month:
|
||||
return "synthreel_monthly_vip".localized
|
||||
|
||||
case .quarter:
|
||||
return "synthreel_quarterly_vip".localized
|
||||
|
||||
case .year:
|
||||
return "synthreel_yearly_vip".localized
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SRPayExtInfo: 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]?
|
||||
|
||||
}
|
||||
8
SynthReel/Class/Store/Model/Untitled.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Untitled.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
222
SynthReel/Class/Store/VC/SRStoreController.swift
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// SRStoreController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRStoreController: SRViewController {
|
||||
|
||||
private var payRequest: SRPayDataRequest?
|
||||
|
||||
///支付数据
|
||||
private var payDataModel = SRIapManager.manager.payDateModel
|
||||
|
||||
private lazy var scrollView: SRScrollView = {
|
||||
let scrollView = SRScrollView()
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.spacing = 18
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinsView: SRStoreCoinsView = {
|
||||
let view = SRStoreCoinsView()
|
||||
// view.buyFinishHandle = { [weak self] in
|
||||
// self?.buyFinish()
|
||||
// }
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
|
||||
private lazy var vipView: SRStoreVipView = {
|
||||
let view = SRStoreVipView()
|
||||
// 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 = .white
|
||||
label.text = "synthreel_tips".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var tipTextLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 10, weight: .regular)
|
||||
label.textColor = .white
|
||||
label.text = "store_tips".localized
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "synthreel_store".localized
|
||||
let barButtonItem = UIBarButtonItem(title: "synthreel_restore".localized, style: .plain, target: self, action: #selector(handleRestore))
|
||||
barButtonItem.tintColor = .white
|
||||
self.navigationItem.rightBarButtonItem = barButtonItem
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
updateLayout()
|
||||
|
||||
requestPayData()
|
||||
|
||||
SRIapManager.manager.restore(isLoding: false) { [weak self] isFinish, buyType in
|
||||
if isFinish {
|
||||
Task{
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self?.buyFinish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
// fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
private func buyFinish() {
|
||||
self.requestPayData()
|
||||
}
|
||||
|
||||
@objc private func handleRestore() {
|
||||
SRIapManager.manager.restore { [weak self] isFinish, buyType in
|
||||
if isFinish {
|
||||
Task{
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self?.buyFinish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout() {
|
||||
self.stackView.sr_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: [SRPayItem] = []
|
||||
|
||||
// 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 SRStoreController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
view.addSubview(scrollView)
|
||||
// scrollView.addSubview(titleLabel)
|
||||
scrollView.addSubview(stackView)
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(29)
|
||||
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRStoreController {
|
||||
|
||||
private func requestPayData() {
|
||||
payRequest = SRPayDataRequest()
|
||||
payRequest?.requestProducts { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else { return }
|
||||
self.payDataModel = model
|
||||
|
||||
self.updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
183
SynthReel/Class/Store/Views/SRBigCoinViewCell.swift
Normal file
@ -0,0 +1,183 @@
|
||||
//
|
||||
// SRBigCoinViewCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRBigCoinViewCell: SRStoreCoinsCell {
|
||||
|
||||
// MARK: - UI Elements
|
||||
private let centerContainer = UIView() // ✅ 提升为成员属性
|
||||
|
||||
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.image = UIImage(named: "hot_cell_back")
|
||||
imageView.contentMode = .scaleToFill
|
||||
imageView.clipsToBounds = true
|
||||
imageView.isUserInteractionEnabled = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var badgeImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.image = UIImage(named: "hotBadge")
|
||||
imageView.contentMode = .scaleToFill
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var badgeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.boldSystemFont(ofSize: 10)
|
||||
label.textColor = UIColor(hexString:"#FFAF1A")
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.image = UIImage(named: "bigCoins")
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var coinLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.boldSystemFont(ofSize: 20)
|
||||
label.textColor = UIColor(hexString: "#FF9F05")
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var bonusLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.systemFont(ofSize: 12)
|
||||
label.textColor = UIColor(hexString: "#FFD400")
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var priceLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.boldSystemFont(ofSize: 17)
|
||||
label.textColor = .white
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
override var model: SRPayItem? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupUI()
|
||||
setupConstraints()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
setupUI()
|
||||
setupConstraints()
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func setupUI() {
|
||||
contentView.addSubview(bgImageView)
|
||||
contentView.addSubview(badgeImageView)
|
||||
badgeImageView.addSubview(badgeLabel)
|
||||
|
||||
// 中间容器(金币 + 数字 + 额外奖励)
|
||||
contentView.addSubview(centerContainer)
|
||||
centerContainer.addSubview(coinImageView)
|
||||
centerContainer.addSubview(coinLabel)
|
||||
centerContainer.addSubview(bonusLabel)
|
||||
|
||||
contentView.addSubview(priceLabel)
|
||||
}
|
||||
|
||||
private func setupConstraints() {
|
||||
// 背景图片
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
// 右上角角标
|
||||
badgeImageView.snp.makeConstraints { make in
|
||||
make.top.right.equalToSuperview().inset(3)
|
||||
}
|
||||
|
||||
badgeLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
}
|
||||
|
||||
// 中间容器
|
||||
centerContainer.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(19)
|
||||
}
|
||||
|
||||
// 金币图片
|
||||
coinImageView.snp.makeConstraints { make in
|
||||
make.left.top.bottom.equalToSuperview()
|
||||
make.size.equalTo(CGSize(width: 32, height: 25))
|
||||
}
|
||||
|
||||
// 金币数量
|
||||
coinLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinImageView)
|
||||
make.left.equalTo(coinImageView.snp.right).offset(0)
|
||||
}
|
||||
|
||||
// 额外奖励
|
||||
bonusLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinImageView)
|
||||
make.left.equalTo(coinLabel.snp.right).offset(0)
|
||||
make.right.equalToSuperview()
|
||||
}
|
||||
|
||||
// 价格标签
|
||||
priceLabel.snp.makeConstraints { make in
|
||||
make.bottom.equalToSuperview().offset(-8)
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Update UI
|
||||
|
||||
private func updateUI() {
|
||||
|
||||
let coins = model?.coins ?? 0
|
||||
let sendCoins = model?.send_coins ?? 0
|
||||
|
||||
coinLabel.text = "\(coins)"
|
||||
|
||||
priceLabel.text = (model?.currency ?? "") + " " + (model?.price ?? "")
|
||||
if sendCoins > 0 {
|
||||
bonusLabel.isHidden = false
|
||||
badgeImageView.isHidden = false
|
||||
bonusLabel.text = "+\(sendCoins) "
|
||||
|
||||
let ratio = String(format: "%.0f", CGFloat(sendCoins) / CGFloat(coins) * 100)
|
||||
badgeLabel.text = "+\(ratio)%"
|
||||
} else {
|
||||
bonusLabel.isHidden = true
|
||||
badgeImageView.isHidden = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
202
SynthReel/Class/Store/Views/SRPackCoinViewCell.swift
Normal file
@ -0,0 +1,202 @@
|
||||
//
|
||||
// SRPackCoinViewCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRPackCoinViewCell: SRStoreCoinsCell {
|
||||
|
||||
override var model: SRPayItem? {
|
||||
didSet {
|
||||
coinsLabel.text = "\(model?.ext_info?.max_total_coins ?? 0)"
|
||||
if let text = model?.ext_info?.receive_coins_rate, !text.isEmpty {
|
||||
ratioLabel.text = text
|
||||
ratioBgView.isHidden = false
|
||||
} else {
|
||||
ratioBgView.isHidden = true
|
||||
}
|
||||
|
||||
priceView.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgImageview: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "coinPackCell"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var moreCoinsImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "moreCoins"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var iconImageview: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bigCoins"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var stackImageview: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "coinStackBg"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .init(700))
|
||||
label.textColor = .white
|
||||
label.text = "synthreel_weekly_refill".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinsLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 18, weight: .init(900))
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var ratioBgView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white.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 = .white
|
||||
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)
|
||||
config.background.image = .coinStackBg
|
||||
let button = UIButton(configuration: config)
|
||||
button.isUserInteractionEnabled = false
|
||||
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(hexString: "#FFE600")
|
||||
]))
|
||||
|
||||
|
||||
button.configuration?.attributedTitle = priceString
|
||||
|
||||
var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||
.foregroundColor : UIColor.white.withAlphaComponent(0.05),
|
||||
.strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
||||
.strikethroughColor: UIColor.white.withAlphaComponent(0.05)
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = subtitle
|
||||
|
||||
} else {
|
||||
|
||||
button.configuration?.attributedTitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 18, weight: .bold),
|
||||
.foregroundColor : UIColor(hexString: "#FFE600")
|
||||
]))
|
||||
|
||||
button.configuration?.attributedSubtitle = AttributedString("/\(timeText)", attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||
.foregroundColor : UIColor.black.withAlphaComponent(0.5)
|
||||
]))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRPackCoinViewCell {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
contentView.addSubview(bgImageview)
|
||||
bgImageview.addSubview(moreCoinsImageView)
|
||||
bgImageview.addSubview(iconImageview)
|
||||
bgImageview.addSubview(titleLabel)
|
||||
bgImageview.addSubview(coinsLabel)
|
||||
bgImageview.addSubview(ratioBgView)
|
||||
ratioBgView.addSubview(ratioLabel)
|
||||
bgImageview.addSubview(priceView)
|
||||
|
||||
bgImageview.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(6)
|
||||
make.left.equalTo(14)
|
||||
}
|
||||
|
||||
moreCoinsImageView.snp.makeConstraints { make in
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(9)
|
||||
make.left.equalTo(11)
|
||||
make.size.equalTo(CGSizeMake(54, 31))
|
||||
}
|
||||
|
||||
iconImageview.snp.makeConstraints { make in
|
||||
make.left.equalTo(moreCoinsImageView.snp.right)
|
||||
make.centerY.equalTo(moreCoinsImageView)
|
||||
}
|
||||
|
||||
coinsLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(iconImageview)
|
||||
make.left.equalTo(iconImageview.snp.right)
|
||||
}
|
||||
|
||||
ratioBgView.snp.makeConstraints { make in
|
||||
make.left.equalTo(coinsLabel.snp.right).offset(4)
|
||||
make.height.equalTo(18)
|
||||
make.centerY.equalTo(moreCoinsImageView)
|
||||
}
|
||||
|
||||
ratioLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(8)
|
||||
}
|
||||
|
||||
priceView.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-12)
|
||||
make.bottom.equalTo(-8)
|
||||
make.height.equalTo(48)
|
||||
make.width.greaterThanOrEqualTo(88)
|
||||
}
|
||||
}
|
||||
}
|
||||
182
SynthReel/Class/Store/Views/SRSmallCoinViewCell.swift
Normal file
@ -0,0 +1,182 @@
|
||||
//
|
||||
// SRSmallCoinViewCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRSmallCoinViewCell: SRStoreCoinsCell {
|
||||
// MARK: - UI Elements
|
||||
private let centerContainer = UIView() // ✅ 提升为成员属性
|
||||
|
||||
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.image = UIImage(named: "samllCellBg")
|
||||
imageView.contentMode = .scaleToFill
|
||||
imageView.clipsToBounds = true
|
||||
imageView.isUserInteractionEnabled = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var badgeImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.image = UIImage(named: "samllBadge")
|
||||
imageView.contentMode = .scaleToFill
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var badgeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.boldSystemFont(ofSize: 10)
|
||||
label.textColor = UIColor(hexString:"#FFAF1A")
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.image = UIImage(named: "smallCoins")
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var coinLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.boldSystemFont(ofSize: 20)
|
||||
label.textColor = UIColor(hexString: "#FF9F05")
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var bonusLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.systemFont(ofSize: 12)
|
||||
label.textColor = UIColor(hexString: "#FFD400")
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var priceLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.boldSystemFont(ofSize: 17)
|
||||
label.textColor = .white
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
override var model: SRPayItem? {
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupUI()
|
||||
setupConstraints()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
setupUI()
|
||||
setupConstraints()
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func setupUI() {
|
||||
contentView.addSubview(bgImageView)
|
||||
contentView.addSubview(badgeImageView)
|
||||
badgeImageView.addSubview(badgeLabel)
|
||||
|
||||
// 中间容器(金币 + 数字 + 额外奖励)
|
||||
contentView.addSubview(centerContainer)
|
||||
centerContainer.addSubview(coinImageView)
|
||||
centerContainer.addSubview(coinLabel)
|
||||
centerContainer.addSubview(bonusLabel)
|
||||
|
||||
contentView.addSubview(priceLabel)
|
||||
}
|
||||
|
||||
private func setupConstraints() {
|
||||
// 背景图片
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
// 右上角角标
|
||||
badgeImageView.snp.makeConstraints { make in
|
||||
make.top.right.equalToSuperview().inset(3)
|
||||
}
|
||||
|
||||
badgeLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
}
|
||||
|
||||
// 中间容器
|
||||
centerContainer.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(19)
|
||||
}
|
||||
|
||||
// 金币图片
|
||||
coinImageView.snp.makeConstraints { make in
|
||||
make.left.top.bottom.equalToSuperview()
|
||||
make.size.equalTo(CGSize(width: 32, height: 25))
|
||||
}
|
||||
|
||||
// 金币数量
|
||||
coinLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinImageView)
|
||||
make.left.equalTo(coinImageView.snp.right).offset(0)
|
||||
}
|
||||
|
||||
// 额外奖励
|
||||
bonusLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(coinImageView)
|
||||
make.left.equalTo(coinLabel.snp.right).offset(0)
|
||||
make.right.equalToSuperview()
|
||||
}
|
||||
|
||||
// 价格标签
|
||||
priceLabel.snp.makeConstraints { make in
|
||||
make.bottom.equalToSuperview().offset(-8)
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Update UI
|
||||
|
||||
private func updateUI() {
|
||||
|
||||
let coins = model?.coins ?? 0
|
||||
let sendCoins = model?.send_coins ?? 0
|
||||
|
||||
coinLabel.text = "\(coins)"
|
||||
|
||||
priceLabel.text = (model?.currency ?? "") + " " + (model?.price ?? "")
|
||||
if sendCoins > 0 {
|
||||
bonusLabel.isHidden = false
|
||||
badgeImageView.isHidden = false
|
||||
bonusLabel.text = "+\(sendCoins) "
|
||||
|
||||
let ratio = String(format: "%.0f", CGFloat(sendCoins) / CGFloat(coins) * 100)
|
||||
badgeLabel.text = "+\(ratio)%"
|
||||
} else {
|
||||
bonusLabel.isHidden = true
|
||||
badgeImageView.isHidden = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
24
SynthReel/Class/Store/Views/SRStoreCoinsCell.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// SRStoreCoinsCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRStoreCoinsCell: UICollectionViewCell {
|
||||
var model: SRPayItem?
|
||||
|
||||
var sr_isSelected = false
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
233
SynthReel/Class/Store/Views/SRStoreCoinsView.swift
Normal file
@ -0,0 +1,233 @@
|
||||
//
|
||||
// SRStoreCoinsView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRStoreCoinsView: UIView {
|
||||
var shortPlayId: String?
|
||||
var videoId: String?
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
|
||||
private lazy var dataArr: [[SRPayItem]] = []
|
||||
|
||||
private var selectedIndexPath: IndexPath?
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white
|
||||
label.text = "store_title_1".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
||||
let config = UICollectionViewCompositionalLayoutConfiguration()
|
||||
config.interSectionSpacing = 10
|
||||
|
||||
let layout = UICollectionViewCompositionalLayout { [weak self] section, _ in
|
||||
guard let self = self else { return nil}
|
||||
guard let model = dataArr[section].first else { return nil }
|
||||
|
||||
if model.buy_type == .subCoins {
|
||||
return self.coinsBigLayoutSection()
|
||||
} else if model.size == .big {
|
||||
return self.bigLayoutSection()
|
||||
} else {
|
||||
return self.smallLayoutSection()
|
||||
}
|
||||
}
|
||||
layout.configuration = config
|
||||
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: SRCollectionView = {
|
||||
let collectionView = SRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.clipsToBounds = false
|
||||
collectionView.isScrollEnabled = false
|
||||
collectionView.register(SRBigCoinViewCell.self, forCellWithReuseIdentifier: "SRBigCoinViewCell")
|
||||
collectionView.register(SRSmallCoinViewCell.self, forCellWithReuseIdentifier: "SRSmallCoinViewCell")
|
||||
collectionView.register(SRPackCoinViewCell.self, forCellWithReuseIdentifier: "SRPackCoinViewCell")
|
||||
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: [SRPayItem]) {
|
||||
self.dataArr.removeAll()
|
||||
var bigArr: [SRPayItem] = []
|
||||
var smallArr: [SRPayItem] = []
|
||||
var coinPackArr: [SRPayItem] = []
|
||||
|
||||
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 SRStoreCoinsView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(collectionView)
|
||||
addSubview(titleLabel)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(0)
|
||||
make.left.equalTo(12)
|
||||
}
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(10)
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.height.equalTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRStoreCoinsView {
|
||||
|
||||
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(80)), subitems: [item])
|
||||
group.interItemSpacing = .fixed(12)
|
||||
|
||||
let layoutSection = NSCollectionLayoutSection(group: group)
|
||||
layoutSection.interGroupSpacing = 12
|
||||
layoutSection.contentInsets = .init(top: 0, leading: 15, bottom: 0, trailing: 15)
|
||||
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 SRStoreCoinsView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let model = dataArr[indexPath.section][indexPath.row]
|
||||
|
||||
var identifier = "SRBigCoinViewCell"
|
||||
if model.buy_type == .subCoins {
|
||||
identifier = "SRPackCoinViewCell"
|
||||
} else if model.size == .small {
|
||||
identifier = "SRSmallCoinViewCell"
|
||||
}
|
||||
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! SRStoreCoinsCell
|
||||
cell.model = model
|
||||
cell.sr_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 = SRCoinPackConfirmView()
|
||||
view.shortPlayId = self.shortPlayId
|
||||
view.videoId = self.videoId
|
||||
view.model = model
|
||||
view.buyFinishHandle = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self.buyFinishHandle?()
|
||||
}
|
||||
}
|
||||
view.present(in: nil)
|
||||
} else {
|
||||
SRIapManager.manager.start(model: model, shortPlayId: self.shortPlayId, videoId: self.videoId) { [weak self] finish in
|
||||
guard let self = self else { return }
|
||||
if finish {
|
||||
Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self.buyFinishHandle?()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
206
SynthReel/Class/Store/Views/SRStoreVipCell.swift
Normal file
@ -0,0 +1,206 @@
|
||||
//
|
||||
// SRStoreVipCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRStoreVipCell: UICollectionViewCell {
|
||||
var item:SRPayItem? {
|
||||
didSet {
|
||||
nameLabel.text = item?.brief
|
||||
desLabel.text = item?.fa_description
|
||||
// coinTimeLabel.text = item?.auto_sub
|
||||
|
||||
if let coins = item?.send_coins, coins > 0 {
|
||||
sendCoinLabel.text = "+\("synthreel_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 = .double
|
||||
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")
|
||||
priceLabel.textColor = UIColor(hexString: "#4CFFD4")
|
||||
|
||||
case .month:
|
||||
bgView.image = UIImage(named: "vip_bg_image_month")
|
||||
priceLabel.textColor = UIColor(hexString: "#00EEFF")
|
||||
|
||||
case .quarter:
|
||||
bgView.image = UIImage(named: "vip_bg_image_quarter")
|
||||
priceLabel.textColor = UIColor(hexString: "#FFC21B")
|
||||
|
||||
case .year:
|
||||
bgView.image = UIImage(named: "vip_bg_image_year")
|
||||
priceLabel.textColor = UIColor(hexString: "#FF721B")
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
coinTimeLabel.textColor = sendCoinLabel.textColor
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
private lazy var nameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 14, weight: .init(800))
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
private lazy var priceLabel: SRLabel = {
|
||||
let label = SRLabel()
|
||||
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 = .white.withAlphaComponent(0.03)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var desLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
label.textColor = .white.withAlphaComponent(0.4)
|
||||
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 SRStoreVipCell {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
contentView.addSubview(bgView)
|
||||
contentView.addSubview(nameLabel)
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
nameLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(11)
|
||||
make.left.equalToSuperview().offset(17)
|
||||
}
|
||||
|
||||
|
||||
priceLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(17)
|
||||
make.top.equalTo(nameLabel.snp.bottom).offset(5)
|
||||
}
|
||||
|
||||
desLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(17)
|
||||
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)
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
133
SynthReel/Class/Store/Views/SRStoreVipView.swift
Normal file
@ -0,0 +1,133 @@
|
||||
//
|
||||
// SRStoreVipView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRStoreVipView: UIView {
|
||||
var dataArr: [SRPayItem] = [] {
|
||||
didSet {
|
||||
collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var shortPlayId: String?
|
||||
var videoId: String?
|
||||
|
||||
var buyFinishHandle: (() -> Void)?
|
||||
|
||||
private lazy var viptitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white
|
||||
label.text = "synthreel_viptitle".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
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(90)), subitems: [item])
|
||||
|
||||
let layoutSection = NSCollectionLayoutSection(group: group)
|
||||
layoutSection.interGroupSpacing = 10
|
||||
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: SRCollectionView = {
|
||||
let collectionView = SRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.isScrollEnabled = false
|
||||
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||
collectionView.register(SRStoreVipCell.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 SRStoreVipView {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
addSubview(viptitleLabel)
|
||||
addSubview(collectionView)
|
||||
|
||||
viptitleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.left.equalTo(12)
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.top.equalTo(viptitleLabel.snp.bottom).offset(10)
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.height.equalTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension SRStoreVipView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SRStoreVipCell
|
||||
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]
|
||||
|
||||
SRIapManager.manager.start(model: model, shortPlayId: self.shortPlayId, videoId: self.videoId) { [weak self] finish in
|
||||
guard let self = self else { return }
|
||||
if finish {
|
||||
Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self.buyFinishHandle?()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
SynthReel/Class/User/VC/SRUserListViewController.swift
Normal file
@ -0,0 +1,127 @@
|
||||
//
|
||||
// SRUserListViewController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/02.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import JXPagingView
|
||||
|
||||
class SRUserListViewController: SRViewController {
|
||||
|
||||
private lazy var dataArr: [SRUserSettingModel] = []
|
||||
|
||||
private lazy var tableViewHeaderView: SRUserListHeaderView = {
|
||||
let view = SRUserListHeaderView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 44))
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tableView: SRTableView = {
|
||||
let tableView = SRTableView(frame: .zero, style: .plain)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = 60
|
||||
tableView.separatorStyle = .none
|
||||
tableView.backgroundColor = .clear
|
||||
tableView.register(SRUserSettingCell.self, forCellReuseIdentifier: "cell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
sr_setupLayout()
|
||||
|
||||
self.backgroundImageView.image = UIImage(named: "settingback")
|
||||
self.backgroundImageView.snp.remakeConstraints { make in
|
||||
make.bottom.top.equalTo(self.tableView)
|
||||
make.left.right.equalToSuperview().inset(15)
|
||||
}
|
||||
|
||||
setDataArr()
|
||||
}
|
||||
|
||||
// override func listScrollView() -> UIScrollView {
|
||||
// return self.tableView
|
||||
// }
|
||||
//
|
||||
// override func listViewDidScrollCallback(callback: @escaping (UIScrollView) -> ()) {
|
||||
// self.didScrollCallback = callback
|
||||
// }
|
||||
}
|
||||
|
||||
extension SRUserListViewController {
|
||||
|
||||
private func sr_setupLayout() {
|
||||
tableView.tableHeaderView = self.tableViewHeaderView
|
||||
|
||||
view.addSubview(tableView)
|
||||
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.left.right.equalToSuperview().inset(15)
|
||||
}
|
||||
}
|
||||
|
||||
private func setDataArr() {
|
||||
let arr = [
|
||||
SRUserSettingModel(type: .feedback, name: "synthreel_feedback".localized, icon: UIImage(named: "icon_feedback")),
|
||||
SRUserSettingModel(type: .login, name: "synthreel_login".localized, icon: UIImage(named: "icon_login")),
|
||||
SRUserSettingModel(type: .deleteAccount, name: "synthreel_delet_account".localized, icon: UIImage(named: "icon_delet")),
|
||||
SRUserSettingModel(type: .about, name: "synthreel_about_us".localized, icon: UIImage(named: "icon_about")),
|
||||
SRUserSettingModel(type: .privacyPolicy, name: "synthreel_privacy_policy".localized, icon: UIImage(named: "icon_privacy")),
|
||||
SRUserSettingModel(type: .userAgreement, name: "synthreel_user_agreement".localized, icon: UIImage(named: "icon_user")),
|
||||
]
|
||||
self.dataArr = arr
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: UITableViewDelegate, UITableViewDataSource
|
||||
extension SRUserListViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SRUserSettingCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
self.didScrollCallback?(scrollView)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let model = dataArr[indexPath.row]
|
||||
switch model.type {
|
||||
case .about:
|
||||
let aboutvc = SRAboutUsController ();
|
||||
self.navigationController?.pushViewController(aboutvc, animated: true)
|
||||
break
|
||||
case .login:
|
||||
let loginview = SRUserLoginView()
|
||||
loginview.present(in: nil)
|
||||
break
|
||||
case .feedback:
|
||||
let vc = SRFeedBackController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
break
|
||||
case .privacyPolicy:
|
||||
if let url = URL(string: SRWebBaseURL + "/private") {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
break
|
||||
case .userAgreement:
|
||||
if let url = URL(string: SRWebBaseURL + "/user_policy") {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
break
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,174 +7,109 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import JXPagingView
|
||||
|
||||
class SRUserViewController: SRViewController {
|
||||
|
||||
private lazy var dataArr: [SRUserSettingModel] = []
|
||||
|
||||
lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
return layout
|
||||
private lazy var headerView: SRUserHeaderView = {
|
||||
let view = SRUserHeaderView()
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var collectionView: SRCollectionView = {
|
||||
let collectionView = SRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.register(SRUserSettingCell.self, forCellWithReuseIdentifier: "cell")
|
||||
collectionView.register(SRUserTopCell.self, forCellWithReuseIdentifier: "topcell")
|
||||
collectionView.register(SRCoinPackCell.self, forCellWithReuseIdentifier: "coincell")
|
||||
collectionView.register(SRUserRewardCell.self, forCellWithReuseIdentifier: "rewardCell")
|
||||
|
||||
collectionView.sr_addRefreshHeader { [weak self] in
|
||||
Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self?.collectionView.reloadData()
|
||||
}
|
||||
private lazy var listView: SRUserListViewController = SRUserListViewController()
|
||||
|
||||
private lazy var pagingView: JXPagingView = {
|
||||
let view = JXPagingView(delegate: self)
|
||||
view.mainTableView.backgroundColor = .clear
|
||||
view.listContainerView.backgroundColor = .clear
|
||||
view.listContainerView.listCellBackgroundColor = .clear
|
||||
view.mainTableView.sr_addRefreshHeader { [weak self] in
|
||||
self?.handleHeaderRefresh()
|
||||
}
|
||||
return collectionView
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
set_ui()
|
||||
setDataArr()
|
||||
|
||||
headerView.coinPackClickCallback = { [weak self] in
|
||||
let vc = SRCoinPackController()
|
||||
self?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
headerView.vipClickCallback = { [weak self] in
|
||||
let vc = SRStoreController()
|
||||
self?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
headerView.rewardClickCallback = { [weak self] in
|
||||
let vc = SRRewardController ()
|
||||
vc.theme = "theme_15"
|
||||
self?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||
}
|
||||
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self.headerView.updateUserInfo()
|
||||
}
|
||||
}
|
||||
|
||||
func handleHeaderRefresh() {
|
||||
Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
self.headerView.updateUserInfo()
|
||||
self.pagingView.mainTableView.sr_endHeaderRefreshing()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SRUserViewController {
|
||||
func set_ui (){
|
||||
view.addSubview(collectionView)
|
||||
view.addSubview(pagingView)
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
pagingView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||
extension SRUserViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
|
||||
if indexPath.section == 0{
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "topcell", for: indexPath) as! SRUserTopCell
|
||||
return cell
|
||||
} else if indexPath.section == 1 {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "coincell", for: indexPath) as! SRCoinPackCell
|
||||
return cell
|
||||
}else if indexPath.section == 2 {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "rewardCell", for: indexPath) as! SRUserRewardCell
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SRUserSettingCell
|
||||
cell.model = self.dataArr[indexPath.row];
|
||||
return cell
|
||||
//MARK: JXPagingViewDelegate
|
||||
extension SRUserViewController: JXPagingViewDelegate {
|
||||
|
||||
func pagingView(_ pagingView: JXPagingView, initListAtIndex index: Int) -> any JXPagingViewListViewDelegate {
|
||||
return listView
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
if section == 0 || section == 1{
|
||||
return 1
|
||||
}
|
||||
return self.dataArr.count
|
||||
func tableHeaderViewHeight(in pagingView: JXPagingView) -> Int {
|
||||
return Int(ceil(headerView.contentHeight))
|
||||
}
|
||||
|
||||
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
return 3
|
||||
func tableHeaderView(in pagingView: JXPagingView) -> UIView {
|
||||
return headerView
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
self.didScrollCallback?(scrollView)
|
||||
func heightForPinSectionHeader(in pagingView: JXPagingView) -> Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
if indexPath.section == 0 { return }
|
||||
if indexPath.section == 1 {
|
||||
let vc = SRCoinPackController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
return
|
||||
}
|
||||
let model = dataArr[indexPath.row]
|
||||
switch model.type {
|
||||
case .about:
|
||||
let aboutvc = SRAboutUsController ();
|
||||
self.navigationController?.pushViewController(aboutvc, animated: true)
|
||||
break
|
||||
case .login:
|
||||
let loginview = SRUserLoginView()
|
||||
loginview.present(in: nil)
|
||||
break
|
||||
case .feedback:
|
||||
// let vc = SRFeedBackController ();
|
||||
// self.navigationController?.pushViewController(vc, animated: true)
|
||||
let vc = SRRewardController ()
|
||||
vc.theme = "theme_15"
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
break
|
||||
case .privacyPolicy:
|
||||
if let url = URL(string: SRWebBaseURL + "/private") {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
break
|
||||
case .userAgreement:
|
||||
if let url = URL(string: SRWebBaseURL + "/user_policy") {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
break
|
||||
default: break
|
||||
}
|
||||
func viewForPinSectionHeader(in pagingView: JXPagingView) -> UIView {
|
||||
return UIView()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRUserViewController: UICollectionViewDelegateFlowLayout {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
if indexPath.section == 0 { return CGSizeMake(UIScreen.width, 278) }
|
||||
if indexPath.section == 1 { return CGSizeMake(UIScreen.width - 30, 70) }
|
||||
return CGSizeMake(UIScreen.width, 60)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension SRFavoritesViewController {
|
||||
|
||||
private func requestDataArr(page: Int) async {
|
||||
|
||||
if let dataArr = await SRHomeApi.requestFavoritesData(page: page) {
|
||||
if page == 1 {
|
||||
self.dataArr.removeAll()
|
||||
}
|
||||
self.dataArr += dataArr
|
||||
self.page = page
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRUserViewController {
|
||||
|
||||
private func setDataArr() {
|
||||
|
||||
let arr = [
|
||||
SRUserSettingModel(type: .feedback, name: "synthreel_feedback".localized, icon: UIImage(named: "icon_feedback")),
|
||||
SRUserSettingModel(type: .login, name: "synthreel_login".localized, icon: UIImage(named: "icon_login")),
|
||||
SRUserSettingModel(type: .about, name: "synthreel_about_us".localized, icon: UIImage(named: "icon_about")),
|
||||
SRUserSettingModel(type: .privacyPolicy, name: "synthreel_privacy_policy".localized, icon: UIImage(named: "icon_privacy")),
|
||||
SRUserSettingModel(type: .userAgreement, name: "synthreel_user_agreement".localized, icon: UIImage(named: "icon_user")),
|
||||
]
|
||||
self.dataArr = arr
|
||||
self.collectionView.reloadData()
|
||||
func numberOfLists(in pagingView: JXPagingView) -> Int {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinPackCell: UICollectionViewCell {
|
||||
class SRCoinPackCell: UIView {
|
||||
|
||||
lazy var bgImageView = UIImageView.init(image: UIImage(named: "userCoinCell"))
|
||||
|
||||
@ -41,9 +41,9 @@ class SRCoinPackCell: UICollectionViewCell {
|
||||
|
||||
extension SRCoinPackCell {
|
||||
func sr_setupUI() {
|
||||
contentView.addSubview(bgImageView)
|
||||
contentView.addSubview(titleLabel)
|
||||
contentView.addSubview(calimLabel)
|
||||
addSubview(bgImageView)
|
||||
addSubview(titleLabel)
|
||||
addSubview(calimLabel)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
|
||||
339
SynthReel/Class/User/view/SRUserHeaderView.swift
Normal file
@ -0,0 +1,339 @@
|
||||
//
|
||||
// SRUserHeaderView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/02.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRUserHeaderView: UIView {
|
||||
|
||||
lazy var topImageView : UIImageView = {
|
||||
let image = UIImageView(image: .顶部bg)
|
||||
image.contentMode = .scaleToFill
|
||||
return image
|
||||
}()
|
||||
|
||||
lazy var iconBgImageView = UIImageView(image: UIImage(named: "头像框"))
|
||||
|
||||
lazy var titleLabel : UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "Visitor"
|
||||
label.textColor = UIColor._51_D_4_FF
|
||||
label.font = .font(ofSize: 18, weight: .regular)
|
||||
label.backgroundColor = UIColor.init(patternImage: .userNameBg)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var userId : UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = UIColor.AAEAFF_0_5
|
||||
label.font = .font(ofSize: 13, weight: .regular)
|
||||
label.text = SRAccountManager.manager.userInfo?.customer_id
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
lazy var iconImageView: SRImageView = {
|
||||
let imageView = SRImageView()
|
||||
imageView.isUserInteractionEnabled = true
|
||||
imageView.image = .logo
|
||||
return imageView
|
||||
}()
|
||||
|
||||
lazy var coinImageView = UIImageView(image: UIImage(named: "coinBg"))
|
||||
lazy var sendCoinImageView = UIImageView(image: UIImage(named: "sendCoinBg"))
|
||||
|
||||
|
||||
lazy var coinTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "Coins"
|
||||
label.textColor = .white
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var coinValueLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "0"
|
||||
label.textColor = UIColor.srGreen
|
||||
label.font = .font(ofSize: 16, weight: .bold)
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var donateTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "Donate"
|
||||
label.textColor = .white
|
||||
label.font = .font(ofSize: 12, weight: .regular)
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var donateValueLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "0"
|
||||
label.textColor = UIColor.srBlue
|
||||
label.font = .font(ofSize: 16, weight: .bold)
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var coinPackView = SRCoinPackCell()
|
||||
|
||||
lazy var vipView = SRUserVIPView()
|
||||
lazy var rewardView = SRRewardView()
|
||||
|
||||
var contentHeight: CGFloat = 580
|
||||
var clickCallback: (() -> Void)? // Kept for backward compatibility or remove if unused
|
||||
var coinPackClickCallback: (() -> Void)?
|
||||
var vipClickCallback: (() -> Void)?
|
||||
var rewardClickCallback: (() -> Void)?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sr_setupUI()
|
||||
|
||||
let coinPackTap = UITapGestureRecognizer(target: self, action: #selector(coinPackTapAction))
|
||||
coinPackView.isUserInteractionEnabled = true
|
||||
coinPackView.addGestureRecognizer(coinPackTap)
|
||||
|
||||
let vipTap = UITapGestureRecognizer(target: self, action: #selector(vipTapAction))
|
||||
vipView.isUserInteractionEnabled = true
|
||||
vipView.addGestureRecognizer(vipTap)
|
||||
|
||||
let rewardTap = UITapGestureRecognizer(target: self, action: #selector(reardTapAction))
|
||||
rewardView.isUserInteractionEnabled = true
|
||||
rewardView.addGestureRecognizer(rewardTap)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc func coinPackTapAction() {
|
||||
coinPackClickCallback?()
|
||||
}
|
||||
|
||||
@objc func vipTapAction() {
|
||||
vipClickCallback?()
|
||||
}
|
||||
|
||||
@objc func reardTapAction() {
|
||||
rewardClickCallback?()
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
DispatchQueue.main.async {
|
||||
self.iconBgImageView.applyHexagonMask(cornerRadius: 2, rotationAngle: .pi / 6)
|
||||
}
|
||||
}
|
||||
|
||||
func updateUserInfo() {
|
||||
self.userId.text = SRAccountManager.manager.userInfo?.customer_id
|
||||
self.coinValueLabel.text = "\(SRAccountManager.manager.userInfo?.totalCoins ?? 0)"
|
||||
self.donateValueLabel.text = "\(SRAccountManager.manager.userInfo?.totalCoins ?? 0)" // Using same value for now as placeholder
|
||||
}
|
||||
}
|
||||
|
||||
extension SRUserHeaderView {
|
||||
func sr_setupUI (){
|
||||
addSubview(topImageView)
|
||||
addSubview(iconBgImageView)
|
||||
iconBgImageView.addSubview(iconImageView)
|
||||
addSubview(titleLabel)
|
||||
addSubview(userId)
|
||||
|
||||
addSubview(coinImageView)
|
||||
addSubview(sendCoinImageView)
|
||||
|
||||
coinImageView.addSubview(coinTitleLabel)
|
||||
coinImageView.addSubview(coinValueLabel)
|
||||
|
||||
sendCoinImageView.addSubview(donateTitleLabel)
|
||||
sendCoinImageView.addSubview(donateValueLabel)
|
||||
|
||||
addSubview(vipView)
|
||||
addSubview(coinPackView)
|
||||
addSubview(rewardView)
|
||||
|
||||
topImageView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
make.height.equalTo(278)
|
||||
}
|
||||
|
||||
iconBgImageView.snp.makeConstraints { make in
|
||||
make.top.equalTo(UIScreen.safeTop + 12);
|
||||
make.centerX.equalToSuperview()
|
||||
make.size.equalTo(CGSizeMake(86 , 96))
|
||||
}
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.edges.equalTo(UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(204);
|
||||
make.centerX.equalToSuperview()
|
||||
make.size.equalTo(CGSizeMake(136, 26))
|
||||
}
|
||||
|
||||
userId.snp.makeConstraints { make in
|
||||
make.top.equalTo(titleLabel.snp_bottomMargin).offset(7)
|
||||
make.centerX.equalToSuperview()
|
||||
make.height.equalTo(26)
|
||||
}
|
||||
|
||||
coinImageView.snp.makeConstraints { make in
|
||||
make.left.equalTo(15)
|
||||
make.top.equalTo(topImageView.snp.bottom).offset(0)
|
||||
make.height.equalTo(40)
|
||||
make.right.equalTo(self.snp.centerX).offset(-5)
|
||||
}
|
||||
|
||||
sendCoinImageView.snp.makeConstraints { make in
|
||||
make.right.equalTo(-15)
|
||||
make.top.equalTo(coinImageView)
|
||||
make.height.equalTo(40)
|
||||
make.left.equalTo(self.snp.centerX).offset(5)
|
||||
}
|
||||
|
||||
coinTitleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(coinImageView.snp.left).offset(52)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
|
||||
coinValueLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(coinTitleLabel.snp.right).offset(24)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
|
||||
donateTitleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(sendCoinImageView.snp.left).offset(52)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
|
||||
donateValueLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(donateTitleLabel.snp.right).offset(24)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
|
||||
coinPackView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview().inset(15)
|
||||
make.height.equalTo(70)
|
||||
make.top.equalTo(vipView.snp.bottom).offset(10)
|
||||
}
|
||||
|
||||
vipView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview().inset(15)
|
||||
make.height.equalTo(48)
|
||||
make.top.equalTo(sendCoinImageView.snp.bottom).offset(20)
|
||||
}
|
||||
|
||||
rewardView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview().inset(15)
|
||||
make.height.equalTo(72)
|
||||
make.top.equalTo(coinPackView.snp.bottom).offset(20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SRUserVIPView: UIView {
|
||||
|
||||
lazy var bgImageView = UIImageView(image: UIImage(named: "userStoreBg"))
|
||||
lazy var iconImageView = UIImageView(image: UIImage(named: "vicon"))
|
||||
lazy var arrowImageView = UIImageView(image: UIImage(named: "storeArrow"))
|
||||
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "Top-Up Coins & VIP"
|
||||
label.textColor = .white
|
||||
label.font = .font(ofSize: 16, weight: .bold)
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setupUI() {
|
||||
addSubview(bgImageView)
|
||||
addSubview(iconImageView)
|
||||
addSubview(titleLabel)
|
||||
addSubview(arrowImageView)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.left.equalTo(15)
|
||||
make.centerY.equalToSuperview()
|
||||
make.size.equalTo(CGSize(width: 24, height: 24))
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(iconImageView.snp.right).offset(10)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
|
||||
arrowImageView.snp.makeConstraints { make in
|
||||
make.right.equalTo(-15)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SRRewardView: UIView {
|
||||
|
||||
lazy var bgImageView = UIImageView(image: UIImage(named: "rewardsbg"))
|
||||
lazy var arrowImageView = UIImageView(image: UIImage(named: "rewardArrow"))
|
||||
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "Premium Rewards for Tasks"
|
||||
label.textColor = .white
|
||||
label.numberOfLines = 2;
|
||||
label.font = .font(ofSize: 16, weight: .bold)
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setupUI() {
|
||||
addSubview(bgImageView)
|
||||
addSubview(titleLabel)
|
||||
addSubview(arrowImageView)
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(110)
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalTo(arrowImageView.snp.left).offset(-20)
|
||||
}
|
||||
|
||||
arrowImageView.snp.makeConstraints { make in
|
||||
make.right.equalTo(-12)
|
||||
make.size.equalTo(CGSizeMake(40, 40))
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
49
SynthReel/Class/User/view/SRUserListHeaderView.swift
Normal file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// SRUserListHeaderView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/02.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRUserListHeaderView: UIView {
|
||||
|
||||
lazy var iconImageView = UIImageView.init(image: UIImage(named: "Union"))
|
||||
|
||||
lazy var titleLabel : UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = UIColor.white
|
||||
label.font = .font(ofSize: 16, weight: .init(500))
|
||||
label.text = "Settings & More".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sr_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
extension SRUserListHeaderView {
|
||||
func sr_setupUI() {
|
||||
addSubview(iconImageView)
|
||||
addSubview(titleLabel)
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.left.equalTo(15)
|
||||
make.centerY.equalToSuperview()
|
||||
make.size.equalTo(CGSizeMake(33, 16))
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(iconImageView.snp.left).offset(15)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRUserSettingCell: UICollectionViewCell {
|
||||
class SRUserSettingCell: SRTableViewCell {
|
||||
|
||||
var model : SRUserSettingModel? {
|
||||
didSet {
|
||||
@ -28,9 +28,8 @@ class SRUserSettingCell: UICollectionViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
sr_setupUI()
|
||||
}
|
||||
|
||||
|
||||
292
SynthReel/Libs/SRAppstore/SRIapManager.swift
Normal file
@ -0,0 +1,292 @@
|
||||
//
|
||||
// SRIapManager.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class SRIapManager {
|
||||
typealias CompletionHandler = ((_ finish: Bool) -> Void)
|
||||
///内购模版前缀
|
||||
static let IAPPrefix = "univico"
|
||||
|
||||
|
||||
static let manager = SRIapManager()
|
||||
|
||||
///成功回调
|
||||
private var completionHandler: CompletionHandler?
|
||||
|
||||
private var shortPlayId: String?
|
||||
private var videoId: String?
|
||||
|
||||
private lazy var iapManager: SRPayManger = {
|
||||
let manager = SRPayManger()
|
||||
manager.delegate = self
|
||||
return manager
|
||||
}()
|
||||
|
||||
private var orderCode: String?
|
||||
private var payId: String?
|
||||
|
||||
///预加载数据
|
||||
private var payRequest: SRPayDataRequest?
|
||||
var payDateModel: SRPayDateModel?
|
||||
|
||||
|
||||
///恢复购买使用
|
||||
///等待恢复的数据
|
||||
private var waitRestoreModel: SRWaitRestoreModel? = UserDefaults.sr_object(forKey: kSRWaitRestoreIAPDefaultsKey, as: SRWaitRestoreModel.self)
|
||||
|
||||
|
||||
///开始内购
|
||||
func start(model: SRPayItem, shortPlayId: String? = nil, videoId: String? = nil, hudShowView: UIView? = nil, handler: CompletionHandler? = nil) {
|
||||
|
||||
if let _ = self.waitRestoreModel {
|
||||
SRToast.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 = SRWaitRestoreModel()
|
||||
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
|
||||
}
|
||||
|
||||
SRHud.show(containerView: hudShowView)
|
||||
|
||||
Task {
|
||||
let orderModel = await SynthReel.SRStoreAPI.requestCreateOrder(payId: payId, shortPlayId: shortPlayId ?? "0", videoId: videoId ?? "0", isDiscount: isDiscount, identifierDiscount: identifierDiscount)
|
||||
guard let orderModel = orderModel else {
|
||||
SRHud.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: SRStoreAPI.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 {
|
||||
SRToast.show(text: "pay_error_5".localized)
|
||||
}
|
||||
completer?(false, buyType)
|
||||
return
|
||||
}
|
||||
|
||||
if isLoding {
|
||||
SRHud.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() ?? ""
|
||||
]
|
||||
Task {
|
||||
await SRStatAPI.requestEventStat(orderCode: orderCode, shortPlayId: shortPlayId, videoId: videoId, eventKey: .payRestore, errorMsg: "restore", otherParamenters: statParamenters)
|
||||
|
||||
let model = await SRStoreAPI.requestVerifyOrder(parameters: verifyData)
|
||||
if model == nil {
|
||||
completer?(false, buyType)
|
||||
return
|
||||
}
|
||||
|
||||
self.waitRestoreModel = nil
|
||||
UserDefaults.sr_setObject(nil, forKey: kSRWaitRestoreIAPDefaultsKey)
|
||||
if model?.status == "success" {
|
||||
if buyType == .subVip {
|
||||
SRLogin.manager.userInfo?.is_vip = true
|
||||
}
|
||||
|
||||
if isLoding {
|
||||
SRToast.show(text: "SRbleo_success".localized)
|
||||
}
|
||||
completer?(true, buyType)
|
||||
if buyType == .subVip {
|
||||
NotificationCenter.default.post(name: SRIapManager.buyVipFinishNotification, object: nil)
|
||||
}
|
||||
} else {
|
||||
completer?(false, buyType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func getProductId(templateId: String?) -> String? {
|
||||
guard let templateId = templateId else { return nil }
|
||||
return SRIapManager.IAPPrefix + "." + templateId
|
||||
}
|
||||
|
||||
func clean() {
|
||||
self.orderCode = nil
|
||||
self.payId = nil
|
||||
self.shortPlayId = nil
|
||||
self.videoId = nil
|
||||
self.completionHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: JXIAPManagerDelegate
|
||||
extension SRIapManager: SRPayMangerDelegate {
|
||||
|
||||
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()
|
||||
SRHud.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
self.waitRestoreModel?.productId = productId
|
||||
self.waitRestoreModel?.receipt = receipt
|
||||
self.waitRestoreModel?.transactionId = transactionIdentifier
|
||||
|
||||
UserDefaults.sr_setObject(self.waitRestoreModel, forKey: kSRWaitRestoreIAPDefaultsKey)
|
||||
|
||||
#if DEBUG
|
||||
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionIdentifier, purchaseToken: receipt)
|
||||
#else
|
||||
let verifyData = self.getVerifyOrderParameters(orderCode: orderCode, payId: payId, transactionId: transactionIdentifier, purchaseToken: receipt)
|
||||
#endif
|
||||
|
||||
Task {
|
||||
let model = await SRStoreAPI.requestVerifyOrder(parameters: verifyData)
|
||||
SRHud.dismiss()
|
||||
|
||||
if model == nil {
|
||||
await SRStatAPI.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.sr_setObject(nil, forKey: kSRWaitRestoreIAPDefaultsKey)
|
||||
|
||||
if model?.status == "success" {
|
||||
if buyType == .subVip {
|
||||
SRLogin.manager.userInfo?.is_vip = true
|
||||
}
|
||||
|
||||
SRToast.show(text: "SRbleo_success".localized)
|
||||
self.completionHandler?(true)
|
||||
if buyType == .subVip {
|
||||
NotificationCenter.default.post(name: SRIapManager.buyVipFinishNotification, object: nil)
|
||||
}
|
||||
} else {
|
||||
SRToast.show(text: "pay_error_4".localized)
|
||||
await SRStatAPI.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: SRPayMangerCode, msg: String?) {
|
||||
SRHud.dismiss()
|
||||
|
||||
if code == .noProduct {
|
||||
SRToast.show(text: "pay_error_2".localized)
|
||||
} else if code == .cancelled {
|
||||
SRToast.show(text: "pay_error_3".localized)
|
||||
}
|
||||
|
||||
if code == .cancelled {
|
||||
Task {
|
||||
await SRStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCancel, errorMsg: "user cancel")
|
||||
}
|
||||
} else {
|
||||
Task {
|
||||
await SRStatAPI.requestEventStat(orderCode: self.orderCode, shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payError, errorMsg: msg)
|
||||
}
|
||||
}
|
||||
|
||||
self.completionHandler?(false)
|
||||
|
||||
self.waitRestoreModel = nil
|
||||
self.clean()
|
||||
}
|
||||
}
|
||||
|
||||
extension SRIapManager {
|
||||
|
||||
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" : kSRAPPBundleName,
|
||||
"transaction_id": transactionId,
|
||||
"purchases_token" : purchaseToken
|
||||
]
|
||||
return parameters
|
||||
}
|
||||
|
||||
///预加载支付项
|
||||
func preloadingProducts() {
|
||||
SRPayManger.manager.fetchReceipt { _ in
|
||||
self.payRequest = SRPayDataRequest()
|
||||
self.payRequest?.requestProducts(isLoding: false, isToast: false) { model in
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRIapManager {
|
||||
///成功购买会员
|
||||
@objc static let buyVipFinishNotification = NSNotification.Name(rawValue: "SRIapManager.buyVipFinishNotification")
|
||||
|
||||
}
|
||||
37
SynthReel/Libs/SRAppstore/SRIapOrderModel.swift
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// SRIapOrderModel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct SRIapOrderModel: SmartCodable {
|
||||
|
||||
var code: Int?
|
||||
var message: String?
|
||||
var order_code: String?
|
||||
var is_backhaul: String?
|
||||
var money: String?
|
||||
var discount: SRIapOrderDiscountModel?
|
||||
|
||||
}
|
||||
|
||||
struct SRIapOrderDiscountModel: SmartCodable {
|
||||
|
||||
var discount_code: String?
|
||||
var is_discount: Bool?
|
||||
var sign_data: SRIapOrderDiscountSign?
|
||||
}
|
||||
|
||||
struct SRIapOrderDiscountSign: SmartCodable {
|
||||
|
||||
var keyIdentifier: String?
|
||||
var nonce: String?
|
||||
var timestamp: TimeInterval?
|
||||
var applicationUsername: String?
|
||||
var signature: String?
|
||||
}
|
||||
133
SynthReel/Libs/SRAppstore/SRPayDataRequest.swift
Normal file
@ -0,0 +1,133 @@
|
||||
//
|
||||
// SRPayDataRequest.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class SRPayDataRequest: NSObject {
|
||||
private var oldTemplateModel: SRPayDateModel?
|
||||
private(set) var newTemplateModel: SRPayDateModel?
|
||||
|
||||
private var payAlertModel: SRPayAlertModel?
|
||||
|
||||
private var completerBlock: ((_ model: SRPayDateModel?) -> Void)?
|
||||
private var payAlertBlock: ((_ model: SRPayAlertModel?) -> Void)?
|
||||
|
||||
private var isLoding = false
|
||||
private var isToast = false
|
||||
|
||||
func requestProducts(isLoding: Bool = false, isToast: Bool = true, completer: @escaping ((_ model: SRPayDateModel?) -> Void)) {
|
||||
self.payAlertBlock = nil
|
||||
self.completerBlock = completer
|
||||
self.isLoding = isLoding
|
||||
self.isToast = isToast
|
||||
|
||||
if isLoding {
|
||||
SRHud.show()
|
||||
}
|
||||
|
||||
Task {
|
||||
let model = await SRStoreAPI.requestPayTemplate()
|
||||
guard let model = model else {
|
||||
if isLoding {
|
||||
SRHud.dismiss()
|
||||
}
|
||||
self.completerBlock?(nil)
|
||||
return
|
||||
}
|
||||
self.oldTemplateModel = model
|
||||
|
||||
var productIdArr: [String] = []
|
||||
model.list_sub_vip?.forEach { item in
|
||||
productIdArr.append(SRIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
model.list_coins?.forEach { item in
|
||||
productIdArr.append(SRIapManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
|
||||
let set = Set(productIdArr)
|
||||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
productsRequest.delegate = self
|
||||
productsRequest.start()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: SKProductsRequestDelegate
|
||||
extension SRPayDataRequest: SKProductsRequestDelegate {
|
||||
|
||||
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||
if isLoding {
|
||||
SRHud.dismiss()
|
||||
}
|
||||
let products = response.products
|
||||
|
||||
if let block = self.completerBlock {
|
||||
guard let templateModel = self.oldTemplateModel else { return }
|
||||
|
||||
var newCoinList: [SRPayItem] = []
|
||||
var newVipList: [SRPayItem] = []
|
||||
|
||||
templateModel.list_coins?.forEach { item in
|
||||
let productId = SRIapManager.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 = SRIapManager.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
|
||||
SRIapManager.manager.payDateModel = templateModel
|
||||
|
||||
DispatchQueue.main.async {
|
||||
block(templateModel)
|
||||
}
|
||||
|
||||
} else if let block = self.payAlertBlock {
|
||||
guard let coinalertModel = self.payAlertModel else { return }
|
||||
let productId = SRIapManager.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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
50
SynthReel/Libs/SRAppstore/SRWaitRestoreModel.swift
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// SRWaitRestoreModel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRWaitRestoreModel: NSObject, NSSecureCoding {
|
||||
|
||||
|
||||
var orderCode: String?
|
||||
var payId: String?
|
||||
var productId: String?
|
||||
var receipt: String?
|
||||
var buyType: SRStoreAPI.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 = SRStoreAPI.BuyType(rawValue: type)
|
||||
}
|
||||
}
|
||||
}
|
||||
216
SynthReel/Libs/payManger/SRPayManger.swift
Normal file
@ -0,0 +1,216 @@
|
||||
//
|
||||
// SRPayManger.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/12/2.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
@objc protocol SRPayMangerDelegate {
|
||||
/// 购买成功
|
||||
@objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String)
|
||||
/// 购买失败
|
||||
@objc optional func jx_iapPayFailed(productId: String, code: SRPayMangerCode, msg: String?)
|
||||
/// 恢复商品(仅限永久有效商品)
|
||||
@objc optional func iapPayRestore(productIds: [String], transactionIds: [String])
|
||||
}
|
||||
|
||||
@objc enum SRPayMangerCode: Int {
|
||||
///未知错误
|
||||
case unknown
|
||||
///取消交易
|
||||
case cancelled
|
||||
///没有商品
|
||||
case noProduct
|
||||
}
|
||||
|
||||
class SRPayManger: NSObject {
|
||||
|
||||
|
||||
static let manager: SRPayManger = SRPayManger()
|
||||
|
||||
weak var delegate: SRPayMangerDelegate?
|
||||
|
||||
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 SRPayManger: 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 SRPayManger: 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 SRPayManger {
|
||||
|
||||
|
||||
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 SRPayManger: 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" : "0.400",
|
||||
"blue" : "0xFF",
|
||||
"green" : "0xFF",
|
||||
"red" : "0xFF"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
SynthReel/Source/Assets.xcassets/Image/Union.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Union@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Union@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
22
SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "dailyIocn@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "dailyIocn@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
22
SynthReel/Source/Assets.xcassets/coin/getBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "getBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "getBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 73 KiB |
22
SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "itemBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "itemBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 948 B |
BIN
SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
22
SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "receiveBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "receiveBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 86 KiB |
22
SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "rewardicon@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "rewardicon@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 18 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "coinBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "coinBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 56 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_delet@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_delet@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 577 B |
BIN
SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 794 B |
22
SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "moreCoins@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "moreCoins@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "rewardArrow@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "rewardArrow@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 20 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "rewardsbg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "rewardsbg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 126 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "sendCoinBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "sendCoinBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 56 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "settingback@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "settingback@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 438 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "storeArrow@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "storeArrow@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "userStoreBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "userStoreBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 42 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "vicon@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "vicon@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
6
SynthReel/Source/Assets.xcassets/store/Contents.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "bigCoins@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "bigCoins@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
22
SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "claimCellbg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "claimCellbg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||