diff --git a/SynthReel.xcodeproj/project.pbxproj b/SynthReel.xcodeproj/project.pbxproj index 3f8c6bd..cafeb7d 100644 --- a/SynthReel.xcodeproj/project.pbxproj +++ b/SynthReel.xcodeproj/project.pbxproj @@ -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 = ""; }; 3754ACF12ED975B9009EBCAD /* SRRewardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRRewardController.swift; sourceTree = ""; }; 3754ACF32ED98609009EBCAD /* SRCoinPackCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackCell.swift; sourceTree = ""; }; - 3754ACF52ED9A2D4009EBCAD /* SRCoinPackTitleview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackTitleview.swift; sourceTree = ""; }; 3754ACF72ED9A32C009EBCAD /* SRCoinPackHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackHeaderView.swift; sourceTree = ""; }; 3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackModel.swift; sourceTree = ""; }; 3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackReceiveModel.swift; sourceTree = ""; }; @@ -320,6 +347,35 @@ 3754AD3B2EDD9C01009EBCAD /* SRThirdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRThirdModel.swift; sourceTree = ""; }; 3754AD3D2EDD9C88009EBCAD /* SRLogin+FB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRLogin+FB.swift"; sourceTree = ""; }; 3754AEF72EDE94CD009EBCAD /* SRUserRewardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserRewardCell.swift; sourceTree = ""; }; + 3754AEF92EDEB4F4009EBCAD /* SRUserListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserListViewController.swift; sourceTree = ""; }; + 3754AEFB2EDEB515009EBCAD /* SRUserHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserHeaderView.swift; sourceTree = ""; }; + 3754AEFC2EDEB515009EBCAD /* SRUserListHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserListHeaderView.swift; sourceTree = ""; }; + 3754AF002EDED6FD009EBCAD /* SRPayManger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayManger.swift; sourceTree = ""; }; + 3754AF032EDED773009EBCAD /* SRIapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRIapManager.swift; sourceTree = ""; }; + 3754AF072EDED91C009EBCAD /* SRPayDateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayDateModel.swift; sourceTree = ""; }; + 3754AF092EDED9A8009EBCAD /* SRStoreAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreAPI.swift; sourceTree = ""; }; + 3754AF0B2EDEDA49009EBCAD /* SRPayDataRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayDataRequest.swift; sourceTree = ""; }; + 3754AF0D2EDEDAA9009EBCAD /* SRPayAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPayAlertModel.swift; sourceTree = ""; }; + 3754AF0F2EDEDD21009EBCAD /* SRWaitRestoreModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRWaitRestoreModel.swift; sourceTree = ""; }; + 3754AF112EDEDEBF009EBCAD /* SRIapOrderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRIapOrderModel.swift; sourceTree = ""; }; + 3754AF132EDEE1AC009EBCAD /* SRStatAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStatAPI.swift; sourceTree = ""; }; + 3754AF152EDEE43E009EBCAD /* SRIapVerifyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRIapVerifyModel.swift; sourceTree = ""; }; + 3754AF182EDEF0AF009EBCAD /* SRStoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreController.swift; sourceTree = ""; }; + 3754AF1B2EDEF112009EBCAD /* SRStoreCoinsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreCoinsView.swift; sourceTree = ""; }; + 3754AF1F2EDEF133009EBCAD /* SRStoreVipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreVipView.swift; sourceTree = ""; }; + 3754AF232EDEF38C009EBCAD /* SRBigCoinViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRBigCoinViewCell.swift; sourceTree = ""; }; + 3754AF252EDEF3A7009EBCAD /* SRSmallCoinViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRSmallCoinViewCell.swift; sourceTree = ""; }; + 3754AF272EDEF3CC009EBCAD /* SRPackCoinViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPackCoinViewCell.swift; sourceTree = ""; }; + 3754AF292EDEF425009EBCAD /* SRStoreCoinsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreCoinsCell.swift; sourceTree = ""; }; + 3754AF2B2EDEF4D5009EBCAD /* SRStoreVipCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRStoreVipCell.swift; sourceTree = ""; }; + 3754B00A2EE12040009EBCAD /* SRCoinsPackClaimListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackClaimListView.swift; sourceTree = ""; }; + 3754B00E2EE120C5009EBCAD /* SRCoinsPackClaimListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackClaimListCell.swift; sourceTree = ""; }; + 3754B0102EE1248D009EBCAD /* SRCoinsPackBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackBuyView.swift; sourceTree = ""; }; + 3754B0142EE12521009EBCAD /* SRCoinPackConfirmView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmView.swift; sourceTree = ""; }; + 3754B0162EE12633009EBCAD /* SRCoinPackConfirmItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmItemView.swift; sourceTree = ""; }; + 3754B0182EE1267B009EBCAD /* SRCoinPackConfirmItem1View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmItem1View.swift; sourceTree = ""; }; + 3754B01A2EE12690009EBCAD /* SRCoinPackConfirmItem2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackConfirmItem2View.swift; sourceTree = ""; }; + 3754B0302EE2C9D4009EBCAD /* SRVideoRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRVideoRechargeView.swift; sourceTree = ""; }; 3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRShortHeaderView.swift; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; @@ -550,6 +606,7 @@ 3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */, 3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */, 3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */, + 3754B0302EE2C9D4009EBCAD /* SRVideoRechargeView.swift */, ); path = V; sourceTree = ""; @@ -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 = ""; @@ -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 = ""; @@ -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 = ""; @@ -881,6 +955,56 @@ path = SRLogin; sourceTree = ""; }; + 3754AEFF2EDED691009EBCAD /* payManger */ = { + isa = PBXGroup; + children = ( + 3754AF002EDED6FD009EBCAD /* SRPayManger.swift */, + ); + path = payManger; + sourceTree = ""; + }; + 3754AF022EDED751009EBCAD /* SRAppstore */ = { + isa = PBXGroup; + children = ( + 3754AF032EDED773009EBCAD /* SRIapManager.swift */, + 3754AF0B2EDEDA49009EBCAD /* SRPayDataRequest.swift */, + 3754AF0F2EDEDD21009EBCAD /* SRWaitRestoreModel.swift */, + 3754AF112EDEDEBF009EBCAD /* SRIapOrderModel.swift */, + ); + path = SRAppstore; + sourceTree = ""; + }; + 3754AF172EDEF09C009EBCAD /* VC */ = { + isa = PBXGroup; + children = ( + 3754AF182EDEF0AF009EBCAD /* SRStoreController.swift */, + ); + path = VC; + sourceTree = ""; + }; + 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 = ""; + }; + 3754B0092EE11F71009EBCAD /* M */ = { + isa = PBXGroup; + children = ( + 3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */, + 3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */, + ); + path = M; + sourceTree = ""; + }; 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; diff --git a/SynthReel/Base/API/SRStatAPI.swift b/SynthReel/Base/API/SRStatAPI.swift new file mode 100644 index 0000000..1bd5edd --- /dev/null +++ b/SynthReel/Base/API/SRStatAPI.swift @@ -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) in + continuation.resume() + } + } + } +} diff --git a/SynthReel/Base/API/SRStoreAPI.swift b/SynthReel/Base/API/SRStoreAPI.swift new file mode 100644 index 0000000..9c50331 --- /dev/null +++ b/SynthReel/Base/API/SRStoreAPI.swift @@ -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) 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) 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) 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) 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) in + if response.isSuccess { + continuation.resume(returning: true) + }else{ + continuation.resume(returning: false) + } + } + } + } + + +} diff --git a/SynthReel/Base/Define/SRUserDefaultsKey.swift b/SynthReel/Base/Define/SRUserDefaultsKey.swift index db5c64d..84905a7 100644 --- a/SynthReel/Base/Define/SRUserDefaultsKey.swift +++ b/SynthReel/Base/Define/SRUserDefaultsKey.swift @@ -12,3 +12,12 @@ let kSRAccountTokenDefaultsKey = "kSRAccountTokenDefaultsKey" ///用户信息 let kSRUserInfoDefaultsKey = "kSRUserInfoDefaultsKey" + + +let kSRWaitRestoreIAPDefaultsKey = "kSRWaitRestoreIAPDefaultsKey" + +let kSRApnsAlertDefaultsKey = "kSRApnsAlertDefaultsKey" + +let kSRVersionUpdateAlertDefaultsKey = "kSRVersionUpdateAlertDefaultsKey" + +let kSRHasBeenOpenedAPPDefaultsKey = "kSRHasBeenOpenedAPPDefaultsKey" diff --git a/SynthReel/Base/Extension/String+SRAdd.swift b/SynthReel/Base/Extension/String+SRAdd.swift index 2ba88f4..5bc47e8 100644 --- a/SynthReel/Base/Extension/String+SRAdd.swift +++ b/SynthReel/Base/Extension/String+SRAdd.swift @@ -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: "
", with: "\n") } func localizedReplace(text: String) -> String { diff --git a/SynthReel/Base/Networking/SRUrlPath.swift b/SynthReel/Base/Networking/SRUrlPath.swift index c7a8c3d..aa41749 100644 --- a/SynthReel/Base/Networking/SRUrlPath.swift +++ b/SynthReel/Base/Networking/SRUrlPath.swift @@ -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" diff --git a/SynthReel/Base/View/SRPanModalContentView.swift b/SynthReel/Base/View/SRPanModalContentView.swift index cf5e474..68bd137 100644 --- a/SynthReel/Base/View/SRPanModalContentView.swift +++ b/SynthReel/Base/View/SRPanModalContentView.swift @@ -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) } diff --git a/SynthReel/Class/Store/Model/SRCoinsPackModel.swift b/SynthReel/Class/Coinpack/M/SRCoinsPackModel.swift similarity index 100% rename from SynthReel/Class/Store/Model/SRCoinsPackModel.swift rename to SynthReel/Class/Coinpack/M/SRCoinsPackModel.swift diff --git a/SynthReel/Class/Store/Model/SRCoinsPackReceiveModel.swift b/SynthReel/Class/Coinpack/M/SRCoinsPackReceiveModel.swift similarity index 100% rename from SynthReel/Class/Store/Model/SRCoinsPackReceiveModel.swift rename to SynthReel/Class/Coinpack/M/SRCoinsPackReceiveModel.swift diff --git a/SynthReel/Class/Coinpack/VC/SRCoinPackController.swift b/SynthReel/Class/Coinpack/VC/SRCoinPackController.swift index 62e2b24..0d072e6 100644 --- a/SynthReel/Class/Coinpack/VC/SRCoinPackController.swift +++ b/SynthReel/Class/Coinpack/VC/SRCoinPackController.swift @@ -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 + } + } + +} diff --git a/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem1View.swift b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem1View.swift new file mode 100644 index 0000000..f41ce7f --- /dev/null +++ b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem1View.swift @@ -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 + } +} diff --git a/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem2View.swift b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem2View.swift new file mode 100644 index 0000000..f683c5e --- /dev/null +++ b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem2View.swift @@ -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") + } + + + } +} diff --git a/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItemView.swift b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItemView.swift new file mode 100644 index 0000000..64cde3b --- /dev/null +++ b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmItemView.swift @@ -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") + } + +} diff --git a/SynthReel/Class/Coinpack/view/SRCoinPackConfirmView.swift b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmView.swift new file mode 100644 index 0000000..ff8c96a --- /dev/null +++ b/SynthReel/Class/Coinpack/view/SRCoinPackConfirmView.swift @@ -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) + } + } + +} diff --git a/SynthReel/Class/Coinpack/view/SRCoinPackHeaderView.swift b/SynthReel/Class/Coinpack/view/SRCoinPackHeaderView.swift index b066456..8b5d033 100644 --- a/SynthReel/Class/Coinpack/view/SRCoinPackHeaderView.swift +++ b/SynthReel/Class/Coinpack/view/SRCoinPackHeaderView.swift @@ -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 }() diff --git a/SynthReel/Class/Coinpack/view/SRCoinPackTitleview.swift b/SynthReel/Class/Coinpack/view/SRCoinPackTitleview.swift deleted file mode 100644 index 28c4508..0000000 --- a/SynthReel/Class/Coinpack/view/SRCoinPackTitleview.swift +++ /dev/null @@ -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") - } - -} diff --git a/SynthReel/Class/Coinpack/view/SRCoinsPackBuyView.swift b/SynthReel/Class/Coinpack/view/SRCoinsPackBuyView.swift new file mode 100644 index 0000000..c40a000 --- /dev/null +++ b/SynthReel/Class/Coinpack/view/SRCoinsPackBuyView.swift @@ -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) + } + +} diff --git a/SynthReel/Class/Coinpack/view/SRCoinsPackClaimListCell.swift b/SynthReel/Class/Coinpack/view/SRCoinsPackClaimListCell.swift new file mode 100644 index 0000000..1027ccd --- /dev/null +++ b/SynthReel/Class/Coinpack/view/SRCoinsPackClaimListCell.swift @@ -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") + } + } + +} diff --git a/SynthReel/Class/Coinpack/view/SRCoinsPackClaimListView.swift b/SynthReel/Class/Coinpack/view/SRCoinsPackClaimListView.swift new file mode 100644 index 0000000..f6726e2 --- /dev/null +++ b/SynthReel/Class/Coinpack/view/SRCoinsPackClaimListView.swift @@ -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 + } + +} diff --git a/SynthReel/Class/Player/V/SREpSelectorCell.swift b/SynthReel/Class/Player/V/SREpSelectorCell.swift index 883acbe..bb17e5f 100644 --- a/SynthReel/Class/Player/V/SREpSelectorCell.swift +++ b/SynthReel/Class/Player/V/SREpSelectorCell.swift @@ -81,8 +81,6 @@ class SREpSelectorCell: UICollectionViewCell { make.right.top.equalToSuperview().inset(4) make.width.height.equalTo(12) } - - } diff --git a/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift b/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift index a50c9f5..c9e553e 100644 --- a/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift +++ b/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift @@ -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 }() diff --git a/SynthReel/Class/Player/V/SRVideoRechargeView.swift b/SynthReel/Class/Player/V/SRVideoRechargeView.swift new file mode 100644 index 0000000..9730eb9 --- /dev/null +++ b/SynthReel/Class/Player/V/SRVideoRechargeView.swift @@ -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") + } + + } + +} diff --git a/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift b/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift index ec6a314..f514e28 100644 --- a/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift +++ b/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift @@ -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 diff --git a/SynthReel/Class/Store/Model/SRIapVerifyModel.swift b/SynthReel/Class/Store/Model/SRIapVerifyModel.swift new file mode 100644 index 0000000..57faacf --- /dev/null +++ b/SynthReel/Class/Store/Model/SRIapVerifyModel.swift @@ -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? +} diff --git a/SynthReel/Class/Store/Model/SRPayAlertModel.swift b/SynthReel/Class/Store/Model/SRPayAlertModel.swift new file mode 100644 index 0000000..7d2b2ee --- /dev/null +++ b/SynthReel/Class/Store/Model/SRPayAlertModel.swift @@ -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? +} diff --git a/SynthReel/Class/Store/Model/SRPayDateModel.swift b/SynthReel/Class/Store/Model/SRPayDateModel.swift new file mode 100644 index 0000000..d8abe2d --- /dev/null +++ b/SynthReel/Class/Store/Model/SRPayDateModel.swift @@ -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]? + +} diff --git a/SynthReel/Class/Store/Model/Untitled.swift b/SynthReel/Class/Store/Model/Untitled.swift new file mode 100644 index 0000000..1c7eb11 --- /dev/null +++ b/SynthReel/Class/Store/Model/Untitled.swift @@ -0,0 +1,8 @@ +// +// Untitled.swift +// SynthReel +// +// Created by CSGY on 2025/12/2. +// Copyright © 2025 SR. All rights reserved. +// + diff --git a/SynthReel/Class/Store/VC/SRStoreController.swift b/SynthReel/Class/Store/VC/SRStoreController.swift new file mode 100644 index 0000000..9c60e56 --- /dev/null +++ b/SynthReel/Class/Store/VC/SRStoreController.swift @@ -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() + } + } + + +} diff --git a/SynthReel/Class/Store/Views/SRBigCoinViewCell.swift b/SynthReel/Class/Store/Views/SRBigCoinViewCell.swift new file mode 100644 index 0000000..066bd5d --- /dev/null +++ b/SynthReel/Class/Store/Views/SRBigCoinViewCell.swift @@ -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 + } + + } + +} + diff --git a/SynthReel/Class/Store/Views/SRPackCoinViewCell.swift b/SynthReel/Class/Store/Views/SRPackCoinViewCell.swift new file mode 100644 index 0000000..ae749de --- /dev/null +++ b/SynthReel/Class/Store/Views/SRPackCoinViewCell.swift @@ -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) + } + } +} diff --git a/SynthReel/Class/Store/Views/SRSmallCoinViewCell.swift b/SynthReel/Class/Store/Views/SRSmallCoinViewCell.swift new file mode 100644 index 0000000..ada9f6e --- /dev/null +++ b/SynthReel/Class/Store/Views/SRSmallCoinViewCell.swift @@ -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 + } + + } + +} + diff --git a/SynthReel/Class/Store/Views/SRStoreCoinsCell.swift b/SynthReel/Class/Store/Views/SRStoreCoinsCell.swift new file mode 100644 index 0000000..a453046 --- /dev/null +++ b/SynthReel/Class/Store/Views/SRStoreCoinsCell.swift @@ -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") + } +} diff --git a/SynthReel/Class/Store/Views/SRStoreCoinsView.swift b/SynthReel/Class/Store/Views/SRStoreCoinsView.swift new file mode 100644 index 0000000..967bec0 --- /dev/null +++ b/SynthReel/Class/Store/Views/SRStoreCoinsView.swift @@ -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?() + } + + } + } + } + + + } +} diff --git a/SynthReel/Class/Store/Views/SRStoreVipCell.swift b/SynthReel/Class/Store/Views/SRStoreVipCell.swift new file mode 100644 index 0000000..f916a95 --- /dev/null +++ b/SynthReel/Class/Store/Views/SRStoreVipCell.swift @@ -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) +// } + + } + +} diff --git a/SynthReel/Class/Store/Views/SRStoreVipView.swift b/SynthReel/Class/Store/Views/SRStoreVipView.swift new file mode 100644 index 0000000..1af557f --- /dev/null +++ b/SynthReel/Class/Store/Views/SRStoreVipView.swift @@ -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?() + } + } + } + } +} diff --git a/SynthReel/Class/User/VC/SRUserListViewController.swift b/SynthReel/Class/User/VC/SRUserListViewController.swift new file mode 100644 index 0000000..c96f5ad --- /dev/null +++ b/SynthReel/Class/User/VC/SRUserListViewController.swift @@ -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 + } + } +} diff --git a/SynthReel/Class/User/VC/SRUserViewController.swift b/SynthReel/Class/User/VC/SRUserViewController.swift index 5962a5b..f3c7b4c 100644 --- a/SynthReel/Class/User/VC/SRUserViewController.swift +++ b/SynthReel/Class/User/VC/SRUserViewController.swift @@ -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 } } diff --git a/SynthReel/Class/User/view/SRCoinPackCell.swift b/SynthReel/Class/User/view/SRCoinPackCell.swift index 1031d76..97b9272 100644 --- a/SynthReel/Class/User/view/SRCoinPackCell.swift +++ b/SynthReel/Class/User/view/SRCoinPackCell.swift @@ -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() diff --git a/SynthReel/Class/User/view/SRUserHeaderView.swift b/SynthReel/Class/User/view/SRUserHeaderView.swift new file mode 100644 index 0000000..1076820 --- /dev/null +++ b/SynthReel/Class/User/view/SRUserHeaderView.swift @@ -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() + } + } +} diff --git a/SynthReel/Class/User/view/SRUserListHeaderView.swift b/SynthReel/Class/User/view/SRUserListHeaderView.swift new file mode 100644 index 0000000..49908bb --- /dev/null +++ b/SynthReel/Class/User/view/SRUserListHeaderView.swift @@ -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() + } + } +} diff --git a/SynthReel/Class/User/view/SRUserSettingCell.swift b/SynthReel/Class/User/view/SRUserSettingCell.swift index 29127a2..5464278 100644 --- a/SynthReel/Class/User/view/SRUserSettingCell.swift +++ b/SynthReel/Class/User/view/SRUserSettingCell.swift @@ -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() } diff --git a/SynthReel/Libs/SRAppstore/SRIapManager.swift b/SynthReel/Libs/SRAppstore/SRIapManager.swift new file mode 100644 index 0000000..7871edc --- /dev/null +++ b/SynthReel/Libs/SRAppstore/SRIapManager.swift @@ -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") + +} diff --git a/SynthReel/Libs/SRAppstore/SRIapOrderModel.swift b/SynthReel/Libs/SRAppstore/SRIapOrderModel.swift new file mode 100644 index 0000000..8d92977 --- /dev/null +++ b/SynthReel/Libs/SRAppstore/SRIapOrderModel.swift @@ -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? +} diff --git a/SynthReel/Libs/SRAppstore/SRPayDataRequest.swift b/SynthReel/Libs/SRAppstore/SRPayDataRequest.swift new file mode 100644 index 0000000..0247485 --- /dev/null +++ b/SynthReel/Libs/SRAppstore/SRPayDataRequest.swift @@ -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) + } + } + + } +} diff --git a/SynthReel/Libs/SRAppstore/SRWaitRestoreModel.swift b/SynthReel/Libs/SRAppstore/SRWaitRestoreModel.swift new file mode 100644 index 0000000..dc02227 --- /dev/null +++ b/SynthReel/Libs/SRAppstore/SRWaitRestoreModel.swift @@ -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) + } + } +} diff --git a/SynthReel/Libs/payManger/SRPayManger.swift b/SynthReel/Libs/payManger/SRPayManger.swift new file mode 100644 index 0000000..08bc773 --- /dev/null +++ b/SynthReel/Libs/payManger/SRPayManger.swift @@ -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) + } +} diff --git a/SynthReel/Source/Assets.xcassets/Color/#FFFFFF_40.colorset/Contents.json b/SynthReel/Source/Assets.xcassets/Color/#FFFFFF_40.colorset/Contents.json new file mode 100644 index 0000000..efdf7c5 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Color/#FFFFFF_40.colorset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Contents.json new file mode 100644 index 0000000..491dc35 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@2x.png b/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@2x.png new file mode 100644 index 0000000..846aa0d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@3x.png b/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@3x.png new file mode 100644 index 0000000..4464e7a Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/Union.imageset/Union@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/Contents.json new file mode 100644 index 0000000..b110740 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@2x.png b/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@2x.png new file mode 100644 index 0000000..6bf3655 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@3x.png b/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@3x.png new file mode 100644 index 0000000..c32699d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/dailyIocn.imageset/dailyIocn@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/Contents.json new file mode 100644 index 0000000..c15df61 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@2x.png b/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@2x.png new file mode 100644 index 0000000..d6b2502 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@3x.png b/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@3x.png new file mode 100644 index 0000000..1042b40 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/getBg.imageset/getBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/Contents.json new file mode 100644 index 0000000..2f9f7c4 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@2x.png b/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@2x.png new file mode 100644 index 0000000..a9ae177 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@3x.png b/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@3x.png new file mode 100644 index 0000000..c05e801 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/itemBg.imageset/itemBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/Contents.json new file mode 100644 index 0000000..ee55b29 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@2x.png b/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@2x.png new file mode 100644 index 0000000..17493a2 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@3x.png b/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@3x.png new file mode 100644 index 0000000..5f11e65 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/receiveBg.imageset/receiveBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/Contents.json new file mode 100644 index 0000000..c4ba084 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@2x.png b/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@2x.png new file mode 100644 index 0000000..700caab Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@3x.png b/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@3x.png new file mode 100644 index 0000000..342610b Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/coin/rewardicon.imageset/rewardicon@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/Contents.json new file mode 100644 index 0000000..b800eed --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@2x.png new file mode 100644 index 0000000..a67da89 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@3x.png new file mode 100644 index 0000000..d5ec3f3 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/coinBg.imageset/coinBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/Contents.json new file mode 100644 index 0000000..715c928 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@2x.png b/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@2x.png new file mode 100644 index 0000000..3771842 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@3x.png b/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@3x.png new file mode 100644 index 0000000..af36a7d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/icon_delet.imageset/icon_delet@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/Contents.json new file mode 100644 index 0000000..9aa1271 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@2x.png b/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@2x.png new file mode 100644 index 0000000..f5bca39 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@3x.png b/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@3x.png new file mode 100644 index 0000000..34c48a4 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/moreCoins.imageset/moreCoins@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/Contents.json new file mode 100644 index 0000000..5dc7c6a --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@2x.png b/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@2x.png new file mode 100644 index 0000000..0c683aa Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@3x.png b/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@3x.png new file mode 100644 index 0000000..0991f5b Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/rewardArrow.imageset/rewardArrow@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/Contents.json new file mode 100644 index 0000000..fa3780a --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@2x.png new file mode 100644 index 0000000..75c382b Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@3x.png new file mode 100644 index 0000000..63e98bb Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/rewardsbg.imageset/rewardsbg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/Contents.json new file mode 100644 index 0000000..998a826 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@2x.png new file mode 100644 index 0000000..76935d2 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@3x.png new file mode 100644 index 0000000..f1c91bd Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/sendCoinBg.imageset/sendCoinBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/Contents.json new file mode 100644 index 0000000..f4f6562 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@2x.png b/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@2x.png new file mode 100644 index 0000000..9a2461d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@3x.png b/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@3x.png new file mode 100644 index 0000000..67d521b Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/settingback.imageset/settingback@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/Contents.json new file mode 100644 index 0000000..de549e4 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@2x.png b/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@2x.png new file mode 100644 index 0000000..77d09c1 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@3x.png b/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@3x.png new file mode 100644 index 0000000..fda81ad Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/storeArrow.imageset/storeArrow@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/Contents.json new file mode 100644 index 0000000..65af18f --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@2x.png new file mode 100644 index 0000000..14cbe44 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@3x.png new file mode 100644 index 0000000..4803a56 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/userStoreBg.imageset/userStoreBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/Contents.json new file mode 100644 index 0000000..fc62baa --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@2x.png b/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@2x.png new file mode 100644 index 0000000..c2570ed Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@3x.png b/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@3x.png new file mode 100644 index 0000000..0dfe552 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/vicon.imageset/vicon@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/Contents.json b/SynthReel/Source/Assets.xcassets/store/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/Contents.json new file mode 100644 index 0000000..b9affd2 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@2x.png b/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@2x.png new file mode 100644 index 0000000..b61629d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@3x.png b/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@3x.png new file mode 100644 index 0000000..440591e Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/bigCoins.imageset/bigCoins@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/Contents.json new file mode 100644 index 0000000..9013135 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/claimCellbg@2x.png b/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/claimCellbg@2x.png new file mode 100644 index 0000000..9b7075b Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/claimCellbg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/claimCellbg@3x.png b/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/claimCellbg@3x.png new file mode 100644 index 0000000..e8eaea7 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/claimCellbg.imageset/claimCellbg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/Contents.json new file mode 100644 index 0000000..89c884b --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "claimd_button_bg@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "claimd_button_bg@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/claimd_button_bg@2x.png b/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/claimd_button_bg@2x.png new file mode 100644 index 0000000..674e424 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/claimd_button_bg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/claimd_button_bg@3x.png b/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/claimd_button_bg@3x.png new file mode 100644 index 0000000..7a288af Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/claimd_button_bg.imageset/claimd_button_bg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/Contents.json new file mode 100644 index 0000000..62a5fba --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "coinPackCell@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "coinPackCell@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/coinPackCell@2x.png b/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/coinPackCell@2x.png new file mode 100644 index 0000000..a126111 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/coinPackCell@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/coinPackCell@3x.png b/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/coinPackCell@3x.png new file mode 100644 index 0000000..40dc5bf Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/coinPackCell.imageset/coinPackCell@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/Contents.json new file mode 100644 index 0000000..c0f3b33 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "coinStackBg@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "coinStackBg@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/coinStackBg@2x.png b/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/coinStackBg@2x.png new file mode 100644 index 0000000..ee0c92e Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/coinStackBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/coinStackBg@3x.png b/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/coinStackBg@3x.png new file mode 100644 index 0000000..4bbd526 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/coinStackBg.imageset/coinStackBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/Contents.json new file mode 100644 index 0000000..debcec7 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "continueBG@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "continueBG@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/continueBG@2x.png b/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/continueBG@2x.png new file mode 100644 index 0000000..65af834 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/continueBG@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/continueBG@3x.png b/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/continueBG@3x.png new file mode 100644 index 0000000..d4f57ad Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/continueBG.imageset/continueBG@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/Contents.json new file mode 100644 index 0000000..615b90d --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "continueBG_none@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "continueBG_none@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/continueBG_none@2x.png b/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/continueBG_none@2x.png new file mode 100644 index 0000000..f0e9023 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/continueBG_none@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/continueBG_none@3x.png b/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/continueBG_none@3x.png new file mode 100644 index 0000000..d0ec2cd Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/continueBG_none.imageset/continueBG_none@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/Contents.json new file mode 100644 index 0000000..e35105f --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "hotBadge@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "hotBadge@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/hotBadge@2x.png b/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/hotBadge@2x.png new file mode 100644 index 0000000..c668818 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/hotBadge@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/hotBadge@3x.png b/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/hotBadge@3x.png new file mode 100644 index 0000000..4b55c6c Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/hotBadge.imageset/hotBadge@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/Contents.json new file mode 100644 index 0000000..7abf2a9 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "hot_cell_back@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "hot_cell_back@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/hot_cell_back@2x.png b/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/hot_cell_back@2x.png new file mode 100644 index 0000000..fb558aa Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/hot_cell_back@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/hot_cell_back@3x.png b/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/hot_cell_back@3x.png new file mode 100644 index 0000000..e3aba75 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/hot_cell_back.imageset/hot_cell_back@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/Contents.json new file mode 100644 index 0000000..24ce86d --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "samllBadge@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "samllBadge@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/samllBadge@2x.png b/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/samllBadge@2x.png new file mode 100644 index 0000000..a5de6b2 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/samllBadge@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/samllBadge@3x.png b/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/samllBadge@3x.png new file mode 100644 index 0000000..b67e33c Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/samllBadge.imageset/samllBadge@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/Contents.json new file mode 100644 index 0000000..076fd38 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "samllCellBg@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "samllCellBg@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/samllCellBg@2x.png b/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/samllCellBg@2x.png new file mode 100644 index 0000000..cd5eae3 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/samllCellBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/samllCellBg@3x.png b/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/samllCellBg@3x.png new file mode 100644 index 0000000..df14045 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/samllCellBg.imageset/samllCellBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/Contents.json new file mode 100644 index 0000000..e87c8b0 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "smallCoins@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "smallCoins@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/smallCoins@2x.png b/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/smallCoins@2x.png new file mode 100644 index 0000000..8339035 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/smallCoins@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/smallCoins@3x.png b/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/smallCoins@3x.png new file mode 100644 index 0000000..52a703b Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/smallCoins.imageset/smallCoins@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/Contents.json new file mode 100644 index 0000000..9982709 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "vipBadge@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "vipBadge@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/vipBadge@2x.png b/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/vipBadge@2x.png new file mode 100644 index 0000000..23f98a1 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/vipBadge@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/vipBadge@3x.png b/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/vipBadge@3x.png new file mode 100644 index 0000000..079f213 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vipBadge.imageset/vipBadge@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/Contents.json new file mode 100644 index 0000000..04097f3 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "vip_bg_image_month@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "vip_bg_image_month@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/vip_bg_image_month@2x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/vip_bg_image_month@2x.png new file mode 100644 index 0000000..255ce37 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/vip_bg_image_month@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/vip_bg_image_month@3x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/vip_bg_image_month@3x.png new file mode 100644 index 0000000..c85528f Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_month.imageset/vip_bg_image_month@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/Contents.json new file mode 100644 index 0000000..a8f31c6 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "vip_bg_image_quarter@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "vip_bg_image_quarter@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/vip_bg_image_quarter@2x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/vip_bg_image_quarter@2x.png new file mode 100644 index 0000000..259f74d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/vip_bg_image_quarter@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/vip_bg_image_quarter@3x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/vip_bg_image_quarter@3x.png new file mode 100644 index 0000000..fa2488d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_quarter.imageset/vip_bg_image_quarter@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/Contents.json new file mode 100644 index 0000000..141885a --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "vip_bg_image_week@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "vip_bg_image_week@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/vip_bg_image_week@2x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/vip_bg_image_week@2x.png new file mode 100644 index 0000000..4bc5e2f Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/vip_bg_image_week@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/vip_bg_image_week@3x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/vip_bg_image_week@3x.png new file mode 100644 index 0000000..c61ae21 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_week.imageset/vip_bg_image_week@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/Contents.json new file mode 100644 index 0000000..d270ad1 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "vip_bg_image_year@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "vip_bg_image_year@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/vip_bg_image_year@2x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/vip_bg_image_year@2x.png new file mode 100644 index 0000000..8e912e8 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/vip_bg_image_year@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/vip_bg_image_year@3x.png b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/vip_bg_image_year@3x.png new file mode 100644 index 0000000..bf8a6ec Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/vip_bg_image_year.imageset/vip_bg_image_year@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/Contents.json new file mode 100644 index 0000000..7910c8c --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "横间隔虚线@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "横间隔虚线@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/横间隔虚线@2x.png b/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/横间隔虚线@2x.png new file mode 100644 index 0000000..c49c71d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/横间隔虚线@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/横间隔虚线@3x.png b/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/横间隔虚线@3x.png new file mode 100644 index 0000000..2bb6562 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/横间隔虚线.imageset/横间隔虚线@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/Contents.json new file mode 100644 index 0000000..fa6d306 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "间隔线@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "间隔线@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/间隔线@2x.png b/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/间隔线@2x.png new file mode 100644 index 0000000..733e064 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/间隔线@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/间隔线@3x.png b/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/间隔线@3x.png new file mode 100644 index 0000000..7aa649f Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/store/间隔线.imageset/间隔线@3x.png differ diff --git a/SynthReel/Source/en.lproj/Localizable.strings b/SynthReel/Source/en.lproj/Localizable.strings index 5d0fb22..3b7efbe 100644 --- a/SynthReel/Source/en.lproj/Localizable.strings +++ b/SynthReel/Source/en.lproj/Localizable.strings @@ -26,6 +26,7 @@ "synthreel_about_us" = "About Us"; "synthreel_privacy_policy" = "Privacy Policy"; "synthreel_user_agreement" = "User Agreement"; +"synthreel_delet_account" = "Delet Account"; "synthreel_visit_website" = "visit website"; "Viral Hits" = "Viral Hits"; "Live Trending Rankings" = "Live Trending Rankings"; @@ -50,3 +51,42 @@ "buy_fail_toast_02" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series"; "Login With Facebook" = "Login With Facebook"; "Login With Apple" = "Login With Apple"; +"synthreel_store" = "store"; +"synthreel_restore" = "Restore"; +"store_title_1" = "Go Coins | Limited-time coin packs"; +"synthreel_weekly_refill" = "Weekly Refill"; +"w_complex" = "week"; +"m_complex" = "month"; +"q_complex" = "quarter"; +"Y_complex" = "year"; +"synthreel_weekly_vip" = "Weekly VIP"; +"synthreel_monthly_vip" = "Monthly VIP"; +"synthreel_quarterly_vip" = "Quarterly VIP"; +"synthreel_yearly_vip" = "Yearly VIP"; +"synthreel_viptitle" = "Go VIP | Auto renew, cancel anytime"; +"synthreel_tips" = "Tips"; +"store_tips" = "1. Coins are virtual items and cannot be refunded. Use it for this product.
2. Both the coins and the reward coins will never expire.
3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used.
4. The purchase has not been credited, click torefresh.
5. For other questions, contact us via Profile > Feedback."; +"synthreel_refills" = "Active Refills"; +"synthreel_rewards_overview" = "Rewards Overview"; +"synthreel_weekly_total" = "Weekly Total"; +"synthreel_claimable_coins" = "Claimable Coins"; +"synthreel_active_refills" = "Active Refills"; +"synthreel_claim_all" = "synthreel_claim_all"; +"synthreel_get_refill_button_text" = "Get a Refill to Claim"; +"coins_pack_tips_title" = "Subscription Rules"; +"synthreel_total_reward" = "Total Reward"; +"synthreel_remaining" = "Remaining"; +"synthreel_claim" = "Claim"; +"synthreel_claimd" = "Claimed"; +"synthreel_what_you_get" = "What You Get"; +"synthreel_bonus_you_get" = "Bonus You Get"; +"synthreel_weekly_refill_package" = "Weekly Refill Package"; +"synthreel_dailu_bonuses" = "Daily Bonuses"; +"synthreel_coin_bag_buy_tip_title" = "How Do I Receive Coins?"; +"synthreel_continue" = "Claim Now"; + +"coins_pack_tips" = "1.Coins are delivered instantly upon purchase.
2.Daily bonus coins available from the next day.
3.All coins will be revoked when the subscription expires, including both initial and daily coins."; + +"synthreel_price" = "price"; +"synthreel_balance" = "balance"; +"synthreel_continue" = "Claim Now";